@alan512/experienceengine 0.3.6 → 0.4.1

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 (137) hide show
  1. package/README.md +15 -4
  2. package/README.zh-CN.md +15 -4
  3. package/dist/adapters/antigravity/artifact-analyzer.d.ts +27 -0
  4. package/dist/adapters/antigravity/artifact-analyzer.js +151 -0
  5. package/dist/adapters/antigravity/artifact-analyzer.js.map +1 -0
  6. package/dist/adapters/codex/behavior-loop.d.ts +15 -43
  7. package/dist/adapters/codex/behavior-loop.js +2 -215
  8. package/dist/adapters/codex/behavior-loop.js.map +1 -1
  9. package/dist/adapters/codex/mcp-server.d.ts +37 -44
  10. package/dist/adapters/codex/mcp-server.js +5 -427
  11. package/dist/adapters/codex/mcp-server.js.map +1 -1
  12. package/dist/adapters/shared-mcp/action-registry.d.ts +121 -0
  13. package/dist/adapters/shared-mcp/action-registry.js +435 -0
  14. package/dist/adapters/shared-mcp/action-registry.js.map +1 -0
  15. package/dist/adapters/shared-mcp/behavior-loop.d.ts +91 -0
  16. package/dist/adapters/shared-mcp/behavior-loop.js +218 -0
  17. package/dist/adapters/shared-mcp/behavior-loop.js.map +1 -0
  18. package/dist/adapters/shared-mcp/server.d.ts +113 -0
  19. package/dist/adapters/shared-mcp/server.js +423 -0
  20. package/dist/adapters/shared-mcp/server.js.map +1 -0
  21. package/dist/cli/commands/agy-exec.d.ts +23 -0
  22. package/dist/cli/commands/agy-exec.js +92 -0
  23. package/dist/cli/commands/agy-exec.js.map +1 -0
  24. package/dist/cli/commands/antigravity-hook.d.ts +58 -0
  25. package/dist/cli/commands/antigravity-hook.js +192 -0
  26. package/dist/cli/commands/antigravity-hook.js.map +1 -0
  27. package/dist/cli/commands/antigravity.d.ts +8 -0
  28. package/dist/cli/commands/antigravity.js +37 -0
  29. package/dist/cli/commands/antigravity.js.map +1 -0
  30. package/dist/cli/commands/doctor.d.ts +2 -0
  31. package/dist/cli/commands/doctor.js +160 -3
  32. package/dist/cli/commands/doctor.js.map +1 -1
  33. package/dist/cli/commands/inspect.js +78 -1
  34. package/dist/cli/commands/inspect.js.map +1 -1
  35. package/dist/cli/commands/install.d.ts +3 -1
  36. package/dist/cli/commands/install.js +32 -2
  37. package/dist/cli/commands/install.js.map +1 -1
  38. package/dist/cli/commands/maintenance.js +80 -2
  39. package/dist/cli/commands/maintenance.js.map +1 -1
  40. package/dist/cli/commands/mcp-server.js +10 -2
  41. package/dist/cli/commands/mcp-server.js.map +1 -1
  42. package/dist/cli/commands/repair.d.ts +1 -1
  43. package/dist/cli/commands/repair.js +21 -3
  44. package/dist/cli/commands/repair.js.map +1 -1
  45. package/dist/cli/commands/upgrade.d.ts +4 -1
  46. package/dist/cli/commands/upgrade.js +25 -2
  47. package/dist/cli/commands/upgrade.js.map +1 -1
  48. package/dist/cli/dispatch.js +22 -6
  49. package/dist/cli/dispatch.js.map +1 -1
  50. package/dist/compiler/command-normalizer.d.ts +27 -0
  51. package/dist/compiler/command-normalizer.js +263 -0
  52. package/dist/compiler/command-normalizer.js.map +1 -0
  53. package/dist/compiler/trajectory-compiler.d.ts +12 -0
  54. package/dist/compiler/trajectory-compiler.js +179 -0
  55. package/dist/compiler/trajectory-compiler.js.map +1 -0
  56. package/dist/compiler/trajectory-matcher.d.ts +18 -0
  57. package/dist/compiler/trajectory-matcher.js +419 -0
  58. package/dist/compiler/trajectory-matcher.js.map +1 -0
  59. package/dist/config/config-schema.d.ts +11 -0
  60. package/dist/config/config-schema.js +9 -0
  61. package/dist/config/config-schema.js.map +1 -1
  62. package/dist/config/default-config.js +1 -0
  63. package/dist/config/default-config.js.map +1 -1
  64. package/dist/controller/candidate-retriever.d.ts +3 -1
  65. package/dist/controller/candidate-retriever.js +247 -7
  66. package/dist/controller/candidate-retriever.js.map +1 -1
  67. package/dist/controller/intervention-controller.js +48 -21
  68. package/dist/controller/intervention-controller.js.map +1 -1
  69. package/dist/controller/trigger-evaluator.d.ts +2 -1
  70. package/dist/controller/trigger-evaluator.js +10 -4
  71. package/dist/controller/trigger-evaluator.js.map +1 -1
  72. package/dist/experience-management/node-lifecycle-governance.js +25 -6
  73. package/dist/experience-management/node-lifecycle-governance.js.map +1 -1
  74. package/dist/input/fingerprint-extractor.d.ts +53 -0
  75. package/dist/input/fingerprint-extractor.js +620 -0
  76. package/dist/input/fingerprint-extractor.js.map +1 -0
  77. package/dist/install/antigravity-global-wiring.d.ts +25 -0
  78. package/dist/install/antigravity-global-wiring.js +165 -0
  79. package/dist/install/antigravity-global-wiring.js.map +1 -0
  80. package/dist/install/antigravity-project-wiring.d.ts +24 -0
  81. package/dist/install/antigravity-project-wiring.js +380 -0
  82. package/dist/install/antigravity-project-wiring.js.map +1 -0
  83. package/dist/install/antigravity.d.ts +78 -0
  84. package/dist/install/antigravity.js +169 -0
  85. package/dist/install/antigravity.js.map +1 -0
  86. package/dist/install/host-detection.d.ts +1 -1
  87. package/dist/install/host-detection.js +2 -1
  88. package/dist/install/host-detection.js.map +1 -1
  89. package/dist/install/public-install.d.ts +2 -0
  90. package/dist/install/public-install.js +8 -0
  91. package/dist/install/public-install.js.map +1 -1
  92. package/dist/interaction/operational-actions-service.d.ts +8 -5
  93. package/dist/interaction/operational-actions-service.js +36 -6
  94. package/dist/interaction/operational-actions-service.js.map +1 -1
  95. package/dist/interaction/operational-service.d.ts +3 -1
  96. package/dist/interaction/operational-service.js +9 -0
  97. package/dist/interaction/operational-service.js.map +1 -1
  98. package/dist/interaction/service.d.ts +11 -1
  99. package/dist/interaction/service.js +11 -1
  100. package/dist/interaction/service.js.map +1 -1
  101. package/dist/maintenance/vector-migrator.d.ts +37 -0
  102. package/dist/maintenance/vector-migrator.js +170 -0
  103. package/dist/maintenance/vector-migrator.js.map +1 -0
  104. package/dist/plugin/openclaw-plugin.d.ts +8 -0
  105. package/dist/runtime/prompt-service.js +10 -0
  106. package/dist/runtime/prompt-service.js.map +1 -1
  107. package/dist/runtime/service.d.ts +2 -0
  108. package/dist/runtime/service.js +127 -2
  109. package/dist/runtime/service.js.map +1 -1
  110. package/dist/store/sqlite/db.js +18 -1
  111. package/dist/store/sqlite/db.js.map +1 -1
  112. package/dist/store/sqlite/repositories/attribution-record-repo.js +12 -0
  113. package/dist/store/sqlite/repositories/attribution-record-repo.js.map +1 -1
  114. package/dist/store/sqlite/repositories/node-repo.d.ts +1 -0
  115. package/dist/store/sqlite/repositories/node-repo.js +47 -2
  116. package/dist/store/sqlite/repositories/node-repo.js.map +1 -1
  117. package/dist/store/sqlite/repositories/scope-fingerprint-repo.d.ts +8 -0
  118. package/dist/store/sqlite/repositories/scope-fingerprint-repo.js +23 -0
  119. package/dist/store/sqlite/repositories/scope-fingerprint-repo.js.map +1 -0
  120. package/dist/store/sqlite/schema.sql +26 -0
  121. package/dist/store/vector/embeddings.d.ts +4 -2
  122. package/dist/store/vector/embeddings.js +19 -6
  123. package/dist/store/vector/embeddings.js.map +1 -1
  124. package/dist/store/vector/local-provider.d.ts +1 -1
  125. package/dist/store/vector/local-provider.js +40 -8
  126. package/dist/store/vector/local-provider.js.map +1 -1
  127. package/dist/store/vector/offline-manifest.d.ts +7 -0
  128. package/dist/store/vector/offline-manifest.js +162 -0
  129. package/dist/store/vector/offline-manifest.js.map +1 -0
  130. package/dist/store/vector/provider-types.d.ts +1 -0
  131. package/dist/types/domain.d.ts +112 -2
  132. package/dist/types/plugin.d.ts +1 -0
  133. package/docs/releases/v0.4.0.md +39 -0
  134. package/docs/releases/v0.4.1.md +22 -0
  135. package/docs/user-guide.md +119 -3
  136. package/openclaw.plugin.json +1 -1
  137. package/package.json +68 -68
package/README.md CHANGED
@@ -6,7 +6,7 @@ ExperienceEngine is a governance layer for coding agents that reuses real execut
6
6
 
7
7
  **Memory does addition. ExperienceEngine does governance.**
8
8
 
9
- Supported hosts today: `OpenClaw`, `Claude Code`, `Codex`
9
+ Supported hosts today: `OpenClaw`, `Claude Code`, `Codex`, and validated Google Antigravity Agent Desktop support
10
10
 
11
11
  ## 10-Second Example
12
12
 
@@ -62,6 +62,9 @@ npm install -g @alan512/experienceengine
62
62
  - `/plugin marketplace add https://github.com/Alan-512/ExperienceEngine.git`
63
63
  - `/plugin install experienceengine@experienceengine`
64
64
  - `ee init`
65
+ - `Google Antigravity`
66
+ - `ee install antigravity`
67
+ - `ee init`
65
68
 
66
69
  `ee init` initializes shared ExperienceEngine state after the host-specific installation step.
67
70
 
@@ -88,6 +91,7 @@ Do not use ExperienceEngine if:
88
91
  | `OpenClaw` | native plugin install | host-native | most complete today |
89
92
  | `Claude Code` | marketplace plugin, with `ee install claude-code` fallback | MCP + plugin hooks | supported |
90
93
  | `Codex` | `ee install codex`, with native MCP fallback | hooks + MCP | supported |
94
+ | Google Antigravity Agent Desktop + `agy` CLI | `ee install antigravity`, `ee agy exec -C <project>` for CLI runs | MCP + validated native hooks | supported through user-level Antigravity plugin wiring and `ee agy exec` |
91
95
 
92
96
  ## Why It Exists
93
97
 
@@ -116,6 +120,9 @@ ExperienceEngine is not trying to remember more things than the host. Its core j
116
120
  - posttask review can revise whether a hint actually helped, harmed, or stayed uncertain
117
121
  - delivery decisions are persisted even when no hint is shipped, so skipped turns can still be explained later
118
122
  - high-match same-repo experience can move out of conservative delivery after successful reuse, while cross-repo reuse stays cautious unless there is stronger evidence
123
+ - calculated cross-repo portability scorecards and SemVer penalties prevent unsafe sharing across different scopes
124
+ - post-task causal trajectory attributions ensure outcome feedback is only recorded when the agent actually adopted the injected guidance
125
+ - quarantine leases and shadow probes provide a safe, monitored recovery path to conservative delivery without erasing historical lessons
119
126
  - the product goal is production-safe reuse, not maximum recall
120
127
 
121
128
  ## Where It Sits In The Agent Loop
@@ -149,8 +156,10 @@ Each node moves through that lifecycle using real task outcomes, not just time-b
149
156
  ### Under The Hood
150
157
 
151
158
  - MCP-native interaction surfaces plus CLI/operator fallback
152
- - semantic retrieval with API and local fallback
153
- - deterministic match scorecards that separate same-repo confidence from broader cross-repo reuse
159
+ - semantic retrieval with API and local fallback (including `strict-offline` profiles, manifest health checks, and vector migration)
160
+ - deterministic match scorecards with portability bands (`validated_portable`, `cautiously_portable`, `incompatible`) and SemVer mismatch penalties
161
+ - post-task causal trajectory attributions (`adoption_detected`, `non_adoption_detected`, `unverifiable`)
162
+ - quarantine shadow-probe lease cycles with no-harm counters and conservative restoration
154
163
  - host-agent driven inspection and feedback, with CLI fallback commands such as `ee inspect --last`, `ee helped`, and `ee harmed`
155
164
 
156
165
  ### Interaction Surface Tiers
@@ -299,7 +308,7 @@ Use the `ee` CLI when you need explicit operator validation or troubleshooting:
299
308
 
300
309
  ```bash
301
310
  ee init
302
- ee doctor <openclaw|claude-code|codex>
311
+ ee doctor <openclaw|claude-code|codex|antigravity>
303
312
  ee status
304
313
  ee maintenance embedding-smoke
305
314
  ```
@@ -342,6 +351,7 @@ If you need explicit per-host control as an operator or while developing the pro
342
351
  ee install openclaw
343
352
  ee install claude-code
344
353
  ee install codex
354
+ ee install antigravity
345
355
  ```
346
356
 
347
357
  <details>
@@ -359,6 +369,7 @@ Notes:
359
369
  - `Codex` installs Codex-native hooks plus the shared ExperienceEngine MCP server. `ee codex exec` remains the deterministic non-interactive fallback.
360
370
  - Codex `UserPromptSubmit` stays synchronous because it owns prompt-time experience injection. `PostToolUse` and `Stop` are queued for background processing by default. `PreToolUse` is not registered by default; set `EXPERIENCE_ENGINE_CODEX_PRETOOL_HOOK_ENABLED=1` only for synchronous gating experiments.
361
371
  - Codex App and Codex CLI both load repo-level project hooks when they open the same repo. If Codex says hooks need review, open `/hooks` and approve ExperienceEngine's `UserPromptSubmit`, `PostToolUse`, and `Stop` hooks. If `EXPERIENCE_ENGINE_CODEX_PRETOOL_HOOK_ENABLED=1` was used, approve `PreToolUse` too.
372
+ - `Google Antigravity` currently means Antigravity Agent Desktop, the standalone `agy` CLI, and Antigravity IDE for validated lifecycle automation. The IDE shell is tracked independently because it stores MCP tool cache under `~/.gemini/antigravity-ide`, but real-host validation showed it loads the shared global plugin hooks from `~/.gemini/config/plugins/experienceengine/hooks.json`. `ee doctor antigravity` reports whether the IDE command exists, whether IDE MCP tool cache files are observed, and whether IDE hooks are observed through the global plugin surface. EE data remains user-level under the configured ExperienceEngine home and project experience remains scope-isolated. `ee install antigravity` records user-level adapter capability and installs Antigravity user-level plugin/MCP wiring for Agent Desktop and `agy` CLI. `ee antigravity activate-project -C <project>` remains a project-local fallback. For CLI runs, prefer `ee agy exec -C <project> "<prompt>"`; it invokes `agy --add-dir <project> --print ...` because direct `agy` project auto-discovery can fail on Windows if symlink creation is not permitted. Antigravity supports both routine stdio MCP calls and an advanced artifact-assisted analyzer that automatically parses planning/verification markdown files (`task.md`, `walkthrough.md`, `implementation_plan.md`) for task outcomes, and reconciles them with runtime finalization telemetry.
362
373
  - `ee install ...` and `ee doctor ...` now warn if `npm` or `pnpm` uses a non-official registry, because managed model downloads are most reliable with `https://registry.npmjs.org`.
363
374
  - successful `ee install ...` also explains the cold-start expectation: capture starts immediately, but formal experience usually appears after a few similar tasks in the same repo.
364
375
 
package/README.zh-CN.md CHANGED
@@ -6,7 +6,7 @@ ExperienceEngine 是一个面向编程 Agent 的治理层。它复用真实执
6
6
 
7
7
  **Memory 做加法,ExperienceEngine 做治理。**
8
8
 
9
- 当前支持的宿主:`OpenClaw`、`Claude Code`、`Codex`
9
+ 当前支持的宿主:`OpenClaw`、`Claude Code`、`Codex`、`Google Antigravity Agent Desktop`
10
10
 
11
11
  ## 10 秒理解
12
12
 
@@ -62,6 +62,9 @@ npm install -g @alan512/experienceengine
62
62
  - `/plugin marketplace add https://github.com/Alan-512/ExperienceEngine.git`
63
63
  - `/plugin install experienceengine@experienceengine`
64
64
  - `ee init`
65
+ - `Google Antigravity`
66
+ - `ee install antigravity`
67
+ - `ee init`
65
68
 
66
69
  `ee init` 用于在宿主安装完成后初始化共享的 ExperienceEngine 状态。
67
70
 
@@ -88,6 +91,7 @@ npm install -g @alan512/experienceengine
88
91
  | `OpenClaw` | 原生插件安装 | 宿主原生 | 当前最完整 |
89
92
  | `Claude Code` | marketplace 插件,保留 `ee install claude-code` fallback | MCP + plugin hooks | 已支持 |
90
93
  | `Codex` | `ee install codex`,保留原生 MCP fallback | hooks + MCP | 已支持 |
94
+ | `Google Antigravity Agent Desktop` + `agy` CLI | `ee install antigravity`,CLI 运行使用 `ee agy exec -C <project>` | MCP + 已验证的原生 hooks | 通过用户级 Antigravity plugin wiring 与 `ee agy exec` 支持 |
91
95
 
92
96
  ## 为什么要做这个
93
97
 
@@ -116,6 +120,9 @@ ExperienceEngine 不是想比宿主“记住更多东西”。它的核心价值
116
120
  - 任务结束后的审查会继续判断这条 hint 到底是帮到了、伤害了,还是仍然不确定
117
121
  - 即使这次没有注入 hint,delivery decision 也会被记录下来,所以之后仍然能解释为什么跳过
118
122
  - 同仓库高匹配经验在成功复用后可以从保守投放提升到正常投放;跨仓库复用默认仍保持保守,除非后续证据更强
123
+ - 计算跨仓库的 portability scorecard 和 SemVer 兼容惩罚,防范跨 scope 的不安全经验复用
124
+ - 任务结束后的因果轨迹归因(Causal Trajectory Attribution)确保只有在 agent 真正采纳了注入约束时,才计入 outcome 反馈
125
+ - 提供隔离租期(quarantine lease)与 shadow probe 周期,引导隔离节点通过无害验证后安全、保守地恢复,同时完整保留历史记录
119
126
  - 这个产品追求的是“生产安全的经验复用”,不是“尽量多记、尽量多召回”
120
127
 
121
128
  ## 它在 Agent Loop 里的位置
@@ -148,8 +155,10 @@ ExperienceEngine 工作在 context 层,不会修改宿主模型权重。
148
155
  ### 底层实现
149
156
 
150
157
  - MCP 原生交互面,加上 CLI / operator fallback
151
- - 支持 API 与本地回退的语义检索
152
- - 确定性的 match scorecard,用来区分同仓库高置信匹配和更宽泛的跨仓库复用
158
+ - 支持 API 与本地回退的语义检索(包含 `strict-offline` 离线配置、模型 manifest 校验和向量迁移状态)
159
+ - 确定性的 match scorecard 包含移植分级(`validated_portable`、`cautiously_portable`、`incompatible`)与 SemVer 版本偏差惩罚
160
+ - 任务后的因果轨迹归因评分(`adoption_detected`、`non_adoption_detected`、`unverifiable`)
161
+ - 隔离节点的 shadow-probe 租期管理,包含无害通过计数器与保守恢复机制
153
162
  - 宿主 agent 内可直接查看和反馈经验,CLI fallback 包括 `ee inspect --last`、`ee helped`、`ee harmed`
154
163
 
155
164
  如果你想看 ExperienceNode 结构和治理字段,见:
@@ -289,7 +298,7 @@ ExperienceEngine 的交互面分成三层:
289
298
 
290
299
  ```bash
291
300
  ee init
292
- ee doctor <openclaw|claude-code|codex>
301
+ ee doctor <openclaw|claude-code|codex|antigravity>
293
302
  ee status
294
303
  ee maintenance embedding-smoke
295
304
  ```
@@ -332,6 +341,7 @@ ExperienceEngine 明确拆分:
332
341
  ee install openclaw
333
342
  ee install claude-code
334
343
  ee install codex
344
+ ee install antigravity
335
345
  ```
336
346
 
337
347
  <details>
@@ -345,6 +355,7 @@ codex mcp add experienceengine --env EXPERIENCE_ENGINE_HOME=$HOME/.experienceeng
345
355
 
346
356
  说明:
347
357
  - `OpenClaw` 走 plugin/runtime integration,而不是 `src/adapters/`
358
+ - `Google Antigravity` 当前指已验证生命周期自动化的 Antigravity Agent Desktop、独立 `agy` CLI 和 Antigravity IDE。IDE 外壳会作为单独 surface 跟踪,因为它的 MCP tool cache 位于 `~/.gemini/antigravity-ide`;真实宿主验证显示 IDE 会加载共享全局插件 hooks:`~/.gemini/config/plugins/experienceengine/hooks.json`。`ee doctor antigravity` 会报告 IDE 命令是否存在、是否观察到 IDE MCP tool cache、以及是否通过全局插件 surface 观察到 IDE hooks。EE 数据仍然是用户级,放在配置的 ExperienceEngine home 下,不同项目通过 project scope 隔离经验。`ee install antigravity` 会记录用户级 adapter 能力,并为 Agent Desktop 与 `agy` CLI 安装 Antigravity 用户级 plugin/MCP wiring;`ee antigravity activate-project -C <project>` 保留为项目级 fallback。CLI 运行优先使用 `ee agy exec -C <project> "<prompt>"`,它会调用 `agy --add-dir <project> --print ...`,因为 Windows 下直接 `agy` 项目自动发现可能因为无法创建 symlink 而不加载项目配置。Antigravity 既支持常规 stdio MCP 调用,也支持高级的“基于文档的因果归因分析器”,会自动解析规划/验证 Markdown 文件(`task.md`、`walkthrough.md`、`implementation_plan.md`)以评估任务执行状态,并与运行时 finalization 遥测数据进行对齐。
348
359
  - `Claude Code` 会安装 hooks 和共享 ExperienceEngine MCP 服务
349
360
  - `Codex` 会安装 Codex 原生 hooks 和共享 ExperienceEngine MCP 服务。`ee codex exec` 仍是确定性的非交互 fallback。
350
361
  - Codex 的 `UserPromptSubmit` 保持同步,因为它负责 prompt-time experience injection。`PostToolUse` 和 `Stop` 默认排队后在后台处理。`PreToolUse` 默认不注册;只有同步 gating 实验需要时才设置 `EXPERIENCE_ENGINE_CODEX_PRETOOL_HOOK_ENABLED=1` 启用。
@@ -0,0 +1,27 @@
1
+ export type VerificationStatus = "passed" | "failed" | "unverified";
2
+ export type ArtifactEvidence = {
3
+ tasksCompleted: number;
4
+ tasksTotal: number;
5
+ hasExperienceEngineRefs: boolean;
6
+ hasCausalAttribution: boolean;
7
+ experienceRefs: string[];
8
+ sessionIds: string[];
9
+ verdicts: Array<{
10
+ file: string;
11
+ line: string;
12
+ verdict: "passed" | "failed";
13
+ }>;
14
+ };
15
+ export type ArtifactAnalysisResult = {
16
+ verificationStatus: VerificationStatus;
17
+ evidence: ArtifactEvidence;
18
+ };
19
+ /**
20
+ * Parses individual file content for task items, verification verdicts, and ExperienceEngine references.
21
+ */
22
+ export declare const parseArtifactContent: (content: string, filename: string) => ArtifactAnalysisResult;
23
+ /**
24
+ * Searches the workspace for target planning artifacts and returns aggregate analysis results.
25
+ * Respects explicit runtime finalization facts by combining telemetry if available.
26
+ */
27
+ export declare const analyzeWorkspaceArtifacts: (workspaceDir: string, targetFiles?: string[]) => ArtifactAnalysisResult;
@@ -0,0 +1,151 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Parses individual file content for task items, verification verdicts, and ExperienceEngine references.
5
+ */
6
+ export const parseArtifactContent = (content, filename) => {
7
+ let tasksCompleted = 0;
8
+ let tasksTotal = 0;
9
+ let hasExperienceEngineRefs = false;
10
+ const experienceRefs = new Set();
11
+ const sessionIds = new Set();
12
+ const verdicts = [];
13
+ const lines = content.split(/\r?\n/);
14
+ // Check for ExperienceEngine general mentions (case insensitive)
15
+ if (/experience[-_]?engine/i.test(content) || /antigravity/i.test(content)) {
16
+ hasExperienceEngineRefs = true;
17
+ }
18
+ // Look for session IDs or UUIDs in the text
19
+ const uuidRegex = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;
20
+ let match;
21
+ while ((match = uuidRegex.exec(content)) !== null) {
22
+ sessionIds.add(match[0].toLowerCase());
23
+ }
24
+ // Look for experience node patterns (e.g. node_xxx or experienceengine://xxx)
25
+ const nodeRegex = /(?:node_[a-zA-Z0-9_]+|experienceengine:\/\/[a-zA-Z0-9_\-\/]+)/gi;
26
+ while ((match = nodeRegex.exec(content)) !== null) {
27
+ experienceRefs.add(match[0]);
28
+ }
29
+ for (const line of lines) {
30
+ const trimmed = line.trim();
31
+ // 1. Task checkbox parsing
32
+ // Supports - [x], - [ ], - [/], * [x], etc.
33
+ const checkboxMatch = trimmed.match(/^[-*]\s+`\[([ x\/])\]`/i) || trimmed.match(/^[-*]\s+\[([ x\/])\]/i);
34
+ if (checkboxMatch) {
35
+ tasksTotal++;
36
+ const marker = checkboxMatch[1].toLowerCase();
37
+ if (marker === "x") {
38
+ tasksCompleted++;
39
+ }
40
+ }
41
+ // 2. Explicit Verification Verdicts
42
+ // Check for explicit "verification status: passed", "verification: failed" etc.
43
+ const explicitPassed = trimmed.match(/(?:verification|verdict|status|result)\s*[:=-]\s*[`"']?(passed|success|helped)[`"']?/i);
44
+ const explicitFailed = trimmed.match(/(?:verification|verdict|status|result)\s*[:=-]\s*[`"']?(failed|harmed|misfired)[`"']?/i);
45
+ if (explicitPassed) {
46
+ verdicts.push({ file: filename, line: trimmed, verdict: "passed" });
47
+ }
48
+ else if (explicitFailed) {
49
+ verdicts.push({ file: filename, line: trimmed, verdict: "failed" });
50
+ }
51
+ // Check for marked checkbox lines with verification terms, e.g. - [x] Passed automated tests
52
+ const checkboxPassed = trimmed.match(/^[-*]\s+\[x\]\s+.*(passed|success|verified|ok|correct)/i) ||
53
+ trimmed.match(/^[-*]\s+`\[x\]`\s+.*(passed|success|verified|ok|correct)/i);
54
+ const checkboxFailed = trimmed.match(/^[-*]\s+\[x\]\s+.*(failed|broken|misfired|error)/i) ||
55
+ trimmed.match(/^[-*]\s+`\[x\]`\s+.*(failed|broken|misfired|error)/i);
56
+ if (checkboxPassed) {
57
+ verdicts.push({ file: filename, line: trimmed, verdict: "passed" });
58
+ }
59
+ else if (checkboxFailed) {
60
+ verdicts.push({ file: filename, line: trimmed, verdict: "failed" });
61
+ }
62
+ }
63
+ // Determine Verification Status for this single file
64
+ let verificationStatus = "unverified";
65
+ if (verdicts.some(v => v.verdict === "failed")) {
66
+ verificationStatus = "failed";
67
+ }
68
+ else if (verdicts.some(v => v.verdict === "passed")) {
69
+ verificationStatus = "passed";
70
+ }
71
+ else if (tasksTotal > 0 && tasksCompleted === tasksTotal) {
72
+ // If all tasks are checked off and no failures found, default to passed
73
+ verificationStatus = "passed";
74
+ }
75
+ return {
76
+ verificationStatus,
77
+ evidence: {
78
+ tasksCompleted,
79
+ tasksTotal,
80
+ hasExperienceEngineRefs,
81
+ hasCausalAttribution: verdicts.length > 0,
82
+ experienceRefs: Array.from(experienceRefs),
83
+ sessionIds: Array.from(sessionIds),
84
+ verdicts
85
+ }
86
+ };
87
+ };
88
+ /**
89
+ * Searches the workspace for target planning artifacts and returns aggregate analysis results.
90
+ * Respects explicit runtime finalization facts by combining telemetry if available.
91
+ */
92
+ export const analyzeWorkspaceArtifacts = (workspaceDir, targetFiles = ["task.md", "walkthrough.md", "implementation_plan.md"]) => {
93
+ let aggregateStatus = "unverified";
94
+ let totalTasksCompleted = 0;
95
+ let totalTasksTotal = 0;
96
+ let hasExperienceEngineRefs = false;
97
+ const experienceRefs = new Set();
98
+ const sessionIds = new Set();
99
+ const allVerdicts = [];
100
+ for (const filename of targetFiles) {
101
+ const filePath = join(workspaceDir, filename);
102
+ if (!existsSync(filePath)) {
103
+ continue;
104
+ }
105
+ try {
106
+ const content = readFileSync(filePath, "utf8");
107
+ const result = parseArtifactContent(content, filename);
108
+ totalTasksCompleted += result.evidence.tasksCompleted;
109
+ totalTasksTotal += result.evidence.tasksTotal;
110
+ if (result.evidence.hasExperienceEngineRefs) {
111
+ hasExperienceEngineRefs = true;
112
+ }
113
+ for (const ref of result.evidence.experienceRefs) {
114
+ experienceRefs.add(ref);
115
+ }
116
+ for (const sid of result.evidence.sessionIds) {
117
+ sessionIds.add(sid);
118
+ }
119
+ for (const v of result.evidence.verdicts) {
120
+ allVerdicts.push(v);
121
+ }
122
+ // Propagate statuses: failed takes precedence over passed, passed over unverified
123
+ if (result.verificationStatus === "failed") {
124
+ aggregateStatus = "failed";
125
+ }
126
+ else if (result.verificationStatus === "passed" && aggregateStatus !== "failed") {
127
+ aggregateStatus = "passed";
128
+ }
129
+ }
130
+ catch {
131
+ // Ignore reading errors gracefully
132
+ }
133
+ }
134
+ // If no explicit verdicts but we checked off all tasks, and total > 0, aggregate is passed
135
+ if (aggregateStatus === "unverified" && totalTasksTotal > 0 && totalTasksCompleted === totalTasksTotal) {
136
+ aggregateStatus = "passed";
137
+ }
138
+ return {
139
+ verificationStatus: aggregateStatus,
140
+ evidence: {
141
+ tasksCompleted: totalTasksCompleted,
142
+ tasksTotal: totalTasksTotal,
143
+ hasExperienceEngineRefs,
144
+ hasCausalAttribution: allVerdicts.length > 0,
145
+ experienceRefs: Array.from(experienceRefs),
146
+ sessionIds: Array.from(sessionIds),
147
+ verdicts: allVerdicts
148
+ }
149
+ };
150
+ };
151
+ //# sourceMappingURL=artifact-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-analyzer.js","sourceRoot":"","sources":["../../../src/adapters/antigravity/artifact-analyzer.ts"],"names":[],"mappings":"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"}
@@ -1,40 +1,12 @@
1
- import type { ExperienceRuntimeService } from "../../runtime/service.js";
2
- import type { ToolEventStatus } from "../../types/domain.js";
3
- export type CodexLookupArgs = {
4
- cwd?: string;
5
- prompt: string;
6
- sessionId?: string;
7
- };
8
- export type CodexToolResultArgs = {
9
- sessionId: string;
10
- toolName: string;
11
- inputSummary?: string;
12
- outputSummary?: string;
13
- errorSignature?: string;
14
- exitCode?: number;
15
- status?: ToolEventStatus;
16
- };
17
- export type CodexFinalizeArgs = {
18
- sessionId: string;
19
- cwd?: string;
20
- prompt?: string;
21
- contextSummary?: string;
22
- injectedNodeIds?: string[];
23
- };
24
- export type CodexHostEventArgs = {
25
- cwd?: string;
26
- sessionId?: string;
27
- trigger: "host_startup" | "prompt_lookup" | "posttask" | "stop";
28
- };
29
- export type CodexServerOptions = {
30
- env?: NodeJS.ProcessEnv;
31
- homeDir?: string;
32
- fetchImpl?: typeof fetch;
33
- runtimeOptions?: ConstructorParameters<typeof ExperienceRuntimeService>[2];
34
- };
1
+ import { type SharedLookupArgs, type SharedToolResultArgs, type SharedFinalizeArgs, type SharedHostEventArgs, type SharedServerOptions } from "../shared-mcp/behavior-loop.js";
2
+ export type CodexLookupArgs = SharedLookupArgs;
3
+ export type CodexToolResultArgs = SharedToolResultArgs;
4
+ export type CodexFinalizeArgs = SharedFinalizeArgs;
5
+ export type CodexHostEventArgs = SharedHostEventArgs;
6
+ export type CodexServerOptions = SharedServerOptions;
35
7
  export declare const createCodexBehaviorLoop: (options?: CodexServerOptions) => {
36
- lookupHints(args: CodexLookupArgs): Promise<{
37
- mode: import("../../types/domain.js").InjectionMode;
8
+ lookupHints(args: SharedLookupArgs): Promise<{
9
+ mode: import("../../index.js").InjectionMode;
38
10
  text: string | undefined;
39
11
  notice: string | undefined;
40
12
  injectedNodeIds: string[] | never[];
@@ -63,25 +35,25 @@ export declare const createCodexBehaviorLoop: (options?: CodexServerOptions) =>
63
35
  harmed: number | undefined;
64
36
  }[];
65
37
  } | undefined;
66
- deliveryMode: import("../../types/domain.js").EvaluationMode | undefined;
38
+ deliveryMode: import("../../index.js").EvaluationMode | undefined;
67
39
  delivered: boolean | undefined;
68
40
  }>;
69
- signalHostEvent(args: CodexHostEventArgs): Promise<{
41
+ signalHostEvent(args: SharedHostEventArgs): Promise<{
70
42
  status: "disabled" | "queued" | "skipped";
71
43
  reason?: "not_due" | "backoff";
72
44
  scopeId?: string;
73
45
  }>;
74
- recordToolResult(args: CodexToolResultArgs): Promise<{
46
+ recordToolResult(args: SharedToolResultArgs): Promise<{
75
47
  status: string;
76
48
  toolName: string;
77
- eventStatus: ToolEventStatus;
49
+ eventStatus: import("../../index.js").ToolEventStatus;
78
50
  hasErrorSignature: boolean;
79
51
  exitCode: number | undefined;
80
52
  }>;
81
- finalizeTask(args: CodexFinalizeArgs): Promise<{
53
+ finalizeTask(args: SharedFinalizeArgs): Promise<{
82
54
  status: string;
83
- taskType: import("../../types/domain.js").ResolvedTaskType;
84
- outcomeSignal: import("../../types/domain.js").OutcomeSignal;
55
+ taskType: import("../../index.js").ResolvedTaskType;
56
+ outcomeSignal: import("../../index.js").OutcomeSignal;
85
57
  injectedNodeIds: string[];
86
58
  recordedToolEvents: number;
87
59
  feedbackHint: string | undefined;
@@ -1,218 +1,5 @@
1
- import { loadConfig } from "../../config/load-config.js";
2
- import { resolveExperienceEnginePaths } from "../../config/path-resolver.js";
3
- import { buildRetrievalPolicyInspectionSummary } from "../../interaction/retrieval-policy-inspection.js";
4
- import { ExperiencePromptRuntimeService } from "../../runtime/prompt-service.js";
5
- const createCodexConfig = (options = {}) => {
6
- const paths = resolveExperienceEnginePaths({
7
- adapter: "codex",
8
- env: options.env ?? process.env,
9
- homeDir: options.homeDir
10
- });
11
- return loadConfig({
12
- dataDir: paths.dataDir,
13
- sqlitePath: paths.sqlitePath,
14
- captureDir: paths.captureDir
15
- }, {
16
- env: options.env ?? process.env,
17
- homeDir: options.homeDir
18
- });
19
- };
20
- const createCodexPromptRuntime = (options = {}) => new ExperiencePromptRuntimeService(createCodexConfig(options));
21
- const createCodexRuntime = async (options = {}) => {
22
- const { ExperienceRuntimeService } = await import("../../runtime/service.js");
23
- return new ExperienceRuntimeService(createCodexConfig(options), undefined, {
24
- ...options.runtimeOptions,
25
- autonomousHygieneGovernance: {
26
- enabled: true,
27
- ...options.runtimeOptions?.autonomousHygieneGovernance
28
- }
29
- });
30
- };
31
- const summarizeActionReason = (scorecard) => {
32
- if (scorecard.mode === "inject_conservative") {
33
- if (scorecard.decisionReason === "ambiguous_same_family_candidate") {
34
- return "ExperienceEngine found a promising same-family match and chose conservative injection instead of skipping.";
35
- }
36
- if (scorecard.decisionReason === "promising_candidate_quality") {
37
- return "ExperienceEngine found a credible candidate, but kept the injection conservative until it has stronger runtime proof.";
38
- }
39
- return "ExperienceEngine chose conservative injection because the best match still needs more runtime evidence.";
40
- }
41
- if (scorecard.decisionReason === "mature_validated_candidate") {
42
- return "A mature validated candidate cleared the fast path, so ExperienceEngine injected it normally.";
43
- }
44
- if (scorecard.decisionReason === "candidate_quality_positive") {
45
- return "Candidate quality was strong enough to justify intervention for this task.";
46
- }
47
- if (scorecard.mode === "inject") {
48
- return "ExperienceEngine injected the best available reusable guidance for this task.";
49
- }
50
- return undefined;
51
- };
52
- const summarizeTrust = (scorecard) => {
53
- const primaryNode = scorecard.nodes?.[0];
54
- if (!scorecard.riskLevel || !primaryNode?.state) {
55
- return undefined;
56
- }
57
- const confidence = scorecard.confidence ? ` ${scorecard.confidence}-confidence` : "";
58
- return `${scorecard.riskLevel}-risk${confidence} ${primaryNode.state} guidance with ${primaryNode.helped ?? 0} helped and ${primaryNode.harmed ?? 0} harmed signal(s).`;
59
- };
60
- const summarizeRetrievalNotes = (scorecard) => {
61
- const notes = [];
62
- if (scorecard.queryRewriteApplied) {
63
- notes.push("Query rewrite preserved retrieval intent for this task.");
64
- }
65
- const rerankSource = scorecard.topCandidates?.[0]?.rerankSource;
66
- if (rerankSource === "model") {
67
- notes.push("Model reranking participated in the final ordering.");
68
- }
69
- if (scorecard.fastPathApplied) {
70
- notes.push("A strong candidate fast path was used.");
71
- }
72
- const topCandidate = scorecard.topCandidates?.[0];
73
- if (topCandidate?.retrievalReasons?.length) {
74
- notes.push(`Top retrieval signals: ${topCandidate.retrievalReasons.slice(0, 2).join(", ")}.`);
75
- }
76
- if (topCandidate?.policyReasons?.length) {
77
- notes.push(`Top policy signals: ${topCandidate.policyReasons.slice(0, 2).join(", ")}.`);
78
- }
79
- if (scorecard.rejectedCandidates?.length) {
80
- notes.push(`Runner-up candidates withheld: ${scorecard.rejectedCandidates.map((candidate) => candidate.id).join(", ")}.`);
81
- }
82
- return notes;
83
- };
84
- const summarizeScorecard = (scorecard) => scorecard
85
- ? {
86
- mode: scorecard.mode,
87
- interventionStrength: scorecard.interventionStrength,
88
- riskLevel: scorecard.riskLevel,
89
- recommendation: scorecard.recommendation,
90
- actionReason: summarizeActionReason(scorecard),
91
- trustSummary: summarizeTrust(scorecard),
92
- retrievalNotes: summarizeRetrievalNotes(scorecard),
93
- retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(scorecard),
94
- confidence: scorecard.confidence,
95
- budgetClass: scorecard.budgetClass,
96
- selectedCandidateIds: scorecard.selectedCandidateIds,
97
- rejectedCandidates: scorecard.rejectedCandidates?.slice(0, 3).map((candidate) => ({
98
- id: candidate.id,
99
- reasonCodes: candidate.reasonCodes
100
- })) ?? [],
101
- reasons: scorecard.reasons?.slice(0, 2),
102
- nodes: scorecard.nodes?.slice(0, 3).map((node) => ({
103
- id: node.id,
104
- state: node.state,
105
- riskLevel: node.riskLevel,
106
- helped: node.helped,
107
- harmed: node.harmed
108
- })) ?? []
109
- }
110
- : undefined;
1
+ import { createSharedBehaviorLoop } from "../shared-mcp/behavior-loop.js";
111
2
  export const createCodexBehaviorLoop = (options = {}) => {
112
- let promptRuntime;
113
- let runtime;
114
- const promptLookups = new Map();
115
- const getPromptRuntime = () => {
116
- promptRuntime ??= createCodexPromptRuntime(options);
117
- return promptRuntime;
118
- };
119
- const getRuntime = async () => {
120
- runtime ??= createCodexRuntime(options);
121
- return runtime;
122
- };
123
- return {
124
- async lookupHints(args) {
125
- if (args.sessionId) {
126
- const existingRuntime = await getRuntime();
127
- existingRuntime.resetSession(args.sessionId);
128
- }
129
- const fullRuntime = await getRuntime();
130
- await fullRuntime.signalHostEvent({
131
- host: "codex",
132
- sessionId: args.sessionId,
133
- cwd: args.cwd,
134
- userMessage: args.prompt,
135
- taskSummary: args.prompt
136
- }, "prompt_lookup");
137
- const context = {
138
- host: "codex",
139
- sessionId: args.sessionId,
140
- cwd: args.cwd,
141
- userMessage: args.prompt,
142
- taskSummary: args.prompt
143
- };
144
- const result = await getPromptRuntime().beforePromptBuild(context);
145
- promptLookups.set(args.sessionId ?? "global", {
146
- context,
147
- injectedNodeIds: result.input.injected_node_ids
148
- });
149
- return {
150
- mode: result.mode,
151
- text: result.text,
152
- notice: result.notice,
153
- injectedNodeIds: result.input.injected_node_ids,
154
- summary: summarizeScorecard(result.scorecard),
155
- deliveryMode: result.deliveryMode,
156
- delivered: result.delivered
157
- };
158
- },
159
- async signalHostEvent(args) {
160
- const fullRuntime = await getRuntime();
161
- return fullRuntime.signalHostEvent({
162
- host: "codex",
163
- sessionId: args.sessionId,
164
- cwd: args.cwd,
165
- userMessage: "",
166
- taskSummary: args.trigger
167
- }, args.trigger);
168
- },
169
- async recordToolResult(args) {
170
- const fullRuntime = await getRuntime();
171
- const event = await fullRuntime.persistToolResult({
172
- sessionId: args.sessionId,
173
- toolName: args.toolName,
174
- inputSummary: args.inputSummary,
175
- outputSummary: args.outputSummary,
176
- errorSignature: args.errorSignature,
177
- exitCode: args.exitCode,
178
- status: args.status
179
- });
180
- return {
181
- status: "recorded",
182
- toolName: event.tool_name,
183
- eventStatus: event.status,
184
- hasErrorSignature: Boolean(event.error_signature),
185
- exitCode: event.exit_code
186
- };
187
- },
188
- async finalizeTask(args) {
189
- const fullRuntime = await getRuntime();
190
- const promptLookup = promptLookups.get(args.sessionId);
191
- const input = await fullRuntime.finalizeTask({
192
- host: "codex",
193
- sessionId: args.sessionId,
194
- cwd: args.cwd ?? promptLookup?.context.cwd,
195
- userMessage: args.prompt ?? "",
196
- taskSummary: args.prompt ?? promptLookup?.context.taskSummary,
197
- contextSummary: args.contextSummary,
198
- injectedNodeIds: args.injectedNodeIds ?? promptLookup?.injectedNodeIds
199
- });
200
- promptLookups.delete(args.sessionId ?? "global");
201
- return {
202
- status: "finalized",
203
- taskType: input.task_type,
204
- outcomeSignal: input.outcome_signal,
205
- injectedNodeIds: input.injected_node_ids,
206
- recordedToolEvents: input.tool_events.length,
207
- feedbackHint: input.injected_node_ids.length > 0
208
- ? "If the injected guidance helped or harmed this task, call experienceengine_quick_feedback."
209
- : undefined
210
- };
211
- },
212
- async waitForBackgroundLearning() {
213
- const fullRuntime = await getRuntime();
214
- await fullRuntime.waitForBackgroundLearning();
215
- }
216
- };
3
+ return createSharedBehaviorLoop("codex", options);
217
4
  };
218
5
  //# sourceMappingURL=behavior-loop.js.map