opencode-matrixx 2.6.11 → 2.6.13

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 (125) hide show
  1. package/dist/agents/architect/default.d.ts +1 -1
  2. package/dist/agents/architect/gpt.d.ts +1 -1
  3. package/dist/agents/dynamic-agent-prompt-builder.d.ts +4 -4
  4. package/dist/agents/model-directives.d.ts +7 -0
  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 +7 -12
  8. package/dist/config/schema/dcp.d.ts +15 -11
  9. package/dist/config/schema/hooks.d.ts +2 -2
  10. package/dist/config/schema/matrixx-config.d.ts +4 -7
  11. package/dist/config/schema.d.ts +0 -1
  12. package/dist/create-hooks.d.ts +2 -2
  13. package/dist/features/builtin-commands/templates/evolution.d.ts +1 -1
  14. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  15. package/dist/features/evolution/compressor/index.d.ts +2 -2
  16. package/dist/features/evolution/compressor/interface.d.ts +9 -4
  17. package/dist/features/evolution/compressor/llm.d.ts +14 -4
  18. package/dist/features/evolution/evaluator.d.ts +10 -0
  19. package/dist/features/evolution/pipeline.d.ts +3 -1
  20. package/dist/features/evolution/schema.d.ts +46 -0
  21. package/dist/features/evolution/store/budget-ledger.d.ts +46 -0
  22. package/dist/features/evolution/store/index.d.ts +5 -0
  23. package/dist/features/evolution/store/lifecycle.d.ts +52 -0
  24. package/dist/features/evolution/store/project-identity.d.ts +27 -0
  25. package/dist/features/evolution/store/query.d.ts +23 -0
  26. package/dist/features/evolution/{store.d.ts → store/trace-store.d.ts} +1 -1
  27. package/dist/features/evolution/types.d.ts +34 -1
  28. package/dist/features/evolution/writer-emit.d.ts +17 -0
  29. package/dist/features/evolution/writer-frontmatter.d.ts +23 -0
  30. package/dist/features/evolution/writer-supersede.d.ts +20 -0
  31. package/dist/features/evolution/writer.d.ts +4 -0
  32. package/dist/features/plan-contract/appendix.d.ts +14 -0
  33. package/dist/features/plan-contract/constants.d.ts +16 -0
  34. package/dist/features/plan-contract/front-matter.d.ts +34 -0
  35. package/dist/features/plan-contract/index.d.ts +14 -0
  36. package/dist/features/plan-contract/migration.d.ts +36 -0
  37. package/dist/features/plan-contract/schema.d.ts +32 -0
  38. package/dist/features/plan-contract/skeleton.d.ts +5 -0
  39. package/dist/features/plan-contract/types.d.ts +56 -0
  40. package/dist/features/plan-contract/validate.d.ts +9 -0
  41. package/dist/features/session-state/state.d.ts +3 -11
  42. package/dist/hooks/dcp-nudge-sanitizer/constants.d.ts +2 -0
  43. package/dist/hooks/dcp-nudge-sanitizer/hook.d.ts +25 -0
  44. package/dist/hooks/dcp-nudge-sanitizer/index.d.ts +1 -0
  45. package/dist/hooks/evolution-compressor/host-llm-call.d.ts +17 -0
  46. package/dist/hooks/index.d.ts +2 -2
  47. package/dist/hooks/nudge-loop-breaker/constants.d.ts +9 -0
  48. package/dist/hooks/nudge-loop-breaker/hook.d.ts +18 -0
  49. package/dist/hooks/nudge-loop-breaker/index.d.ts +1 -0
  50. package/dist/hooks/nudge-loop-breaker/session-state.d.ts +11 -0
  51. package/dist/hooks/task-continuation-enforcer/constants.d.ts +0 -5
  52. package/dist/index.js +3155 -1624
  53. package/dist/matrixx.schema.json +39 -28
  54. package/dist/plugin/hooks/create-continuation-hooks.d.ts +2 -1
  55. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -2
  56. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
  57. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +1 -2
  58. package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -0
  59. package/dist/plugin/tool-gating.d.ts +2 -0
  60. package/dist/shared/dcp-switch-profile.d.ts +12 -0
  61. package/dist/tools/evolution/constants.d.ts +24 -0
  62. package/dist/tools/evolution/index.d.ts +3 -0
  63. package/dist/tools/evolution/query-actions.d.ts +3 -0
  64. package/dist/tools/evolution/tools.d.ts +16 -0
  65. package/dist/tools/evolution/types.d.ts +20 -0
  66. package/dist/tools/index.d.ts +1 -0
  67. package/dist/tools/plan/constants.d.ts +1 -0
  68. package/dist/tools/plan/index.d.ts +1 -0
  69. package/dist/tools/plan/plan-tasks.d.ts +3 -0
  70. package/dist/tools/plan/types.d.ts +10 -0
  71. package/package.json +1 -1
  72. package/dist/cli/setup/config-writer.test.d.ts +0 -1
  73. package/dist/cli/setup/deps.test.d.ts +0 -1
  74. package/dist/cli/setup/index.test.d.ts +0 -1
  75. package/dist/cli/setup/opencode-sync.test.d.ts +0 -1
  76. package/dist/cli/setup/prompts.test.d.ts +0 -1
  77. package/dist/config/schema/failure-counter.d.ts +0 -7
  78. package/dist/features/background-agent/handle-index.test.d.ts +0 -1
  79. package/dist/features/background-agent/manager-handles.test.d.ts +0 -1
  80. package/dist/features/knowledge-hub/loader.test.d.ts +0 -1
  81. package/dist/features/knowledge-hub/resolver.test.d.ts +0 -1
  82. package/dist/features/mission-state/plan-storage.test.d.ts +0 -1
  83. package/dist/features/mission-state/reconcile.test.d.ts +0 -1
  84. package/dist/features/session-state/state.test.d.ts +0 -1
  85. package/dist/hooks/failure-counter/counter.d.ts +0 -7
  86. package/dist/hooks/failure-counter/counter.test.d.ts +0 -1
  87. package/dist/hooks/failure-counter/hook.d.ts +0 -18
  88. package/dist/hooks/failure-counter/index.d.ts +0 -3
  89. package/dist/hooks/failure-counter/patterns.d.ts +0 -6
  90. package/dist/hooks/failure-counter/patterns.test.d.ts +0 -1
  91. package/dist/hooks/hashline-edit-diff-enhancer/hook.d.ts +0 -28
  92. package/dist/hooks/hashline-edit-diff-enhancer/index.d.ts +0 -1
  93. package/dist/hooks/input-secret-guard/detector.test.d.ts +0 -1
  94. package/dist/hooks/input-secret-guard/hook.test.d.ts +0 -1
  95. package/dist/hooks/input-secret-guard/redactor.test.d.ts +0 -1
  96. package/dist/hooks/input-secret-guard/session-allow-cache.test.d.ts +0 -1
  97. package/dist/hooks/interactive-bash-session/hook.test.d.ts +0 -1
  98. package/dist/hooks/knowledge-hub-guard/hook.test.d.ts +0 -1
  99. package/dist/hooks/knowledge-hub-injector/hook.test.d.ts +0 -1
  100. package/dist/hooks/knowledge-hub-search-nudge/hook.test.d.ts +0 -1
  101. package/dist/hooks/plan-persister/task-sync.test.d.ts +0 -1
  102. package/dist/hooks/rtk-bash-rewriter/hook.test.d.ts +0 -1
  103. package/dist/hooks/stop-continuation-guard/repro.test.d.ts +0 -1
  104. package/dist/hooks/task-continuation-enforcer/awaiting-user.test.d.ts +0 -1
  105. package/dist/hooks/task-continuation-enforcer/continuation-injection.test.d.ts +0 -1
  106. package/dist/hooks/task-continuation-enforcer/countdown.test.d.ts +0 -1
  107. package/dist/hooks/task-continuation-enforcer/idle-event.test.d.ts +0 -1
  108. package/dist/hooks/task-continuation-enforcer/staleness.test.d.ts +0 -1
  109. package/dist/hooks/task-continuation-enforcer/todo.test.d.ts +0 -1
  110. package/dist/hooks/task-continuation-enforcer/ulw-bootstrap.test.d.ts +0 -1
  111. package/dist/hooks/todo-continuation-enforcer/awaiting-user.test.d.ts +0 -1
  112. package/dist/hooks/todo-continuation-enforcer/countdown.test.d.ts +0 -1
  113. package/dist/hooks/todo-continuation-enforcer/idle-event.test.d.ts +0 -1
  114. package/dist/shared/format-bytes.test.d.ts +0 -1
  115. package/dist/shared/is-abort-error.test.d.ts +0 -1
  116. package/dist/shared/task-system-gating.test.d.ts +0 -1
  117. package/dist/shared/with-timeout.test.d.ts +0 -1
  118. package/dist/tools/delegate-task/poll-timeout-outcome.test.d.ts +0 -1
  119. package/dist/tools/delegate-task/prompt-builder.tdd.test.d.ts +0 -1
  120. package/dist/tools/delegate-task/sync-task.test.d.ts +0 -1
  121. package/dist/tools/delegate-task/tdd-enforcement.test.d.ts +0 -1
  122. package/dist/tools/delegate-task/timing.test.d.ts +0 -1
  123. package/dist/tools/github-search/result-formatter.test.d.ts +0 -1
  124. package/dist/tools/knowledge-hub-confirm/tools.test.d.ts +0 -1
  125. package/dist/tools/task/task-cleanup.test.d.ts +0 -1
@@ -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,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,14 @@
1
+ /**
2
+ * Plan Contract — Appendix Boundary
3
+ *
4
+ * Locates the designated appendix region of a plan. The region begins at the
5
+ * first H2 whose normalized text is exactly `Appendix` and extends to EOF.
6
+ * H2s at/after it are exempt from canonical-section and ordering checks.
7
+ *
8
+ * Pure content-level helper — accepts a string only, never touches the file system.
9
+ */
10
+ /**
11
+ * Return the ZERO-BASED line index of the first `## Appendix` H2, or `-1` when
12
+ * the plan has no appendix. "Normalized" means the heading text is trimmed.
13
+ */
14
+ export declare function findAppendixStart(content: string): number;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Plan Contract Constants
3
+ *
4
+ * Canonical structure of an Oracle work plan: the ordered H2 sections and the
5
+ * required per-task grammar. Checkbox regexes are the single source of truth in
6
+ * mission-state — re-exported here, never re-declared.
7
+ */
8
+ export { NUMBERED_CHECKED_RE, NUMBERED_UNCHECKED_RE, TOP_CHECKED_RE, TOP_UNCHECKED_RE, } from "../../features/mission-state/constants";
9
+ /** Ordered H2 section titles, exactly as emitted by the Oracle plan template. */
10
+ export declare const CANONICAL_SECTIONS: readonly ["TL;DR", "Context", "Work Objectives", "Verification Strategy (MANDATORY)", "Execution Strategy", "TODOs", "Commit Strategy", "Success Criteria"];
11
+ /** Ordered labels that every TODO task block must declare. */
12
+ export declare const REQUIRED_TASK_SUBFIELDS: readonly ["What to do", "Must NOT do", "Recommended Agent Profile", "Parallelization", "References", "Acceptance Criteria", "Agent-Executed QA Scenarios"];
13
+ /** Canonical section title union derived from {@link CANONICAL_SECTIONS}. */
14
+ export type PlanSection = (typeof CANONICAL_SECTIONS)[number];
15
+ /** Canonical task subfield label union derived from {@link REQUIRED_TASK_SUBFIELDS}. */
16
+ export type PlanTaskSubfield = (typeof REQUIRED_TASK_SUBFIELDS)[number];
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Plan Front-Matter
3
+ *
4
+ * Structured YAML front-matter (a leading `---` fenced block) for Oracle plan
5
+ * files, parsed with `js-yaml`.
6
+ *
7
+ * PRECEDENCE: when a front-matter block is present it is authoritative for
8
+ * `status` and `revision`. The legacy `<!-- plan-persister: {...} -->` comment
9
+ * (see mission-state `plan-storage.ts`) remains authoritative for `todoTotal`,
10
+ * `todoCompleted`, `updatedAt` and `sessionId`, and is NEVER removed. Front-matter
11
+ * is ADDITIVE over that comment, not a replacement.
12
+ *
13
+ * Serialization is IDEMPOTENT: `parse(serialize(parse(content)))` equals
14
+ * `parse(content)`, and `serialize(parse(serialize(fm)))` equals
15
+ * `serialize(fm)`. On disagreement `status` comes from the front-matter while
16
+ * the legacy comment is left untouched.
17
+ */
18
+ import type { PlanFrontMatter } from "./types";
19
+ /**
20
+ * Parse the leading YAML front-matter block.
21
+ *
22
+ * Returns `null` when the block is absent, malformed, or fails the
23
+ * {@link PlanFrontMatter} shape (e.g. missing `status`/`revision` or an
24
+ * out-of-vocabulary status).
25
+ */
26
+ export declare function parsePlanFrontMatter(content: string): PlanFrontMatter | null;
27
+ /**
28
+ * Serialize front-matter to a `---` fenced YAML block.
29
+ *
30
+ * Optional fields are omitted when `undefined`; array fields are emitted even
31
+ * when empty. The returned block ends with a trailing newline so it can be
32
+ * prepended to plan content additively.
33
+ */
34
+ export declare function serializePlanFrontMatter(fm: PlanFrontMatter): string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Plan Contract — barrel
3
+ *
4
+ * Foundation module for the plan contract: canonical sections, task grammar,
5
+ * and the Zod schema for the structured plan view.
6
+ */
7
+ export { findAppendixStart } from "./appendix";
8
+ export { CANONICAL_SECTIONS, NUMBERED_CHECKED_RE, NUMBERED_UNCHECKED_RE, type PlanSection, type PlanTaskSubfield, REQUIRED_TASK_SUBFIELDS, TOP_CHECKED_RE, TOP_UNCHECKED_RE, } from "./constants";
9
+ export { parsePlanFrontMatter, serializePlanFrontMatter } from "./front-matter";
10
+ export { isGrandfathered, shouldMigrate } from "./migration";
11
+ export { type PlanContract, PlanContractSchema } from "./schema";
12
+ export { renderPlanSkeleton } from "./skeleton";
13
+ export type { PlanContractResult, PlanContractWarning, PlanFrontMatter, PlanStatus, PlanTask, } from "./types";
14
+ export { parsePlanContract, parsePlanTasks, validatePlanContract } from "./validate";
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Plan Front-Matter Migration & Grandfathering
3
+ *
4
+ * Front-matter is ADDITIVE over the legacy `<!-- plan-persister: {...} -->`
5
+ * comment (`mission-state/plan-storage.ts`) — it does not replace it. Migration
6
+ * is apply-on-next-edit ONLY: no `plan_migrate` tool is shipped and no plan is
7
+ * rewritten automatically.
8
+ *
9
+ * Grandfathering protects the pre-existing plan corpus from retro-breaking: a
10
+ * plan that lacks front-matter is only exempt when its id is on the frozen
11
+ * {@link GRANDFATHER_ALLOWLIST}. A brand-new plan lacking front-matter is NOT
12
+ * grandfathered.
13
+ */
14
+ /**
15
+ * Frozen allowlist of plan ids (filename without `.md`) that predate the
16
+ * front-matter requirement — captured from the live `.matrixx/plans` corpus
17
+ * (23 files) at planning time.
18
+ *
19
+ * Grandfathered plans never emit a front-matter warning and are exempt from any
20
+ * future FAIL-mode front-matter requirement. The exemption clears as soon as
21
+ * the plan gains a front-matter block.
22
+ */
23
+ export declare const GRANDFATHER_ALLOWLIST: readonly string[];
24
+ /**
25
+ * True IFF the plan has no front-matter AND its id is on the frozen allowlist.
26
+ *
27
+ * This is deliberately narrower than "any plan lacking front-matter": a new
28
+ * non-allowlisted plan returns `false`.
29
+ */
30
+ export declare function isGrandfathered(filePath: string, content: string): boolean;
31
+ /**
32
+ * True IFF front-matter is absent, for ANY plan (grandfathered included),
33
+ * because injection is additive. Idempotent: once front-matter is present this
34
+ * returns `false`.
35
+ */
36
+ export declare function shouldMigrate(content: string): boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Plan Contract Schema
3
+ *
4
+ * Zod v4 schema for the STRUCTURED view of an Oracle plan. The Markdown grammar
5
+ * itself is parsed elsewhere; this validates the parsed shape.
6
+ */
7
+ import { z } from "zod";
8
+ export declare const PlanContractSchema: z.ZodObject<{
9
+ frontMatter: z.ZodOptional<z.ZodObject<{
10
+ status: z.ZodEnum<{
11
+ pending: "pending";
12
+ completed: "completed";
13
+ in_progress: "in_progress";
14
+ }>;
15
+ revision: z.ZodNumber;
16
+ phase: z.ZodOptional<z.ZodString>;
17
+ wave: z.ZodOptional<z.ZodString>;
18
+ deps: z.ZodOptional<z.ZodArray<z.ZodString>>;
19
+ blockedBy: z.ZodOptional<z.ZodArray<z.ZodString>>;
20
+ }, z.core.$strip>>;
21
+ sections: z.ZodArray<z.ZodString>;
22
+ tasks: z.ZodArray<z.ZodObject<{
23
+ n: z.ZodNumber;
24
+ title: z.ZodString;
25
+ checked: z.ZodBoolean;
26
+ line: z.ZodNumber;
27
+ anchor: z.ZodString;
28
+ }, z.core.$strip>>;
29
+ dod: z.ZodArray<z.ZodString>;
30
+ }, z.core.$strip>;
31
+ /** Parsed, validated structured view of a plan. */
32
+ export type PlanContract = z.infer<typeof PlanContractSchema>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Render the full canonical Oracle plan markdown skeleton — the content between
3
+ * the `\`\`\`markdown` fences of {@link ORACLE_PLAN_TEMPLATE}.
4
+ */
5
+ export declare function renderPlanSkeleton(): string;