Claude Cursor Skill

cordis-plugin-sofagent-evolve

经验沉淀——think.md 反思 + Dream Cycle + evolve + instinct→skill + refine(seam: turn/end)——桥接 @sofagent/think generateThinkEntry——DSH(DeepSeek Harness)cordis plugin。sofagent 约束层在 DeepSeek Harness 生态的插件形态。

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download KongFangXun-sofagent-engine_dsh-plugins_cordis-plugin-sofagent-evolve-b8c9032.zip · 8 KB
Part of kongfangxun/sofagent — 15 skills

Install

skills CLI npx skills add https://github.com/KongFangXun/sofagent/tree/main/engine/dsh-plugins/cordis-plugin-sofagent-evolve
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kongfangxun-sofagent@llmmart
Git git clone https://github.com/KongFangXun/sofagent.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole kongfangxun/sofagent collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

cordis-plugin-sofagent-evolve

经验沉淀——think.md 反思 + Dream Cycle + evolve + instinct→skill + refine(seam: session/event)——桥接 @sofagent/think generateThinkEntry

用途

装上之后:任务收尾自动写一条 think.md 反思条目。什么时候用:同一个坑反复踩、想让经验留下来被下次检索。

接入点(seam: session/event):桥接 @sofagent/think,缺依赖时该能力静默跳过;接入形态(声明 / 实现)见 SEAMS.md。

本插件随 sofagent 主线版本发布(SkillHub 通道:skillhub install cordis-plugin-sofagent-evolve 安装与检索;npm 通道未开通)。版本号与 sofagent 主线对齐。

相关链接

  • sofagent 主仓:https://github.com/KongFangXun/sofagent
  • 开发日志:docs/changelog/v1.4/v1.4.0.md(DSH 插件家族)
Files (sofagent)
  • src
    • index.test.ts 8.8 KB
      // ============================================================
      // cordis-plugin-evolve · 插件单测(v1.4.0 交付五 · v1.5.0 章十补接线面)
      // ============================================================
      
      import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
      import pluginDefault, { pluginMeta, capability, invoke } from './index';
      import { parseDiff, getDataDir } from '@sofagent/core';
      import { runRules } from '@sofagent/audit';
      import { generateThinkEntry } from '@sofagent/think';
      
      // 章十:沉淀链三源(parseDiff → runRules → generateThinkEntry)打桩成确定性替身——
      // 接线正确性 = 三源被调用的**顺序与参数**,与引擎内部实现无关(引擎自有其单测)。
      vi.mock('@sofagent/core', () => ({
        parseDiff: vi.fn(() => ['src/a.ts']),
        getDataDir: vi.fn(() => '/data/dir'),
      }));
      vi.mock('@sofagent/audit', () => ({
        runRules: vi.fn(async () => [{ rule: 'no-archaeology', pass: true }]),
      }));
      vi.mock('@sofagent/think', () => ({
        // 返回值须有定义:既有元数据用例用 `invoke()` 走同一桥接面(返回 undefined 会被判失败)
        generateThinkEntry: vi.fn(async () => ({ ok: true, entry: 'think-entry' })),
      }));
      
      describe('cordis-plugin-sofagent-evolve', () => {
        it('插件元数据完整(id/version/description/seam)', () => {
          expect(pluginMeta.id).toBe('cordis-plugin-sofagent-evolve');
          expect(pluginMeta.version).toBe(require('../package.json').version); // SSOT 对齐:版本跟随主版本(读 package.json)
          expect(pluginMeta.description.length).toBeGreaterThan(10);
          expect(pluginMeta.seam.length).toBeGreaterThan(0);
        });
      
        it('能力说明非空', () => {
          expect(capability.length).toBeGreaterThan(0);
        });
      
        it('invoke 可调用(成功或降级,不挂死)', async () => {
          const r = await invoke().catch((e) => e);
          expect(r).toBeDefined();
        });
      });
      
      // ─────────────────────────────────────────────────────────────────────────────
      // v1.5.0 章十 · seam 事件接线(seam 从声明到实现)
      // 断言面:① 订阅真实存在 ② disposer 收进复合卸载契约 ③ turn/end **真沉淀**
      //        ④ 其余会话事件 / 空 diff / 判定源缺席 → 零副作用(fail-open)
      // 🔴 关键形状:订阅点是 `session/event`(`turn/end` 是会话事件类型,由过滤条件承载),
      //    宿主/仓内都没有 ctx 级 `turn/end` 派发点——`ctx.on('turn/end')` 会永不触发。
      // ─────────────────────────────────────────────────────────────────────────────
      describe('章十 · seam 事件接线', () => {
        const MANIFEST = require('../../plugins.json') as {
          plugins: Array<{
            id: string;
            seamHandlers?: string[];
            bridges?: Array<{ pkg: string; api: string }>;
          }>;
        };
        const entry = MANIFEST.plugins.find((p) => p.id === 'cordis-plugin-sofagent-evolve');
        const declared: string[] = entry?.seamHandlers ?? [];
        const ONE = ['session/event'];
      
        const errSpy = () => vi.spyOn(console, 'error').mockImplementation(() => {});
      
        beforeEach(() => {
          vi.clearAllMocks();
          delete process.env.SOFAGENT_TASK;
          delete process.env.SOFAGENT_PROJECT_ROOT;
          vi.mocked(parseDiff).mockImplementation(() => ['src/a.ts']);
          vi.mocked(getDataDir).mockImplementation(() => '/data/dir');
          vi.mocked(runRules).mockImplementation(async () => [{ rule: 'no-archaeology', pass: true }]);
          vi.mocked(generateThinkEntry).mockImplementation(async () => ({ ok: true, entry: 'think-entry' }));
        });
        afterEach(() => {
          vi.restoreAllMocks();
          delete process.env.SOFAGENT_TASK;
          delete process.env.SOFAGENT_PROJECT_ROOT;
        });
      
        /** 宿主 ctx 替身:记录订阅名 + 保留 disposer */
        function hostCtx() {
          const subscribed = new Map<string, (...a: unknown[]) => unknown>();
          const disposed: string[] = [];
          const on = vi.fn((event: string, handler: (...a: unknown[]) => unknown) => {
            subscribed.set(event, handler);
            return () => {
              disposed.push(event);
            };
          });
          return { ctx: { provide: vi.fn(() => () => undefined), on }, subscribed, disposed };
        }
      
        const sessionOf = (cwd?: string) => ({ header: cwd === undefined ? {} : { cwd } });
      
        it('seamHandlers 与 plugins.json 声明同集合(三处对账的插件侧)', () => {
          expect(declared.slice().sort()).toEqual([...ONE].sort());
        });
      
        it('订阅名是 session/event 而非 turn/end(后者不是 ctx 派发点)', () => {
          expect(declared).toContain('session/event');
          expect(declared).not.toContain('turn/end');
        });
      
        it('bridges 声明覆盖沉淀链三源(parseDiff / runRules / generateThinkEntry)', () => {
          const keys = (entry?.bridges ?? []).map((b) => `${b.pkg}.${b.api}`).sort();
          expect(keys).toEqual(
            [
              '@sofagent/audit.runRules',
              '@sofagent/core.getDataDir',
              '@sofagent/core.parseDiff',
              '@sofagent/think.generateThinkEntry',
            ].sort(),
          );
        });
      
        it('apply 经 ctx.on 订阅 session/event;复合 disposer 逐个反注册', async () => {
          const spy = errSpy();
          const { ctx, subscribed, disposed } = hostCtx();
          const disposer = (pluginDefault.apply as (c: unknown) => unknown)(ctx) as
            | (() => Promise<void>)
            | undefined;
          expect([...subscribed.keys()].sort()).toEqual([...ONE].sort());
          expect(typeof disposer).toBe('function');
          await disposer!();
          expect(disposed.slice().sort()).toEqual([...ONE].sort());
          spy.mockRestore();
        });
      
        it('turn/end + 有变更:parseDiff → runRules → generateThinkEntry 逐参透传', async () => {
          const spy = errSpy();
          process.env.SOFAGENT_TASK = 'T-SEAM';
          const { ctx, subscribed } = hostCtx();
          (pluginDefault.apply as (c: unknown) => unknown)(ctx);
      
          await subscribed.get('session/event')!(sessionOf('/proj'), {
            type: 'turn/end',
            turn: 3,
            reason: 'stop',
          });
      
          expect(parseDiff).toHaveBeenCalledWith('HEAD', '/proj'); // session.header.cwd 优先
          expect(runRules).toHaveBeenCalledWith({ diffFiles: ['src/a.ts'], silent: true });
          expect(generateThinkEntry).toHaveBeenCalledWith(
            ['src/a.ts'],
            [{ rule: 'no-archaeology', pass: true }],
            'T-SEAM',
            { dataDir: '/data/dir' },
          );
          spy.mockRestore();
        });
      
        it('其余会话事件:零副作用(不进沉淀链)', async () => {
          const spy = errSpy();
          const { ctx, subscribed } = hostCtx();
          (pluginDefault.apply as (c: unknown) => unknown)(ctx);
          const handler = subscribed.get('session/event')!;
      
          await handler(sessionOf('/proj'), { type: 'turn/start', turn: 1 });
          await handler(sessionOf('/proj'), { type: 'message/added' });
          await handler(sessionOf('/proj'), undefined);
      
          expect(parseDiff).not.toHaveBeenCalled();
          expect(runRules).not.toHaveBeenCalled();
          expect(generateThinkEntry).not.toHaveBeenCalled();
          spy.mockRestore();
        });
      
        it('turn/end 但工作区无变更:不跑规则、不写沉淀(零副作用)', async () => {
          const spy = errSpy();
          vi.mocked(parseDiff).mockImplementation(() => []);
          const { ctx, subscribed } = hostCtx();
          (pluginDefault.apply as (c: unknown) => unknown)(ctx);
      
          await subscribed.get('session/event')!(sessionOf('/proj'), { type: 'turn/end', turn: 2 });
      
          expect(parseDiff).toHaveBeenCalledTimes(1);
          expect(runRules).not.toHaveBeenCalled();
          expect(generateThinkEntry).not.toHaveBeenCalled();
          spy.mockRestore();
        });
      
        it('diff 取数失败:不抛、不进入后续链路(fail-open,不影响 Turn 收尾)', async () => {
          const spy = errSpy();
          vi.mocked(parseDiff).mockImplementation(() => {
            throw new Error('git 不可用');
          });
          const { ctx, subscribed } = hostCtx();
          (pluginDefault.apply as (c: unknown) => unknown)(ctx);
      
          await expect(
            subscribed.get('session/event')!(sessionOf('/proj'), { type: 'turn/end', turn: 1 }),
          ).resolves.toBeUndefined();
          expect(runRules).not.toHaveBeenCalled();
          expect(generateThinkEntry).not.toHaveBeenCalled();
          spy.mockRestore();
        });
      
        it('数据目录解析失败:沉淀照跑(dataDir 交引擎兜底),不中断链', async () => {
          const spy = errSpy();
          vi.mocked(getDataDir).mockImplementation(() => {
            throw new Error('数据目录不可达');
          });
          const { ctx, subscribed } = hostCtx();
          (pluginDefault.apply as (c: unknown) => unknown)(ctx);
      
          await subscribed.get('session/event')!(sessionOf('/proj'), { type: 'turn/end', turn: 1 });
      
          expect(generateThinkEntry).toHaveBeenCalledWith(['src/a.ts'], expect.anything(), undefined, {
            dataDir: undefined,
          });
          spy.mockRestore();
        });
      });
      
    • index.ts 4.7 KB
      // cordis-plugin-sofagent-evolve · DSH 反向插件(v1.5.2:98 行样板收敛到 @sofagent/dsh-plugin-kit)
      // seam 挂载:session/event    # 语义:会话事件流中的 Turn 结束(turn/end)→ 经验沉淀(think.md 反思)
      // 清单生成源 = engine/dsh-plugins/plugins.json(生成 package.json 的 description/sofagent/dsh 段与 cordis.patch.yml);本文件的 seam 字面量由生成器 --check 与之对账。
      
      import {
        createSofagentPlugin,
        seamHelpers,
        type SeamHandler,
        type SeamHelpers,
      } from '@sofagent/dsh-plugin-kit';
      
      /** 一次性日志表(接线自证 / 降级提示只打一次) */
      const logged = new Set<string>();
      function logOnce(helpers: SeamHelpers, key: string, message: string): void {
        if (logged.has(key)) return;
        logged.add(key);
        helpers.log(message);
      }
      
      const errMsg = (err: unknown): string => (err instanceof Error ? err.message : String(err));
      
      /** 项目根:会话 header 的 cwd 优先,缺省进程工作目录 */
      function cwdOf(session: unknown): string {
        const cwd = (session as { header?: { cwd?: unknown } } | null | undefined)?.header?.cwd;
        if (typeof cwd === 'string' && cwd !== '') return cwd;
        return process.env.SOFAGENT_PROJECT_ROOT ?? process.cwd();
      }
      
      /** 数据目录:交给 @sofagent/core 自己的解析(与 MCP/CLI 同源) */
      async function resolveDataDir(helpers: SeamHelpers): Promise<string | undefined> {
        try {
          const dir = await helpers.call('@sofagent/core', 'getDataDir');
          return typeof dir === 'string' && dir !== '' ? dir : undefined;
        } catch (err) {
          helpers.log(`数据目录解析不可用(交引擎默认值):${errMsg(err)}`);
          return undefined;
        }
      }
      
      /**
       * seam 事件处理器(v1.5.0 章十)——`turn/end` 的**实现**(此前只有声明)。
       *
       * 🔴 订阅点是 `session/event`,不是 `turn/end`:宿主把 `turn/end` 作为**会话事件
       *    类型**发布(`session.append('turn/end', { turn, reason })` → 广播到
       *    `session/event`,listener 收到 `(session, event)`),仓内/宿主均无 ctx 级
       *    `turn/end` 派发点——`ctx.on('turn/end')` 会订阅到一个永不触发的事件名。
       *    故 seam 名与订阅名都写真实可订阅的 `session/event`,收尾语义由过滤条件承载。
       *
       * 判定逻辑零改动:diff 取数 / 规则运行 / 沉淀写入全部是既有 @public API
       * (`parseDiff` → `runRules` → `generateThinkEntry`),插件只做串联。
       * 空 diff 即返回(`generateThinkEntry` 自身也判空)——工作区干净时零副作用。
       */
      const seamHandlers: Record<string, SeamHandler> = {
        'session/event': async (...args: unknown[]) => {
          const helpers = seamHelpers(args);
          const [session, event] = args;
          const e = event as { type?: unknown } | null | undefined;
          if (e?.type !== 'turn/end') return; // 收尾过滤:其余会话事件不参与沉淀
          try {
            const root = cwdOf(session);
            const diffFiles = await helpers.call('@sofagent/core', 'parseDiff', 'HEAD', root);
            if (!Array.isArray(diffFiles) || diffFiles.length === 0) return; // 无变更不沉淀
            const results = await helpers.call('@sofagent/audit', 'runRules', {
              diffFiles,
              silent: true,
            });
            await helpers.call(
              '@sofagent/think',
              'generateThinkEntry',
              diffFiles,
              results,
              process.env.SOFAGENT_TASK,
              { dataDir: await resolveDataDir(helpers) },
            );
            logOnce(helpers, 'turn-end-sedimented', 'Turn 收尾经验沉淀已执行(think.md 反思条目)');
          } catch (err) {
            logOnce(helpers, 'turn-end-unavailable', `经验沉淀不可用(本次跳过,不影响 Turn 收尾):${errMsg(err)}`);
          }
        },
      };
      
      /** 插件声明(本文件唯一手写处;适配层红线由 kit 承担:ctx 鸭子类型 + 宿主 API 缺席降级不抛) */
      const kit = createSofagentPlugin(
        {
          id: 'cordis-plugin-sofagent-evolve',
          seam: 'session/event',
          seamSemantics: '会话事件流中的 Turn 结束(turn/end)→ 经验沉淀(think.md 反思)',
          capability: '进化能力(经验自动沉淀)',
          bridgePkg: '@sofagent/think',
          bridgeApi: 'generateThinkEntry',
          description: '经验沉淀——think.md 反思 + Dream Cycle + evolve + instinct→skill + refine',
          seamHandlers,
        },
        require('../package.json') as { version?: string },
      );
      
      export const pluginMeta = kit.pluginMeta; // 插件元数据(DSH profile/注册表消费)
      export const capability = kit.capability; // 依赖的 sofagent 能力说明(DSH skill 引导链展示)
      export const invoke = kit.invoke; // 桥接 @sofagent/* 公共 API(懒加载 + 降级不抛)
      export default kit.plugin; // DSH Cordis 插件契约(apply 三段式由 kit 提供)
      
  • cordis.patch.yml 592 B
    # sofagent cordis-plugin-sofagent-evolve bundle patch v1.5.2——注册为 DSH profile layer
    - insert:
        - id: sofagent-evolve
          name: 'cordis-plugin-sofagent-evolve'
          inject: [settings, dynamicCordisRunner]
          config:
            seam: "session/event"    # 语义:会话事件流中的 Turn 结束(turn/end)→ 经验沉淀(think.md 反思)
            description: "给宿主加上经验沉淀——任务收尾自动写 think.md 反思条目——桥接 @sofagent/think generateThinkEntry / @sofagent/core parseDiff / @sofagent/audit runRules / @sofagent/core getDataDir"
    
  • package.json 1.7 KB
    {
      "name": "cordis-plugin-sofagent-evolve",
      "version": "1.5.2",
      "engines": {
        "node": ">=18"
      },
      "description": "给宿主加上经验沉淀——任务收尾自动写 think.md 反思条目(seam: session/event)——桥接 @sofagent/think generateThinkEntry / @sofagent/core parseDiff / @sofagent/audit runRules / @sofagent/core getDataDir",
      "license": "MIT",
      "author": "KongFangXun",
      "main": "dist/index.js",
      "types": "dist/index.d.ts",
      "scripts": {
        "build": "tsc",
        "test": "vitest run src/index.test.ts"
      },
      "keywords": [
        "sofagent",
        "dsh",
        "cordis-plugin"
      ],
      "sofagent": {
        "type": "dsh-plugin",
        "family": "cordis",
        "seam": "session/event",
        "seamSemantics": "会话事件流中的 Turn 结束(turn/end)→ 经验沉淀(think.md 反思)",
        "seamHandlers": [
          "session/event"
        ]
      },
      "//optionalDependencies": "v1.4.5 T6 (R4):src/index.ts 惰性 await import(懒加载 + 缺依赖降级不抛;v1.4.8 起该样板由 @sofagent/dsh-plugin-kit 统一封装;v1.4.9 P2 起厚插件多包 bridges 按序解析、部分可用即部分成功),此前未声明任何依赖——对齐 root package.json F-18 optionalDependencies 先例。",
      "optionalDependencies": {
        "@sofagent/think": "1.5.2",
        "@sofagent/core": "1.5.2",
        "@sofagent/audit": "1.5.2"
      },
      "devDependencies": {
        "typescript": "^7.0.2",
        "vitest": "^5.0.0"
      },
      "dsh": {
        "bundle": {
          "patch": "./cordis.patch.yml"
        }
      },
      "files": [
        "dist/",
        "cordis.patch.yml",
        "SKILL.md",
        "!dist/**/*.js.map",
        "!dist/**/*.d.ts.map",
        "!dist/**/*.test.*"
      ],
      "dependencies": {
        "@sofagent/dsh-plugin-kit": "1.5.2"
      }
    }
    
  • SKILL.md 1.3 KB
    ---
    name: cordis-plugin-sofagent-evolve
    slug: cordis-plugin-sofagent-evolve
    version: 1.5.2
    displayName: cordis-plugin-sofagent-evolve
    description: >
      经验沉淀——think.md 反思 + Dream Cycle + evolve + instinct→skill + refine(seam: session/event)——桥接 @sofagent/think generateThinkEntry——DSH(DeepSeek Harness)cordis plugin。sofagent 约束层在 DeepSeek Harness 生态的插件形态。
    ---
    
    # cordis-plugin-sofagent-evolve
    
    经验沉淀——think.md 反思 + Dream Cycle + evolve + instinct→skill + refine(seam: session/event)——桥接 @sofagent/think generateThinkEntry
    
    ## 用途
    
    **装上之后**:任务收尾自动写一条 think.md 反思条目。**什么时候用**:同一个坑反复踩、想让经验留下来被下次检索。
    
    **接入点**(seam: session/event):桥接 `@sofagent/think`,缺依赖时该能力静默跳过;接入形态(声明 / 实现)见 [SEAMS.md](../SEAMS.md)。
    
    本插件随 sofagent 主线版本发布(SkillHub 通道:`skillhub install cordis-plugin-sofagent-evolve` 安装与检索;npm 通道未开通)。版本号与 sofagent 主线对齐。
    
    ## 相关链接
    
    - sofagent 主仓:https://github.com/KongFangXun/sofagent
    - 开发日志:docs/changelog/v1.4/v1.4.0.md(DSH 插件家族)
    
  • tsconfig.json 185 B
    {
      "extends": "../tsconfig.base.json",
      "compilerOptions": {
        "rootDir": "src",
        "outDir": "dist"
      },
      "include": [
        "src"
      ],
      "exclude": [
        "src/**/*.test.ts"
      ]
    }
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related