flavor-code 1.2.11 → 1.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +39 -35
  2. package/README.zh-CN.md +39 -35
  3. package/dist/{app-MXWPZBEU.js → app-UJAGMKD5.js} +6 -4
  4. package/dist/astgraph/db.mjs +237 -0
  5. package/dist/astgraph/extract.mjs +239 -0
  6. package/dist/astgraph/flavor-plugin.json +25 -0
  7. package/dist/astgraph/grammars.mjs +68 -0
  8. package/dist/astgraph/index.js +301 -0
  9. package/dist/astgraph/indexer.mjs +175 -0
  10. package/dist/astgraph/query.mjs +165 -0
  11. package/dist/astgraph/resolve.mjs +93 -0
  12. package/dist/astgraph/vendor/tree-sitter-javascript.wasm +0 -0
  13. package/dist/astgraph/vendor/tree-sitter-tsx.wasm +0 -0
  14. package/dist/astgraph/vendor/tree-sitter-typescript.wasm +0 -0
  15. package/dist/astgraph/vendor/tree-sitter.js +3980 -0
  16. package/dist/astgraph/vendor/tree-sitter.wasm +0 -0
  17. package/dist/astgraph/vendor/zod/LICENSE +21 -0
  18. package/dist/astgraph/vendor/zod/index.js +4 -0
  19. package/dist/astgraph/vendor/zod/locales/index.js +1 -0
  20. package/dist/astgraph/vendor/zod/locales/package.json +7 -0
  21. package/dist/astgraph/vendor/zod/package.json +135 -0
  22. package/dist/astgraph/vendor/zod/v4/classic/checks.js +1 -0
  23. package/dist/astgraph/vendor/zod/v4/classic/coerce.js +17 -0
  24. package/dist/astgraph/vendor/zod/v4/classic/compat.js +31 -0
  25. package/dist/astgraph/vendor/zod/v4/classic/errors.js +48 -0
  26. package/dist/astgraph/vendor/zod/v4/classic/external.js +20 -0
  27. package/dist/astgraph/vendor/zod/v4/classic/from-json-schema.js +599 -0
  28. package/dist/astgraph/vendor/zod/v4/classic/index.js +4 -0
  29. package/dist/astgraph/vendor/zod/v4/classic/iso.js +30 -0
  30. package/dist/astgraph/vendor/zod/v4/classic/package.json +7 -0
  31. package/dist/astgraph/vendor/zod/v4/classic/parse.js +15 -0
  32. package/dist/astgraph/vendor/zod/v4/classic/schemas.js +1395 -0
  33. package/dist/astgraph/vendor/zod/v4/core/api.js +1087 -0
  34. package/dist/astgraph/vendor/zod/v4/core/checks.js +575 -0
  35. package/dist/astgraph/vendor/zod/v4/core/core.js +78 -0
  36. package/dist/astgraph/vendor/zod/v4/core/doc.js +35 -0
  37. package/dist/astgraph/vendor/zod/v4/core/errors.js +185 -0
  38. package/dist/astgraph/vendor/zod/v4/core/index.js +16 -0
  39. package/dist/astgraph/vendor/zod/v4/core/json-schema-generator.js +95 -0
  40. package/dist/astgraph/vendor/zod/v4/core/json-schema-processors.js +601 -0
  41. package/dist/astgraph/vendor/zod/v4/core/json-schema.js +1 -0
  42. package/dist/astgraph/vendor/zod/v4/core/package.json +7 -0
  43. package/dist/astgraph/vendor/zod/v4/core/parse.js +93 -0
  44. package/dist/astgraph/vendor/zod/v4/core/regexes.js +139 -0
  45. package/dist/astgraph/vendor/zod/v4/core/registries.js +51 -0
  46. package/dist/astgraph/vendor/zod/v4/core/schemas.js +2239 -0
  47. package/dist/astgraph/vendor/zod/v4/core/standard-schema.js +1 -0
  48. package/dist/astgraph/vendor/zod/v4/core/to-json-schema.js +448 -0
  49. package/dist/astgraph/vendor/zod/v4/core/util.js +674 -0
  50. package/dist/astgraph/vendor/zod/v4/core/versions.js +5 -0
  51. package/dist/astgraph/vendor/zod/v4/index.js +3 -0
  52. package/dist/astgraph/vendor/zod/v4/locales/ar.js +106 -0
  53. package/dist/astgraph/vendor/zod/v4/locales/az.js +105 -0
  54. package/dist/astgraph/vendor/zod/v4/locales/be.js +156 -0
  55. package/dist/astgraph/vendor/zod/v4/locales/bg.js +120 -0
  56. package/dist/astgraph/vendor/zod/v4/locales/ca.js +107 -0
  57. package/dist/astgraph/vendor/zod/v4/locales/cs.js +111 -0
  58. package/dist/astgraph/vendor/zod/v4/locales/da.js +115 -0
  59. package/dist/astgraph/vendor/zod/v4/locales/de.js +108 -0
  60. package/dist/astgraph/vendor/zod/v4/locales/el.js +109 -0
  61. package/dist/astgraph/vendor/zod/v4/locales/en.js +113 -0
  62. package/dist/astgraph/vendor/zod/v4/locales/eo.js +109 -0
  63. package/dist/astgraph/vendor/zod/v4/locales/es.js +132 -0
  64. package/dist/astgraph/vendor/zod/v4/locales/fa.js +114 -0
  65. package/dist/astgraph/vendor/zod/v4/locales/fi.js +112 -0
  66. package/dist/astgraph/vendor/zod/v4/locales/fr-CA.js +107 -0
  67. package/dist/astgraph/vendor/zod/v4/locales/fr.js +125 -0
  68. package/dist/astgraph/vendor/zod/v4/locales/he.js +214 -0
  69. package/dist/astgraph/vendor/zod/v4/locales/hr.js +122 -0
  70. package/dist/astgraph/vendor/zod/v4/locales/hu.js +108 -0
  71. package/dist/astgraph/vendor/zod/v4/locales/hy.js +147 -0
  72. package/dist/astgraph/vendor/zod/v4/locales/id.js +106 -0
  73. package/dist/astgraph/vendor/zod/v4/locales/index.js +52 -0
  74. package/dist/astgraph/vendor/zod/v4/locales/is.js +109 -0
  75. package/dist/astgraph/vendor/zod/v4/locales/it.js +108 -0
  76. package/dist/astgraph/vendor/zod/v4/locales/ja.js +107 -0
  77. package/dist/astgraph/vendor/zod/v4/locales/ka.js +112 -0
  78. package/dist/astgraph/vendor/zod/v4/locales/kh.js +5 -0
  79. package/dist/astgraph/vendor/zod/v4/locales/km.js +110 -0
  80. package/dist/astgraph/vendor/zod/v4/locales/ko.js +111 -0
  81. package/dist/astgraph/vendor/zod/v4/locales/lt.js +203 -0
  82. package/dist/astgraph/vendor/zod/v4/locales/mk.js +109 -0
  83. package/dist/astgraph/vendor/zod/v4/locales/ms.js +107 -0
  84. package/dist/astgraph/vendor/zod/v4/locales/nl.js +110 -0
  85. package/dist/astgraph/vendor/zod/v4/locales/no.js +108 -0
  86. package/dist/astgraph/vendor/zod/v4/locales/ota.js +109 -0
  87. package/dist/astgraph/vendor/zod/v4/locales/package.json +7 -0
  88. package/dist/astgraph/vendor/zod/v4/locales/pl.js +109 -0
  89. package/dist/astgraph/vendor/zod/v4/locales/ps.js +114 -0
  90. package/dist/astgraph/vendor/zod/v4/locales/pt.js +108 -0
  91. package/dist/astgraph/vendor/zod/v4/locales/ro.js +119 -0
  92. package/dist/astgraph/vendor/zod/v4/locales/ru.js +156 -0
  93. package/dist/astgraph/vendor/zod/v4/locales/sl.js +109 -0
  94. package/dist/astgraph/vendor/zod/v4/locales/sv.js +110 -0
  95. package/dist/astgraph/vendor/zod/v4/locales/ta.js +110 -0
  96. package/dist/astgraph/vendor/zod/v4/locales/th.js +110 -0
  97. package/dist/astgraph/vendor/zod/v4/locales/tr.js +105 -0
  98. package/dist/astgraph/vendor/zod/v4/locales/ua.js +5 -0
  99. package/dist/astgraph/vendor/zod/v4/locales/uk.js +108 -0
  100. package/dist/astgraph/vendor/zod/v4/locales/ur.js +110 -0
  101. package/dist/astgraph/vendor/zod/v4/locales/uz.js +110 -0
  102. package/dist/astgraph/vendor/zod/v4/locales/vi.js +108 -0
  103. package/dist/astgraph/vendor/zod/v4/locales/yo.js +107 -0
  104. package/dist/astgraph/vendor/zod/v4/locales/zh-CN.js +109 -0
  105. package/dist/astgraph/vendor/zod/v4/locales/zh-TW.js +107 -0
  106. package/dist/astgraph/vendor/zod/v4/mini/checks.js +1 -0
  107. package/dist/astgraph/vendor/zod/v4/mini/coerce.js +22 -0
  108. package/dist/astgraph/vendor/zod/v4/mini/external.js +14 -0
  109. package/dist/astgraph/vendor/zod/v4/mini/index.js +3 -0
  110. package/dist/astgraph/vendor/zod/v4/mini/iso.js +34 -0
  111. package/dist/astgraph/vendor/zod/v4/mini/package.json +7 -0
  112. package/dist/astgraph/vendor/zod/v4/mini/parse.js +1 -0
  113. package/dist/astgraph/vendor/zod/v4/mini/schemas.js +961 -0
  114. package/dist/astgraph/vendor/zod/v4/package.json +7 -0
  115. package/dist/{chunk-OT5XIN6G.js → chunk-4YXDGGIC.js} +4763 -3763
  116. package/dist/{chunk-XFCJXRJ2.js → chunk-IG4Z23CL.js} +6 -0
  117. package/dist/{chunk-EY6KE7L2.js → chunk-KL6TR2KG.js} +1 -1
  118. package/dist/cli.js +5 -5
  119. package/dist/config/schema.d.ts +6 -0
  120. package/dist/desktop/main.js +5028 -4023
  121. package/dist/desktop-renderer/assets/{index-sgEm4kjf.js → index-CcD0D6x0.js} +2 -2
  122. package/dist/desktop-renderer/index.html +1 -1
  123. package/dist/evolve/loader.d.ts +21 -0
  124. package/dist/evolve/service.d.ts +37 -0
  125. package/dist/evolve/store.d.ts +91 -0
  126. package/dist/hooks/types.d.ts +5 -1
  127. package/dist/init/project.d.ts +8 -0
  128. package/dist/{load-6ZMEBHSG.js → load-GKA7P6RJ.js} +1 -1
  129. package/dist/models/structured.d.ts +14 -0
  130. package/dist/permissions/engine.d.ts +2 -0
  131. package/dist/plugins/host.d.ts +9 -0
  132. package/dist/plugins/types.d.ts +3 -2
  133. package/dist/sdk/index.js +3 -3
  134. package/dist/tools/shell.d.ts +14 -1
  135. package/dist/tools/types.d.ts +2 -0
  136. package/dist/ui/commands.d.ts +5 -2
  137. package/dist/ui/session.d.ts +5 -1
  138. package/package.json +5 -3
  139. package//346/212/200/346/234/257/346/226/271/346/241/210/346/212/245/345/221/212.md +303 -1
package/README.md CHANGED
@@ -35,7 +35,9 @@ Flavor Code connects to OpenAI, Anthropic, or compatible services and works with
35
35
  | 🧭 | **Controlled progress on complex tasks** | Task plans, sub-agents, steering, follow-ups, `/loop`, and `/goal` |
36
36
  | ⏪ | **Traceable, resumable results** | Full timeline, checkpoints, rewind, traces, diffs, and failure audits |
37
37
  | 🧠 | **Local long-term context** | Memory, Skills, plugins, and project guides stored on your machine |
38
+ | 🔎 | **Code graph navigation** | A local AST code-graph index (`.flavor/astgraph/`) powers `ast_search`/`ast_callers`/`ast_impact` queries for precise symbol lookup and reachability tracing |
38
39
  | 🎨 | **E2E requirement-to-delivery** | From a rough requirement or a design export to a delivered product: PRD, interactive prototype, visual implementation, API integration, autonomous acceptance, and scored delivery (Electron only) |
40
+ | 🔁 | **Bounded self-improvement** | Repeated tool failures are captured, deduped, and proposed as suggestions; fixes ship as plugins that must pass sandbox verification and the test suite before hot-reload (`/evolve`) |
39
41
  | 🛡️ | **Clear permission boundaries** | Independent control over read, write, Shell, network, and destructive actions; Docker supported |
40
42
 
41
43
  ## Quick Start
@@ -152,41 +154,42 @@ Common commands:
152
154
  | `/memory`, `/remember`, `/forget`, `/forget-cold` | Manage long-term memory; `/forget-cold` purges cold entries and their files |
153
155
  | `/mcp` | View and manage MCP servers |
154
156
  | `/loop <goal>` | Run an autonomous loop with verification |
155
- | `/goal <objective>` | Run the plan, execute, adversarial-review workflow |
156
- | `/pals`, `/chat`, `/co-work` | Discover and collaborate with other local CLI instances |
157
- | `/audit` | View tool failure audits |
158
-
159
- You can submit steering or queue follow-ups while a run is in progress; once the current model response finishes, the task picks up new instructions at safe boundaries.
160
-
161
- #### CLI pals and cross-project work
162
-
163
- Interactive CLI instances on the same Windows or macOS user account can collaborate over local-only IPC (Windows named pipes or Unix sockets; no TCP fallback). Give each window a memorable alias:
164
-
165
- ```bash
166
- # terminal A, in project A
167
- flavor --pal-name A
168
-
169
- # terminal B, in project B
170
- flavor --pal-name B
171
- ```
172
-
173
- Useful commands:
174
-
175
- ```text
176
- /pals # aliases and per-process UUIDs
177
- /pals --verbose # also show project paths and timestamps
178
- /pals rename api # rename this active instance
179
- /chat B Update the API and tests # deliver to B and start its agent safely
180
- /co-work B Upgrade B, then adapt A # negotiate one plan before parallel work
181
- /co-work status [co-work-uuid]
182
- /co-work cancel <co-work-uuid> [reason]
183
- ```
184
-
185
- `/chat` is bidirectional and task-oriented. If B is idle, the attributed message starts a normal model turn; if B is already running, it becomes steering, or a follow-up when another local submission is pending. Remote text is converted to a safe non-slash prompt, so `/exit`-like text is not dispatched as a local command. B can answer with `/chat A ...`.
186
-
187
- `/co-work` first places both agents in planning and waits for both to accept the same hashed plan and declare READY. Early READY intents are retained, and only the broker's exactly-once START event opens parallel execution. Each agent works only in its own project, receives only its assigned tasks, and reports bounded completion evidence. The broker-selected integration owner verifies all assertions and emits END or FAIL through `CoWorkIntegrate`. Communication uses authenticated, bounded local IPC with no TCP listener; peer input cannot approve tools or access the other workspace. UUID/alias routing and the protocol already support a third active client; durable artifact exchange, broker-restart journaling/recovery, and large-group coordination are later hardening work. See the [CLI pals specification](./docs/specs/2026-08-14-cli-pals-cowork.md).
188
-
189
- ### Electron Desktop
157
+ | `/goal <objective>` | Run the plan, execute, adversarial-review workflow |
158
+ | `/evolve <signals\|suggest\|improve ...>` | Self-improvement loop: review repeated tool failures, scaffold fix plugins, verify and hot-reload them |
159
+ | `/pals`, `/chat`, `/co-work` | Discover and collaborate with other local CLI instances |
160
+ | `/audit` | View tool failure audits |
161
+
162
+ You can submit steering or queue follow-ups while a run is in progress; once the current model response finishes, the task picks up new instructions at safe boundaries.
163
+
164
+ #### CLI pals and cross-project work
165
+
166
+ Interactive CLI instances on the same Windows or macOS user account can collaborate over local-only IPC (Windows named pipes or Unix sockets; no TCP fallback). Give each window a memorable alias:
167
+
168
+ ```bash
169
+ # terminal A, in project A
170
+ flavor --pal-name A
171
+
172
+ # terminal B, in project B
173
+ flavor --pal-name B
174
+ ```
175
+
176
+ Useful commands:
177
+
178
+ ```text
179
+ /pals # aliases and per-process UUIDs
180
+ /pals --verbose # also show project paths and timestamps
181
+ /pals rename api # rename this active instance
182
+ /chat B Update the API and tests # deliver to B and start its agent safely
183
+ /co-work B Upgrade B, then adapt A # negotiate one plan before parallel work
184
+ /co-work status [co-work-uuid]
185
+ /co-work cancel <co-work-uuid> [reason]
186
+ ```
187
+
188
+ `/chat` is bidirectional and task-oriented. If B is idle, the attributed message starts a normal model turn; if B is already running, it becomes steering, or a follow-up when another local submission is pending. Remote text is converted to a safe non-slash prompt, so `/exit`-like text is not dispatched as a local command. B can answer with `/chat A ...`.
189
+
190
+ `/co-work` first places both agents in planning and waits for both to accept the same hashed plan and declare READY. Early READY intents are retained, and only the broker's exactly-once START event opens parallel execution. Each agent works only in its own project, receives only its assigned tasks, and reports bounded completion evidence. The broker-selected integration owner verifies all assertions and emits END or FAIL through `CoWorkIntegrate`. Communication uses authenticated, bounded local IPC with no TCP listener; peer input cannot approve tools or access the other workspace. UUID/alias routing and the protocol already support a third active client; durable artifact exchange, broker-restart journaling/recovery, and large-group coordination are later hardening work. See the [CLI pals specification](./docs/specs/2026-08-14-cli-pals-cowork.md).
191
+
192
+ ### Electron Desktop
190
193
 
191
194
  ```bash
192
195
  npm run desktop:dev # dev mode
@@ -260,6 +263,7 @@ Project runtime data lives under `.flavor/`:
260
263
  ├── memory/ # Long-term memory
261
264
  ├── traces/ # Optional execution traces
262
265
  ├── audit.jsonl # Tool failure audits
266
+ ├── evolve/ # Self-improvement signals and run reflections
263
267
  ├── skills/ # Project skills
264
268
  └── plugins/ # Project plugins
265
269
  ```
package/README.zh-CN.md CHANGED
@@ -35,7 +35,9 @@ Flavor Code 接入 OpenAI、Anthropic 或兼容服务,在受控工作区内使
35
35
  | 🧭 | **复杂任务可控推进** | 任务计划、子 Agent、steering、follow-up、`/loop` 和 `/goal` |
36
36
  | ⏪ | **结果可追溯、可恢复** | 完整时间线、checkpoint、rewind、trace、Diff 和失败审计 |
37
37
  | 🧠 | **本地长期上下文** | 记忆、Skill、插件和项目指南均保存在本机 |
38
+ | 🔎 | **代码图导航** | 本地 AST 代码图索引(`.flavor/astgraph/`),通过 `ast_search`/`ast_callers`/`ast_impact` 等查询精确定位符号、追踪可达性 |
38
39
  | 🎨 | **E2E 需求到交付** | 从粗需求或设计稿到可交付产品:PRD、交互原型、视觉还原、接口联调、自主验收与评分交付(仅 Electron) |
40
+ | 🔁 | **有界自进化** | 重复的工具失败被捕获、去重并形成建议;修复以插件形式落地,必须通过沙箱验证与测试套件后才能热重载(`/evolve`) |
39
41
  | 🛡️ | **明确的权限边界** | 分别控制读、写、Shell、网络和破坏性操作,也可使用 Docker |
40
42
 
41
43
  ## 快速开始
@@ -152,41 +154,42 @@ OAuth PKCE 的运行时行为与配置约定见 [PKCE 规范](./docs/specs/pkce-
152
154
  | `/memory`、`/remember`、`/forget`、`/forget-cold` | 管理长期记忆;`/forget-cold` 清空 cold 记忆及其文件 |
153
155
  | `/mcp` | 查看和管理 MCP 服务 |
154
156
  | `/loop <goal>` | 运行带验证的自治循环 |
155
- | `/goal <objective>` | 运行规划、执行、对抗审查流程 |
156
- | `/pals`、`/chat`、`/co-work` | 发现并协作其他本机 CLI 实例 |
157
- | `/audit` | 查看工具失败审计 |
158
-
159
- 运行中可以提交 steering 或排队 follow-up;当前模型响应结束后,任务会在安全边界处接收新指令。
160
-
161
- #### CLI Pals 与跨项目协作
162
-
163
- 同一 Windows 或 macOS 用户下的交互式 CLI 可以通过纯本地 IPC 协作(Windows named pipe 或 Unix socket,不回退到 TCP)。先给每个窗口一个容易识别的别名:
164
-
165
- ```bash
166
- # 终端 A,位于项目 A
167
- flavor --pal-name A
168
-
169
- # 终端 B,位于项目 B
170
- flavor --pal-name B
171
- ```
172
-
173
- 常用命令:
174
-
175
- ```text
176
- /pals # 查看别名和每进程 UUID
177
- /pals --verbose # 额外显示项目路径和时间
178
- /pals rename api # 重命名当前活动实例
179
- /chat B 更新 API 和测试 # 投递给 B,并安全启动其 Agent
180
- /co-work B 先升级 B,再兼容 A # 先协商同一计划,再并行开工
181
- /co-work status [co-work-uuid]
182
- /co-work cancel <co-work-uuid> [reason]
183
- ```
184
-
185
- `/chat` 支持双向任务通信。B 空闲时,带来源标识的消息会启动正常模型回合;B 正在运行时,消息会成为 steering;已有本地提交待运行时则成为 follow-up。远端文本会转换成安全的非斜杠 prompt,因此 `/exit` 一类文本不会被当成本地命令分派。B 可以用 `/chat A ...` 回复。
186
-
187
- `/co-work` 会先让双方进入规划,等待双方接受同一个哈希计划并声明 READY;较早的 READY 意图会被保留,只有 broker 恰好一次的 START 事件才会放行并行执行。每个 Agent 只在自己的项目内工作,只接收分配给自己的任务,并提交有界的完成证据。broker 指定的集成负责人会检查所有断言,再通过 `CoWorkIntegrate` 广播 END 或 FAIL。通信使用经过认证、有大小上限的本机 IPC,不开放 TCP 监听;peer 输入不能代替本机工具审批,也不能访问另一工作区。UUID/别名路由和协议已能支持第三个活动实例;持久化成果物交换、broker 重启日志与恢复、大规模多方协调属于后续强化。详见 [CLI Pals 规范](./docs/specs/2026-08-14-cli-pals-cowork.md)。
188
-
189
- ### Electron 桌面端
157
+ | `/goal <objective>` | 运行规划、执行、对抗审查流程 |
158
+ | `/evolve <signals\|suggest\|improve ...>` | 自进化循环:查看重复工具失败、脚手架修复插件、验证并热重载 |
159
+ | `/pals`、`/chat`、`/co-work` | 发现并协作其他本机 CLI 实例 |
160
+ | `/audit` | 查看工具失败审计 |
161
+
162
+ 运行中可以提交 steering 或排队 follow-up;当前模型响应结束后,任务会在安全边界处接收新指令。
163
+
164
+ #### CLI Pals 与跨项目协作
165
+
166
+ 同一 Windows 或 macOS 用户下的交互式 CLI 可以通过纯本地 IPC 协作(Windows named pipe 或 Unix socket,不回退到 TCP)。先给每个窗口一个容易识别的别名:
167
+
168
+ ```bash
169
+ # 终端 A,位于项目 A
170
+ flavor --pal-name A
171
+
172
+ # 终端 B,位于项目 B
173
+ flavor --pal-name B
174
+ ```
175
+
176
+ 常用命令:
177
+
178
+ ```text
179
+ /pals # 查看别名和每进程 UUID
180
+ /pals --verbose # 额外显示项目路径和时间
181
+ /pals rename api # 重命名当前活动实例
182
+ /chat B 更新 API 和测试 # 投递给 B,并安全启动其 Agent
183
+ /co-work B 先升级 B,再兼容 A # 先协商同一计划,再并行开工
184
+ /co-work status [co-work-uuid]
185
+ /co-work cancel <co-work-uuid> [reason]
186
+ ```
187
+
188
+ `/chat` 支持双向任务通信。B 空闲时,带来源标识的消息会启动正常模型回合;B 正在运行时,消息会成为 steering;已有本地提交待运行时则成为 follow-up。远端文本会转换成安全的非斜杠 prompt,因此 `/exit` 一类文本不会被当成本地命令分派。B 可以用 `/chat A ...` 回复。
189
+
190
+ `/co-work` 会先让双方进入规划,等待双方接受同一个哈希计划并声明 READY;较早的 READY 意图会被保留,只有 broker 恰好一次的 START 事件才会放行并行执行。每个 Agent 只在自己的项目内工作,只接收分配给自己的任务,并提交有界的完成证据。broker 指定的集成负责人会检查所有断言,再通过 `CoWorkIntegrate` 广播 END 或 FAIL。通信使用经过认证、有大小上限的本机 IPC,不开放 TCP 监听;peer 输入不能代替本机工具审批,也不能访问另一工作区。UUID/别名路由和协议已能支持第三个活动实例;持久化成果物交换、broker 重启日志与恢复、大规模多方协调属于后续强化。详见 [CLI Pals 规范](./docs/specs/2026-08-14-cli-pals-cowork.md)。
191
+
192
+ ### Electron 桌面端
190
193
 
191
194
  ```bash
192
195
  npm run desktop:dev # 开发模式
@@ -260,6 +263,7 @@ Skill 是带有 YAML 头信息的 `SKILL.md`,放在 `.flavor/skills/<name>/`
260
263
  ├── memory/ # 长期记忆
261
264
  ├── traces/ # 可选执行 trace
262
265
  ├── audit.jsonl # 工具失败审计
266
+ ├── evolve/ # 自进化信号与运行评估记录
263
267
  ├── skills/ # 项目 Skill
264
268
  └── plugins/ # 项目插件
265
269
  ```
@@ -15,8 +15,8 @@ import {
15
15
  packageVersion,
16
16
  redactErrorText,
17
17
  transcriptReducer
18
- } from "./chunk-OT5XIN6G.js";
19
- import "./chunk-XFCJXRJ2.js";
18
+ } from "./chunk-4YXDGGIC.js";
19
+ import "./chunk-IG4Z23CL.js";
20
20
  import {
21
21
  Box_default,
22
22
  ClockContext,
@@ -1249,8 +1249,10 @@ function buildSlashCandidates(commands, plugins, skills) {
1249
1249
  for (const command of commands) {
1250
1250
  candidates.set(command.name, { name: command.name, kind: "command", description: command.description });
1251
1251
  }
1252
- for (const name of plugins) {
1253
- if (!candidates.has(name)) candidates.set(name, { name, kind: "plugin" });
1252
+ for (const plugin of plugins) {
1253
+ if (!candidates.has(plugin.name)) {
1254
+ candidates.set(plugin.name, plugin.description === void 0 ? { name: plugin.name, kind: "plugin" } : { name: plugin.name, kind: "plugin", description: plugin.description });
1255
+ }
1254
1256
  }
1255
1257
  for (const skill of skills) {
1256
1258
  if (!candidates.has(skill.name)) {
@@ -0,0 +1,237 @@
1
+ // astgraph graph database — SQLite-backed node/edge graph (codegraph-inspired).
2
+ // Uses node:sqlite with WAL mode so concurrent readers never block on a writer.
3
+
4
+ import { mkdirSync } from "node:fs";
5
+ import { dirname } from "node:path";
6
+ import { DatabaseSync } from "node:sqlite";
7
+
8
+ const SCHEMA = `
9
+ CREATE TABLE IF NOT EXISTS schema_versions (
10
+ version INTEGER PRIMARY KEY,
11
+ applied_at INTEGER NOT NULL,
12
+ description TEXT
13
+ );
14
+
15
+ CREATE TABLE IF NOT EXISTS files (
16
+ path TEXT PRIMARY KEY,
17
+ content_hash TEXT NOT NULL,
18
+ language TEXT NOT NULL,
19
+ size INTEGER NOT NULL,
20
+ modified_at INTEGER NOT NULL DEFAULT 0,
21
+ indexed_at INTEGER NOT NULL DEFAULT 0,
22
+ node_count INTEGER NOT NULL DEFAULT 0
23
+ );
24
+
25
+ CREATE TABLE IF NOT EXISTS nodes (
26
+ id TEXT PRIMARY KEY,
27
+ kind TEXT NOT NULL,
28
+ name TEXT NOT NULL,
29
+ qualified_name TEXT NOT NULL,
30
+ file_path TEXT NOT NULL,
31
+ language TEXT NOT NULL,
32
+ start_line INTEGER NOT NULL,
33
+ end_line INTEGER NOT NULL,
34
+ signature TEXT,
35
+ docstring TEXT,
36
+ is_exported INTEGER NOT NULL DEFAULT 0,
37
+ is_async INTEGER NOT NULL DEFAULT 0
38
+ );
39
+
40
+ CREATE TABLE IF NOT EXISTS edges (
41
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
42
+ source TEXT NOT NULL,
43
+ target TEXT NOT NULL,
44
+ kind TEXT NOT NULL,
45
+ line INTEGER,
46
+ col INTEGER,
47
+ FOREIGN KEY (source) REFERENCES nodes(id) ON DELETE CASCADE,
48
+ FOREIGN KEY (target) REFERENCES nodes(id) ON DELETE CASCADE
49
+ );
50
+
51
+ CREATE TABLE IF NOT EXISTS unresolved_refs (
52
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
53
+ from_node_id TEXT,
54
+ reference_name TEXT NOT NULL,
55
+ reference_kind TEXT NOT NULL,
56
+ line INTEGER NOT NULL,
57
+ col INTEGER NOT NULL,
58
+ file_path TEXT NOT NULL DEFAULT '',
59
+ module_specifier TEXT,
60
+ status TEXT NOT NULL DEFAULT 'pending',
61
+ FOREIGN KEY (from_node_id) REFERENCES nodes(id) ON DELETE CASCADE
62
+ );
63
+
64
+ CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);
65
+ CREATE INDEX IF NOT EXISTS idx_nodes_lower_name ON nodes(lower(name));
66
+ CREATE INDEX IF NOT EXISTS idx_nodes_file_path ON nodes(file_path);
67
+ CREATE INDEX IF NOT EXISTS idx_nodes_kind ON nodes(kind);
68
+ CREATE INDEX IF NOT EXISTS idx_edges_source_kind ON edges(source, kind);
69
+ CREATE INDEX IF NOT EXISTS idx_edges_target_kind ON edges(target, kind);
70
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_edges_identity
71
+ ON edges(source, target, kind, IFNULL(line, -1), IFNULL(col, -1));
72
+ CREATE INDEX IF NOT EXISTS idx_unresolved_from ON unresolved_refs(from_node_id);
73
+ CREATE INDEX IF NOT EXISTS idx_unresolved_name ON unresolved_refs(reference_name);
74
+
75
+ CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
76
+ name,
77
+ qualified_name,
78
+ signature,
79
+ docstring,
80
+ content='nodes',
81
+ content_rowid='rowid'
82
+ );
83
+
84
+ CREATE TRIGGER IF NOT EXISTS nodes_ai AFTER INSERT ON nodes BEGIN
85
+ INSERT INTO nodes_fts(rowid, name, qualified_name, signature, docstring)
86
+ VALUES (NEW.rowid, NEW.name, NEW.qualified_name, NEW.signature, NEW.docstring);
87
+ END;
88
+
89
+ CREATE TRIGGER IF NOT EXISTS nodes_ad AFTER DELETE ON nodes BEGIN
90
+ INSERT INTO nodes_fts(nodes_fts, rowid, name, qualified_name, signature, docstring)
91
+ VALUES ('delete', OLD.rowid, OLD.name, OLD.qualified_name, OLD.signature, OLD.docstring);
92
+ END;
93
+
94
+ CREATE TRIGGER IF NOT EXISTS nodes_au AFTER UPDATE ON nodes BEGIN
95
+ INSERT INTO nodes_fts(nodes_fts, rowid, name, qualified_name, signature, docstring)
96
+ VALUES ('delete', OLD.rowid, OLD.name, OLD.qualified_name, OLD.signature, OLD.docstring);
97
+ INSERT INTO nodes_fts(rowid, name, qualified_name, signature, docstring)
98
+ VALUES (NEW.rowid, NEW.name, NEW.qualified_name, NEW.signature, NEW.docstring);
99
+ END;
100
+
101
+ CREATE TABLE IF NOT EXISTS project_metadata (
102
+ key TEXT PRIMARY KEY,
103
+ value TEXT NOT NULL,
104
+ updated_at INTEGER NOT NULL
105
+ );
106
+ `;
107
+
108
+ /** Open (creating when absent) the graph database at `path`. Returns a DatabaseSync. */
109
+ export function openDb(path) {
110
+ if (path !== ":memory:") mkdirSync(dirname(path), { recursive: true });
111
+ const db = new DatabaseSync(path);
112
+ db.exec("PRAGMA journal_mode = WAL");
113
+ db.exec("PRAGMA foreign_keys = ON");
114
+ db.exec("PRAGMA synchronous = NORMAL");
115
+ db.exec(SCHEMA);
116
+ const version = db.prepare("SELECT COUNT(*) AS count FROM schema_versions").get();
117
+ if (version.count === 0) {
118
+ db.prepare("INSERT INTO schema_versions(version, applied_at, description) VALUES (?, ?, ?)")
119
+ .run(1, Date.now(), "Initial astgraph schema");
120
+ }
121
+ return db;
122
+ }
123
+
124
+ /** Insert or replace the tracking record for one source file. */
125
+ export function upsertFileRecord(db, record) {
126
+ db.prepare(`
127
+ INSERT INTO files(path, content_hash, language, size, modified_at, indexed_at, node_count)
128
+ VALUES (?, ?, ?, ?, ?, ?, ?)
129
+ ON CONFLICT(path) DO UPDATE SET
130
+ content_hash = excluded.content_hash,
131
+ language = excluded.language,
132
+ size = excluded.size,
133
+ modified_at = excluded.modified_at,
134
+ indexed_at = excluded.indexed_at,
135
+ node_count = excluded.node_count
136
+ `).run(
137
+ record.path, record.contentHash, record.language, record.size,
138
+ record.modifiedAt ?? Date.now(), record.indexedAt ?? Date.now(), record.nodeCount ?? 0,
139
+ );
140
+ }
141
+
142
+ /** Read the tracking record for one source file, or undefined when absent. */
143
+ export function getFileRecord(db, path) {
144
+ const row = db.prepare("SELECT * FROM files WHERE path = ?").get(path);
145
+ if (row === undefined) return undefined;
146
+ return {
147
+ path: row.path, contentHash: row.content_hash, language: row.language,
148
+ size: row.size, modifiedAt: row.modified_at, indexedAt: row.indexed_at,
149
+ nodeCount: row.node_count,
150
+ };
151
+ }
152
+
153
+ /** Delete a file record; nodes cascade (and with them edges + refs + FTS rows). */
154
+ export function deleteFileRecord(db, path) {
155
+ db.prepare("DELETE FROM nodes WHERE file_path = ?").run(path);
156
+ db.prepare("DELETE FROM files WHERE path = ?").run(path);
157
+ }
158
+
159
+ /**
160
+ * Replace every node belonging to a file. Runs inside one transaction; the FTS
161
+ * triggers keep nodes_fts in sync.
162
+ */
163
+ export function replaceNodes(db, filePath, nodes) {
164
+ const insert = db.prepare(`
165
+ INSERT OR REPLACE INTO nodes(
166
+ id, kind, name, qualified_name, file_path, language,
167
+ start_line, end_line, signature, docstring, is_exported, is_async
168
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
169
+ `);
170
+ const clear = db.prepare("DELETE FROM nodes WHERE file_path = ?");
171
+ db.exec("BEGIN");
172
+ try {
173
+ clear.run(filePath);
174
+ for (const node of nodes) {
175
+ insert.run(
176
+ node.id, node.kind, node.name, node.qualifiedName, node.filePath, node.language,
177
+ node.startLine, node.endLine, node.signature ?? null, node.docstring ?? null,
178
+ node.isExported ? 1 : 0, node.isAsync ? 1 : 0,
179
+ );
180
+ }
181
+ db.exec("COMMIT");
182
+ } catch (error) {
183
+ db.exec("ROLLBACK");
184
+ throw error;
185
+ }
186
+ }
187
+
188
+ /** Insert one edge; duplicate (source, target, kind, line, col) rows are ignored. */
189
+ export function insertEdge(db, edge) {
190
+ db.prepare(`
191
+ INSERT OR IGNORE INTO edges(source, target, kind, line, col) VALUES (?, ?, ?, ?, ?)
192
+ `).run(edge.source, edge.target, edge.kind, edge.line ?? null, edge.col ?? null);
193
+ }
194
+
195
+ /** Delete every edge whose source OR target belongs to a file. */
196
+ export function deleteEdgesForFile(db, filePath) {
197
+ db.prepare(`
198
+ DELETE FROM edges WHERE source IN (SELECT id FROM nodes WHERE file_path = ?)
199
+ OR target IN (SELECT id FROM nodes WHERE file_path = ?)
200
+ `).run(filePath, filePath);
201
+ }
202
+
203
+ /** Insert one unresolved cross-file reference (status 'pending'). */
204
+ export function insertUnresolvedRef(db, ref) {
205
+ db.prepare(`
206
+ INSERT INTO unresolved_refs(from_node_id, reference_name, reference_kind, line, col, file_path, module_specifier, status)
207
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')
208
+ `).run(ref.fromNodeId, ref.referenceName, ref.referenceKind, ref.line, ref.col, ref.filePath, ref.moduleSpecifier ?? null);
209
+ }
210
+
211
+ /** Delete every unresolved reference originating from a file. */
212
+ export function deleteUnresolvedRefsForFile(db, filePath) {
213
+ db.prepare("DELETE FROM unresolved_refs WHERE file_path = ?").run(filePath);
214
+ }
215
+
216
+ /** Summary counters used by /ast status. */
217
+ export function stats(db) {
218
+ const files = db.prepare("SELECT COUNT(*) AS count FROM files").get().count;
219
+ const nodes = db.prepare("SELECT COUNT(*) AS count FROM nodes").get().count;
220
+ const edges = db.prepare("SELECT COUNT(*) AS count FROM edges").get().count;
221
+ const unresolved = db.prepare("SELECT COUNT(*) AS count FROM unresolved_refs WHERE status = 'pending'").get().count;
222
+ return { files, nodes, edges, unresolved };
223
+ }
224
+
225
+ /** Store a provenance metadata value. */
226
+ export function setMetadata(db, key, value) {
227
+ db.prepare(`
228
+ INSERT INTO project_metadata(key, value, updated_at) VALUES (?, ?, ?)
229
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at
230
+ `).run(key, value, Date.now());
231
+ }
232
+
233
+ /** Read a provenance metadata value, or undefined when absent. */
234
+ export function getMetadata(db, key) {
235
+ const row = db.prepare("SELECT value FROM project_metadata WHERE key = ?").get(key);
236
+ return row?.value;
237
+ }