opencode-matrixx 2.6.10 → 2.6.12

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 (132) hide show
  1. package/README.md +6 -5
  2. package/dist/agents/architect/default.d.ts +1 -1
  3. package/dist/agents/architect/gpt.d.ts +1 -1
  4. package/dist/agents/dynamic-agent-prompt-builder.d.ts +6 -5
  5. package/dist/agents/oracle/plan-template.d.ts +1 -7
  6. package/dist/agents/oracle/system-prompt.d.ts +1 -1
  7. package/dist/cli.js +29 -86
  8. package/dist/config/schema/agent-overrides.d.ts +126 -126
  9. package/dist/config/schema/commands.d.ts +0 -5
  10. package/dist/config/schema/dcp.d.ts +3 -3
  11. package/dist/config/schema/hooks.d.ts +3 -2
  12. package/dist/config/schema/internal/permission.d.ts +8 -8
  13. package/dist/config/schema/knowledge.d.ts +34 -0
  14. package/dist/config/schema/matrixx-config.d.ts +145 -132
  15. package/dist/config/schema/tool-gating.d.ts +9 -0
  16. package/dist/config/schema.d.ts +2 -1
  17. package/dist/create-hooks.d.ts +3 -2
  18. package/dist/features/background-agent/manager.d.ts +19 -0
  19. package/dist/features/bdd/schema.d.ts +5 -5
  20. package/dist/features/builtin-commands/templates/evolution.d.ts +1 -1
  21. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  22. package/dist/features/builtin-commands/types.d.ts +1 -1
  23. package/dist/features/evolution/compressor/index.d.ts +2 -2
  24. package/dist/features/evolution/compressor/interface.d.ts +9 -4
  25. package/dist/features/evolution/compressor/llm.d.ts +14 -4
  26. package/dist/features/evolution/evaluator.d.ts +10 -0
  27. package/dist/features/evolution/pipeline.d.ts +3 -1
  28. package/dist/features/evolution/schema.d.ts +46 -0
  29. package/dist/features/evolution/store/budget-ledger.d.ts +46 -0
  30. package/dist/features/evolution/store/index.d.ts +5 -0
  31. package/dist/features/evolution/store/lifecycle.d.ts +52 -0
  32. package/dist/features/evolution/store/project-identity.d.ts +27 -0
  33. package/dist/features/evolution/store/query.d.ts +23 -0
  34. package/dist/features/evolution/{store.d.ts → store/trace-store.d.ts} +1 -1
  35. package/dist/features/evolution/types.d.ts +34 -1
  36. package/dist/features/evolution/writer-emit.d.ts +17 -0
  37. package/dist/features/evolution/writer-frontmatter.d.ts +23 -0
  38. package/dist/features/evolution/writer-supersede.d.ts +20 -0
  39. package/dist/features/evolution/writer.d.ts +4 -0
  40. package/dist/features/knowledge-hub/index.d.ts +3 -0
  41. package/dist/features/knowledge-hub/loader.d.ts +11 -0
  42. package/dist/features/knowledge-hub/resolver.d.ts +2 -0
  43. package/dist/features/mission-state/constants.d.ts +20 -0
  44. package/dist/features/mission-state/index.d.ts +1 -0
  45. package/dist/features/mission-state/plan-storage.d.ts +32 -6
  46. package/dist/features/mission-state/reconcile.d.ts +75 -0
  47. package/dist/features/mission-state/reconcile.test.d.ts +1 -0
  48. package/dist/features/mission-state/storage.d.ts +26 -0
  49. package/dist/features/mission-state/types.d.ts +6 -0
  50. package/dist/features/plan-contract/appendix.d.ts +14 -0
  51. package/dist/features/plan-contract/constants.d.ts +16 -0
  52. package/dist/features/plan-contract/front-matter.d.ts +34 -0
  53. package/dist/features/plan-contract/index.d.ts +14 -0
  54. package/dist/features/plan-contract/migration.d.ts +36 -0
  55. package/dist/features/plan-contract/schema.d.ts +32 -0
  56. package/dist/features/plan-contract/skeleton.d.ts +5 -0
  57. package/dist/features/plan-contract/types.d.ts +56 -0
  58. package/dist/features/plan-contract/validate.d.ts +9 -0
  59. package/dist/features/session-state/state.d.ts +0 -11
  60. package/dist/hooks/auto-slash-command/executor.d.ts +11 -3
  61. package/dist/hooks/auto-slash-command/hook.d.ts +0 -2
  62. package/dist/hooks/evolution-compressor/host-llm-call.d.ts +17 -0
  63. package/dist/hooks/index.d.ts +3 -2
  64. package/dist/hooks/knowledge-hub-guard/approvals.d.ts +5 -0
  65. package/dist/hooks/knowledge-hub-guard/hook.d.ts +15 -0
  66. package/dist/hooks/knowledge-hub-guard/hook.test.d.ts +1 -0
  67. package/dist/hooks/knowledge-hub-guard/index.d.ts +3 -0
  68. package/dist/hooks/knowledge-hub-injector/hook.d.ts +26 -0
  69. package/dist/hooks/knowledge-hub-injector/hook.test.d.ts +1 -0
  70. package/dist/hooks/knowledge-hub-injector/index.d.ts +2 -0
  71. package/dist/hooks/knowledge-hub-search-nudge/hook.d.ts +16 -0
  72. package/dist/hooks/knowledge-hub-search-nudge/hook.test.d.ts +1 -0
  73. package/dist/hooks/knowledge-hub-search-nudge/index.d.ts +2 -0
  74. package/dist/hooks/plan-persister/index.d.ts +4 -0
  75. package/dist/hooks/plan-persister/task-link.d.ts +31 -0
  76. package/dist/hooks/plan-persister/task-sync.d.ts +39 -0
  77. package/dist/hooks/plan-persister/task-sync.test.d.ts +1 -0
  78. package/dist/hooks/start-work/index.d.ts +1 -0
  79. package/dist/hooks/start-work/plan-filter.d.ts +48 -0
  80. package/dist/hooks/task-continuation-enforcer/constants.d.ts +0 -5
  81. package/dist/index.js +6247 -4111
  82. package/dist/matrixx.schema.json +88 -145
  83. package/dist/plugin/hooks/create-core-hooks.d.ts +3 -2
  84. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
  85. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +3 -2
  86. package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -1
  87. package/dist/plugin/tool-gating.d.ts +35 -0
  88. package/dist/shared/dcp-guidance.d.ts +16 -0
  89. package/dist/{tools/dcp-switch-profile/tools.d.ts → shared/dcp-switch-profile.d.ts} +1 -3
  90. package/dist/shared/index.d.ts +1 -0
  91. package/dist/tools/background-task/constants.d.ts +1 -0
  92. package/dist/tools/background-task/create-background-wait-all.d.ts +3 -0
  93. package/dist/tools/background-task/index.d.ts +1 -1
  94. package/dist/tools/background-task/tools.d.ts +1 -0
  95. package/dist/tools/background-task/types.d.ts +3 -0
  96. package/dist/tools/delegate-task/constants.d.ts +6 -0
  97. package/dist/tools/delegate-task/prompt-builder.d.ts +1 -0
  98. package/dist/tools/delegate-task/prompt-builder.tdd.test.d.ts +1 -0
  99. package/dist/tools/delegate-task/tdd-enforcement.test.d.ts +1 -0
  100. package/dist/tools/delegate-task/tools.d.ts +6 -0
  101. package/dist/tools/delegate-task/types.d.ts +1 -0
  102. package/dist/tools/evolution/constants.d.ts +24 -0
  103. package/dist/tools/evolution/index.d.ts +3 -0
  104. package/dist/tools/evolution/query-actions.d.ts +3 -0
  105. package/dist/tools/evolution/query-actions.test.d.ts +1 -0
  106. package/dist/tools/evolution/tools.d.ts +16 -0
  107. package/dist/tools/evolution/tools.test.d.ts +1 -0
  108. package/dist/tools/evolution/types.d.ts +20 -0
  109. package/dist/tools/index.d.ts +2 -1
  110. package/dist/tools/knowledge-hub-confirm/index.d.ts +1 -0
  111. package/dist/tools/knowledge-hub-confirm/tools.d.ts +12 -0
  112. package/dist/tools/knowledge-hub-confirm/tools.test.d.ts +1 -0
  113. package/dist/tools/plan/constants.d.ts +1 -0
  114. package/dist/tools/plan/index.d.ts +1 -0
  115. package/dist/tools/plan/plan-tasks.d.ts +3 -0
  116. package/dist/tools/plan/types.d.ts +10 -0
  117. package/package.json +1 -1
  118. package/dist/config/schema/failure-counter.d.ts +0 -7
  119. package/dist/features/builtin-commands/templates/bdd-backend.d.ts +0 -1
  120. package/dist/features/builtin-commands/templates/bdd-contract.d.ts +0 -1
  121. package/dist/features/builtin-commands/templates/bdd-frontend.d.ts +0 -1
  122. package/dist/features/builtin-commands/templates/bdd-tests.d.ts +0 -1
  123. package/dist/features/builtin-commands/templates/dcp-profile.d.ts +0 -1
  124. package/dist/hooks/failure-counter/counter.d.ts +0 -7
  125. package/dist/hooks/failure-counter/hook.d.ts +0 -18
  126. package/dist/hooks/failure-counter/index.d.ts +0 -3
  127. package/dist/hooks/failure-counter/patterns.d.ts +0 -6
  128. package/dist/hooks/hashline-edit-diff-enhancer/hook.d.ts +0 -28
  129. package/dist/hooks/hashline-edit-diff-enhancer/index.d.ts +0 -1
  130. package/dist/tools/dcp-switch-profile/index.d.ts +0 -1
  131. /package/dist/{hooks/failure-counter/counter.test.d.ts → features/knowledge-hub/loader.test.d.ts} +0 -0
  132. /package/dist/{hooks/failure-counter/patterns.test.d.ts → features/knowledge-hub/resolver.test.d.ts} +0 -0
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ /** Startup-token tool auto-gating — defer rarely-needed LLM tools until auto-detect or opt-in */
3
+ export declare const ToolGatingConfigSchema: z.ZodObject<{
4
+ bdd_tools: z.ZodOptional<z.ZodBoolean>;
5
+ pdf_figures: z.ZodOptional<z.ZodBoolean>;
6
+ look_at: z.ZodOptional<z.ZodBoolean>;
7
+ preset_tools: z.ZodDefault<z.ZodBoolean>;
8
+ }, z.core.$strip>;
9
+ export type ToolGatingConfig = z.infer<typeof ToolGatingConfigSchema>;
@@ -13,9 +13,9 @@ export * from "./schema/context-mode";
13
13
  export * from "./schema/dcp";
14
14
  export * from "./schema/evolution";
15
15
  export * from "./schema/experimental";
16
- export * from "./schema/failure-counter";
17
16
  export * from "./schema/headroom";
18
17
  export * from "./schema/hooks";
18
+ export * from "./schema/knowledge";
19
19
  export * from "./schema/matrix-loop";
20
20
  export * from "./schema/matrixx-config";
21
21
  export * from "./schema/matrixx-self-config";
@@ -32,4 +32,5 @@ export * from "./schema/task";
32
32
  export * from "./schema/tasks";
33
33
  export * from "./schema/tdd-enforcer";
34
34
  export * from "./schema/tmux";
35
+ export * from "./schema/tool-gating";
35
36
  export * from "./schema/websearch";
@@ -29,6 +29,7 @@ export declare function createHooks(args: {
29
29
  inputSecretGuard: ReturnType<typeof import("./hooks").createInputSecretGuardHook> | null;
30
30
  keywordDetector: ReturnType<typeof import("./hooks").createKeywordDetectorHook> | null;
31
31
  contextInjectorMessagesTransform: ReturnType<typeof import("./features/context-injector").createContextInjectorMessagesTransformHook>;
32
+ knowledgeHubInjector: ReturnType<typeof import("./hooks").createKnowledgeHubInjectorHook> | null;
32
33
  envContextInjector: ReturnType<typeof import("./hooks").createEnvContextInjectorHook> | null;
33
34
  thinkingBlockValidator: ReturnType<typeof import("./hooks").createThinkingBlockValidatorHook> | null;
34
35
  toolPairValidator: ReturnType<typeof import("./hooks").createToolPairValidatorHook> | null;
@@ -49,11 +50,12 @@ export declare function createHooks(args: {
49
50
  contextModeEnforcer: ReturnType<typeof import("./hooks").createContextModeEnforcerHook> | null;
50
51
  readImageResizer: ReturnType<typeof import("./hooks").createReadImageResizerHook> | null;
51
52
  webfetchRedirectGuard: ReturnType<typeof import("./hooks").createWebFetchRedirectGuardHook> | null;
52
- hashlineEditDiffEnhancer: ReturnType<typeof import("./hooks").createHashlineEditDiffEnhancerHook> | null;
53
53
  qualityGate: ReturnType<typeof import("./hooks").createQualityGateHook> | null;
54
54
  taskNotepad: ReturnType<typeof import("./hooks").createTaskNotepadHook> | null;
55
55
  taskEditGuard: ReturnType<typeof import("./hooks").createTaskEditGuardHook> | null;
56
56
  documentReaderGuard: ReturnType<typeof import("./hooks").createDocumentReaderGuardHook> | null;
57
+ knowledgeHubGuard: ReturnType<typeof import("./hooks").createKnowledgeHubGuardHook> | null;
58
+ knowledgeHubSearchNudge: ReturnType<typeof import("./hooks").createKnowledgeHubSearchNudgeHook> | null;
57
59
  evolutionWatcher: ReturnType<typeof import("./hooks").createEvolutionWatcherHook> | null;
58
60
  contextWindowMonitor: ReturnType<typeof import("./hooks").createContextWindowMonitorHook> | null;
59
61
  preemptiveCompaction: ReturnType<typeof import("./hooks").createPreemptiveCompactionHook> | null;
@@ -68,7 +70,6 @@ export declare function createHooks(args: {
68
70
  matrixLoop: ReturnType<typeof import("./hooks").createMatrixLoopHook> | null;
69
71
  editErrorRecovery: ReturnType<typeof import("./hooks").createEditErrorRecoveryHook> | null;
70
72
  delegateTaskRetry: ReturnType<typeof import("./hooks").createDelegateTaskRetryHook> | null;
71
- failureCounter: ReturnType<typeof import("./hooks").createFailureCounterHook> | null;
72
73
  startWork: ReturnType<typeof import("./hooks").createStartWorkHook> | null;
73
74
  oracleMdOnly: ReturnType<typeof import("./hooks").createOracleMdOnlyHook> | null;
74
75
  mouseNotepad: ReturnType<typeof import("./hooks").createMouseNotepadHook> | null;
@@ -184,6 +184,25 @@ export declare class BackgroundManager {
184
184
  * Returns the number of tasks cancelled.
185
185
  */
186
186
  cancelAllForSession(parentSessionID: string): number;
187
+ /**
188
+ * Wait for all descendant tasks (running/pending) to reach a terminal state.
189
+ * Polls every `pollIntervalMs` until all tasks are terminal or `timeoutMs` elapses.
190
+ * Returns per-task results: completed tasks and timed-out (still running) tasks.
191
+ */
192
+ waitForAllDescendants(sessionID: string, timeoutMs?: number, pollIntervalMs?: number): Promise<{
193
+ completed: Array<{
194
+ id: string;
195
+ description: string;
196
+ agent: string;
197
+ status: string;
198
+ }>;
199
+ timedOut: Array<{
200
+ id: string;
201
+ description: string;
202
+ agent: string;
203
+ status: string;
204
+ }>;
205
+ }>;
187
206
  private startPolling;
188
207
  private stopPolling;
189
208
  private registerProcessCleanup;
@@ -86,8 +86,8 @@ export declare const HttpMethodSchema: z.ZodEnum<{
86
86
  }>;
87
87
  export declare const ResponseFormatSchema: z.ZodEnum<{
88
88
  binary: "binary";
89
- text: "text";
90
89
  json: "json";
90
+ text: "text";
91
91
  html: "html";
92
92
  xml: "xml";
93
93
  }>;
@@ -118,8 +118,8 @@ export declare const ApiResponseSchema: z.ZodObject<{
118
118
  status: z.ZodNumber;
119
119
  format: z.ZodEnum<{
120
120
  binary: "binary";
121
- text: "text";
122
121
  json: "json";
122
+ text: "text";
123
123
  html: "html";
124
124
  xml: "xml";
125
125
  }>;
@@ -174,8 +174,8 @@ export declare const ApiAnnotationsSchema: z.ZodObject<{
174
174
  status: z.ZodNumber;
175
175
  format: z.ZodEnum<{
176
176
  binary: "binary";
177
- text: "text";
178
177
  json: "json";
178
+ text: "text";
179
179
  html: "html";
180
180
  xml: "xml";
181
181
  }>;
@@ -236,8 +236,8 @@ export declare const ContractAnnotationsSchema: z.ZodObject<{
236
236
  status: z.ZodNumber;
237
237
  format: z.ZodEnum<{
238
238
  binary: "binary";
239
- text: "text";
240
239
  json: "json";
240
+ text: "text";
241
241
  html: "html";
242
242
  xml: "xml";
243
243
  }>;
@@ -366,8 +366,8 @@ export declare const ContractSchema: z.ZodObject<{
366
366
  status: z.ZodNumber;
367
367
  format: z.ZodEnum<{
368
368
  binary: "binary";
369
- text: "text";
370
369
  json: "json";
370
+ text: "text";
371
371
  html: "html";
372
372
  xml: "xml";
373
373
  }>;
@@ -1 +1 @@
1
- export declare const EVOLUTION_TEMPLATE = "# Evolution Command\n\n## Purpose\n\nManage self-evolution proposals staged in `.matrixx/evolution/pending`.\n\n## Commands\n\n- `/evolution list` \u2014 list pending proposals\n- `/evolution approve <slug>` \u2014 promote pending skill to `.opencode/skills/<slug>/SKILL.md`\n- `/evolution reject <slug>` \u2014 discard pending proposal\n- `/evolution audit` \u2014 show last 20 audit entries\n\n---\n\n# PHASE 1: PARSE ARGUMENTS\n\nArguments: $ARGUMENTS\n\n- If empty or \"list\": list pending\n- If \"approve <slug>\" or \"approve <slug> --global\": promote\n- If \"reject <slug>\": discard\n- If \"audit\" or \"log\": show audit\n- Otherwise: show help and list pending\n\n---\n\n# PHASE 2: EXECUTE\n\n## List\n\nUse bash: `ls -1 .matrixx/evolution/pending/*.md 2>/dev/null | xargs -I {} basename {} .md` or `rtk ls .matrixx/evolution/pending`\nFor each slug, read `.matrixx/evolution/pending/<slug>.meta.json` to show confidence, version, derived_from.\nIf none: \"No pending evolution proposals.\"\n\n## Approve\n\n1. Verify `.matrixx/evolution/pending/<slug>.md` exists \u2014 if not, error: \"Pending <slug> not found. Run /evolution list to see available.\"\n2. Copy staged skill:\n - `mkdir -p .opencode/skills/<slug>`\n - `cp .matrixx/evolution/pending/<slug>.md .opencode/skills/<slug>/SKILL.md`\n - Also preserve versioned copy: `mkdir -p .matrixx/evolution/skills/<slug>/versions && cp .matrixx/evolution/pending/<slug>.md .matrixx/evolution/skills/<slug>/SKILL.md`\n3. Append audit: `echo '{\"action\":\"promoted\",\"slug\":\"<slug>\",\"timestamp\":\"'$(date -Iseconds)'\"}' >> .matrixx/evolution/audit.log`\n4. Remove pending: `rm .matrixx/evolution/pending/<slug>.md .matrixx/evolution/pending/<slug>.meta.json`\n5. If argument includes --global, also copy to `~/.agents/skills/<slug>/SKILL.md`\n6. Confirm: \"Promoted <slug> to .opencode/skills/<slug>/SKILL.md \u2014 will be loaded on next session start.\"\n\n## Reject\n\n1. Verify pending exists\n2. `rm .matrixx/evolution/pending/<slug>.md .matrixx/evolution/pending/<slug>.meta.json`\n3. Append audit with action rejected\n4. Confirm: \"Rejected <slug>.\"\n\n## Audit\n\nRead `.matrixx/evolution/audit.log` last 20 lines: `tail -n 20 .matrixx/evolution/audit.log 2>/dev/null || echo \"No audit entries.\"`\n\n---\n\n# CONSTRAINTS\n\n- Use bash/rtk for file ops \u2014 no dedicated evolution tool yet\n- Never invent slug \u2014 read from pending dir\n- Keep operations atomic; report errors clearly\n- Do not modify pending content \u2014 promote as-is after human review\n";
1
+ export declare const EVOLUTION_TEMPLATE = "# Evolution Command\n\n## Purpose\n\nManage self-evolution proposals staged in `.matrixx/evolution/pending`.\n\n## Commands\n\n- `/evolution list` \u2014 list pending proposals\n- `/evolution approve <slug>` \u2014 promote pending skill to `.opencode/skills/<slug>/SKILL.md`\n- `/evolution reject <slug>` \u2014 discard pending proposal\n- `/evolution audit` \u2014 show last 20 audit entries\n\n---\n\n# PHASE 1: PARSE ARGUMENTS\n\nArguments: $ARGUMENTS\n\n- If empty or \"list\": list pending\n- If \"approve <slug>\" or \"approve <slug> --global\": promote\n- If \"reject <slug>\": discard\n- If \"audit\" or \"log\": show audit\n- Otherwise: show help and list pending\n\n---\n\n# PHASE 2: EXECUTE\n\nUse the `evolution` tool for every operation below \u2014 never shell out for\nevolution state. Parse $ARGUMENTS into one tool call per user request.\n\n## List\n\nCall `evolution` with `{ \"action\": \"list\" }`.\nFor each slug, call `evolution` with `{ \"action\": \"get\", \"slug\": \"<slug>\" }` to show confidence, version, derived_from.\nIf none: \"No pending evolution proposals.\"\n\n## Approve\n\n1. Call `evolution` with `{ \"action\": \"get\", \"slug\": \"<slug>\" }` \u2014 if not found, error: \"Pending <slug> not found. Run /evolution list to see available.\"\n2. Call `evolution` with `{ \"action\": \"approve\", \"slug\": \"<slug>\" }` to promote the staged skill (audit entry recorded by the tool).\n3. If argument includes --global, call `evolution` with `{ \"action\": \"approve\", \"slug\": \"<slug>\", \"global\": true }` instead to also copy to `~/.agents/skills/<slug>/SKILL.md`.\n4. Confirm: \"Promoted <slug> to .opencode/skills/<slug>/SKILL.md \u2014 will be loaded on next session start.\"\n\n## Reject\n\n1. Call `evolution` with `{ \"action\": \"reject\", \"slug\": \"<slug>\" }` (verifies pending exists, discards it, records the audit entry).\n2. Confirm: \"Rejected <slug>.\"\n\n## Audit\n\nCall `evolution` with `{ \"action\": \"status\" }` and show the audit tail section. If no entries: \"No audit entries.\"\n\n---\n\n# CONSTRAINTS\n\n- Use the `evolution` tool for all state ops \u2014 no bash/rtk for evolution state\n- Never invent slug \u2014 read from the `list` action\n- Keep operations atomic; report errors clearly\n- Do not modify pending content \u2014 promote as-is after human review\n";
@@ -1 +1 @@
1
- export declare const START_WORK_TEMPLATE = "You are starting a Morpheus work session.\n\n## WHAT TO DO\n\n1. **Find available plans**: List Oracle-generated plan files via plan_list at `.matrixx/plans/`\n\n2. **Check for active mission state**: Read `.matrixx/mission.json` if it exists\n\n3. **Decision logic**:\n - If `.matrixx/mission.json` exists AND plan is NOT complete (has unchecked boxes):\n - **APPEND** current session to session_ids\n - Continue work on existing plan\n - If no active plan OR plan is complete:\n - List available plan files via plan_list\n - If ONE plan: auto-select it\n - If MULTIPLE plans: show list with timestamps, ask user to select\n\n4. **Create/Update mission.json**:\n ```json\n {\n \"active_plan\": \"/absolute/path/to/plan.md\",\n \"started_at\": \"ISO_TIMESTAMP\",\n \"session_ids\": [\"session_id_1\", \"session_id_2\"],\n \"plan_name\": \"plan-name\"\n }\n ```\n\n5. **Read the plan file via plan_read** and start executing tasks according to architect workflow\n\n## OUTPUT FORMAT\n\nWhen listing plans for selection:\n```\nAvailable Work Plans\n\nCurrent Time: {ISO timestamp}\nSession ID: {current session id}\n\n1. [plan-name-1.md] - Modified: {date} - Progress: 3/10 tasks\n2. [plan-name-2.md] - Modified: {date} - Progress: 0/5 tasks\n\nWhich plan would you like to work on? (Enter number or plan name)\n```\n\nWhen resuming existing work:\n```\nResuming Work Session\n\nActive Plan: {plan-name}\nProgress: {completed}/{total} tasks\nSessions: {count} (appending current session)\n\nReading plan and continuing from last incomplete task...\n```\n\nWhen auto-selecting single plan:\n```\nStarting Work Session\n\nPlan: {plan-name}\nSession ID: {session_id}\nStarted: {timestamp}\n\nReading plan and beginning execution...\n```\n\n## CRITICAL\n\n- The session_id is injected by the hook - use it directly\n- Always update mission.json BEFORE starting work\n- Read the FULL plan file via plan_read before delegating any tasks\n- Follow architect delegation protocols (7-section format)";
1
+ export declare const START_WORK_TEMPLATE = "You are starting a Morpheus work session.\n\n## WHAT TO DO\n\n1. **Find available plans**: List Oracle-generated plan files via plan_list at `.matrixx/plans/`; each entry carries a progress field (total, completed, remaining, isComplete)\n\n2. **Check for active mission state**: Read `.matrixx/mission.json` if it exists\n\n3. **Decision logic**:\n - If `.matrixx/mission.json` exists AND plan is NOT complete (has unchecked boxes):\n - **APPEND** current session to session_ids\n - Continue work on existing plan\n - If no active plan OR plan is complete:\n - List available plan files via plan_list\n - If ONE plan: auto-select it\n - If MULTIPLE plans: show list with timestamps, ask user to select\n\n4. **Create/Update mission.json**:\n ```json\n {\n \"active_plan\": \"/absolute/path/to/plan.md\",\n \"started_at\": \"ISO_TIMESTAMP\",\n \"session_ids\": [\"session_id_1\", \"session_id_2\"],\n \"plan_name\": \"plan-name\"\n }\n ```\n\n5. **Read the plan**: Call plan_tasks for the task manifest and progress; then read the plan body via paginated plan_read (offset/limit). One call cannot return a plan that renders above the soft cap.\n\n## OUTPUT FORMAT\n\nWhen listing plans for selection:\n```\nAvailable Work Plans\n\nCurrent Time: {ISO timestamp}\nSession ID: {current session id}\n\n1. [plan-name-1.md] - Modified: {date} - Progress: {completed}/{total} tasks\n2. [plan-name-2.md] - Modified: {date} - Progress: {completed}/{total} tasks\n\nWhich plan would you like to work on? (Enter number or plan name)\n```\n\nWhen resuming existing work:\n```\nResuming Work Session\n\nActive Plan: {plan-name}\nProgress: {completed}/{total} tasks\nSessions: {count} (appending current session)\n\nReading plan and continuing from last incomplete task...\n```\n\nWhen auto-selecting single plan:\n```\nStarting Work Session\n\nPlan: {plan-name}\nSession ID: {session_id}\nStarted: {timestamp}\n\nReading plan and beginning execution...\n```\n\n## CRITICAL\n\n- The session_id is injected by the hook - use it directly\n- Always update mission.json BEFORE starting work\n- Call plan_tasks for the manifest; use paginated plan_read (offset/limit) for content \u2014 one call cannot return a plan that renders above the soft cap\n- Follow architect delegation protocols (7-section format)";
@@ -1,3 +1,3 @@
1
1
  import type { CommandDefinition } from "../command-loader";
2
- export type BuiltinCommandName = "init-deep" | "matrix-loop" | "cancel-loop" | "ulw-loop" | "refactor" | "start-work" | "stop-continuation" | "handoff" | "pickup" | "remove-deadcode" | "preset" | "end-ultrawork" | "research" | "assembly" | "ultrawork" | "bdd-backend" | "bdd-contract" | "bdd-frontend" | "bdd-pipeline" | "bdd-tests" | "dcp-profile" | "evolution" | "cleanup-tasks" | "task-list";
2
+ export type BuiltinCommandName = "init-deep" | "matrix-loop" | "cancel-loop" | "ulw-loop" | "refactor" | "start-work" | "stop-continuation" | "handoff" | "pickup" | "remove-deadcode" | "preset" | "end-ultrawork" | "research" | "assembly" | "ultrawork" | "bdd-pipeline" | "evolution" | "cleanup-tasks" | "task-list";
3
3
  export type BuiltinCommands = Record<string, CommandDefinition>;
@@ -1,5 +1,5 @@
1
1
  export * from "./interface";
2
2
  export * from "./llm";
3
3
  import type { EvolutionCompressorConfig } from "../../../config/schema/evolution";
4
- import type { Compressor } from "./interface";
5
- export declare function createCompressor(config: EvolutionCompressorConfig, llmCall?: (prompt: string) => Promise<string>): Compressor;
4
+ import type { Compressor, LlmCall } from "./interface";
5
+ export declare function createCompressor(config: EvolutionCompressorConfig, llmCall?: LlmCall): Compressor;
@@ -1,5 +1,10 @@
1
- import type { CompressionInput, DistilledKnowledge } from "../types";
2
- export interface Compressor {
3
- compress(input: CompressionInput): Promise<DistilledKnowledge>;
4
- }
1
+ import type { CompressionUsage, CompressResult } from "../types";
2
+ export type { Compressor } from "../types";
3
+ export type LlmUsage = CompressionUsage;
4
+ export type LlmResponse = {
5
+ text: string;
6
+ usage?: LlmUsage;
7
+ };
8
+ export type LlmCall = (prompt: string, model?: string) => Promise<string | LlmResponse>;
9
+ export type CompressionResult = CompressResult;
5
10
  export type { CompressionInput, DistilledKnowledge, TraceRecord } from "../types";
@@ -1,12 +1,22 @@
1
1
  import type { EvolutionCompressorConfig } from "../../../config/schema/evolution";
2
- import type { CompressionInput, DistilledKnowledge } from "../types";
3
- import type { Compressor } from "./interface";
2
+ import { type CompressionInput, type KnowledgeKind, type TraceRecord } from "../types";
3
+ import type { CompressionResult, Compressor, LlmCall } from "./interface";
4
+ /**
5
+ * Deterministic best-effort kind from trace signals (offline heuristic path).
6
+ * Rule (pure function of counts + final outcome, no randomness):
7
+ * - no traces at all → `convention` (nothing to learn from)
8
+ * - all failed → `gotcha` (warn about the dead end)
9
+ * - failures present and final trace succeeded → `debugging_pattern` (recovery worth replaying)
10
+ * - failures present and final trace still failed → `correction` (needs fixes first)
11
+ * - all succeeded → `workflow` (clean success path)
12
+ */
13
+ export declare function heuristicKind(traces: TraceRecord[]): KnowledgeKind;
4
14
  export declare class LlmCompressor implements Compressor {
5
15
  private config;
6
16
  private llmCall?;
7
17
  constructor(options: {
8
18
  config: EvolutionCompressorConfig;
9
- llmCall?: (prompt: string) => Promise<string>;
19
+ llmCall?: LlmCall;
10
20
  });
11
- compress(input: CompressionInput): Promise<DistilledKnowledge>;
21
+ compress(input: CompressionInput): Promise<CompressionResult>;
12
22
  }
@@ -9,3 +9,13 @@ export declare function evaluateSkill(slug: string, opts?: {
9
9
  threshold?: number;
10
10
  projectRoot?: string;
11
11
  }): Promise<EvalResult>;
12
+ export type EvaluationSweepResult = {
13
+ evaluated: string[];
14
+ demoted: string[];
15
+ };
16
+ /** Evaluate every promoted evolution skill (demoting/quarantining low scorers). Safe to call on session idle. */
17
+ export declare function evaluatePromotedSkills(opts?: {
18
+ threshold?: number;
19
+ projectRoot?: string;
20
+ slugs?: string[];
21
+ }): Promise<EvaluationSweepResult>;
@@ -1,7 +1,9 @@
1
1
  import type { EvolutionConfig } from "../../config/schema/evolution";
2
+ import type { LlmCall, LlmUsage } from "./compressor/interface";
2
3
  import type { CompressionInput } from "./types";
3
- export declare function runEvolutionPipeline(input: CompressionInput, config: EvolutionConfig): Promise<{
4
+ export declare function runEvolutionPipeline(input: CompressionInput, config: EvolutionConfig, llmCall?: LlmCall): Promise<{
4
5
  staged?: string;
5
6
  promoted?: string;
6
7
  reason?: string;
8
+ usage?: LlmUsage;
7
9
  }>;
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ import type { KnowledgeKind } from "./types";
3
+ /**
4
+ * D5 typed knowledge kinds — DATA schemas (not config knobs).
5
+ *
6
+ * The `KnowledgeKind` union lives in `./types` (single source); this module
7
+ * owns the Zod runtime schema plus the fail-open normalizer used on every
8
+ * read path (LLM output, stored JSON, legacy meta.json without `kind`).
9
+ */
10
+ export declare const KNOWLEDGE_KINDS: readonly ["workflow", "correction", "debugging_pattern", "gotcha", "convention"];
11
+ export declare const KnowledgeKindSchema: z.ZodEnum<{
12
+ workflow: "workflow";
13
+ correction: "correction";
14
+ debugging_pattern: "debugging_pattern";
15
+ gotcha: "gotcha";
16
+ convention: "convention";
17
+ }>;
18
+ export declare const DEFAULT_KNOWLEDGE_KIND: KnowledgeKind;
19
+ /**
20
+ * Fail-open normalizer: valid kinds pass through, missing/unknown values
21
+ * become `convention` instead of throwing (back-compat for stored JSON).
22
+ */
23
+ export declare function normalizeKnowledgeKind(value: unknown): KnowledgeKind;
24
+ /** Data-shape schema for distilled knowledge (stored/LLM JSON, not config). */
25
+ export declare const DistilledKnowledgeDataSchema: z.ZodObject<{
26
+ title: z.ZodString;
27
+ summary: z.ZodString;
28
+ patterns: z.ZodArray<z.ZodString>;
29
+ pitfalls: z.ZodArray<z.ZodString>;
30
+ prerequisites: z.ZodArray<z.ZodString>;
31
+ skillDraft: z.ZodOptional<z.ZodString>;
32
+ confidence: z.ZodNumber;
33
+ sourceSessionIDs: z.ZodArray<z.ZodString>;
34
+ kind: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
35
+ workflow: "workflow";
36
+ correction: "correction";
37
+ debugging_pattern: "debugging_pattern";
38
+ gotcha: "gotcha";
39
+ convention: "convention";
40
+ }>>>;
41
+ projectId: z.ZodOptional<z.ZodString>;
42
+ sourceTraceIDs: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;
43
+ distilledAt: z.ZodOptional<z.ZodString>;
44
+ superseded_by: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$strip>;
46
+ export type DistilledKnowledgeData = z.infer<typeof DistilledKnowledgeDataSchema>;
@@ -0,0 +1,46 @@
1
+ import type { CompressionUsage } from "../types";
2
+ export declare const BUDGET_FILE = ".matrixx/evolution/budget.json";
3
+ /** Typed capacity breach for the writer's pending queue. */
4
+ export declare class MaxPendingError extends Error {
5
+ readonly pending: number;
6
+ readonly maxPending: number;
7
+ constructor(pending: number, maxPending: number);
8
+ }
9
+ /** One recorded compression charge. */
10
+ export type BudgetEvent = {
11
+ at: string;
12
+ inputTokens: number;
13
+ outputTokens: number;
14
+ costCents: number;
15
+ };
16
+ /** Persisted per-day ledger shape for `.matrixx/evolution/budget.json`. */
17
+ export type BudgetLedger = {
18
+ day: string;
19
+ spendCents: number;
20
+ events: BudgetEvent[];
21
+ };
22
+ /** UTC calendar-day key (`YYYY-MM-DD`) for an instant. Pure. */
23
+ export declare function utcDayKey(at: Date): string;
24
+ /** Absolute ledger path for an evolution dir. */
25
+ export declare function budgetPath(evolutionDir: string): string;
26
+ export declare function emptyLedger(day: string): BudgetLedger;
27
+ /** Reset a ledger when the UTC day rolls over. Pure. */
28
+ export declare function rollLedger(ledger: BudgetLedger, day: string): BudgetLedger;
29
+ /** Include-inclusive cap check for one more charge. Pure. */
30
+ export declare function withinDailyCap(ledger: BudgetLedger, usage: CompressionUsage, maxCostCentsPerDay: number): boolean;
31
+ /** Append a charge to the ledger, rolling the day first. Pure (caller persists). */
32
+ export declare function recordUsage(ledger: BudgetLedger, usage: CompressionUsage, at: Date): BudgetLedger;
33
+ /** True once recorded spend meets or exceeds the daily cap. */
34
+ export declare function isOverDailyCap(ledger: BudgetLedger, maxCostCentsPerDay: number): boolean;
35
+ /** Throw MaxPendingError when the pending queue is full. */
36
+ export declare function checkPendingCapacity(pendingCount: number, maxPending: number): void;
37
+ /** Read the persisted ledger, rolling to `now`'s UTC day; fail-open on any error. */
38
+ export declare function loadLedger(evolutionDir: string, now?: Date): BudgetLedger;
39
+ /** Persist the ledger atomically (tmp + rename), mirroring the repo convention. */
40
+ export declare function saveLedger(evolutionDir: string, ledger: BudgetLedger): void;
41
+ /**
42
+ * Load-modify-write a charge. Not locked across processes: concurrent writers
43
+ * follow last-write-wins (a lost charge is acceptable for a single-process
44
+ * plugin). Sequential callers accumulate correctly.
45
+ */
46
+ export declare function recordUsageToDisk(evolutionDir: string, usage: CompressionUsage, at?: Date): BudgetLedger;
@@ -0,0 +1,5 @@
1
+ export * from "./budget-ledger";
2
+ export * from "./lifecycle";
3
+ export * from "./project-identity";
4
+ export * from "./query";
5
+ export * from "./trace-store";
@@ -0,0 +1,52 @@
1
+ import type { KnowledgeKind } from "../types";
2
+ export declare const QUARANTINE_SEGMENT = "quarantine";
3
+ export type ProposalStatus = "pending" | "approved" | "rejected" | "quarantined" | "superseded";
4
+ export type RetrievalMeta = {
5
+ status: ProposalStatus;
6
+ quarantined?: boolean;
7
+ superseded?: boolean;
8
+ projectId?: string;
9
+ kind?: KnowledgeKind;
10
+ tokenCost?: number;
11
+ };
12
+ export type RetrievalScope = {
13
+ projectId?: string;
14
+ kinds?: KnowledgeKind[];
15
+ tokenCap?: number;
16
+ };
17
+ /**
18
+ * Normative retrieval contract: approved && !quarantined && !superseded &&
19
+ * projectScope match && kind match && tokenCap.
20
+ */
21
+ export declare function isRetrievable(meta: RetrievalMeta, scope: RetrievalScope): boolean;
22
+ export type QuarantineOptions = {
23
+ projectRoot?: string;
24
+ sourceDir?: string;
25
+ reason?: string;
26
+ };
27
+ export type QuarantineResult = {
28
+ quarantined: boolean;
29
+ slug: string;
30
+ quarantinePath: string;
31
+ reason?: string;
32
+ };
33
+ export declare function promotedDirFor(slug: string, projectRoot?: string): string;
34
+ export declare function quarantineDirFor(slug: string, projectRoot?: string): string;
35
+ /** MOVE a promoted skill under `<evolutionDir>/quarantine/<slug>/` and audit it (instead of rm -rf). */
36
+ export declare function quarantineSkill(slug: string, opts?: QuarantineOptions): Promise<QuarantineResult>;
37
+ /** Restore a previously quarantined skill back to the promoted dir. Owned by T6. */
38
+ export declare function restoreFromQuarantine(slug: string, opts?: {
39
+ projectRoot?: string;
40
+ destDir?: string;
41
+ }): Promise<boolean>;
42
+ export type SupersedeOptions = {
43
+ projectRoot?: string;
44
+ supersededBy: string;
45
+ };
46
+ export type SupersedeResult = {
47
+ slug: string;
48
+ supersededBy: string;
49
+ superseded: boolean;
50
+ };
51
+ /** Point an old artifact at its live head. Updates meta atomically, audits, never unlinks. */
52
+ export declare function supersedeSkill(slug: string, opts: SupersedeOptions): Promise<SupersedeResult>;
@@ -0,0 +1,27 @@
1
+ import { type DistilledKnowledge, UNSCOPED_LEGACY } from "../types";
2
+ export { UNSCOPED_LEGACY };
3
+ export type ProjectIdentity = {
4
+ projectId: string;
5
+ root: string;
6
+ remote?: string;
7
+ };
8
+ /** Injectable git runner: returns trimmed stdout, or null when the command fails. */
9
+ export type GitRunner = (args: string[], cwd: string) => string | null;
10
+ /** Normalize a missing/empty project id to the unscoped sentinel. Pure. */
11
+ export declare function normalizeProjectId(projectId: string | undefined): string;
12
+ /** Lowercase, trim, collapse runs of non-alphanumerics to a single dash. Pure. */
13
+ export declare function normalizeTitle(title: string): string;
14
+ /** Drop the memoized identities (test hook + explicit invalidation). */
15
+ export declare function clearProjectIdentityCache(): void;
16
+ /** Short, stable project suffix used to disambiguate cross-project slugs. Pure. */
17
+ export declare function projectSlugSuffix(projectId: string): string;
18
+ /**
19
+ * Resolve the git identity for a project root. The id is `sha256:<hex>` of the
20
+ * git remote URL when one exists, otherwise of the canonical repo-root path.
21
+ * Results are memoized per canonical root: a second resolve for the same root
22
+ * spawns no git. `remote` is returned for in-memory use only — callers MUST NOT
23
+ * persist or log it.
24
+ */
25
+ export declare function resolveProjectIdentity(root: string, runner?: GitRunner): ProjectIdentity;
26
+ /** Scoped dedup key: projectId + kind + normalized title. Owned by T5. */
27
+ export declare function dedupKey(identity: ProjectIdentity, knowledge: DistilledKnowledge): string;
@@ -0,0 +1,23 @@
1
+ import { type RetrievalMeta, type RetrievalScope } from "./lifecycle";
2
+ /** Appended when `get_context` output is cut at the char cap. */
3
+ export declare const CONTEXT_TRUNCATION_MARKER = "\n...[context truncated]";
4
+ /** One read-only retrieval candidate: normalized meta + searchable body. */
5
+ export type RetrievalRecord = {
6
+ id: string;
7
+ meta: RetrievalMeta;
8
+ text: string;
9
+ };
10
+ /**
11
+ * Enumerate retrieval candidates from the staged skill store and the pending
12
+ * queue. Staged entries win on slug collisions. Read-only; missing dirs → [].
13
+ */
14
+ export declare function readRetrievalRecords(projectRoot: string): RetrievalRecord[];
15
+ export type SearchOptions = {
16
+ /** Case-insensitive substring match against id + body. Absent matches all. */
17
+ query?: string;
18
+ scope: RetrievalScope;
19
+ };
20
+ /** Filter records through the T4a predicate, then narrow by text match. */
21
+ export declare function searchRecords(records: RetrievalRecord[], options: SearchOptions): RetrievalRecord[];
22
+ /** Cut text at `cap` chars, appending the marker only when truncation happens. */
23
+ export declare function truncateContext(text: string, cap: number): string;
@@ -1,4 +1,4 @@
1
- import type { EvolutionState, TraceRecord } from "./types";
1
+ import type { EvolutionState, TraceRecord } from "../types";
2
2
  export declare const EVOLUTION_DIR = ".matrixx/evolution";
3
3
  export declare const TRACES_DIR = ".matrixx/evolution/traces";
4
4
  export declare const DISTILLED_DIR = ".matrixx/evolution/distilled";
@@ -12,6 +12,9 @@ export type TraceRecord = {
12
12
  errorType?: string;
13
13
  model?: string;
14
14
  };
15
+ export type KnowledgeKind = "workflow" | "correction" | "debugging_pattern" | "gotcha" | "convention";
16
+ /** Project scope used when git identity is unknown (T4a contract; populated by T5). */
17
+ export declare const UNSCOPED_LEGACY = "unscoped-legacy";
15
18
  export type DistilledKnowledge = {
16
19
  title: string;
17
20
  summary: string;
@@ -21,6 +24,27 @@ export type DistilledKnowledge = {
21
24
  skillDraft?: string;
22
25
  confidence: number;
23
26
  sourceSessionIDs: string[];
27
+ kind: KnowledgeKind;
28
+ /** Git-derived project scope; absent normalizes to UNSCOPED_LEGACY. Populated by T5. */
29
+ projectId?: string;
30
+ /** Trace ids backing this distillation; absent defaults to []. */
31
+ sourceTraceIDs: string[];
32
+ /** ISO timestamp of distillation; absent is back-filled at parse time. */
33
+ distilledAt: string;
34
+ };
35
+ export type CompressionUsage = {
36
+ inputTokens: number;
37
+ outputTokens: number;
38
+ costCents: number;
39
+ };
40
+ /**
41
+ * Cost/usage channel (T4a): `compress()` resolves to `{ knowledge, usage? }` with
42
+ * `usage = { inputTokens, outputTokens, costCents }`. T1 emits it, T3 (budget-ledger)
43
+ * consumes it, T8 provenance cites it. No separate store-appended ledger event.
44
+ */
45
+ export type CompressResult = {
46
+ knowledge: DistilledKnowledge;
47
+ usage?: CompressionUsage;
24
48
  };
25
49
  export type CompressionInput = {
26
50
  sessionID: string;
@@ -31,7 +55,7 @@ export type CompressionInput = {
31
55
  taskHistory?: unknown[];
32
56
  };
33
57
  export interface Compressor {
34
- compress(input: CompressionInput): Promise<DistilledKnowledge>;
58
+ compress(input: CompressionInput): Promise<CompressResult>;
35
59
  }
36
60
  export type EvolutionState = {
37
61
  totalTraces: number;
@@ -45,7 +69,16 @@ export type SkillMeta = {
45
69
  derived_from: string[];
46
70
  created_at: string;
47
71
  confidence: number;
72
+ kind?: KnowledgeKind;
73
+ /** Git-derived project scope; absent/failing back-compat normalizes to unscoped. */
74
+ projectId?: string;
48
75
  eval_score?: number | null;
49
76
  tags?: string[];
50
77
  prerequisites?: string[];
78
+ /** Live-head pointer set on an old artifact when a later re-distill replaces it. */
79
+ superseded_by?: string;
80
+ /** Canonical title slug shared across a supersede chain (old + new coexist). */
81
+ base_slug?: string;
82
+ /** Content hash used to detect byte-identical re-distills (idempotent suppression). */
83
+ content_hash?: string;
51
84
  };
@@ -0,0 +1,17 @@
1
+ import type { DistilledKnowledge, KnowledgeKind } from "./types";
2
+ export declare function slugify(title: string): string;
3
+ export type EmitInput = {
4
+ pendingDir: string;
5
+ skillsDir: string;
6
+ slug: string;
7
+ knowledge: DistilledKnowledge;
8
+ projectId: string;
9
+ kind: KnowledgeKind;
10
+ contentHash: string;
11
+ baseSlug: string;
12
+ };
13
+ export declare function emitArtifact(input: EmitInput): Promise<{
14
+ slug: string;
15
+ pendingPath: string;
16
+ metaPath: string;
17
+ }>;
@@ -0,0 +1,23 @@
1
+ import { type KnowledgeKind, type SkillMeta } from "./types";
2
+ /**
3
+ * Provenance (T8) is the evidence trail behind a generated skill: which
4
+ * sessions and trace rows it was distilled from, and when. It is emitted both
5
+ * as SKILL.md YAML frontmatter and mirrored into meta.json.
6
+ */
7
+ export type ProvenanceMeta = SkillMeta & {
8
+ session_ids: string[];
9
+ trace_ids: string[];
10
+ distilled_at: string;
11
+ };
12
+ export type Provenance = {
13
+ session_ids: string[];
14
+ trace_ids: string[];
15
+ project_id: string;
16
+ kind: KnowledgeKind;
17
+ confidence: number;
18
+ distilled_at: string;
19
+ };
20
+ /** Legacy artifacts predate provenance; loading them must never throw. */
21
+ export declare function hasProvenance(meta: unknown): boolean;
22
+ export declare function provenanceOf(meta: ProvenanceMeta): Provenance;
23
+ export declare function toFrontmatter(meta: ProvenanceMeta): string;
@@ -0,0 +1,20 @@
1
+ import type { DistilledKnowledge, KnowledgeKind, SkillMeta } from "./types";
2
+ export type SupersedeKey = {
3
+ baseSlug: string;
4
+ projectId: string;
5
+ kind: KnowledgeKind;
6
+ };
7
+ /** Stable hash of the distillable payload, ignoring volatile timestamps/provenance. */
8
+ export declare function contentHashFor(knowledge: DistilledKnowledge): string;
9
+ /** Distinct, deterministic slug for a chain entry so old and new coexist on disk. */
10
+ export declare function chainSlug(baseSlug: string, contentHash: string): string;
11
+ /** Return `desired`, or the first free `desired-N` when it is already taken. */
12
+ export declare function uniqueSlug(taken: ReadonlySet<string>, desired: string): string;
13
+ /** Read every pending `*.meta.json`; malformed files are skipped, missing dirs yield []. */
14
+ export declare function listPendingMetas(pendingDir: string): SkillMeta[];
15
+ /** Whether a meta shares the (projectId, kind, normalized title) key of a candidate. */
16
+ export declare function knowledgeKeyMatches(meta: SkillMeta, key: SupersedeKey): boolean;
17
+ /** The live artifact for a key: newest matching meta without `superseded_by`. */
18
+ export declare function findLiveHead(metas: SkillMeta[], key: SupersedeKey): SkillMeta | null;
19
+ /** Follow `superseded_by` from `startSlug` to the chain end; fail-open on breaks/cycles. */
20
+ export declare function resolveHeadSlug(metas: SkillMeta[], startSlug: string): string;
@@ -5,11 +5,15 @@ export declare class EvolutionWriter {
5
5
  private skillsDir;
6
6
  private promotedBase;
7
7
  private globalBase?;
8
+ private projectRoot;
8
9
  constructor(config: EvolutionWriterConfig, projectRoot?: string);
10
+ private readMeta;
11
+ private emit;
9
12
  stage(knowledge: DistilledKnowledge): Promise<{
10
13
  slug: string;
11
14
  pendingPath: string;
12
15
  metaPath: string;
16
+ deduped?: boolean;
13
17
  }>;
14
18
  promote(slug: string): Promise<{
15
19
  promotedPath: string;
@@ -0,0 +1,3 @@
1
+ export type { LoadedHub } from "./loader";
2
+ export { expandHubPath, loadKnowledgeHubs } from "./loader";
3
+ export { resolveKnowledgeFile } from "./resolver";
@@ -0,0 +1,11 @@
1
+ import { type KnowledgeConfig, type KnowledgeHub } from "../../config/schema/knowledge";
2
+ export interface LoadedHub {
3
+ name: string;
4
+ root: string;
5
+ indexPath: string;
6
+ scope: KnowledgeHub["scope"];
7
+ mode: KnowledgeHub["mode"];
8
+ exclude: string[];
9
+ }
10
+ export declare function expandHubPath(rawPath: string, projectDir?: string): string;
11
+ export declare function loadKnowledgeHubs(config: KnowledgeConfig | KnowledgeHub[], projectDir?: string): LoadedHub[];
@@ -0,0 +1,2 @@
1
+ import type { LoadedHub } from "./loader";
2
+ export declare function resolveKnowledgeFile(hubs: LoadedHub[], ref: string): string | null;