@caupulican/pi-adaptative 0.94.0 → 0.94.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 (103) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/core/agent-paths.d.ts +2 -0
  3. package/dist/core/agent-paths.d.ts.map +1 -1
  4. package/dist/core/agent-paths.js +7 -0
  5. package/dist/core/agent-paths.js.map +1 -1
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +5 -1
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/background-lane-controller.d.ts +8 -0
  10. package/dist/core/background-lane-controller.d.ts.map +1 -1
  11. package/dist/core/background-lane-controller.js +75 -5
  12. package/dist/core/background-lane-controller.js.map +1 -1
  13. package/dist/core/background-tool-task-controller.d.ts +15 -0
  14. package/dist/core/background-tool-task-controller.d.ts.map +1 -1
  15. package/dist/core/background-tool-task-controller.js +122 -15
  16. package/dist/core/background-tool-task-controller.js.map +1 -1
  17. package/dist/core/context/long-term-memory-trigger.d.ts +3 -1
  18. package/dist/core/context/long-term-memory-trigger.d.ts.map +1 -1
  19. package/dist/core/context/long-term-memory-trigger.js +1 -1
  20. package/dist/core/context/long-term-memory-trigger.js.map +1 -1
  21. package/dist/core/context/okf-memory-provider.d.ts +3 -0
  22. package/dist/core/context/okf-memory-provider.d.ts.map +1 -1
  23. package/dist/core/context/okf-memory-provider.js +66 -31
  24. package/dist/core/context/okf-memory-provider.js.map +1 -1
  25. package/dist/core/context/okf-memory.d.ts +18 -1
  26. package/dist/core/context/okf-memory.d.ts.map +1 -1
  27. package/dist/core/context/okf-memory.js +48 -0
  28. package/dist/core/context/okf-memory.js.map +1 -1
  29. package/dist/core/delegation/worker-agent-control.d.ts +4 -0
  30. package/dist/core/delegation/worker-agent-control.d.ts.map +1 -1
  31. package/dist/core/delegation/worker-agent-control.js.map +1 -1
  32. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -1
  33. package/dist/core/delegation/worker-execution-policy.js +1 -1
  34. package/dist/core/delegation/worker-execution-policy.js.map +1 -1
  35. package/dist/core/delegation/worker-notification-coordinator.d.ts +10 -0
  36. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -1
  37. package/dist/core/delegation/worker-notification-coordinator.js +69 -3
  38. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -1
  39. package/dist/core/foreground-terminal-handoff-controller.d.ts +17 -0
  40. package/dist/core/foreground-terminal-handoff-controller.d.ts.map +1 -1
  41. package/dist/core/foreground-terminal-handoff-controller.js +78 -10
  42. package/dist/core/foreground-terminal-handoff-controller.js.map +1 -1
  43. package/dist/core/learning/learning-audit.d.ts +5 -1
  44. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  45. package/dist/core/learning/learning-audit.js +32 -1
  46. package/dist/core/learning/learning-audit.js.map +1 -1
  47. package/dist/core/learning/reflection-engine.d.ts +20 -0
  48. package/dist/core/learning/reflection-engine.d.ts.map +1 -1
  49. package/dist/core/learning/reflection-engine.js +58 -0
  50. package/dist/core/learning/reflection-engine.js.map +1 -1
  51. package/dist/core/memory/okf-project-memory-store.d.ts +28 -0
  52. package/dist/core/memory/okf-project-memory-store.d.ts.map +1 -0
  53. package/dist/core/memory/okf-project-memory-store.js +111 -0
  54. package/dist/core/memory/okf-project-memory-store.js.map +1 -0
  55. package/dist/core/memory/providers/file-store.d.ts +42 -1
  56. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  57. package/dist/core/memory/providers/file-store.js +274 -13
  58. package/dist/core/memory/providers/file-store.js.map +1 -1
  59. package/dist/core/memory-controller.d.ts +10 -1
  60. package/dist/core/memory-controller.d.ts.map +1 -1
  61. package/dist/core/memory-controller.js +72 -8
  62. package/dist/core/memory-controller.js.map +1 -1
  63. package/dist/core/provider-prompt-contracts.d.ts.map +1 -1
  64. package/dist/core/provider-prompt-contracts.js +9 -19
  65. package/dist/core/provider-prompt-contracts.js.map +1 -1
  66. package/dist/core/reflection-controller.d.ts +7 -0
  67. package/dist/core/reflection-controller.d.ts.map +1 -1
  68. package/dist/core/reflection-controller.js +94 -15
  69. package/dist/core/reflection-controller.js.map +1 -1
  70. package/dist/core/tools/delegate-status.d.ts +2 -0
  71. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  72. package/dist/core/tools/delegate-status.js +4 -0
  73. package/dist/core/tools/delegate-status.js.map +1 -1
  74. package/dist/core/tools/delegate.d.ts +2 -0
  75. package/dist/core/tools/delegate.d.ts.map +1 -1
  76. package/dist/core/tools/delegate.js +83 -21
  77. package/dist/core/tools/delegate.js.map +1 -1
  78. package/dist/core/tools/tool-task.d.ts +1 -0
  79. package/dist/core/tools/tool-task.d.ts.map +1 -1
  80. package/dist/core/tools/tool-task.js +13 -8
  81. package/dist/core/tools/tool-task.js.map +1 -1
  82. package/dist/core/util/atomic-file.d.ts +2 -0
  83. package/dist/core/util/atomic-file.d.ts.map +1 -1
  84. package/dist/core/util/atomic-file.js +4 -0
  85. package/dist/core/util/atomic-file.js.map +1 -1
  86. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  87. package/dist/modes/interactive/auto-learn-controller.js +2 -0
  88. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  89. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
  90. package/dist/modes/interactive/components/activity-lane.js +12 -23
  91. package/dist/modes/interactive/components/activity-lane.js.map +1 -1
  92. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  93. package/dist/modes/interactive/components/custom-message.js +125 -1
  94. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  95. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  96. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  97. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  98. package/examples/extensions/sandbox/package-lock.json +2 -2
  99. package/examples/extensions/sandbox/package.json +1 -1
  100. package/examples/extensions/with-deps/package-lock.json +2 -2
  101. package/examples/extensions/with-deps/package.json +1 -1
  102. package/npm-shrinkwrap.json +12 -12
  103. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"foreground-terminal-handoff-controller.js","sourceRoot":"","sources":["../../src/core/foreground-terminal-handoff-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CustomMessage } from \"@caupulican/pi-agent-core\";\nimport type { LaneTerminalStatus } from \"./autonomy/lane-tracker.ts\";\nimport {\n\ttype BackgroundToolTaskRecord,\n\tcreateBackgroundToolTerminalMessage,\n} from \"./background-tool-task-controller.ts\";\nimport type { WorkerClaimSnapshotPayload } from \"./delegation/session-worker-claim.ts\";\nimport type { WorkerTerminalHandoffRecord } from \"./delegation/worker-notification-coordinator.ts\";\nimport { WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE } from \"./delegation/worker-terminal-handoff-coordinator.ts\";\nimport { workerTerminalOutputArtifact } from \"./delegation/worker-terminal-output-artifact.ts\";\nimport type { ForegroundRecoveryController, ForegroundSubmissionLease } from \"./foreground-recovery-controller.ts\";\nimport { type GoalState, isGoalExecutionActive } from \"./goals/goal-state.ts\";\nimport type { ArtifactContract, WorkerResultContract } from \"./orchestration/contracts.ts\";\n\ninterface ForegroundTerminalHandoffControllerDeps {\n\tforeground: ForegroundRecoveryController;\n\tisDisposed(): boolean;\n\tgetGoalStateSnapshot(): Pick<GoalState, \"goalId\" | \"status\"> | undefined;\n\tgetWorkerClaimSnapshot?(laneId: string): WorkerClaimSnapshotPayload | undefined;\n\tgetWorkerResult?(laneId: string): Pick<WorkerResultContract, \"artifacts\"> | undefined;\n\tstartCustomMessageTurn(\n\t\tmessage: Pick<CustomMessage<unknown>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\t\tlease: ForegroundSubmissionLease,\n\t\tgoalId?: string,\n\t): Promise<{ completion: Promise<void> }>;\n\tsendCustomMessage(\n\t\tmessage: Pick<CustomMessage<unknown>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\t\toptions: { triggerTurn: false; deliverAs: \"followUp\" },\n\t\tlease: ForegroundSubmissionLease,\n\t): Promise<void>;\n\twarn(message: string): void;\n}\n\nexport function buildForegroundWorkerTerminalHandoffContent(\n\trecords: readonly {\n\t\tlaneId: string;\n\t\tstatus: LaneTerminalStatus;\n\t\treasonCode?: string;\n\t\toutputArtifact?: ArtifactContract;\n\t\tclaim?: {\n\t\t\tsummary?: string;\n\t\t\tstatus?: string;\n\t\t\tchangedFiles?: readonly string[];\n\t\t\tblockers?: readonly string[];\n\t\t\tparentReviewRequired?: boolean;\n\t\t};\n\t}[],\n\toptions?: { wakeParent?: boolean },\n): string {\n\tconst included = records.slice(0, 8);\n\tconst omitted = records.length - included.length;\n\tconst wakeParent = options?.wakeParent ?? true;\n\tconst sanitize = (value: string): string => value.replace(/[\\r\\n]+/g, \" \").slice(0, 120);\n\treturn [\n\t\t\"Background worker terminal handoff:\",\n\t\t...included.flatMap((record) => {\n\t\t\tconst reason = record.reasonCode ? ` reason=${sanitize(record.reasonCode)}` : \"\";\n\t\t\tconst lines = [`- ${record.laneId}: ${record.status}${reason}`];\n\t\t\tif (record.outputArtifact) {\n\t\t\t\tlines.push(\n\t\t\t\t\t` Full Output: ${record.outputArtifact.uri}${record.outputArtifact.sizeBytes === undefined ? \"\" : ` (${record.outputArtifact.sizeBytes} bytes)`}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (record.claim?.summary) {\n\t\t\t\tlines.push(` Claim Status: ${record.claim.status || record.status}`);\n\t\t\t\tlines.push(` Claim Summary: ${sanitize(record.claim.summary)}`);\n\t\t\t\tif (record.claim.changedFiles && record.claim.changedFiles.length > 0) {\n\t\t\t\t\tlines.push(` Changed Files: ${record.claim.changedFiles.map((f) => sanitize(f)).join(\", \")}`);\n\t\t\t\t}\n\t\t\t\tif (record.claim.blockers && record.claim.blockers.length > 0) {\n\t\t\t\t\tlines.push(` Blockers: ${record.claim.blockers.map((b) => sanitize(b)).join(\"; \")}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}),\n\t\t...(omitted > 0 ? [`- ${omitted} additional terminal worker(s) omitted.`] : []),\n\t\t\"CAVEMAN MODE - MANDATORY: this event proves terminal persistence and delivery. Do not report missed completion or lost worker state from these records.\",\n\t\t...(wakeParent\n\t\t\t? [\"Read each lane with delegate status, verify the claim, then continue or replan the parent task.\"]\n\t\t\t: [\n\t\t\t\t\t\"The owning parent is no longer eligible for automatic continuation. Persist this handoff, but do not continue or replan automatically.\",\n\t\t\t\t]),\n\t\t...(records.some((record) => record.reasonCode === \"worker_blocked\")\n\t\t\t? [\"worker_blocked is a task claim with blockers, not harness failure.\"]\n\t\t\t: []),\n\t\t...(records.some((record) => record.status === \"budget_exhausted\")\n\t\t\t? [\n\t\t\t\t\t\"CAVEMAN MODE - MANDATORY: budget_exhausted means an admitted limit ended work, not harness failure. Terminal reason is authoritative; never replace it with earlier transcript errors. Read evidence, then replan only within remaining authority.\",\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(records.some((record) => record.reasonCode === \"completion_error\")\n\t\t\t? [WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE]\n\t\t\t: []),\n\t\t...(wakeParent\n\t\t\t? [\n\t\t\t\t\t'Parent woke. Evaluated terminal claim payload above. Use delegate { action: \"status\", laneId } for deep view if needed.',\n\t\t\t\t]\n\t\t\t: [\"Parent was not woken. Wait for explicit user input before reading a lane or starting more work.\"]),\n\t].join(\"\\n\");\n}\n\n/** Serializes durable background terminal delivery through the foreground submission owner. */\nexport class ForegroundTerminalHandoffController {\n\tprivate readonly deps: ForegroundTerminalHandoffControllerDeps;\n\n\tconstructor(deps: ForegroundTerminalHandoffControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync notifyWorkers(records: readonly WorkerTerminalHandoffRecord[]): Promise<void> {\n\t\tif (records.length === 0) return;\n\t\tthis.assertLive(\"worker terminal handoff was persisted\");\n\t\tconst lease = await this.deps.foreground.acquireSubmission();\n\t\tlet releaseLease = true;\n\t\ttry {\n\t\t\tthis.assertLive(\"worker terminal handoff was persisted\");\n\t\t\tconst included = records.slice(0, 8).map((record) => {\n\t\t\t\tconst snapshot = this.deps.getWorkerClaimSnapshot?.(record.laneId);\n\t\t\t\tconst claim = snapshot?.claim;\n\t\t\t\tconst outputArtifact = workerTerminalOutputArtifact(this.deps.getWorkerResult?.(record.laneId));\n\t\t\t\treturn {\n\t\t\t\t\tlaneId: record.laneId,\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\t...(record.reasonCode ? { reasonCode: record.reasonCode } : {}),\n\t\t\t\t\t...(outputArtifact ? { outputArtifact } : {}),\n\t\t\t\t\t...(claim\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tclaim: {\n\t\t\t\t\t\t\t\t\tstatus: claim.status,\n\t\t\t\t\t\t\t\t\tsummary: claim.summary.slice(0, 1000),\n\t\t\t\t\t\t\t\t\tchangedFiles: claim.changedFiles,\n\t\t\t\t\t\t\t\t\t...(claim.blockers ? { blockers: claim.blockers } : {}),\n\t\t\t\t\t\t\t\t\t...(claim.parentReviewRequired ? { parentReviewRequired: true } : {}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst goal = this.deps.getGoalStateSnapshot();\n\t\t\tconst wakeParent = records.some(\n\t\t\t\t(record) => !record.goalId || (goal?.goalId === record.goalId && isGoalExecutionActive(goal.status)),\n\t\t\t);\n\t\t\tconst message = {\n\t\t\t\tcustomType: \"background-worker-completion\",\n\t\t\t\tcontent: buildForegroundWorkerTerminalHandoffContent(included, { wakeParent }),\n\t\t\t\tdisplay: true,\n\t\t\t\tdetails: { records: included },\n\t\t\t};\n\t\t\tif (wakeParent) {\n\t\t\t\tconst goalId = records.find((record) => record.goalId === goal?.goalId)?.goalId;\n\t\t\t\tconst started = await this.deps.startCustomMessageTurn(message, lease, goalId);\n\t\t\t\tthis.releaseAfterTurn(started.completion, lease, \"worker terminal handoff turn\");\n\t\t\t\treleaseLease = false;\n\t\t\t} else {\n\t\t\t\tawait this.deps.sendCustomMessage(message, { triggerTurn: false, deliverAs: \"followUp\" }, lease);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (releaseLease) this.deps.foreground.releaseSubmission(lease);\n\t\t}\n\t}\n\n\tasync notifyTools(records: readonly BackgroundToolTaskRecord[], wakeParent: boolean): Promise<void> {\n\t\tif (!wakeParent) return;\n\t\tthis.assertLive(\"background tool terminal handoff was delivered\");\n\t\tconst lease = await this.deps.foreground.acquireSubmission();\n\t\tlet releaseLease = true;\n\t\ttry {\n\t\t\tthis.assertLive(\"background tool terminal handoff was delivered\");\n\t\t\tconst started = await this.deps.startCustomMessageTurn(createBackgroundToolTerminalMessage(records), lease);\n\t\t\tthis.releaseAfterTurn(started.completion, lease, \"background tool terminal handoff turn\");\n\t\t\treleaseLease = false;\n\t\t} finally {\n\t\t\tif (releaseLease) this.deps.foreground.releaseSubmission(lease);\n\t\t}\n\t}\n\n\tprivate releaseAfterTurn(completion: Promise<void>, lease: ForegroundSubmissionLease, label: string): void {\n\t\tvoid completion.then(\n\t\t\t() => this.deps.foreground.releaseSubmission(lease),\n\t\t\t(error: unknown) => {\n\t\t\t\tthis.deps.foreground.releaseSubmission(lease);\n\t\t\t\tthis.deps.warn(\n\t\t\t\t\t`${label} failed after durable delivery: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate assertLive(action: string): void {\n\t\tif (this.deps.isDisposed()) throw new Error(`Session disposed before ${action}`);\n\t}\n}\n"]}
1
+ {"version":3,"file":"foreground-terminal-handoff-controller.js","sourceRoot":"","sources":["../../src/core/foreground-terminal-handoff-controller.ts"],"names":[],"mappings":"AAEA,OAAO,EAEN,mCAAmC,GACnC,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,wCAAwC,EAAE,MAAM,qDAAqD,CAAC;AAC/G,OAAO,EAAE,4BAA4B,EAAE,MAAM,iDAAiD,CAAC;AAE/F,OAAO,EAAkB,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAoB9E,MAAM,UAAU,uCAAuC,CACtD,IAAmC,EACnC,KAA+C;IAE/C,OAAO;QACN,IAAI;QACJ,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM;QAC1E,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM;QACpE,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM;KACxE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,KAAc;IACjE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,MAAM,OAAO,GAAG,KAAgC,CAAC;IACjD,MAAM,MAAM,GAAG,CAAC,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,CAAU,CAAC;IACzF,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACtE,IACC,MAAM,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE,CACT,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,QAAQ;QAClC,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,KAAK,CAAY,GAAG,CAAC,CAC/B,EACA,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAoB,CAAC;IAChD,OAAO,CACN,UAAU,GAAG,CAAC;QACb,OAAO,CAAC,cAAyB,GAAI,OAAO,CAAC,WAAsB,GAAI,OAAO,CAAC,aAAwB;YACvG,UAAU,CACX,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAC3B,MAAmD,EACnD,gBAAyB;IAEzB,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,kBAAkB,EAAE,CAAC;QACvG,OAAO,QAAQ,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IACpD,IAAI,gBAAgB,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IACvG,OAAO,SAAS,CAAC;AAClB,CAAC;AAqBD,MAAM,UAAU,2CAA2C,CAC1D,OAYG,EACH,OAAuD;IAEvD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvF,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC;IAC/C,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzF,OAAO;QACN,qCAAqC;QACrC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,MAAM,KAAK,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;YAChE,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CACT,kBAAkB,MAAM,CAAC,cAAc,CAAC,GAAG,GAAG,MAAM,CAAC,cAAc,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,cAAc,CAAC,SAAS,SAAS,EAAE,CAClJ,CAAC;YACH,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;gBACtE,KAAK,CAAC,IAAI,CAAC,oBAAoB,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACjE,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvE,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChG,CAAC;gBACD,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC/D,KAAK,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACvF,CAAC;YACF,CAAC;YACD,OAAO,KAAK,CAAC;QACd,CAAC,CAAC;QACF,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,yCAAyC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,yJAAyJ;QACzJ,GAAG,CAAC,UAAU;YACb,CAAC,CAAC,CAAC,iGAAiG,CAAC;YACrG,CAAC,CAAC;gBACA,wIAAwI;aACxI,CAAC;QACJ,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,gBAAgB,CAAC;YACnE,CAAC,CAAC,CAAC,oEAAoE,CAAC;YACxE,CAAC,CAAC,EAAE,CAAC;QACN,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,kBAAkB,CAAC;YACjE,CAAC,CAAC;gBACA,oPAAoP;aACpP;YACF,CAAC,CAAC,EAAE,CAAC;QACN,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,kBAAkB,CAAC;YACrE,CAAC,CAAC,CAAC,wCAAwC,CAAC;YAC5C,CAAC,CAAC,EAAE,CAAC;QACN,GAAG,CAAC,UAAU;YACb,CAAC,CAAC;gBACA,yHAAyH;aACzH;YACF,CAAC,CAAC,CAAC,iGAAiG,CAAC,CAAC;KACvG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAED,+FAA+F;AAC/F,MAAM,OAAO,mCAAmC;IAG/C,YAAY,IAA6C;QACxD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAA+C;QAClE,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC;YAAE,OAAO;QACvE,IAAI,CAAC,UAAU,CAAC,uCAAuC,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC;QAC7D,IAAI,YAAY,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC;YACJ,IAAI,CAAC,UAAU,CAAC,uCAAuC,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;YAC3E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;gBAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACnE,MAAM,KAAK,GAAG,QAAQ,EAAE,KAAK,CAAC;gBAC9B,MAAM,cAAc,GACnB,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAClG,OAAO;oBACN,WAAW,EAAE;wBACZ,EAAE,EAAE,MAAM,CAAC,MAAM;wBACjB,MAAM,EAAE,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;qBACzE;oBACD,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/D,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC7C,GAAG,CAAC,KAAK;wBACR,CAAC,CAAC;4BACA,KAAK,EAAE;gCACN,MAAM,EAAE,KAAK,CAAC,MAAM;gCACpB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;gCACrC,YAAY,EAAE,KAAK,CAAC,YAAY;gCAChC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gCACvD,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;6BACrE;yBACD;wBACF,CAAC,CAAC,EAAE,CAAC;iBACN,CAAC;YACH,CAAC,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;YAChG,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAC7B,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CACpG,CAAC;YACF,MAAM,OAAO,GAAG;gBACf,UAAU,EAAE,8BAA8B;gBAC1C,OAAO,EAAE,2CAA2C,CAAC,QAAQ,EAAE;oBAC9D,UAAU;oBACV,UAAU,EAAE,MAAM,CAAC,MAAM;iBACzB,CAAC;gBACF,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACR,OAAO,EAAE,QAAQ;oBACjB,OAAO,EAAE,uCAAuC,CAC/C,OAAO,EACP,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAC1C;iBACD;aACD,CAAC;YACF,IAAI,UAAU,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC;gBAC/E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;gBAC/E,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,8BAA8B,CAAC,CAAC;gBACjF,YAAY,GAAG,KAAK,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;YAClG,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,IAAI,YAAY;gBAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACjE,CAAC;IACF,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAA4C,EAAE,UAAmB;QAClF,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC;YAAE,OAAO;QACtF,IAAI,CAAC,UAAU,CAAC,gDAAgD,CAAC,CAAC;QAClE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC;QAC7D,IAAI,YAAY,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC;YACJ,IAAI,CAAC,UAAU,CAAC,gDAAgD,CAAC,CAAC;YAClE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;YAC3E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAChC,MAAM,WAAW,GAAG,mCAAmC,CAAC,MAAM,CAAC,CAAC;YAChE,MAAM,OAAO,GAAG;gBACf,GAAG,WAAW;gBACd,OAAO,EAAE;oBACR,GAAG,WAAW,CAAC,OAAO;oBACtB,OAAO,EAAE,uCAAuC,CAC/C,MAAM,EACN,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;wBACvB,EAAE,EAAE,MAAM,CAAC,MAAM;wBACjB,MAAM,EACL,MAAM,CAAC,MAAM,KAAK,QAAQ;4BACzB,CAAC,CAAE,QAAkB;4BACrB,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU;gCAC7B,CAAC,CAAE,UAAoB;gCACvB,CAAC,CAAE,SAAmB;qBACzB,CAAC,CAAC,CACH;iBACD;aACD,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACvE,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,uCAAuC,CAAC,CAAC;YAC1F,YAAY,GAAG,KAAK,CAAC;QACtB,CAAC;gBAAS,CAAC;YACV,IAAI,YAAY;gBAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACjE,CAAC;IACF,CAAC;IAEO,gBAAgB,CAAC,UAAyB,EAAE,KAAgC,EAAE,KAAa;QAClG,KAAK,UAAU,CAAC,IAAI,CACnB,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,EACnD,CAAC,KAAc,EAAE,EAAE;YAClB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,IAAI,CAAC,IAAI,CACb,GAAG,KAAK,mCAAmC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACnG,CAAC;QACH,CAAC,CACD,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,MAAc;QAChC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,EAAE,CAAC,CAAC;IAClF,CAAC;CACD","sourcesContent":["import type { CustomMessage } from \"@caupulican/pi-agent-core\";\nimport type { LaneTerminalStatus } from \"./autonomy/lane-tracker.ts\";\nimport {\n\ttype BackgroundToolTaskRecord,\n\tcreateBackgroundToolTerminalMessage,\n} from \"./background-tool-task-controller.ts\";\nimport type { WorkerClaimSnapshotPayload } from \"./delegation/session-worker-claim.ts\";\nimport type { WorkerTerminalHandoffRecord } from \"./delegation/worker-notification-coordinator.ts\";\nimport { WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE } from \"./delegation/worker-terminal-handoff-coordinator.ts\";\nimport { workerTerminalOutputArtifact } from \"./delegation/worker-terminal-output-artifact.ts\";\nimport type { ForegroundRecoveryController, ForegroundSubmissionLease } from \"./foreground-recovery-controller.ts\";\nimport { type GoalState, isGoalExecutionActive } from \"./goals/goal-state.ts\";\nimport type { ArtifactContract, WorkerResultContract } from \"./orchestration/contracts.ts\";\n\nexport type BackgroundActivitySummaryKind = \"agent\" | \"task\";\nexport type BackgroundActivitySummaryStatus = \"success\" | \"attention\" | \"failed\" | \"canceled\";\n\nexport interface BackgroundActivitySummaryItem {\n\tid: string;\n\tstatus: BackgroundActivitySummaryStatus;\n}\n\n/** Provider-neutral counts retained when the detailed handoff is bounded. */\nexport interface BackgroundActivitySummaryContract {\n\tkind: BackgroundActivitySummaryKind;\n\ttotalCount: number;\n\tattentionCount: number;\n\tfailedCount: number;\n\tcanceledCount: number;\n}\n\nexport function createBackgroundActivitySummaryContract(\n\tkind: BackgroundActivitySummaryKind,\n\titems: readonly BackgroundActivitySummaryItem[],\n): BackgroundActivitySummaryContract {\n\treturn {\n\t\tkind,\n\t\ttotalCount: items.length,\n\t\tattentionCount: items.filter((item) => item.status === \"attention\").length,\n\t\tfailedCount: items.filter((item) => item.status === \"failed\").length,\n\t\tcanceledCount: items.filter((item) => item.status === \"canceled\").length,\n\t};\n}\n\nexport function isBackgroundActivitySummaryContract(value: unknown): value is BackgroundActivitySummaryContract {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst summary = value as Record<string, unknown>;\n\tconst counts = [\"totalCount\", \"attentionCount\", \"failedCount\", \"canceledCount\"] as const;\n\tif (summary.kind !== \"agent\" && summary.kind !== \"task\") return false;\n\tif (\n\t\tcounts.some(\n\t\t\t(field) =>\n\t\t\t\ttypeof summary[field] !== \"number\" ||\n\t\t\t\t!Number.isSafeInteger(summary[field]) ||\n\t\t\t\t(summary[field] as number) < 0,\n\t\t)\n\t) {\n\t\treturn false;\n\t}\n\tconst totalCount = summary.totalCount as number;\n\treturn (\n\t\ttotalCount > 0 &&\n\t\t(summary.attentionCount as number) + (summary.failedCount as number) + (summary.canceledCount as number) <=\n\t\t\ttotalCount\n\t);\n}\n\nfunction workerSummaryStatus(\n\trecord: Pick<WorkerTerminalHandoffRecord, \"status\">,\n\tclaimNeedsReview: boolean,\n): BackgroundActivitySummaryStatus {\n\tif (record.status === \"failed\" || record.status === \"timeout\" || record.status === \"budget_exhausted\") {\n\t\treturn \"failed\";\n\t}\n\tif (record.status === \"canceled\") return \"canceled\";\n\tif (claimNeedsReview || record.status === \"partial\" || record.status === \"blocked\") return \"attention\";\n\treturn \"success\";\n}\n\ninterface ForegroundTerminalHandoffControllerDeps {\n\tforeground: ForegroundRecoveryController;\n\tisDisposed(): boolean;\n\tgetGoalStateSnapshot(): Pick<GoalState, \"goalId\" | \"status\"> | undefined;\n\tgetWorkerClaimSnapshot?(laneId: string): WorkerClaimSnapshotPayload | undefined;\n\tgetWorkerResult?(laneId: string): Pick<WorkerResultContract, \"artifacts\"> | undefined;\n\tstartCustomMessageTurn(\n\t\tmessage: Pick<CustomMessage<unknown>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\t\tlease: ForegroundSubmissionLease,\n\t\tgoalId?: string,\n\t): Promise<{ completion: Promise<void> }>;\n\tsendCustomMessage(\n\t\tmessage: Pick<CustomMessage<unknown>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\t\toptions: { triggerTurn: false; deliverAs: \"followUp\" },\n\t\tlease: ForegroundSubmissionLease,\n\t): Promise<void>;\n\twarn(message: string): void;\n}\n\nexport function buildForegroundWorkerTerminalHandoffContent(\n\trecords: readonly {\n\t\tlaneId: string;\n\t\tstatus: LaneTerminalStatus;\n\t\treasonCode?: string;\n\t\toutputArtifact?: ArtifactContract;\n\t\tclaim?: {\n\t\t\tsummary?: string;\n\t\t\tstatus?: string;\n\t\t\tchangedFiles?: readonly string[];\n\t\t\tblockers?: readonly string[];\n\t\t\tparentReviewRequired?: boolean;\n\t\t};\n\t}[],\n\toptions?: { wakeParent?: boolean; totalCount?: number },\n): string {\n\tconst included = records.slice(0, 8);\n\tconst omitted = Math.max(0, (options?.totalCount ?? records.length) - included.length);\n\tconst wakeParent = options?.wakeParent ?? true;\n\tconst sanitize = (value: string): string => value.replace(/[\\r\\n]+/g, \" \").slice(0, 120);\n\treturn [\n\t\t\"Background worker terminal handoff:\",\n\t\t...included.flatMap((record) => {\n\t\t\tconst reason = record.reasonCode ? ` reason=${sanitize(record.reasonCode)}` : \"\";\n\t\t\tconst lines = [`- ${record.laneId}: ${record.status}${reason}`];\n\t\t\tif (record.outputArtifact) {\n\t\t\t\tlines.push(\n\t\t\t\t\t` Full Output: ${record.outputArtifact.uri}${record.outputArtifact.sizeBytes === undefined ? \"\" : ` (${record.outputArtifact.sizeBytes} bytes)`}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (record.claim?.summary) {\n\t\t\t\tlines.push(` Claim Status: ${record.claim.status || record.status}`);\n\t\t\t\tlines.push(` Claim Summary: ${sanitize(record.claim.summary)}`);\n\t\t\t\tif (record.claim.changedFiles && record.claim.changedFiles.length > 0) {\n\t\t\t\t\tlines.push(` Changed Files: ${record.claim.changedFiles.map((f) => sanitize(f)).join(\", \")}`);\n\t\t\t\t}\n\t\t\t\tif (record.claim.blockers && record.claim.blockers.length > 0) {\n\t\t\t\t\tlines.push(` Blockers: ${record.claim.blockers.map((b) => sanitize(b)).join(\"; \")}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}),\n\t\t...(omitted > 0 ? [`- ${omitted} additional terminal worker(s) omitted.`] : []),\n\t\t\"CAVEMAN MODE - MANDATORY: this event proves terminal persistence and delivery. Do not report missed completion or lost worker state from these records.\",\n\t\t...(wakeParent\n\t\t\t? [\"Read each lane with delegate status, verify the claim, then continue or replan the parent task.\"]\n\t\t\t: [\n\t\t\t\t\t\"The owning parent is no longer eligible for automatic continuation. Persist this handoff, but do not continue or replan automatically.\",\n\t\t\t\t]),\n\t\t...(records.some((record) => record.reasonCode === \"worker_blocked\")\n\t\t\t? [\"worker_blocked is a task claim with blockers, not harness failure.\"]\n\t\t\t: []),\n\t\t...(records.some((record) => record.status === \"budget_exhausted\")\n\t\t\t? [\n\t\t\t\t\t\"CAVEMAN MODE - MANDATORY: budget_exhausted means an admitted limit ended work, not harness failure. Terminal reason is authoritative; never replace it with earlier transcript errors. Read evidence, then replan only within remaining authority.\",\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(records.some((record) => record.reasonCode === \"completion_error\")\n\t\t\t? [WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE]\n\t\t\t: []),\n\t\t...(wakeParent\n\t\t\t? [\n\t\t\t\t\t'Parent woke. Evaluated terminal claim payload above. Use delegate { action: \"status\", laneId } for deep view if needed.',\n\t\t\t\t]\n\t\t\t: [\"Parent was not woken. Wait for explicit user input before reading a lane or starting more work.\"]),\n\t].join(\"\\n\");\n}\n\n/** Serializes durable background terminal delivery through the foreground submission owner. */\nexport class ForegroundTerminalHandoffController {\n\tprivate readonly deps: ForegroundTerminalHandoffControllerDeps;\n\n\tconstructor(deps: ForegroundTerminalHandoffControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync notifyWorkers(records: readonly WorkerTerminalHandoffRecord[]): Promise<void> {\n\t\tif (records.every((record) => record.observedAt !== undefined)) return;\n\t\tthis.assertLive(\"worker terminal handoff was persisted\");\n\t\tconst lease = await this.deps.foreground.acquireSubmission();\n\t\tlet releaseLease = true;\n\t\ttry {\n\t\t\tthis.assertLive(\"worker terminal handoff was persisted\");\n\t\t\tconst unread = records.filter((record) => record.observedAt === undefined);\n\t\t\tif (unread.length === 0) return;\n\t\t\tconst prepared = unread.map((record, index) => {\n\t\t\t\tconst snapshot = this.deps.getWorkerClaimSnapshot?.(record.laneId);\n\t\t\t\tconst claim = snapshot?.claim;\n\t\t\t\tconst outputArtifact =\n\t\t\t\t\tindex < 8 ? workerTerminalOutputArtifact(this.deps.getWorkerResult?.(record.laneId)) : undefined;\n\t\t\t\treturn {\n\t\t\t\t\tsummaryItem: {\n\t\t\t\t\t\tid: record.laneId,\n\t\t\t\t\t\tstatus: workerSummaryStatus(record, claim?.parentReviewRequired === true),\n\t\t\t\t\t},\n\t\t\t\t\tlaneId: record.laneId,\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\t...(record.reasonCode ? { reasonCode: record.reasonCode } : {}),\n\t\t\t\t\t...(outputArtifact ? { outputArtifact } : {}),\n\t\t\t\t\t...(claim\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tclaim: {\n\t\t\t\t\t\t\t\t\tstatus: claim.status,\n\t\t\t\t\t\t\t\t\tsummary: claim.summary.slice(0, 1000),\n\t\t\t\t\t\t\t\t\tchangedFiles: claim.changedFiles,\n\t\t\t\t\t\t\t\t\t...(claim.blockers ? { blockers: claim.blockers } : {}),\n\t\t\t\t\t\t\t\t\t...(claim.parentReviewRequired ? { parentReviewRequired: true } : {}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst included = prepared.slice(0, 8).map(({ summaryItem: _summaryItem, ...record }) => record);\n\t\t\tconst goal = this.deps.getGoalStateSnapshot();\n\t\t\tconst wakeParent = unread.some(\n\t\t\t\t(record) => !record.goalId || (goal?.goalId === record.goalId && isGoalExecutionActive(goal.status)),\n\t\t\t);\n\t\t\tconst message = {\n\t\t\t\tcustomType: \"background-worker-completion\",\n\t\t\t\tcontent: buildForegroundWorkerTerminalHandoffContent(included, {\n\t\t\t\t\twakeParent,\n\t\t\t\t\ttotalCount: unread.length,\n\t\t\t\t}),\n\t\t\t\tdisplay: true,\n\t\t\t\tdetails: {\n\t\t\t\t\trecords: included,\n\t\t\t\t\tsummary: createBackgroundActivitySummaryContract(\n\t\t\t\t\t\t\"agent\",\n\t\t\t\t\t\tprepared.map((entry) => entry.summaryItem),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t};\n\t\t\tif (wakeParent) {\n\t\t\t\tconst goalId = unread.find((record) => record.goalId === goal?.goalId)?.goalId;\n\t\t\t\tconst started = await this.deps.startCustomMessageTurn(message, lease, goalId);\n\t\t\t\tthis.releaseAfterTurn(started.completion, lease, \"worker terminal handoff turn\");\n\t\t\t\treleaseLease = false;\n\t\t\t} else {\n\t\t\t\tawait this.deps.sendCustomMessage(message, { triggerTurn: false, deliverAs: \"followUp\" }, lease);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (releaseLease) this.deps.foreground.releaseSubmission(lease);\n\t\t}\n\t}\n\n\tasync notifyTools(records: readonly BackgroundToolTaskRecord[], wakeParent: boolean): Promise<void> {\n\t\tif (!wakeParent || records.every((record) => record.observedAt !== undefined)) return;\n\t\tthis.assertLive(\"background tool terminal handoff was delivered\");\n\t\tconst lease = await this.deps.foreground.acquireSubmission();\n\t\tlet releaseLease = true;\n\t\ttry {\n\t\t\tthis.assertLive(\"background tool terminal handoff was delivered\");\n\t\t\tconst unread = records.filter((record) => record.observedAt === undefined);\n\t\t\tif (unread.length === 0) return;\n\t\t\tconst toolMessage = createBackgroundToolTerminalMessage(unread);\n\t\t\tconst message = {\n\t\t\t\t...toolMessage,\n\t\t\t\tdetails: {\n\t\t\t\t\t...toolMessage.details,\n\t\t\t\t\tsummary: createBackgroundActivitySummaryContract(\n\t\t\t\t\t\t\"task\",\n\t\t\t\t\t\tunread.map((record) => ({\n\t\t\t\t\t\t\tid: record.taskId,\n\t\t\t\t\t\t\tstatus:\n\t\t\t\t\t\t\t\trecord.status === \"failed\"\n\t\t\t\t\t\t\t\t\t? (\"failed\" as const)\n\t\t\t\t\t\t\t\t\t: record.status === \"canceled\"\n\t\t\t\t\t\t\t\t\t\t? (\"canceled\" as const)\n\t\t\t\t\t\t\t\t\t\t: (\"success\" as const),\n\t\t\t\t\t\t})),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t};\n\t\t\tconst started = await this.deps.startCustomMessageTurn(message, lease);\n\t\t\tthis.releaseAfterTurn(started.completion, lease, \"background tool terminal handoff turn\");\n\t\t\treleaseLease = false;\n\t\t} finally {\n\t\t\tif (releaseLease) this.deps.foreground.releaseSubmission(lease);\n\t\t}\n\t}\n\n\tprivate releaseAfterTurn(completion: Promise<void>, lease: ForegroundSubmissionLease, label: string): void {\n\t\tvoid completion.then(\n\t\t\t() => this.deps.foreground.releaseSubmission(lease),\n\t\t\t(error: unknown) => {\n\t\t\t\tthis.deps.foreground.releaseSubmission(lease);\n\t\t\t\tthis.deps.warn(\n\t\t\t\t\t`${label} failed after durable delivery: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate assertLive(action: string): void {\n\t\tif (this.deps.isDisposed()) throw new Error(`Session disposed before ${action}`);\n\t}\n}\n"]}
@@ -9,13 +9,17 @@ import type { ReflectionWrite } from "./reflection-engine.ts";
9
9
  * log, so `/autonomy diagnostics` can explain what changed, why, and how to undo it — and
10
10
  * `rollbackLearningWrite` can execute the inverse operation.
11
11
  */
12
- export type LearningRollbackKind = "memory_remove" | "memory_restore" | "memory_add" | "archive_skill";
12
+ export type LearningRollbackKind = "memory_remove" | "memory_restore" | "memory_add" | "okf_remove" | "okf_organize" | "archive_skill";
13
13
  export interface LearningRollbackPlan {
14
14
  kind: LearningRollbackKind;
15
15
  /** Text currently present because of the change (to remove/replace), or the skill name to archive. */
16
16
  target?: string;
17
17
  /** Original text to restore (memory_restore/memory_add). */
18
18
  previous?: string;
19
+ /** Compare-and-delete guard for a structured record created by this exact audited write. */
20
+ expectedDigest?: string;
21
+ /** Organization rollback only: false when the OKF record predated this hot-memory move. */
22
+ removeOkf?: boolean;
19
23
  instructions: string;
20
24
  }
21
25
  export type LearningAuditAction = "apply" | "apply_failed" | "propose" | "rollback";
@@ -1 +1 @@
1
- {"version":3,"file":"learning-audit.d.ts","sourceRoot":"","sources":["../../../src/core/learning/learning-audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAIN,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;GAKG;AAEH,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,gBAAgB,GAAG,YAAY,GAAG,eAAe,CAAC;AAEvG,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,sGAAsG;IACtG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACrB;AAKD,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;AAEpF;;0DAE0D;AAC1D,eAAO,MAAM,+BAA+B,wBAAwB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CAClB;AAeD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAO7G;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAS/E;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,eAAe,GAAG,oBAAoB,CA4B3F;AA8BD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAYlF;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAMnG;AAED,eAAO,MAAM,0BAA0B,mBAAmB,CAAC;AAE3D,MAAM,MAAM,4BAA4B,GAAG,sBAAsB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;AASjG,wBAAgB,2BAA2B,CAC1C,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,EACzD,MAAM,EAAE,mBAAmB,GACzB,MAAM,CAER;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,mBAAmB,EAAE,CAEjG"}
1
+ {"version":3,"file":"learning-audit.d.ts","sourceRoot":"","sources":["../../../src/core/learning/learning-audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAIN,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;GAKG;AAEH,MAAM,MAAM,oBAAoB,GAC7B,eAAe,GACf,gBAAgB,GAChB,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,eAAe,CAAC;AAEnB,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,sGAAsG;IACtG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACrB;AAKD,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;AAEpF;;0DAE0D;AAC1D,eAAO,MAAM,+BAA+B,wBAAwB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CAClB;AAmBD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAO7G;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAW/E;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,eAAe,GAAG,oBAAoB,CA0C3F;AAuCD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAYlF;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAMnG;AAED,eAAO,MAAM,0BAA0B,mBAAmB,CAAC;AAE3D,MAAM,MAAM,4BAA4B,GAAG,sBAAsB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;AASjG,wBAAgB,2BAA2B,CAC1C,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,EACzD,MAAM,EAAE,mBAAmB,GACzB,MAAM,CAER;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,mBAAmB,EAAE,CAEjG"}
@@ -7,6 +7,10 @@ function describeWrite(write) {
7
7
  switch (write.kind) {
8
8
  case "memory_add":
9
9
  return `Add ${write.section} memory: ${write.text}`;
10
+ case "okf_add":
11
+ return `Add OKF ${write.type}: ${write.title}`;
12
+ case "okf_organize":
13
+ return `Organize MEMORY fact into OKF ${write.type}: ${write.title}`;
10
14
  case "memory_replace":
11
15
  return `Replace memory "${write.target}" with "${write.text}"`;
12
16
  case "memory_remove":
@@ -36,6 +40,8 @@ export function contradictionsForReflectionWrite(write) {
36
40
  case "memory_remove":
37
41
  return 1;
38
42
  case "memory_add":
43
+ case "okf_add":
44
+ case "okf_organize":
39
45
  case "promote_skill":
40
46
  return 0;
41
47
  }
@@ -48,6 +54,20 @@ export function rollbackPlanForReflectionWrite(write) {
48
54
  target: write.text,
49
55
  instructions: `Remove the added ${write.section} memory text.`,
50
56
  };
57
+ case "okf_add":
58
+ return {
59
+ kind: "okf_remove",
60
+ target: `${write.type}\0${write.title}`,
61
+ instructions: "Remove the added structured OKF memory record.",
62
+ };
63
+ case "okf_organize":
64
+ return {
65
+ kind: "okf_organize",
66
+ target: `${write.type}\0${write.title}`,
67
+ previous: write.sourceText,
68
+ removeOkf: true,
69
+ instructions: "Restore the exact hot-memory source first, then remove only the audited OKF record.",
70
+ };
51
71
  case "memory_replace":
52
72
  return {
53
73
  kind: "memory_restore",
@@ -70,7 +90,14 @@ export function rollbackPlanForReflectionWrite(write) {
70
90
  }
71
91
  }
72
92
  const AUDIT_ACTIONS = ["apply", "apply_failed", "propose", "rollback"];
73
- const ROLLBACK_KINDS = ["memory_remove", "memory_restore", "memory_add", "archive_skill"];
93
+ const ROLLBACK_KINDS = [
94
+ "memory_remove",
95
+ "memory_restore",
96
+ "memory_add",
97
+ "okf_remove",
98
+ "okf_organize",
99
+ "archive_skill",
100
+ ];
74
101
  const LAYERS = ["memory", "skill", "prompt", "extension", "tool", "script", "settings", "source"];
75
102
  function isOptionalString(value) {
76
103
  return value === undefined || typeof value === "string";
@@ -83,6 +110,10 @@ function isLearningRollbackPlan(value) {
83
110
  return false;
84
111
  if (!isOptionalString(plan.target) || !isOptionalString(plan.previous))
85
112
  return false;
113
+ if (!isOptionalString(plan.expectedDigest))
114
+ return false;
115
+ if (plan.removeOkf !== undefined && typeof plan.removeOkf !== "boolean")
116
+ return false;
86
117
  return typeof plan.instructions === "string";
87
118
  }
88
119
  function isLearningDecisionShape(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"learning-audit.js","sourceRoot":"","sources":["../../../src/core/learning/learning-audit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { LearningDecision } from \"../autonomy/contracts.ts\";\nimport {\n\tappendSessionSnapshot,\n\tgetSessionSnapshots,\n\ttype SessionSnapshotCodec,\n\ttype SessionSnapshotPayload,\n} from \"../session-snapshot.ts\";\nimport type { DurableChangeLayer, DurableChangeProposal } from \"./learning-gate.ts\";\nimport type { ReflectionWrite } from \"./reflection-engine.ts\";\n\n/**\n * Audit + rollback metadata for durable learning changes. Every reflection-sourced write that the\n * learning policy applies (or converts to a proposal) leaves one of these records in the session\n * log, so `/autonomy diagnostics` can explain what changed, why, and how to undo it — and\n * `rollbackLearningWrite` can execute the inverse operation.\n */\n\nexport type LearningRollbackKind = \"memory_remove\" | \"memory_restore\" | \"memory_add\" | \"archive_skill\";\n\nexport interface LearningRollbackPlan {\n\tkind: LearningRollbackKind;\n\t/** Text currently present because of the change (to remove/replace), or the skill name to archive. */\n\ttarget?: string;\n\t/** Original text to restore (memory_restore/memory_add). */\n\tprevious?: string;\n\tinstructions: string;\n}\n\n// \"apply_failed\" is distinct from \"apply\": the gate decided to apply, but the underlying write tool\n// (e.g. the memory tool) refused it (budget exceeded, drift, threat) without throwing. It must never\n// be treated as \"apply\" by a rollback-eligibility check — there is nothing durable to undo.\nexport type LearningAuditAction = \"apply\" | \"apply_failed\" | \"propose\" | \"rollback\";\n\n/** reasonCode for an \"apply_failed\" audit — distinct from the gate's own reasonCode (e.g.\n * \"eligible_auto_apply\") so the record is honest about WHERE it stopped: the gate approved the\n * write, but the write tool refused it after the fact. */\nexport const APPLY_WRITE_REFUSED_REASON_CODE = \"apply_write_refused\";\n\nexport interface LearningAuditRecord {\n\tid: string;\n\tproposalId: string;\n\tlayer: DurableChangeLayer;\n\taction: LearningAuditAction;\n\tsummary: string;\n\treasonCode: string;\n\tdecision: LearningDecision;\n\trollback?: LearningRollbackPlan;\n\t/** For action \"rollback\": the audit id of the applied change this record undoes. */\n\trollbackOf?: string;\n\tcreatedAt: string;\n}\n\nfunction describeWrite(write: ReflectionWrite): string {\n\tswitch (write.kind) {\n\t\tcase \"memory_add\":\n\t\t\treturn `Add ${write.section} memory: ${write.text}`;\n\t\tcase \"memory_replace\":\n\t\t\treturn `Replace memory \"${write.target}\" with \"${write.text}\"`;\n\t\tcase \"memory_remove\":\n\t\t\treturn `Remove memory: ${write.target}`;\n\t\tcase \"promote_skill\":\n\t\t\treturn `Promote skill \"${write.name}\": ${write.description}`;\n\t}\n}\n\nexport function proposalFromReflectionWrite(write: ReflectionWrite, proposalId: string): DurableChangeProposal {\n\treturn {\n\t\tid: proposalId,\n\t\tlayer: write.kind === \"promote_skill\" ? \"skill\" : \"memory\",\n\t\tsummary: describeWrite(write),\n\t\trollbackPlan: rollbackPlanForReflectionWrite(write).instructions,\n\t};\n}\n\n/**\n * Contradiction count a reflection write carries against existing durable knowledge. A\n * `memory_replace`/`memory_remove` is only emitted when the reflection engine CONFRONTS an existing\n * fact (it supersedes or deletes it) — that supersession is the gate's contradiction signal, so such\n * a write must route through approval rather than silently overwriting prior memory. A `memory_add`\n * or `promote_skill` is purely additive and contradicts nothing.\n */\nexport function contradictionsForReflectionWrite(write: ReflectionWrite): number {\n\tswitch (write.kind) {\n\t\tcase \"memory_replace\":\n\t\tcase \"memory_remove\":\n\t\t\treturn 1;\n\t\tcase \"memory_add\":\n\t\tcase \"promote_skill\":\n\t\t\treturn 0;\n\t}\n}\n\nexport function rollbackPlanForReflectionWrite(write: ReflectionWrite): LearningRollbackPlan {\n\tswitch (write.kind) {\n\t\tcase \"memory_add\":\n\t\t\treturn {\n\t\t\t\tkind: \"memory_remove\",\n\t\t\t\ttarget: write.text,\n\t\t\t\tinstructions: `Remove the added ${write.section} memory text.`,\n\t\t\t};\n\t\tcase \"memory_replace\":\n\t\t\treturn {\n\t\t\t\tkind: \"memory_restore\",\n\t\t\t\ttarget: write.text,\n\t\t\t\tprevious: write.target,\n\t\t\t\tinstructions: \"Replace the new memory text with the original text it overwrote.\",\n\t\t\t};\n\t\tcase \"memory_remove\":\n\t\t\treturn {\n\t\t\t\tkind: \"memory_add\",\n\t\t\t\tprevious: write.target,\n\t\t\t\tinstructions: \"Re-add the removed text to the MEMORY file (it may originally have lived in USER).\",\n\t\t\t};\n\t\tcase \"promote_skill\":\n\t\t\treturn {\n\t\t\t\tkind: \"archive_skill\",\n\t\t\t\ttarget: write.name,\n\t\t\t\tinstructions: \"Archive the promoted skill so it no longer loads.\",\n\t\t\t};\n\t}\n}\n\nconst AUDIT_ACTIONS: readonly string[] = [\"apply\", \"apply_failed\", \"propose\", \"rollback\"];\nconst ROLLBACK_KINDS: readonly string[] = [\"memory_remove\", \"memory_restore\", \"memory_add\", \"archive_skill\"];\nconst LAYERS: readonly string[] = [\"memory\", \"skill\", \"prompt\", \"extension\", \"tool\", \"script\", \"settings\", \"source\"];\n\nfunction isOptionalString(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"string\";\n}\n\nfunction isLearningRollbackPlan(value: unknown): value is LearningRollbackPlan {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst plan = value as Record<string, unknown>;\n\tif (typeof plan.kind !== \"string\" || !ROLLBACK_KINDS.includes(plan.kind)) return false;\n\tif (!isOptionalString(plan.target) || !isOptionalString(plan.previous)) return false;\n\treturn typeof plan.instructions === \"string\";\n}\n\nfunction isLearningDecisionShape(value: unknown): value is LearningDecision {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst decision = value as Record<string, unknown>;\n\treturn (\n\t\t(decision.kind === \"no-op\" || decision.kind === \"proposal\" || decision.kind === \"apply\") &&\n\t\ttypeof decision.reasonCode === \"string\" &&\n\t\ttypeof decision.confidence === \"number\" &&\n\t\ttypeof decision.summary === \"string\" &&\n\t\ttypeof decision.requiresApproval === \"boolean\"\n\t);\n}\n\nexport function isLearningAuditRecord(value: unknown): value is LearningAuditRecord {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst record = value as Record<string, unknown>;\n\tif (typeof record.id !== \"string\" || record.id.length === 0) return false;\n\tif (typeof record.proposalId !== \"string\") return false;\n\tif (typeof record.layer !== \"string\" || !LAYERS.includes(record.layer)) return false;\n\tif (typeof record.action !== \"string\" || !AUDIT_ACTIONS.includes(record.action)) return false;\n\tif (typeof record.summary !== \"string\" || typeof record.reasonCode !== \"string\") return false;\n\tif (!isLearningDecisionShape(record.decision)) return false;\n\tif (record.rollback !== undefined && !isLearningRollbackPlan(record.rollback)) return false;\n\tif (!isOptionalString(record.rollbackOf)) return false;\n\treturn typeof record.createdAt === \"string\";\n}\n\nexport function cloneLearningAuditRecordForStorage(record: LearningAuditRecord): LearningAuditRecord {\n\treturn {\n\t\t...record,\n\t\tdecision: { ...record.decision },\n\t\t...(record.rollback ? { rollback: { ...record.rollback } } : {}),\n\t};\n}\n\nexport const LEARNING_AUDIT_CUSTOM_TYPE = \"learning_audit\";\n\nexport type LearningAuditSnapshotPayload = SessionSnapshotPayload<\"record\", LearningAuditRecord>;\n\nconst LEARNING_AUDIT_SNAPSHOT_CODEC: SessionSnapshotCodec<LearningAuditRecord, \"record\"> = {\n\tcustomType: LEARNING_AUDIT_CUSTOM_TYPE,\n\tvalueKey: \"record\",\n\tisValue: isLearningAuditRecord,\n\tclone: cloneLearningAuditRecordForStorage,\n};\n\nexport function appendLearningAuditSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\trecord: LearningAuditRecord,\n): string {\n\treturn appendSessionSnapshot(sessionManager, LEARNING_AUDIT_SNAPSHOT_CODEC, record);\n}\n\nexport function getLearningAuditSnapshots(entries: readonly SessionEntry[]): LearningAuditRecord[] {\n\treturn getSessionSnapshots(entries, LEARNING_AUDIT_SNAPSHOT_CODEC);\n}\n"]}
1
+ {"version":3,"file":"learning-audit.js","sourceRoot":"","sources":["../../../src/core/learning/learning-audit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { LearningDecision } from \"../autonomy/contracts.ts\";\nimport {\n\tappendSessionSnapshot,\n\tgetSessionSnapshots,\n\ttype SessionSnapshotCodec,\n\ttype SessionSnapshotPayload,\n} from \"../session-snapshot.ts\";\nimport type { DurableChangeLayer, DurableChangeProposal } from \"./learning-gate.ts\";\nimport type { ReflectionWrite } from \"./reflection-engine.ts\";\n\n/**\n * Audit + rollback metadata for durable learning changes. Every reflection-sourced write that the\n * learning policy applies (or converts to a proposal) leaves one of these records in the session\n * log, so `/autonomy diagnostics` can explain what changed, why, and how to undo it — and\n * `rollbackLearningWrite` can execute the inverse operation.\n */\n\nexport type LearningRollbackKind =\n\t| \"memory_remove\"\n\t| \"memory_restore\"\n\t| \"memory_add\"\n\t| \"okf_remove\"\n\t| \"okf_organize\"\n\t| \"archive_skill\";\n\nexport interface LearningRollbackPlan {\n\tkind: LearningRollbackKind;\n\t/** Text currently present because of the change (to remove/replace), or the skill name to archive. */\n\ttarget?: string;\n\t/** Original text to restore (memory_restore/memory_add). */\n\tprevious?: string;\n\t/** Compare-and-delete guard for a structured record created by this exact audited write. */\n\texpectedDigest?: string;\n\t/** Organization rollback only: false when the OKF record predated this hot-memory move. */\n\tremoveOkf?: boolean;\n\tinstructions: string;\n}\n\n// \"apply_failed\" is distinct from \"apply\": the gate decided to apply, but the underlying write tool\n// (e.g. the memory tool) refused it (budget exceeded, drift, threat) without throwing. It must never\n// be treated as \"apply\" by a rollback-eligibility check — there is nothing durable to undo.\nexport type LearningAuditAction = \"apply\" | \"apply_failed\" | \"propose\" | \"rollback\";\n\n/** reasonCode for an \"apply_failed\" audit — distinct from the gate's own reasonCode (e.g.\n * \"eligible_auto_apply\") so the record is honest about WHERE it stopped: the gate approved the\n * write, but the write tool refused it after the fact. */\nexport const APPLY_WRITE_REFUSED_REASON_CODE = \"apply_write_refused\";\n\nexport interface LearningAuditRecord {\n\tid: string;\n\tproposalId: string;\n\tlayer: DurableChangeLayer;\n\taction: LearningAuditAction;\n\tsummary: string;\n\treasonCode: string;\n\tdecision: LearningDecision;\n\trollback?: LearningRollbackPlan;\n\t/** For action \"rollback\": the audit id of the applied change this record undoes. */\n\trollbackOf?: string;\n\tcreatedAt: string;\n}\n\nfunction describeWrite(write: ReflectionWrite): string {\n\tswitch (write.kind) {\n\t\tcase \"memory_add\":\n\t\t\treturn `Add ${write.section} memory: ${write.text}`;\n\t\tcase \"okf_add\":\n\t\t\treturn `Add OKF ${write.type}: ${write.title}`;\n\t\tcase \"okf_organize\":\n\t\t\treturn `Organize MEMORY fact into OKF ${write.type}: ${write.title}`;\n\t\tcase \"memory_replace\":\n\t\t\treturn `Replace memory \"${write.target}\" with \"${write.text}\"`;\n\t\tcase \"memory_remove\":\n\t\t\treturn `Remove memory: ${write.target}`;\n\t\tcase \"promote_skill\":\n\t\t\treturn `Promote skill \"${write.name}\": ${write.description}`;\n\t}\n}\n\nexport function proposalFromReflectionWrite(write: ReflectionWrite, proposalId: string): DurableChangeProposal {\n\treturn {\n\t\tid: proposalId,\n\t\tlayer: write.kind === \"promote_skill\" ? \"skill\" : \"memory\",\n\t\tsummary: describeWrite(write),\n\t\trollbackPlan: rollbackPlanForReflectionWrite(write).instructions,\n\t};\n}\n\n/**\n * Contradiction count a reflection write carries against existing durable knowledge. A\n * `memory_replace`/`memory_remove` is only emitted when the reflection engine CONFRONTS an existing\n * fact (it supersedes or deletes it) — that supersession is the gate's contradiction signal, so such\n * a write must route through approval rather than silently overwriting prior memory. A `memory_add`\n * or `promote_skill` is purely additive and contradicts nothing.\n */\nexport function contradictionsForReflectionWrite(write: ReflectionWrite): number {\n\tswitch (write.kind) {\n\t\tcase \"memory_replace\":\n\t\tcase \"memory_remove\":\n\t\t\treturn 1;\n\t\tcase \"memory_add\":\n\t\tcase \"okf_add\":\n\t\tcase \"okf_organize\":\n\t\tcase \"promote_skill\":\n\t\t\treturn 0;\n\t}\n}\n\nexport function rollbackPlanForReflectionWrite(write: ReflectionWrite): LearningRollbackPlan {\n\tswitch (write.kind) {\n\t\tcase \"memory_add\":\n\t\t\treturn {\n\t\t\t\tkind: \"memory_remove\",\n\t\t\t\ttarget: write.text,\n\t\t\t\tinstructions: `Remove the added ${write.section} memory text.`,\n\t\t\t};\n\t\tcase \"okf_add\":\n\t\t\treturn {\n\t\t\t\tkind: \"okf_remove\",\n\t\t\t\ttarget: `${write.type}\\0${write.title}`,\n\t\t\t\tinstructions: \"Remove the added structured OKF memory record.\",\n\t\t\t};\n\t\tcase \"okf_organize\":\n\t\t\treturn {\n\t\t\t\tkind: \"okf_organize\",\n\t\t\t\ttarget: `${write.type}\\0${write.title}`,\n\t\t\t\tprevious: write.sourceText,\n\t\t\t\tremoveOkf: true,\n\t\t\t\tinstructions: \"Restore the exact hot-memory source first, then remove only the audited OKF record.\",\n\t\t\t};\n\t\tcase \"memory_replace\":\n\t\t\treturn {\n\t\t\t\tkind: \"memory_restore\",\n\t\t\t\ttarget: write.text,\n\t\t\t\tprevious: write.target,\n\t\t\t\tinstructions: \"Replace the new memory text with the original text it overwrote.\",\n\t\t\t};\n\t\tcase \"memory_remove\":\n\t\t\treturn {\n\t\t\t\tkind: \"memory_add\",\n\t\t\t\tprevious: write.target,\n\t\t\t\tinstructions: \"Re-add the removed text to the MEMORY file (it may originally have lived in USER).\",\n\t\t\t};\n\t\tcase \"promote_skill\":\n\t\t\treturn {\n\t\t\t\tkind: \"archive_skill\",\n\t\t\t\ttarget: write.name,\n\t\t\t\tinstructions: \"Archive the promoted skill so it no longer loads.\",\n\t\t\t};\n\t}\n}\n\nconst AUDIT_ACTIONS: readonly string[] = [\"apply\", \"apply_failed\", \"propose\", \"rollback\"];\nconst ROLLBACK_KINDS: readonly string[] = [\n\t\"memory_remove\",\n\t\"memory_restore\",\n\t\"memory_add\",\n\t\"okf_remove\",\n\t\"okf_organize\",\n\t\"archive_skill\",\n];\nconst LAYERS: readonly string[] = [\"memory\", \"skill\", \"prompt\", \"extension\", \"tool\", \"script\", \"settings\", \"source\"];\n\nfunction isOptionalString(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"string\";\n}\n\nfunction isLearningRollbackPlan(value: unknown): value is LearningRollbackPlan {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst plan = value as Record<string, unknown>;\n\tif (typeof plan.kind !== \"string\" || !ROLLBACK_KINDS.includes(plan.kind)) return false;\n\tif (!isOptionalString(plan.target) || !isOptionalString(plan.previous)) return false;\n\tif (!isOptionalString(plan.expectedDigest)) return false;\n\tif (plan.removeOkf !== undefined && typeof plan.removeOkf !== \"boolean\") return false;\n\treturn typeof plan.instructions === \"string\";\n}\n\nfunction isLearningDecisionShape(value: unknown): value is LearningDecision {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst decision = value as Record<string, unknown>;\n\treturn (\n\t\t(decision.kind === \"no-op\" || decision.kind === \"proposal\" || decision.kind === \"apply\") &&\n\t\ttypeof decision.reasonCode === \"string\" &&\n\t\ttypeof decision.confidence === \"number\" &&\n\t\ttypeof decision.summary === \"string\" &&\n\t\ttypeof decision.requiresApproval === \"boolean\"\n\t);\n}\n\nexport function isLearningAuditRecord(value: unknown): value is LearningAuditRecord {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst record = value as Record<string, unknown>;\n\tif (typeof record.id !== \"string\" || record.id.length === 0) return false;\n\tif (typeof record.proposalId !== \"string\") return false;\n\tif (typeof record.layer !== \"string\" || !LAYERS.includes(record.layer)) return false;\n\tif (typeof record.action !== \"string\" || !AUDIT_ACTIONS.includes(record.action)) return false;\n\tif (typeof record.summary !== \"string\" || typeof record.reasonCode !== \"string\") return false;\n\tif (!isLearningDecisionShape(record.decision)) return false;\n\tif (record.rollback !== undefined && !isLearningRollbackPlan(record.rollback)) return false;\n\tif (!isOptionalString(record.rollbackOf)) return false;\n\treturn typeof record.createdAt === \"string\";\n}\n\nexport function cloneLearningAuditRecordForStorage(record: LearningAuditRecord): LearningAuditRecord {\n\treturn {\n\t\t...record,\n\t\tdecision: { ...record.decision },\n\t\t...(record.rollback ? { rollback: { ...record.rollback } } : {}),\n\t};\n}\n\nexport const LEARNING_AUDIT_CUSTOM_TYPE = \"learning_audit\";\n\nexport type LearningAuditSnapshotPayload = SessionSnapshotPayload<\"record\", LearningAuditRecord>;\n\nconst LEARNING_AUDIT_SNAPSHOT_CODEC: SessionSnapshotCodec<LearningAuditRecord, \"record\"> = {\n\tcustomType: LEARNING_AUDIT_CUSTOM_TYPE,\n\tvalueKey: \"record\",\n\tisValue: isLearningAuditRecord,\n\tclone: cloneLearningAuditRecordForStorage,\n};\n\nexport function appendLearningAuditSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\trecord: LearningAuditRecord,\n): string {\n\treturn appendSessionSnapshot(sessionManager, LEARNING_AUDIT_SNAPSHOT_CODEC, record);\n}\n\nexport function getLearningAuditSnapshots(entries: readonly SessionEntry[]): LearningAuditRecord[] {\n\treturn getSessionSnapshots(entries, LEARNING_AUDIT_SNAPSHOT_CODEC);\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { Usage } from "@caupulican/pi-ai";
2
+ import { type PiOkfType } from "../context/okf-memory.ts";
2
3
  import { REFLECTION_SYSTEM_PROMPT } from "../provider-prompt-contracts.ts";
3
4
  export { REFLECTION_SYSTEM_PROMPT };
4
5
  export type StopReason = "stop" | "toolUse" | "aborted" | "error" | string;
@@ -35,6 +36,25 @@ export type ReflectionWrite = {
35
36
  kind: "memory_add";
36
37
  section: "MEMORY" | "USER";
37
38
  text: string;
39
+ } | {
40
+ kind: "okf_add";
41
+ type: PiOkfType;
42
+ title: string;
43
+ description: string;
44
+ scope: "project";
45
+ text: string;
46
+ tags?: string[];
47
+ evidenceRefs: string[];
48
+ } | {
49
+ kind: "okf_organize";
50
+ type: PiOkfType;
51
+ title: string;
52
+ description: string;
53
+ scope: "project";
54
+ text: string;
55
+ sourceText: string;
56
+ tags?: string[];
57
+ evidenceRefs: string[];
38
58
  } | {
39
59
  kind: "memory_replace";
40
60
  target: string;
@@ -1 +1 @@
1
- {"version":3,"file":"reflection-engine.d.ts","sourceRoot":"","sources":["../../../src/core/learning/reflection-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,OAAO,EAAE,wBAAwB,EAAE,CAAC;AAEpC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3E,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAE9F,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,UAAU,CA4B/D;AAED,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,UAAU,CAAC;IAEjB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC1F;AAED,MAAM,MAAM,eAAe,GACxB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAEzC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9E,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC5B;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiF/D;CACD"}
1
+ {"version":3,"file":"reflection-engine.d.ts","sourceRoot":"","sources":["../../../src/core/learning/reflection-engine.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { PI_OKF_TYPES, validateOkfMemoryDocumentInput } from "../context/okf-memory.js";
1
2
  import { REFLECTION_SYSTEM_PROMPT } from "../provider-prompt-contracts.js";
2
3
  export { REFLECTION_SYSTEM_PROMPT };
3
4
  /**
@@ -30,6 +31,59 @@ export function decideDemand(signals) {
30
31
  }
31
32
  return { act: "skip", reason: "Signals do not justify reflection overhead", tokenBudget: 0 };
32
33
  }
34
+ function isRecord(value) {
35
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36
+ }
37
+ function isStringArray(value) {
38
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
39
+ }
40
+ /** One parser/validation path for both structured reflection operations. */
41
+ function parseStructuredReflectionWrite(value, existingMemory) {
42
+ if (!isRecord(value) || (value.kind !== "okf_add" && value.kind !== "okf_organize"))
43
+ return undefined;
44
+ if (!PI_OKF_TYPES.includes(value.type) ||
45
+ typeof value.title !== "string" ||
46
+ typeof value.description !== "string" ||
47
+ value.scope !== "project" ||
48
+ typeof value.text !== "string" ||
49
+ !isStringArray(value.evidenceRefs) ||
50
+ value.evidenceRefs.length === 0 ||
51
+ (value.tags !== undefined && !isStringArray(value.tags))) {
52
+ return undefined;
53
+ }
54
+ const common = {
55
+ type: value.type,
56
+ title: value.title,
57
+ description: value.description,
58
+ scope: "project",
59
+ text: value.text,
60
+ ...(value.tags !== undefined ? { tags: value.tags } : {}),
61
+ evidenceRefs: value.evidenceRefs,
62
+ };
63
+ let write;
64
+ if (value.kind === "okf_organize") {
65
+ if (typeof value.sourceText !== "string" ||
66
+ value.sourceText.length === 0 ||
67
+ !existingMemory.includes(value.sourceText)) {
68
+ return undefined;
69
+ }
70
+ write = { kind: "okf_organize", ...common, sourceText: value.sourceText };
71
+ }
72
+ else {
73
+ write = { kind: "okf_add", ...common };
74
+ }
75
+ return validateOkfMemoryDocumentInput({
76
+ type: write.type,
77
+ title: write.title,
78
+ description: write.description,
79
+ scope: write.scope,
80
+ body: write.text,
81
+ tags: write.tags,
82
+ evidenceRefs: write.evidenceRefs,
83
+ }, { projectOnly: true, requireEvidence: true }).length === 0
84
+ ? write
85
+ : undefined;
86
+ }
33
87
  /**
34
88
  * STATIC reflection system prompt (Hermes-parity #33). It is byte-identical across every reflection
35
89
  * pass — the variable parts (existing memory snapshot + the turn transcript) live in the USER prompt —
@@ -71,11 +125,15 @@ Return JSON updates.`;
71
125
  if (Array.isArray(parsed.writes)) {
72
126
  for (const w of parsed.writes) {
73
127
  if (w && typeof w === "object") {
128
+ const structuredWrite = parseStructuredReflectionWrite(w, input.existingMemory);
74
129
  if (w.kind === "memory_add" &&
75
130
  (w.section === "MEMORY" || w.section === "USER") &&
76
131
  typeof w.text === "string") {
77
132
  writes.push({ kind: "memory_add", section: w.section, text: w.text });
78
133
  }
134
+ else if (structuredWrite) {
135
+ writes.push(structuredWrite);
136
+ }
79
137
  else if (w.kind === "memory_replace" &&
80
138
  typeof w.target === "string" &&
81
139
  typeof w.text === "string") {
@@ -1 +1 @@
1
- {"version":3,"file":"reflection-engine.js","sourceRoot":"","sources":["../../../src/core/learning/reflection-engine.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Usage } from \"@caupulican/pi-ai\";\nimport { REFLECTION_SYSTEM_PROMPT } from \"../provider-prompt-contracts.ts\";\n\nexport { REFLECTION_SYSTEM_PROMPT };\n\nexport type StopReason = \"stop\" | \"toolUse\" | \"aborted\" | \"error\" | string;\n\nexport interface IsolatedCompletionResult {\n\ttext: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n}\n\nexport type ReflectionTrigger = \"complex\" | \"corrective\" | \"durable\" | \"session-end\" | \"none\";\n\nexport interface DemandSignals {\n\ttrigger: ReflectionTrigger;\n\ttoolCallCount: number;\n\thadCorrection: boolean;\n\tcontextHeadroomPct: number; // 0..100\n\tusefulLately: number; // 0..1 rolling score\n}\n\nexport interface DemandPlan {\n\tact: \"skip\" | \"reflect\";\n\treason: string;\n\ttokenBudget: number;\n}\n\n/**\n * Pure zero-I/O heuristic to decide whether the current turn justifies a reflection run\n * and determine the token budget under the cheap-tool net-negative doctrine.\n */\nexport function decideDemand(signals: DemandSignals): DemandPlan {\n\tif (signals.trigger === \"none\") {\n\t\treturn { act: \"skip\", reason: \"No trigger detected\", tokenBudget: 0 };\n\t}\n\tif (signals.contextHeadroomPct < 10) {\n\t\treturn { act: \"skip\", reason: \"Context headroom is critically low (< 10%)\", tokenBudget: 0 };\n\t}\n\n\t// Dynamic token budget based on headroom (keep reflection bounded between 500 and 1500 tokens)\n\tconst baseBudget = 1000;\n\tconst tokenBudget = Math.max(500, Math.min(1500, Math.round(baseBudget * (signals.contextHeadroomPct / 100))));\n\n\tif (signals.hadCorrection) {\n\t\treturn { act: \"reflect\", reason: \"Correction detected in the turn\", tokenBudget };\n\t}\n\tif (signals.trigger === \"durable\") {\n\t\treturn { act: \"reflect\", reason: \"Durable fact or preference detected in the turn\", tokenBudget };\n\t}\n\tif (signals.trigger === \"session-end\") {\n\t\treturn { act: \"reflect\", reason: \"Session end reflection triggered\", tokenBudget };\n\t}\n\tif (signals.trigger === \"complex\") {\n\t\tif (signals.toolCallCount >= 3) {\n\t\t\treturn { act: \"reflect\", reason: `Complex turn with ${signals.toolCallCount} tool calls`, tokenBudget };\n\t\t}\n\t}\n\n\treturn { act: \"skip\", reason: \"Signals do not justify reflection overhead\", tokenBudget: 0 };\n}\n\nexport interface ReflectionInput {\n\trecentTurnText: string; // host serializes the just-finished turn\n\texistingMemory: string; // current MEMORY.md + USER.md snapshot\n\tplan: DemandPlan;\n\t// host-injected isolated completion function:\n\tcomplete: (systemPrompt: string, userPrompt: string) => Promise<IsolatedCompletionResult>;\n}\n\nexport type ReflectionWrite =\n\t| { kind: \"memory_add\"; section: \"MEMORY\" | \"USER\"; text: string }\n\t| { kind: \"memory_replace\"; target: string; text: string }\n\t| { kind: \"memory_remove\"; target: string }\n\t// R7 memory-to-behavior: promote a recurring procedural workflow into an executable skill.\n\t| { kind: \"promote_skill\"; name: string; description: string; body: string };\n\nexport interface ReflectionResult {\n\twrites: ReflectionWrite[];\n\tusage: Usage;\n\trationale: string;\n}\n\n/**\n * STATIC reflection system prompt (Hermes-parity #33). It is byte-identical across every reflection\n * pass — the variable parts (existing memory snapshot + the turn transcript) live in the USER prompt —\n * so the provider prompt-cache reuses this prefix instead of re-billing it each pass (cost guard).\n * Do NOT interpolate per-call data into this constant or caching breaks.\n */\nexport class ReflectionEngine {\n\t/**\n\t * Build the reflection prompt, call the injected isolated complete(),\n\t * parse the response, confront existing memory, and return memory writes.\n\t * Zero direct I/O.\n\t */\n\tasync reflect(input: ReflectionInput): Promise<ReflectionResult> {\n\t\tconst systemPrompt = REFLECTION_SYSTEM_PROMPT;\n\n\t\t// Variable inputs go in the USER prompt so the system prefix above stays cache-stable (#33).\n\t\tconst userPrompt = `Existing memory:\n${input.existingMemory}\n\nRecent turn transcript:\n${input.recentTurnText}\n\nReturn JSON updates.`;\n\n\t\tlet usage: Usage | undefined;\n\t\ttry {\n\t\t\tconst compResult = await input.complete(systemPrompt, userPrompt);\n\t\t\tusage = compResult.usage;\n\t\t\tconst text = compResult.text;\n\n\t\t\tconst jsonMatch = text.match(/```json\\s*([\\s\\S]*?)\\s*```/) || text.match(/{[\\s\\S]*}/);\n\t\t\tif (!jsonMatch) {\n\t\t\t\treturn {\n\t\t\t\t\twrites: [],\n\t\t\t\t\tusage: compResult.usage,\n\t\t\t\t\trationale: `Failed to locate JSON response. Raw text:\\n${text}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst parsed = JSON.parse(jsonMatch[1] || jsonMatch[0]);\n\t\t\tconst rationale = parsed.rationale || \"\";\n\t\t\tconst writes: ReflectionWrite[] = [];\n\n\t\t\tif (Array.isArray(parsed.writes)) {\n\t\t\t\tfor (const w of parsed.writes) {\n\t\t\t\t\tif (w && typeof w === \"object\") {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tw.kind === \"memory_add\" &&\n\t\t\t\t\t\t\t(w.section === \"MEMORY\" || w.section === \"USER\") &&\n\t\t\t\t\t\t\ttypeof w.text === \"string\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrites.push({ kind: \"memory_add\", section: w.section, text: w.text });\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tw.kind === \"memory_replace\" &&\n\t\t\t\t\t\t\ttypeof w.target === \"string\" &&\n\t\t\t\t\t\t\ttypeof w.text === \"string\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrites.push({ kind: \"memory_replace\", target: w.target, text: w.text });\n\t\t\t\t\t\t} else if (w.kind === \"memory_remove\" && typeof w.target === \"string\") {\n\t\t\t\t\t\t\twrites.push({ kind: \"memory_remove\", target: w.target });\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tw.kind === \"promote_skill\" &&\n\t\t\t\t\t\t\ttypeof w.name === \"string\" &&\n\t\t\t\t\t\t\ttypeof w.description === \"string\" &&\n\t\t\t\t\t\t\ttypeof w.body === \"string\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrites.push({ kind: \"promote_skill\", name: w.name, description: w.description, body: w.body });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twrites,\n\t\t\t\tusage: compResult.usage,\n\t\t\t\trationale,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\t// Zeroed/fallback usage representation\n\t\t\tconst emptyUsage: Usage = {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\treturn {\n\t\t\t\twrites: [],\n\t\t\t\tusage: usage ?? emptyUsage,\n\t\t\t\trationale: `Error during reflection: ${String(err)}`,\n\t\t\t};\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"reflection-engine.js","sourceRoot":"","sources":["../../../src/core/learning/reflection-engine.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Usage } from \"@caupulican/pi-ai\";\nimport { PI_OKF_TYPES, type PiOkfType, validateOkfMemoryDocumentInput } from \"../context/okf-memory.ts\";\nimport { REFLECTION_SYSTEM_PROMPT } from \"../provider-prompt-contracts.ts\";\n\nexport { REFLECTION_SYSTEM_PROMPT };\n\nexport type StopReason = \"stop\" | \"toolUse\" | \"aborted\" | \"error\" | string;\n\nexport interface IsolatedCompletionResult {\n\ttext: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n}\n\nexport type ReflectionTrigger = \"complex\" | \"corrective\" | \"durable\" | \"session-end\" | \"none\";\n\nexport interface DemandSignals {\n\ttrigger: ReflectionTrigger;\n\ttoolCallCount: number;\n\thadCorrection: boolean;\n\tcontextHeadroomPct: number; // 0..100\n\tusefulLately: number; // 0..1 rolling score\n}\n\nexport interface DemandPlan {\n\tact: \"skip\" | \"reflect\";\n\treason: string;\n\ttokenBudget: number;\n}\n\n/**\n * Pure zero-I/O heuristic to decide whether the current turn justifies a reflection run\n * and determine the token budget under the cheap-tool net-negative doctrine.\n */\nexport function decideDemand(signals: DemandSignals): DemandPlan {\n\tif (signals.trigger === \"none\") {\n\t\treturn { act: \"skip\", reason: \"No trigger detected\", tokenBudget: 0 };\n\t}\n\tif (signals.contextHeadroomPct < 10) {\n\t\treturn { act: \"skip\", reason: \"Context headroom is critically low (< 10%)\", tokenBudget: 0 };\n\t}\n\n\t// Dynamic token budget based on headroom (keep reflection bounded between 500 and 1500 tokens)\n\tconst baseBudget = 1000;\n\tconst tokenBudget = Math.max(500, Math.min(1500, Math.round(baseBudget * (signals.contextHeadroomPct / 100))));\n\n\tif (signals.hadCorrection) {\n\t\treturn { act: \"reflect\", reason: \"Correction detected in the turn\", tokenBudget };\n\t}\n\tif (signals.trigger === \"durable\") {\n\t\treturn { act: \"reflect\", reason: \"Durable fact or preference detected in the turn\", tokenBudget };\n\t}\n\tif (signals.trigger === \"session-end\") {\n\t\treturn { act: \"reflect\", reason: \"Session end reflection triggered\", tokenBudget };\n\t}\n\tif (signals.trigger === \"complex\") {\n\t\tif (signals.toolCallCount >= 3) {\n\t\t\treturn { act: \"reflect\", reason: `Complex turn with ${signals.toolCallCount} tool calls`, tokenBudget };\n\t\t}\n\t}\n\n\treturn { act: \"skip\", reason: \"Signals do not justify reflection overhead\", tokenBudget: 0 };\n}\n\nexport interface ReflectionInput {\n\trecentTurnText: string; // host serializes the just-finished turn\n\texistingMemory: string; // current MEMORY.md + USER.md snapshot\n\tplan: DemandPlan;\n\t// host-injected isolated completion function:\n\tcomplete: (systemPrompt: string, userPrompt: string) => Promise<IsolatedCompletionResult>;\n}\n\nexport type ReflectionWrite =\n\t| { kind: \"memory_add\"; section: \"MEMORY\" | \"USER\"; text: string }\n\t| {\n\t\t\tkind: \"okf_add\";\n\t\t\ttype: PiOkfType;\n\t\t\ttitle: string;\n\t\t\tdescription: string;\n\t\t\tscope: \"project\";\n\t\t\ttext: string;\n\t\t\ttags?: string[];\n\t\t\tevidenceRefs: string[];\n\t }\n\t| {\n\t\t\tkind: \"okf_organize\";\n\t\t\ttype: PiOkfType;\n\t\t\ttitle: string;\n\t\t\tdescription: string;\n\t\t\tscope: \"project\";\n\t\t\ttext: string;\n\t\t\tsourceText: string;\n\t\t\ttags?: string[];\n\t\t\tevidenceRefs: string[];\n\t }\n\t| { kind: \"memory_replace\"; target: string; text: string }\n\t| { kind: \"memory_remove\"; target: string }\n\t// R7 memory-to-behavior: promote a recurring procedural workflow into an executable skill.\n\t| { kind: \"promote_skill\"; name: string; description: string; body: string };\n\nexport interface ReflectionResult {\n\twrites: ReflectionWrite[];\n\tusage: Usage;\n\trationale: string;\n}\n\ntype StructuredReflectionWrite = Extract<ReflectionWrite, { kind: \"okf_add\" | \"okf_organize\" }>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\n/** One parser/validation path for both structured reflection operations. */\nfunction parseStructuredReflectionWrite(value: unknown, existingMemory: string): StructuredReflectionWrite | undefined {\n\tif (!isRecord(value) || (value.kind !== \"okf_add\" && value.kind !== \"okf_organize\")) return undefined;\n\tif (\n\t\t!PI_OKF_TYPES.includes(value.type as PiOkfType) ||\n\t\ttypeof value.title !== \"string\" ||\n\t\ttypeof value.description !== \"string\" ||\n\t\tvalue.scope !== \"project\" ||\n\t\ttypeof value.text !== \"string\" ||\n\t\t!isStringArray(value.evidenceRefs) ||\n\t\tvalue.evidenceRefs.length === 0 ||\n\t\t(value.tags !== undefined && !isStringArray(value.tags))\n\t) {\n\t\treturn undefined;\n\t}\n\tconst common = {\n\t\ttype: value.type as PiOkfType,\n\t\ttitle: value.title,\n\t\tdescription: value.description,\n\t\tscope: \"project\" as const,\n\t\ttext: value.text,\n\t\t...(value.tags !== undefined ? { tags: value.tags } : {}),\n\t\tevidenceRefs: value.evidenceRefs,\n\t};\n\tlet write: StructuredReflectionWrite;\n\tif (value.kind === \"okf_organize\") {\n\t\tif (\n\t\t\ttypeof value.sourceText !== \"string\" ||\n\t\t\tvalue.sourceText.length === 0 ||\n\t\t\t!existingMemory.includes(value.sourceText)\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\twrite = { kind: \"okf_organize\", ...common, sourceText: value.sourceText };\n\t} else {\n\t\twrite = { kind: \"okf_add\", ...common };\n\t}\n\treturn validateOkfMemoryDocumentInput(\n\t\t{\n\t\t\ttype: write.type,\n\t\t\ttitle: write.title,\n\t\t\tdescription: write.description,\n\t\t\tscope: write.scope,\n\t\t\tbody: write.text,\n\t\t\ttags: write.tags,\n\t\t\tevidenceRefs: write.evidenceRefs,\n\t\t},\n\t\t{ projectOnly: true, requireEvidence: true },\n\t).length === 0\n\t\t? write\n\t\t: undefined;\n}\n\n/**\n * STATIC reflection system prompt (Hermes-parity #33). It is byte-identical across every reflection\n * pass — the variable parts (existing memory snapshot + the turn transcript) live in the USER prompt —\n * so the provider prompt-cache reuses this prefix instead of re-billing it each pass (cost guard).\n * Do NOT interpolate per-call data into this constant or caching breaks.\n */\nexport class ReflectionEngine {\n\t/**\n\t * Build the reflection prompt, call the injected isolated complete(),\n\t * parse the response, confront existing memory, and return memory writes.\n\t * Zero direct I/O.\n\t */\n\tasync reflect(input: ReflectionInput): Promise<ReflectionResult> {\n\t\tconst systemPrompt = REFLECTION_SYSTEM_PROMPT;\n\n\t\t// Variable inputs go in the USER prompt so the system prefix above stays cache-stable (#33).\n\t\tconst userPrompt = `Existing memory:\n${input.existingMemory}\n\nRecent turn transcript:\n${input.recentTurnText}\n\nReturn JSON updates.`;\n\n\t\tlet usage: Usage | undefined;\n\t\ttry {\n\t\t\tconst compResult = await input.complete(systemPrompt, userPrompt);\n\t\t\tusage = compResult.usage;\n\t\t\tconst text = compResult.text;\n\n\t\t\tconst jsonMatch = text.match(/```json\\s*([\\s\\S]*?)\\s*```/) || text.match(/{[\\s\\S]*}/);\n\t\t\tif (!jsonMatch) {\n\t\t\t\treturn {\n\t\t\t\t\twrites: [],\n\t\t\t\t\tusage: compResult.usage,\n\t\t\t\t\trationale: `Failed to locate JSON response. Raw text:\\n${text}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst parsed = JSON.parse(jsonMatch[1] || jsonMatch[0]);\n\t\t\tconst rationale = parsed.rationale || \"\";\n\t\t\tconst writes: ReflectionWrite[] = [];\n\n\t\t\tif (Array.isArray(parsed.writes)) {\n\t\t\t\tfor (const w of parsed.writes) {\n\t\t\t\t\tif (w && typeof w === \"object\") {\n\t\t\t\t\t\tconst structuredWrite = parseStructuredReflectionWrite(w, input.existingMemory);\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tw.kind === \"memory_add\" &&\n\t\t\t\t\t\t\t(w.section === \"MEMORY\" || w.section === \"USER\") &&\n\t\t\t\t\t\t\ttypeof w.text === \"string\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrites.push({ kind: \"memory_add\", section: w.section, text: w.text });\n\t\t\t\t\t\t} else if (structuredWrite) {\n\t\t\t\t\t\t\twrites.push(structuredWrite);\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tw.kind === \"memory_replace\" &&\n\t\t\t\t\t\t\ttypeof w.target === \"string\" &&\n\t\t\t\t\t\t\ttypeof w.text === \"string\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrites.push({ kind: \"memory_replace\", target: w.target, text: w.text });\n\t\t\t\t\t\t} else if (w.kind === \"memory_remove\" && typeof w.target === \"string\") {\n\t\t\t\t\t\t\twrites.push({ kind: \"memory_remove\", target: w.target });\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tw.kind === \"promote_skill\" &&\n\t\t\t\t\t\t\ttypeof w.name === \"string\" &&\n\t\t\t\t\t\t\ttypeof w.description === \"string\" &&\n\t\t\t\t\t\t\ttypeof w.body === \"string\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrites.push({ kind: \"promote_skill\", name: w.name, description: w.description, body: w.body });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twrites,\n\t\t\t\tusage: compResult.usage,\n\t\t\t\trationale,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\t// Zeroed/fallback usage representation\n\t\t\tconst emptyUsage: Usage = {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\treturn {\n\t\t\t\twrites: [],\n\t\t\t\tusage: usage ?? emptyUsage,\n\t\t\t\trationale: `Error during reflection: ${String(err)}`,\n\t\t\t};\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { type OkfMemoryDocumentInput, type PiOkfType } from "../context/okf-memory.ts";
2
+ export interface OkfProjectMemoryPutResult {
3
+ created: boolean;
4
+ digest: string;
5
+ path: string;
6
+ }
7
+ export interface OkfProjectMemoryRemoveResult {
8
+ removed: boolean;
9
+ }
10
+ /**
11
+ * Durable storage owner for model-authored project OKF records. It owns project identity, bounds,
12
+ * conflict policy, symlink containment, per-record locking, and atomic replacement. Existing
13
+ * different content is never overwritten by an `add`; reflection must confront it explicitly.
14
+ */
15
+ export declare class OkfProjectMemoryStore {
16
+ readonly projectId: string;
17
+ readonly projectRoot: string;
18
+ private readonly agentDir;
19
+ private readonly rootDir;
20
+ private readonly projectDir;
21
+ constructor(agentDir: string, cwd: string);
22
+ private recordPath;
23
+ private assertContained;
24
+ put(input: Omit<OkfMemoryDocumentInput, "projectId">): Promise<OkfProjectMemoryPutResult>;
25
+ remove(type: PiOkfType, title: string, expectedDigest?: string): Promise<OkfProjectMemoryRemoveResult>;
26
+ list(maxDocuments?: number): string;
27
+ }
28
+ //# sourceMappingURL=okf-project-memory-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okf-project-memory-store.d.ts","sourceRoot":"","sources":["../../../src/core/memory/okf-project-memory-store.ts"],"names":[],"mappings":"AAKA,OAAO,EAEN,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EAEd,MAAM,0BAA0B,CAAC;AAYlC,MAAM,WAAW,yBAAyB;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,4BAA4B;IAC5C,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,qBAAqB;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,YAAY,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAOxC;IAED,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,eAAe;IAgBjB,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAmB9F;IAEK,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAkB3G;IAED,IAAI,CAAC,YAAY,SAAK,GAAG,MAAM,CAc9B;CACD"}
@@ -0,0 +1,111 @@
1
+ import { createHash } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { okfMemoryDir, okfProjectMemoryDir } from "../agent-paths.js";
5
+ import { isPathWithinScope, safeRealpathSync } from "../autonomy/path-scope.js";
6
+ import { formatOkfMemoryDocument, validateOkfMemoryDocumentInput, } from "../context/okf-memory.js";
7
+ import { loadOkfMemoryBundle } from "../context/okf-memory-provider.js";
8
+ import { getDirectoryResourceProfileInfo } from "../settings-manager.js";
9
+ import { isMissingFileError, withFileLock, writeFileAtomic } from "../util/atomic-file.js";
10
+ import { readBoundedTextFile } from "../util/bounded-file.js";
11
+ const MAX_OKF_DOCUMENT_BYTES = 16_384;
12
+ function digest(content) {
13
+ return createHash("sha256").update(content, "utf8").digest("hex");
14
+ }
15
+ /**
16
+ * Durable storage owner for model-authored project OKF records. It owns project identity, bounds,
17
+ * conflict policy, symlink containment, per-record locking, and atomic replacement. Existing
18
+ * different content is never overwritten by an `add`; reflection must confront it explicitly.
19
+ */
20
+ export class OkfProjectMemoryStore {
21
+ constructor(agentDir, cwd) {
22
+ const identity = getDirectoryResourceProfileInfo(cwd, agentDir);
23
+ this.agentDir = agentDir;
24
+ this.rootDir = okfMemoryDir(agentDir);
25
+ this.projectId = identity.hash;
26
+ this.projectRoot = identity.root;
27
+ this.projectDir = okfProjectMemoryDir(agentDir, identity.hash);
28
+ }
29
+ recordPath(type, title) {
30
+ const path = join(this.projectDir, `${digest(`${type}\0${title}`)}.okf.md`);
31
+ if (!isPathWithinScope(path, this.projectDir))
32
+ throw new Error("OKF record escaped its project root.");
33
+ return path;
34
+ }
35
+ assertContained(path) {
36
+ const canonicalAgentDir = safeRealpathSync(this.agentDir);
37
+ const canonicalRootDir = safeRealpathSync(this.rootDir);
38
+ const canonicalProjectDir = safeRealpathSync(this.projectDir);
39
+ const canonicalPath = safeRealpathSync(path);
40
+ if (!isPathWithinScope(canonicalRootDir, canonicalAgentDir)) {
41
+ throw new Error("OKF memory root escapes the agent directory.");
42
+ }
43
+ if (!isPathWithinScope(canonicalProjectDir, canonicalRootDir)) {
44
+ throw new Error("OKF project root escapes the OKF memory root.");
45
+ }
46
+ if (!isPathWithinScope(canonicalPath, canonicalProjectDir)) {
47
+ throw new Error("OKF record escapes its project root.");
48
+ }
49
+ }
50
+ async put(input) {
51
+ const errors = validateOkfMemoryDocumentInput(input, { projectOnly: true, requireEvidence: true });
52
+ if (errors.length > 0)
53
+ throw new Error(`Invalid OKF record: ${errors.join("; ")}`);
54
+ const document = formatOkfMemoryDocument({ ...input, projectId: this.projectId });
55
+ const documentDigest = digest(document);
56
+ const path = this.recordPath(input.type, input.title);
57
+ this.assertContained(path);
58
+ return withFileLock(path, async () => {
59
+ this.assertContained(path);
60
+ try {
61
+ const existing = await readBoundedTextFile(path, MAX_OKF_DOCUMENT_BYTES, "OKF project record");
62
+ if (existing === document)
63
+ return { created: false, digest: documentDigest, path };
64
+ throw new Error("A different structured record already exists for this type and title.");
65
+ }
66
+ catch (error) {
67
+ if (!isMissingFileError(error))
68
+ throw error;
69
+ }
70
+ await writeFileAtomic(path, document, { mode: 0o600 });
71
+ return { created: true, digest: documentDigest, path };
72
+ });
73
+ }
74
+ async remove(type, title, expectedDigest) {
75
+ const path = this.recordPath(type, title);
76
+ this.assertContained(path);
77
+ return withFileLock(path, async () => {
78
+ this.assertContained(path);
79
+ let existing;
80
+ try {
81
+ existing = await readBoundedTextFile(path, MAX_OKF_DOCUMENT_BYTES, "OKF project record");
82
+ }
83
+ catch (error) {
84
+ if (isMissingFileError(error))
85
+ return { removed: false };
86
+ throw error;
87
+ }
88
+ if (expectedDigest !== undefined && digest(existing) !== expectedDigest) {
89
+ throw new Error("OKF record changed after the audited write; refusing removal.");
90
+ }
91
+ await fs.unlink(path);
92
+ return { removed: true };
93
+ });
94
+ }
95
+ list(maxDocuments = 64) {
96
+ return loadOkfMemoryBundle({
97
+ rootDir: this.rootDir,
98
+ projectId: this.projectId,
99
+ projectRoot: this.projectRoot,
100
+ maxDocuments,
101
+ })
102
+ .entries.map(({ relativePath, parsed }) => {
103
+ const item = parsed.item;
104
+ return item === undefined ? "" : `${relativePath}: ${item.title ?? "Untitled"} — ${item.summary}`;
105
+ })
106
+ .filter((entry) => entry.length > 0)
107
+ .join("\n")
108
+ .slice(0, 8_000);
109
+ }
110
+ }
111
+ //# sourceMappingURL=okf-project-memory-store.js.map