open-multi-agent-kit 0.95.2 → 0.96.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 (259) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +37 -4
  3. package/dist/approvals/approval-receipt-store.d.ts.map +1 -1
  4. package/dist/approvals/approval-receipt-store.js +25 -0
  5. package/dist/approvals/approval-receipt-store.js.map +1 -1
  6. package/dist/commands/doctor-provider.d.ts.map +1 -1
  7. package/dist/commands/doctor-provider.js +15 -20
  8. package/dist/commands/doctor-provider.js.map +1 -1
  9. package/dist/commands/sdk-session-cli.d.ts +24 -0
  10. package/dist/commands/sdk-session-cli.d.ts.map +1 -0
  11. package/dist/commands/sdk-session-cli.js +225 -0
  12. package/dist/commands/sdk-session-cli.js.map +1 -0
  13. package/dist/core/advisory-judge-model.d.ts +18 -0
  14. package/dist/core/advisory-judge-model.d.ts.map +1 -0
  15. package/dist/core/advisory-judge-model.js +168 -0
  16. package/dist/core/advisory-judge-model.js.map +1 -0
  17. package/dist/core/advisory-judge-response.d.ts +8 -0
  18. package/dist/core/advisory-judge-response.d.ts.map +1 -0
  19. package/dist/core/advisory-judge-response.js +61 -0
  20. package/dist/core/advisory-judge-response.js.map +1 -0
  21. package/dist/core/advisory-judge-types.d.ts +53 -0
  22. package/dist/core/advisory-judge-types.d.ts.map +1 -0
  23. package/dist/core/advisory-judge-types.js +2 -0
  24. package/dist/core/advisory-judge-types.js.map +1 -0
  25. package/dist/core/advisory-judge.d.ts +8 -0
  26. package/dist/core/advisory-judge.d.ts.map +1 -0
  27. package/dist/core/advisory-judge.js +178 -0
  28. package/dist/core/advisory-judge.js.map +1 -0
  29. package/dist/core/agent-session-services.d.ts +1 -0
  30. package/dist/core/agent-session-services.d.ts.map +1 -1
  31. package/dist/core/agent-session-services.js +1 -0
  32. package/dist/core/agent-session-services.js.map +1 -1
  33. package/dist/core/agent-session.d.ts +6 -3
  34. package/dist/core/agent-session.d.ts.map +1 -1
  35. package/dist/core/agent-session.js +141 -184
  36. package/dist/core/agent-session.js.map +1 -1
  37. package/dist/core/auth-storage.d.ts.map +1 -1
  38. package/dist/core/auth-storage.js +28 -4
  39. package/dist/core/auth-storage.js.map +1 -1
  40. package/dist/core/compaction-gate.d.ts +28 -0
  41. package/dist/core/compaction-gate.d.ts.map +1 -0
  42. package/dist/core/compaction-gate.js +34 -0
  43. package/dist/core/compaction-gate.js.map +1 -0
  44. package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
  45. package/dist/core/context-budget-system-prompt-items.js +5 -3
  46. package/dist/core/context-budget-system-prompt-items.js.map +1 -1
  47. package/dist/core/domain-loadouts.d.ts.map +1 -1
  48. package/dist/core/domain-loadouts.js +2 -2
  49. package/dist/core/domain-loadouts.js.map +1 -1
  50. package/dist/core/durable-goal-checkpoint.d.ts +6 -0
  51. package/dist/core/durable-goal-checkpoint.d.ts.map +1 -0
  52. package/dist/core/durable-goal-checkpoint.js +195 -0
  53. package/dist/core/durable-goal-checkpoint.js.map +1 -0
  54. package/dist/core/durable-goal-parse.d.ts +3 -0
  55. package/dist/core/durable-goal-parse.d.ts.map +1 -0
  56. package/dist/core/durable-goal-parse.js +86 -0
  57. package/dist/core/durable-goal-parse.js.map +1 -0
  58. package/dist/core/durable-goal-reducer.d.ts +3 -0
  59. package/dist/core/durable-goal-reducer.d.ts.map +1 -0
  60. package/dist/core/durable-goal-reducer.js +175 -0
  61. package/dist/core/durable-goal-reducer.js.map +1 -0
  62. package/dist/core/durable-goal-store.d.ts +19 -0
  63. package/dist/core/durable-goal-store.d.ts.map +1 -0
  64. package/dist/core/durable-goal-store.js +126 -0
  65. package/dist/core/durable-goal-store.js.map +1 -0
  66. package/dist/core/durable-goal.d.ts +92 -0
  67. package/dist/core/durable-goal.d.ts.map +1 -0
  68. package/dist/core/durable-goal.js +62 -0
  69. package/dist/core/durable-goal.js.map +1 -0
  70. package/dist/core/extensions/builtin/goal-controller.d.ts +3 -0
  71. package/dist/core/extensions/builtin/goal-controller.d.ts.map +1 -0
  72. package/dist/core/extensions/builtin/goal-controller.js +125 -0
  73. package/dist/core/extensions/builtin/goal-controller.js.map +1 -0
  74. package/dist/core/extensions/builtin/identical-loop.d.ts +3 -0
  75. package/dist/core/extensions/builtin/identical-loop.d.ts.map +1 -0
  76. package/dist/core/extensions/builtin/identical-loop.js +31 -0
  77. package/dist/core/extensions/builtin/identical-loop.js.map +1 -0
  78. package/dist/core/extensions/builtin/prompt-preset.d.ts +3 -0
  79. package/dist/core/extensions/builtin/prompt-preset.d.ts.map +1 -0
  80. package/dist/core/extensions/builtin/prompt-preset.js +13 -0
  81. package/dist/core/extensions/builtin/prompt-preset.js.map +1 -0
  82. package/dist/core/extensions/builtin/tool-pair-repair.d.ts +3 -0
  83. package/dist/core/extensions/builtin/tool-pair-repair.d.ts.map +1 -0
  84. package/dist/core/extensions/builtin/tool-pair-repair.js +12 -0
  85. package/dist/core/extensions/builtin/tool-pair-repair.js.map +1 -0
  86. package/dist/core/extensions/types.d.ts +6 -2
  87. package/dist/core/extensions/types.d.ts.map +1 -1
  88. package/dist/core/extensions/types.js.map +1 -1
  89. package/dist/core/goal-continuation.d.ts +13 -0
  90. package/dist/core/goal-continuation.d.ts.map +1 -0
  91. package/dist/core/goal-continuation.js +10 -0
  92. package/dist/core/goal-continuation.js.map +1 -0
  93. package/dist/core/grok-harness.d.ts +1 -1
  94. package/dist/core/grok-harness.d.ts.map +1 -1
  95. package/dist/core/grok-harness.js +1 -1
  96. package/dist/core/grok-harness.js.map +1 -1
  97. package/dist/core/grok-playbook.d.ts +1 -1
  98. package/dist/core/grok-playbook.d.ts.map +1 -1
  99. package/dist/core/grok-playbook.js +1 -1
  100. package/dist/core/grok-playbook.js.map +1 -1
  101. package/dist/core/identical-loop.d.ts +15 -0
  102. package/dist/core/identical-loop.d.ts.map +1 -0
  103. package/dist/core/identical-loop.js +34 -0
  104. package/dist/core/identical-loop.js.map +1 -0
  105. package/dist/core/index.d.ts +1 -1
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js +1 -1
  108. package/dist/core/index.js.map +1 -1
  109. package/dist/core/model-prompt-policy.d.ts +11 -0
  110. package/dist/core/model-prompt-policy.d.ts.map +1 -0
  111. package/dist/core/model-prompt-policy.js +17 -0
  112. package/dist/core/model-prompt-policy.js.map +1 -0
  113. package/dist/core/model-registry.d.ts.map +1 -1
  114. package/dist/core/model-registry.js +16 -4
  115. package/dist/core/model-registry.js.map +1 -1
  116. package/dist/core/model-resolver.d.ts.map +1 -1
  117. package/dist/core/model-resolver.js +2 -2
  118. package/dist/core/model-resolver.js.map +1 -1
  119. package/dist/core/prompt-budget.d.ts +21 -0
  120. package/dist/core/prompt-budget.d.ts.map +1 -0
  121. package/dist/core/prompt-budget.js +51 -0
  122. package/dist/core/prompt-budget.js.map +1 -0
  123. package/dist/core/prompt-cache.d.ts +14 -0
  124. package/dist/core/prompt-cache.d.ts.map +1 -0
  125. package/dist/core/prompt-cache.js +16 -0
  126. package/dist/core/prompt-cache.js.map +1 -0
  127. package/dist/core/prompt-preset.d.ts +8 -0
  128. package/dist/core/prompt-preset.d.ts.map +1 -0
  129. package/dist/core/prompt-preset.js +56 -0
  130. package/dist/core/prompt-preset.js.map +1 -0
  131. package/dist/core/provider-resilience.d.ts +23 -0
  132. package/dist/core/provider-resilience.d.ts.map +1 -1
  133. package/dist/core/provider-resilience.js +34 -1
  134. package/dist/core/provider-resilience.js.map +1 -1
  135. package/dist/core/provider-retry.d.ts +29 -0
  136. package/dist/core/provider-retry.d.ts.map +1 -0
  137. package/dist/core/provider-retry.js +49 -0
  138. package/dist/core/provider-retry.js.map +1 -0
  139. package/dist/core/provider-usage.d.ts +2 -1
  140. package/dist/core/provider-usage.d.ts.map +1 -1
  141. package/dist/core/provider-usage.js +40 -6
  142. package/dist/core/provider-usage.js.map +1 -1
  143. package/dist/core/resource-loader.d.ts.map +1 -1
  144. package/dist/core/resource-loader.js +32 -0
  145. package/dist/core/resource-loader.js.map +1 -1
  146. package/dist/core/sandbox/backend.d.ts +12 -0
  147. package/dist/core/sandbox/backend.d.ts.map +1 -1
  148. package/dist/core/sandbox/backend.js +52 -42
  149. package/dist/core/sandbox/backend.js.map +1 -1
  150. package/dist/core/sandbox/policy.d.ts +2 -0
  151. package/dist/core/sandbox/policy.d.ts.map +1 -1
  152. package/dist/core/sandbox/policy.js +2 -1
  153. package/dist/core/sandbox/policy.js.map +1 -1
  154. package/dist/core/sdk.d.ts +2 -0
  155. package/dist/core/sdk.d.ts.map +1 -1
  156. package/dist/core/sdk.js +1 -0
  157. package/dist/core/sdk.js.map +1 -1
  158. package/dist/core/session-system-prompt.d.ts +28 -0
  159. package/dist/core/session-system-prompt.d.ts.map +1 -0
  160. package/dist/core/session-system-prompt.js +37 -0
  161. package/dist/core/session-system-prompt.js.map +1 -0
  162. package/dist/core/strict-record.d.ts +2 -0
  163. package/dist/core/strict-record.d.ts.map +1 -0
  164. package/dist/core/strict-record.js +9 -0
  165. package/dist/core/strict-record.js.map +1 -0
  166. package/dist/core/subagent-orchestration.d.ts.map +1 -1
  167. package/dist/core/subagent-orchestration.js +4 -2
  168. package/dist/core/subagent-orchestration.js.map +1 -1
  169. package/dist/core/tool-pair-repair.d.ts +11 -0
  170. package/dist/core/tool-pair-repair.d.ts.map +1 -0
  171. package/dist/core/tool-pair-repair.js +38 -0
  172. package/dist/core/tool-pair-repair.js.map +1 -0
  173. package/dist/core/tools/artifact-spill.d.ts +13 -0
  174. package/dist/core/tools/artifact-spill.d.ts.map +1 -0
  175. package/dist/core/tools/artifact-spill.js +26 -0
  176. package/dist/core/tools/artifact-spill.js.map +1 -0
  177. package/dist/core/tools/bash.d.ts +7 -4
  178. package/dist/core/tools/bash.d.ts.map +1 -1
  179. package/dist/core/tools/bash.js +8 -7
  180. package/dist/core/tools/bash.js.map +1 -1
  181. package/dist/core/tools/diagnostics.d.ts.map +1 -1
  182. package/dist/core/tools/diagnostics.js +8 -2
  183. package/dist/core/tools/diagnostics.js.map +1 -1
  184. package/dist/core/tools/index.d.ts +1 -1
  185. package/dist/core/tools/index.d.ts.map +1 -1
  186. package/dist/core/tools/index.js.map +1 -1
  187. package/dist/core/tools/read.d.ts +1 -0
  188. package/dist/core/tools/read.d.ts.map +1 -1
  189. package/dist/core/tools/read.js +10 -1
  190. package/dist/core/tools/read.js.map +1 -1
  191. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  192. package/dist/core/tools/tool-definition-wrapper.js +2 -0
  193. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  194. package/dist/guardrails/evidence-protocol.d.ts +10 -0
  195. package/dist/guardrails/evidence-protocol.d.ts.map +1 -0
  196. package/dist/guardrails/evidence-protocol.js +34 -0
  197. package/dist/guardrails/evidence-protocol.js.map +1 -0
  198. package/dist/guardrails/evidence-system.d.ts +3 -1
  199. package/dist/guardrails/evidence-system.d.ts.map +1 -1
  200. package/dist/guardrails/evidence-system.js +22 -14
  201. package/dist/guardrails/evidence-system.js.map +1 -1
  202. package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -1
  203. package/dist/guardrails/replay-ledger-lock-owner.js +3 -1
  204. package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -1
  205. package/dist/guardrails/replay-payload-hash.d.ts +6 -0
  206. package/dist/guardrails/replay-payload-hash.d.ts.map +1 -0
  207. package/dist/guardrails/replay-payload-hash.js +24 -0
  208. package/dist/guardrails/replay-payload-hash.js.map +1 -0
  209. package/dist/index.d.ts +20 -2
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +19 -0
  212. package/dist/index.js.map +1 -1
  213. package/dist/main.d.ts.map +1 -1
  214. package/dist/main.js +8 -0
  215. package/dist/main.js.map +1 -1
  216. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  217. package/dist/modes/interactive/theme/theme.js +14 -3
  218. package/dist/modes/interactive/theme/theme.js.map +1 -1
  219. package/dist/types/evidence.d.ts +11 -3
  220. package/dist/types/evidence.d.ts.map +1 -1
  221. package/dist/types/evidence.js.map +1 -1
  222. package/docs/adaptorch-preview-spec.md +1 -1
  223. package/docs/adaptorch-preview.md +2 -2
  224. package/docs/book-to-skill.md +79 -0
  225. package/docs/compaction.md +10 -0
  226. package/docs/containerization.md +9 -0
  227. package/docs/docs.json +18 -2
  228. package/docs/environment-variables.md +11 -4
  229. package/docs/extensions.md +14 -1
  230. package/docs/grok-harness.md +35 -12
  231. package/docs/index.md +9 -5
  232. package/docs/loadout-domains/grok-harness.md +2 -2
  233. package/docs/models.md +21 -8
  234. package/docs/provider-resilience.md +42 -55
  235. package/docs/providers.md +13 -4
  236. package/docs/run-protocol.md +104 -0
  237. package/docs/sdk.md +111 -5
  238. package/docs/security.md +22 -32
  239. package/docs/sessions.md +20 -0
  240. package/docs/settings.md +2 -0
  241. package/docs/skills.md +9 -1
  242. package/docs/usage.md +38 -16
  243. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  244. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  245. package/examples/extensions/custom-provider-gitlab-duo/index.ts +6 -1
  246. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  247. package/examples/extensions/gondolin/package-lock.json +2 -2
  248. package/examples/extensions/gondolin/package.json +1 -1
  249. package/examples/extensions/sandbox/package-lock.json +2 -2
  250. package/examples/extensions/sandbox/package.json +1 -1
  251. package/examples/extensions/with-deps/package-lock.json +2 -2
  252. package/examples/extensions/with-deps/package.json +1 -1
  253. package/npm-shrinkwrap.json +37 -15
  254. package/package.json +8 -5
  255. package/dist/core/context-budget-compressors.d.ts +0 -50
  256. package/dist/core/context-budget-compressors.d.ts.map +0 -1
  257. package/dist/core/context-budget-compressors.js +0 -166
  258. package/dist/core/context-budget-compressors.js.map +0 -1
  259. package/dist/core/extensions/loader.js.bak-sharedjiti-20260812-111246 +0 -553
@@ -0,0 +1,126 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import lockfile from "proper-lockfile";
5
+ import { DurableGoalError } from "./durable-goal.js";
6
+ import { parseDurableGoalSnapshot } from "./durable-goal-parse.js";
7
+ import { applyDurableGoalCommand } from "./durable-goal-reducer.js";
8
+ export const DURABLE_GOAL_JOURNAL_SCHEMA_VERSION = "omk.goal.journal.v1";
9
+ export class DurableGoalStore {
10
+ filePath;
11
+ constructor(filePath) {
12
+ if (filePath.trim().length === 0)
13
+ throw new DurableGoalError("invalid-input", "goal file path must not be empty");
14
+ this.filePath = filePath;
15
+ }
16
+ async readJournal() {
17
+ return this.readUnlocked();
18
+ }
19
+ async current() {
20
+ const journal = await this.readUnlocked();
21
+ return journal?.revisions.at(-1) ?? null;
22
+ }
23
+ async create(goal) {
24
+ return this.withLock(async () => {
25
+ if ((await this.readUnlocked()) !== null) {
26
+ throw new DurableGoalError("store-exists", "durable goal already exists");
27
+ }
28
+ const initial = parseDurableGoalSnapshot(goal);
29
+ if (initial.ref.revision !== 1 ||
30
+ initial.status !== "active" ||
31
+ initial.completedRounds !== 0 ||
32
+ initial.evidence.length !== 0 ||
33
+ initial.checkpoint !== undefined ||
34
+ initial.createdAt !== initial.updatedAt ||
35
+ initial.createdAt !== initial.generationStartedAt) {
36
+ throw invalidStore();
37
+ }
38
+ await this.writeUnlocked({
39
+ schemaVersion: DURABLE_GOAL_JOURNAL_SCHEMA_VERSION,
40
+ goalId: initial.ref.id,
41
+ revisions: [initial],
42
+ });
43
+ return initial;
44
+ });
45
+ }
46
+ async transition(command, now) {
47
+ return this.withLock(async () => {
48
+ const journal = await this.readUnlocked();
49
+ const current = journal?.revisions.at(-1);
50
+ if (!journal || !current)
51
+ throw new DurableGoalError("store-missing", "durable goal does not exist");
52
+ const next = applyDurableGoalCommand(current, command, now);
53
+ await this.writeUnlocked({ ...journal, revisions: [...journal.revisions, next] });
54
+ return next;
55
+ });
56
+ }
57
+ async withLock(operation) {
58
+ const directory = dirname(this.filePath);
59
+ await mkdir(directory, { recursive: true });
60
+ const release = await lockfile.lock(this.filePath, {
61
+ realpath: false,
62
+ retries: { retries: 5, factor: 1, minTimeout: 5, maxTimeout: 25 },
63
+ });
64
+ try {
65
+ return await operation();
66
+ }
67
+ finally {
68
+ await release();
69
+ }
70
+ }
71
+ async readUnlocked() {
72
+ let raw;
73
+ try {
74
+ raw = await readFile(this.filePath, "utf8");
75
+ }
76
+ catch (error) {
77
+ if (isFileSystemError(error, "ENOENT"))
78
+ return null;
79
+ throw error;
80
+ }
81
+ try {
82
+ return parseJournal(JSON.parse(raw));
83
+ }
84
+ catch (error) {
85
+ if (error instanceof DurableGoalError && error.code === "invalid-store")
86
+ throw error;
87
+ throw new DurableGoalError("invalid-store", "durable goal journal is invalid");
88
+ }
89
+ }
90
+ async writeUnlocked(journal) {
91
+ const tempPath = join(dirname(this.filePath), `.goal-${randomUUID()}.tmp`);
92
+ try {
93
+ await writeFile(tempPath, `${JSON.stringify(journal, null, 2)}\n`, "utf8");
94
+ await rename(tempPath, this.filePath);
95
+ }
96
+ catch (error) {
97
+ await rm(tempPath, { force: true });
98
+ throw error;
99
+ }
100
+ }
101
+ }
102
+ function parseJournal(value) {
103
+ if (!isRecord(value) || value.schemaVersion !== DURABLE_GOAL_JOURNAL_SCHEMA_VERSION)
104
+ throw invalidStore();
105
+ if (typeof value.goalId !== "string" || value.goalId.length === 0 || !Array.isArray(value.revisions)) {
106
+ throw invalidStore();
107
+ }
108
+ const revisions = value.revisions.map(parseDurableGoalSnapshot);
109
+ if (revisions.length === 0)
110
+ throw invalidStore();
111
+ for (const [index, revision] of revisions.entries()) {
112
+ if (revision.ref.id !== value.goalId || revision.ref.revision !== index + 1)
113
+ throw invalidStore();
114
+ }
115
+ return { schemaVersion: DURABLE_GOAL_JOURNAL_SCHEMA_VERSION, goalId: value.goalId, revisions };
116
+ }
117
+ function isRecord(value) {
118
+ return typeof value === "object" && value !== null && !Array.isArray(value);
119
+ }
120
+ function isFileSystemError(error, code) {
121
+ return error instanceof Error && "code" in error && error.code === code;
122
+ }
123
+ function invalidStore() {
124
+ return new DurableGoalError("invalid-store", "durable goal journal is invalid");
125
+ }
126
+ //# sourceMappingURL=durable-goal-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-goal-store.js","sourceRoot":"","sources":["../../src/core/durable-goal-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { type DurableGoalCommand, DurableGoalError, type DurableGoalSnapshot } from \"./durable-goal.ts\";\nimport { parseDurableGoalSnapshot } from \"./durable-goal-parse.ts\";\nimport { applyDurableGoalCommand } from \"./durable-goal-reducer.ts\";\n\nexport const DURABLE_GOAL_JOURNAL_SCHEMA_VERSION = \"omk.goal.journal.v1\" as const;\n\nexport interface DurableGoalJournal {\n\treadonly schemaVersion: typeof DURABLE_GOAL_JOURNAL_SCHEMA_VERSION;\n\treadonly goalId: string;\n\treadonly revisions: readonly DurableGoalSnapshot[];\n}\n\nexport class DurableGoalStore {\n\treadonly filePath: string;\n\n\tconstructor(filePath: string) {\n\t\tif (filePath.trim().length === 0) throw new DurableGoalError(\"invalid-input\", \"goal file path must not be empty\");\n\t\tthis.filePath = filePath;\n\t}\n\n\tasync readJournal(): Promise<DurableGoalJournal | null> {\n\t\treturn this.readUnlocked();\n\t}\n\n\tasync current(): Promise<DurableGoalSnapshot | null> {\n\t\tconst journal = await this.readUnlocked();\n\t\treturn journal?.revisions.at(-1) ?? null;\n\t}\n\n\tasync create(goal: DurableGoalSnapshot): Promise<DurableGoalSnapshot> {\n\t\treturn this.withLock(async () => {\n\t\t\tif ((await this.readUnlocked()) !== null) {\n\t\t\t\tthrow new DurableGoalError(\"store-exists\", \"durable goal already exists\");\n\t\t\t}\n\t\t\tconst initial = parseDurableGoalSnapshot(goal);\n\t\t\tif (\n\t\t\t\tinitial.ref.revision !== 1 ||\n\t\t\t\tinitial.status !== \"active\" ||\n\t\t\t\tinitial.completedRounds !== 0 ||\n\t\t\t\tinitial.evidence.length !== 0 ||\n\t\t\t\tinitial.checkpoint !== undefined ||\n\t\t\t\tinitial.createdAt !== initial.updatedAt ||\n\t\t\t\tinitial.createdAt !== initial.generationStartedAt\n\t\t\t) {\n\t\t\t\tthrow invalidStore();\n\t\t\t}\n\t\t\tawait this.writeUnlocked({\n\t\t\t\tschemaVersion: DURABLE_GOAL_JOURNAL_SCHEMA_VERSION,\n\t\t\t\tgoalId: initial.ref.id,\n\t\t\t\trevisions: [initial],\n\t\t\t});\n\t\t\treturn initial;\n\t\t});\n\t}\n\n\tasync transition(command: DurableGoalCommand, now: string): Promise<DurableGoalSnapshot> {\n\t\treturn this.withLock(async () => {\n\t\t\tconst journal = await this.readUnlocked();\n\t\t\tconst current = journal?.revisions.at(-1);\n\t\t\tif (!journal || !current) throw new DurableGoalError(\"store-missing\", \"durable goal does not exist\");\n\t\t\tconst next = applyDurableGoalCommand(current, command, now);\n\t\t\tawait this.writeUnlocked({ ...journal, revisions: [...journal.revisions, next] });\n\t\t\treturn next;\n\t\t});\n\t}\n\n\tprivate async withLock<T>(operation: () => Promise<T>): Promise<T> {\n\t\tconst directory = dirname(this.filePath);\n\t\tawait mkdir(directory, { recursive: true });\n\t\tconst release = await lockfile.lock(this.filePath, {\n\t\t\trealpath: false,\n\t\t\tretries: { retries: 5, factor: 1, minTimeout: 5, maxTimeout: 25 },\n\t\t});\n\t\ttry {\n\t\t\treturn await operation();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t}\n\n\tprivate async readUnlocked(): Promise<DurableGoalJournal | null> {\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = await readFile(this.filePath, \"utf8\");\n\t\t} catch (error) {\n\t\t\tif (isFileSystemError(error, \"ENOENT\")) return null;\n\t\t\tthrow error;\n\t\t}\n\t\ttry {\n\t\t\treturn parseJournal(JSON.parse(raw));\n\t\t} catch (error) {\n\t\t\tif (error instanceof DurableGoalError && error.code === \"invalid-store\") throw error;\n\t\t\tthrow new DurableGoalError(\"invalid-store\", \"durable goal journal is invalid\");\n\t\t}\n\t}\n\n\tprivate async writeUnlocked(journal: DurableGoalJournal): Promise<void> {\n\t\tconst tempPath = join(dirname(this.filePath), `.goal-${randomUUID()}.tmp`);\n\t\ttry {\n\t\t\tawait writeFile(tempPath, `${JSON.stringify(journal, null, 2)}\\n`, \"utf8\");\n\t\t\tawait rename(tempPath, this.filePath);\n\t\t} catch (error) {\n\t\t\tawait rm(tempPath, { force: true });\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nfunction parseJournal(value: unknown): DurableGoalJournal {\n\tif (!isRecord(value) || value.schemaVersion !== DURABLE_GOAL_JOURNAL_SCHEMA_VERSION) throw invalidStore();\n\tif (typeof value.goalId !== \"string\" || value.goalId.length === 0 || !Array.isArray(value.revisions)) {\n\t\tthrow invalidStore();\n\t}\n\tconst revisions = value.revisions.map(parseDurableGoalSnapshot);\n\tif (revisions.length === 0) throw invalidStore();\n\tfor (const [index, revision] of revisions.entries()) {\n\t\tif (revision.ref.id !== value.goalId || revision.ref.revision !== index + 1) throw invalidStore();\n\t}\n\treturn { schemaVersion: DURABLE_GOAL_JOURNAL_SCHEMA_VERSION, goalId: value.goalId, revisions };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isFileSystemError(error: unknown, code: string): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === code;\n}\n\nfunction invalidStore(): DurableGoalError {\n\treturn new DurableGoalError(\"invalid-store\", \"durable goal journal is invalid\");\n}\n"]}
@@ -0,0 +1,92 @@
1
+ export declare const DURABLE_GOAL_SCHEMA_VERSION: "omk.goal.v1";
2
+ export declare const DURABLE_GOAL_STATUS_VALUES: readonly ["active", "paused", "blocked", "completed", "cleared"];
3
+ export type DurableGoalStatus = (typeof DURABLE_GOAL_STATUS_VALUES)[number];
4
+ export type DurableGoalErrorCode = "evidence-required" | "illegal-transition" | "invalid-input" | "invalid-store" | "round-limit" | "stale-ref" | "store-exists" | "store-missing";
5
+ export interface DurableGoalRef {
6
+ readonly id: string;
7
+ readonly revision: number;
8
+ }
9
+ export interface DurableGoalEvidence {
10
+ readonly id: string;
11
+ readonly digest: string;
12
+ readonly capturedAt: string;
13
+ readonly goalGeneration: string;
14
+ }
15
+ export declare const DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION: "omk.goal.checkpoint.v1";
16
+ export interface DurableGoalCheckpointInput {
17
+ readonly core: readonly string[];
18
+ readonly verifiedEvidenceIds: readonly string[];
19
+ readonly open: readonly string[];
20
+ readonly next: string;
21
+ readonly capturedAt: string;
22
+ }
23
+ export interface DurableGoalCheckpoint extends DurableGoalCheckpointInput {
24
+ readonly schemaVersion: typeof DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION;
25
+ readonly goalGeneration: string;
26
+ readonly digest: string;
27
+ }
28
+ export interface DurableGoalSnapshot {
29
+ readonly schemaVersion: typeof DURABLE_GOAL_SCHEMA_VERSION;
30
+ readonly ref: DurableGoalRef;
31
+ readonly objective: string;
32
+ readonly status: DurableGoalStatus;
33
+ readonly maxRounds: number;
34
+ readonly completedRounds: number;
35
+ readonly evidence: readonly DurableGoalEvidence[];
36
+ readonly createdAt: string;
37
+ readonly generationStartedAt: string;
38
+ readonly updatedAt: string;
39
+ readonly checkpoint?: DurableGoalCheckpoint;
40
+ readonly blockedReason?: string;
41
+ readonly terminalAt?: string;
42
+ }
43
+ export type DurableGoalCommand = {
44
+ readonly kind: "edit";
45
+ readonly ref: DurableGoalRef;
46
+ readonly objective?: string;
47
+ readonly maxRounds?: number;
48
+ } | {
49
+ readonly kind: "pause";
50
+ readonly ref: DurableGoalRef;
51
+ } | {
52
+ readonly kind: "resume";
53
+ readonly ref: DurableGoalRef;
54
+ } | {
55
+ readonly kind: "block";
56
+ readonly ref: DurableGoalRef;
57
+ readonly reason: string;
58
+ } | {
59
+ readonly kind: "advance-round";
60
+ readonly ref: DurableGoalRef;
61
+ } | {
62
+ readonly kind: "record-checkpoint";
63
+ readonly ref: DurableGoalRef;
64
+ readonly checkpoint: DurableGoalCheckpointInput;
65
+ } | {
66
+ readonly kind: "attach-evidence";
67
+ readonly ref: DurableGoalRef;
68
+ readonly evidence: {
69
+ readonly id: string;
70
+ readonly digest: string;
71
+ readonly capturedAt: string;
72
+ };
73
+ } | {
74
+ readonly kind: "complete";
75
+ readonly ref: DurableGoalRef;
76
+ } | {
77
+ readonly kind: "clear";
78
+ readonly ref: DurableGoalRef;
79
+ };
80
+ export declare class DurableGoalError extends Error {
81
+ readonly code: DurableGoalErrorCode;
82
+ constructor(code: DurableGoalErrorCode, message: string);
83
+ }
84
+ export declare function createDurableGoal(input: {
85
+ readonly id: string;
86
+ readonly objective: string;
87
+ readonly maxRounds: number;
88
+ readonly now: string;
89
+ }): DurableGoalSnapshot;
90
+ export declare function computeDurableGoalGeneration(goal: DurableGoalSnapshot): string;
91
+ export declare function freshDurableGoalEvidence(goal: DurableGoalSnapshot): readonly DurableGoalEvidence[];
92
+ //# sourceMappingURL=durable-goal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-goal.d.ts","sourceRoot":"","sources":["../../src/core/durable-goal.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\n\nexport const DURABLE_GOAL_SCHEMA_VERSION = \"omk.goal.v1\" as const;\nexport const DURABLE_GOAL_STATUS_VALUES = [\"active\", \"paused\", \"blocked\", \"completed\", \"cleared\"] as const;\n\nexport type DurableGoalStatus = (typeof DURABLE_GOAL_STATUS_VALUES)[number];\nexport type DurableGoalErrorCode =\n\t| \"evidence-required\"\n\t| \"illegal-transition\"\n\t| \"invalid-input\"\n\t| \"invalid-store\"\n\t| \"round-limit\"\n\t| \"stale-ref\"\n\t| \"store-exists\"\n\t| \"store-missing\";\n\nexport interface DurableGoalRef {\n\treadonly id: string;\n\treadonly revision: number;\n}\n\nexport interface DurableGoalEvidence {\n\treadonly id: string;\n\treadonly digest: string;\n\treadonly capturedAt: string;\n\treadonly goalGeneration: string;\n}\n\nexport const DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION = \"omk.goal.checkpoint.v1\" as const;\n\nexport interface DurableGoalCheckpointInput {\n\treadonly core: readonly string[];\n\treadonly verifiedEvidenceIds: readonly string[];\n\treadonly open: readonly string[];\n\treadonly next: string;\n\treadonly capturedAt: string;\n}\n\nexport interface DurableGoalCheckpoint extends DurableGoalCheckpointInput {\n\treadonly schemaVersion: typeof DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION;\n\treadonly goalGeneration: string;\n\treadonly digest: string;\n}\n\nexport interface DurableGoalSnapshot {\n\treadonly schemaVersion: typeof DURABLE_GOAL_SCHEMA_VERSION;\n\treadonly ref: DurableGoalRef;\n\treadonly objective: string;\n\treadonly status: DurableGoalStatus;\n\treadonly maxRounds: number;\n\treadonly completedRounds: number;\n\treadonly evidence: readonly DurableGoalEvidence[];\n\treadonly createdAt: string;\n\treadonly generationStartedAt: string;\n\treadonly updatedAt: string;\n\treadonly checkpoint?: DurableGoalCheckpoint;\n\treadonly blockedReason?: string;\n\treadonly terminalAt?: string;\n}\n\nexport type DurableGoalCommand =\n\t| { readonly kind: \"edit\"; readonly ref: DurableGoalRef; readonly objective?: string; readonly maxRounds?: number }\n\t| { readonly kind: \"pause\"; readonly ref: DurableGoalRef }\n\t| { readonly kind: \"resume\"; readonly ref: DurableGoalRef }\n\t| { readonly kind: \"block\"; readonly ref: DurableGoalRef; readonly reason: string }\n\t| { readonly kind: \"advance-round\"; readonly ref: DurableGoalRef }\n\t| {\n\t\t\treadonly kind: \"record-checkpoint\";\n\t\t\treadonly ref: DurableGoalRef;\n\t\t\treadonly checkpoint: DurableGoalCheckpointInput;\n\t }\n\t| {\n\t\t\treadonly kind: \"attach-evidence\";\n\t\t\treadonly ref: DurableGoalRef;\n\t\t\treadonly evidence: { readonly id: string; readonly digest: string; readonly capturedAt: string };\n\t }\n\t| { readonly kind: \"complete\"; readonly ref: DurableGoalRef }\n\t| { readonly kind: \"clear\"; readonly ref: DurableGoalRef };\n\nexport class DurableGoalError extends Error {\n\treadonly code: DurableGoalErrorCode;\n\n\tconstructor(code: DurableGoalErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"DurableGoalError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport function createDurableGoal(input: {\n\treadonly id: string;\n\treadonly objective: string;\n\treadonly maxRounds: number;\n\treadonly now: string;\n}): DurableGoalSnapshot {\n\treturn {\n\t\tschemaVersion: DURABLE_GOAL_SCHEMA_VERSION,\n\t\tref: { id: requireText(input.id, \"goal id\"), revision: 1 },\n\t\tobjective: requireText(input.objective, \"goal objective\"),\n\t\tstatus: \"active\",\n\t\tmaxRounds: requirePositiveInteger(input.maxRounds, \"maxRounds\"),\n\t\tcompletedRounds: 0,\n\t\tevidence: [],\n\t\tcreatedAt: requireTimestamp(input.now, \"now\"),\n\t\tgenerationStartedAt: input.now,\n\t\tupdatedAt: input.now,\n\t};\n}\n\nexport function computeDurableGoalGeneration(goal: DurableGoalSnapshot): string {\n\treturn createHash(\"sha256\")\n\t\t.update(\n\t\t\tJSON.stringify([goal.ref.id, goal.objective, goal.maxRounds, goal.completedRounds, goal.generationStartedAt]),\n\t\t)\n\t\t.digest(\"hex\");\n}\n\nexport function freshDurableGoalEvidence(goal: DurableGoalSnapshot): readonly DurableGoalEvidence[] {\n\tconst generation = computeDurableGoalGeneration(goal);\n\tconst legacyInitialGeneration =\n\t\tgoal.generationStartedAt === goal.createdAt ? computeLegacyDurableGoalGeneration(goal) : undefined;\n\treturn goal.evidence.filter(\n\t\t(evidence) =>\n\t\t\t(evidence.goalGeneration === generation || evidence.goalGeneration === legacyInitialGeneration) &&\n\t\t\tDate.parse(evidence.capturedAt) >= Date.parse(goal.generationStartedAt) &&\n\t\t\tDate.parse(evidence.capturedAt) <= Date.parse(goal.updatedAt),\n\t);\n}\n\nfunction computeLegacyDurableGoalGeneration(goal: DurableGoalSnapshot): string {\n\treturn createHash(\"sha256\")\n\t\t.update(JSON.stringify([goal.ref.id, goal.objective, goal.maxRounds, goal.completedRounds]))\n\t\t.digest(\"hex\");\n}\n\nfunction requireText(value: string, label: string): string {\n\tconst normalized = value.trim();\n\tif (normalized.length === 0) throw new DurableGoalError(\"invalid-input\", `${label} must not be empty`);\n\treturn normalized;\n}\n\nfunction requirePositiveInteger(value: number, label: string): number {\n\tif (!Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new DurableGoalError(\"invalid-input\", `${label} must be a positive integer`);\n\t}\n\treturn value;\n}\n\nfunction requireTimestamp(value: string, label: string): string {\n\tif (value.length === 0 || Number.isNaN(Date.parse(value))) {\n\t\tthrow new DurableGoalError(\"invalid-input\", `${label} must be an ISO timestamp`);\n\t}\n\treturn value;\n}\n"]}
@@ -0,0 +1,62 @@
1
+ import { createHash } from "node:crypto";
2
+ export const DURABLE_GOAL_SCHEMA_VERSION = "omk.goal.v1";
3
+ export const DURABLE_GOAL_STATUS_VALUES = ["active", "paused", "blocked", "completed", "cleared"];
4
+ export const DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION = "omk.goal.checkpoint.v1";
5
+ export class DurableGoalError extends Error {
6
+ code;
7
+ constructor(code, message) {
8
+ super(message);
9
+ this.name = "DurableGoalError";
10
+ this.code = code;
11
+ }
12
+ }
13
+ export function createDurableGoal(input) {
14
+ return {
15
+ schemaVersion: DURABLE_GOAL_SCHEMA_VERSION,
16
+ ref: { id: requireText(input.id, "goal id"), revision: 1 },
17
+ objective: requireText(input.objective, "goal objective"),
18
+ status: "active",
19
+ maxRounds: requirePositiveInteger(input.maxRounds, "maxRounds"),
20
+ completedRounds: 0,
21
+ evidence: [],
22
+ createdAt: requireTimestamp(input.now, "now"),
23
+ generationStartedAt: input.now,
24
+ updatedAt: input.now,
25
+ };
26
+ }
27
+ export function computeDurableGoalGeneration(goal) {
28
+ return createHash("sha256")
29
+ .update(JSON.stringify([goal.ref.id, goal.objective, goal.maxRounds, goal.completedRounds, goal.generationStartedAt]))
30
+ .digest("hex");
31
+ }
32
+ export function freshDurableGoalEvidence(goal) {
33
+ const generation = computeDurableGoalGeneration(goal);
34
+ const legacyInitialGeneration = goal.generationStartedAt === goal.createdAt ? computeLegacyDurableGoalGeneration(goal) : undefined;
35
+ return goal.evidence.filter((evidence) => (evidence.goalGeneration === generation || evidence.goalGeneration === legacyInitialGeneration) &&
36
+ Date.parse(evidence.capturedAt) >= Date.parse(goal.generationStartedAt) &&
37
+ Date.parse(evidence.capturedAt) <= Date.parse(goal.updatedAt));
38
+ }
39
+ function computeLegacyDurableGoalGeneration(goal) {
40
+ return createHash("sha256")
41
+ .update(JSON.stringify([goal.ref.id, goal.objective, goal.maxRounds, goal.completedRounds]))
42
+ .digest("hex");
43
+ }
44
+ function requireText(value, label) {
45
+ const normalized = value.trim();
46
+ if (normalized.length === 0)
47
+ throw new DurableGoalError("invalid-input", `${label} must not be empty`);
48
+ return normalized;
49
+ }
50
+ function requirePositiveInteger(value, label) {
51
+ if (!Number.isSafeInteger(value) || value < 1) {
52
+ throw new DurableGoalError("invalid-input", `${label} must be a positive integer`);
53
+ }
54
+ return value;
55
+ }
56
+ function requireTimestamp(value, label) {
57
+ if (value.length === 0 || Number.isNaN(Date.parse(value))) {
58
+ throw new DurableGoalError("invalid-input", `${label} must be an ISO timestamp`);
59
+ }
60
+ return value;
61
+ }
62
+ //# sourceMappingURL=durable-goal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-goal.js","sourceRoot":"","sources":["../../src/core/durable-goal.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\n\nexport const DURABLE_GOAL_SCHEMA_VERSION = \"omk.goal.v1\" as const;\nexport const DURABLE_GOAL_STATUS_VALUES = [\"active\", \"paused\", \"blocked\", \"completed\", \"cleared\"] as const;\n\nexport type DurableGoalStatus = (typeof DURABLE_GOAL_STATUS_VALUES)[number];\nexport type DurableGoalErrorCode =\n\t| \"evidence-required\"\n\t| \"illegal-transition\"\n\t| \"invalid-input\"\n\t| \"invalid-store\"\n\t| \"round-limit\"\n\t| \"stale-ref\"\n\t| \"store-exists\"\n\t| \"store-missing\";\n\nexport interface DurableGoalRef {\n\treadonly id: string;\n\treadonly revision: number;\n}\n\nexport interface DurableGoalEvidence {\n\treadonly id: string;\n\treadonly digest: string;\n\treadonly capturedAt: string;\n\treadonly goalGeneration: string;\n}\n\nexport const DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION = \"omk.goal.checkpoint.v1\" as const;\n\nexport interface DurableGoalCheckpointInput {\n\treadonly core: readonly string[];\n\treadonly verifiedEvidenceIds: readonly string[];\n\treadonly open: readonly string[];\n\treadonly next: string;\n\treadonly capturedAt: string;\n}\n\nexport interface DurableGoalCheckpoint extends DurableGoalCheckpointInput {\n\treadonly schemaVersion: typeof DURABLE_GOAL_CHECKPOINT_SCHEMA_VERSION;\n\treadonly goalGeneration: string;\n\treadonly digest: string;\n}\n\nexport interface DurableGoalSnapshot {\n\treadonly schemaVersion: typeof DURABLE_GOAL_SCHEMA_VERSION;\n\treadonly ref: DurableGoalRef;\n\treadonly objective: string;\n\treadonly status: DurableGoalStatus;\n\treadonly maxRounds: number;\n\treadonly completedRounds: number;\n\treadonly evidence: readonly DurableGoalEvidence[];\n\treadonly createdAt: string;\n\treadonly generationStartedAt: string;\n\treadonly updatedAt: string;\n\treadonly checkpoint?: DurableGoalCheckpoint;\n\treadonly blockedReason?: string;\n\treadonly terminalAt?: string;\n}\n\nexport type DurableGoalCommand =\n\t| { readonly kind: \"edit\"; readonly ref: DurableGoalRef; readonly objective?: string; readonly maxRounds?: number }\n\t| { readonly kind: \"pause\"; readonly ref: DurableGoalRef }\n\t| { readonly kind: \"resume\"; readonly ref: DurableGoalRef }\n\t| { readonly kind: \"block\"; readonly ref: DurableGoalRef; readonly reason: string }\n\t| { readonly kind: \"advance-round\"; readonly ref: DurableGoalRef }\n\t| {\n\t\t\treadonly kind: \"record-checkpoint\";\n\t\t\treadonly ref: DurableGoalRef;\n\t\t\treadonly checkpoint: DurableGoalCheckpointInput;\n\t }\n\t| {\n\t\t\treadonly kind: \"attach-evidence\";\n\t\t\treadonly ref: DurableGoalRef;\n\t\t\treadonly evidence: { readonly id: string; readonly digest: string; readonly capturedAt: string };\n\t }\n\t| { readonly kind: \"complete\"; readonly ref: DurableGoalRef }\n\t| { readonly kind: \"clear\"; readonly ref: DurableGoalRef };\n\nexport class DurableGoalError extends Error {\n\treadonly code: DurableGoalErrorCode;\n\n\tconstructor(code: DurableGoalErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"DurableGoalError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport function createDurableGoal(input: {\n\treadonly id: string;\n\treadonly objective: string;\n\treadonly maxRounds: number;\n\treadonly now: string;\n}): DurableGoalSnapshot {\n\treturn {\n\t\tschemaVersion: DURABLE_GOAL_SCHEMA_VERSION,\n\t\tref: { id: requireText(input.id, \"goal id\"), revision: 1 },\n\t\tobjective: requireText(input.objective, \"goal objective\"),\n\t\tstatus: \"active\",\n\t\tmaxRounds: requirePositiveInteger(input.maxRounds, \"maxRounds\"),\n\t\tcompletedRounds: 0,\n\t\tevidence: [],\n\t\tcreatedAt: requireTimestamp(input.now, \"now\"),\n\t\tgenerationStartedAt: input.now,\n\t\tupdatedAt: input.now,\n\t};\n}\n\nexport function computeDurableGoalGeneration(goal: DurableGoalSnapshot): string {\n\treturn createHash(\"sha256\")\n\t\t.update(\n\t\t\tJSON.stringify([goal.ref.id, goal.objective, goal.maxRounds, goal.completedRounds, goal.generationStartedAt]),\n\t\t)\n\t\t.digest(\"hex\");\n}\n\nexport function freshDurableGoalEvidence(goal: DurableGoalSnapshot): readonly DurableGoalEvidence[] {\n\tconst generation = computeDurableGoalGeneration(goal);\n\tconst legacyInitialGeneration =\n\t\tgoal.generationStartedAt === goal.createdAt ? computeLegacyDurableGoalGeneration(goal) : undefined;\n\treturn goal.evidence.filter(\n\t\t(evidence) =>\n\t\t\t(evidence.goalGeneration === generation || evidence.goalGeneration === legacyInitialGeneration) &&\n\t\t\tDate.parse(evidence.capturedAt) >= Date.parse(goal.generationStartedAt) &&\n\t\t\tDate.parse(evidence.capturedAt) <= Date.parse(goal.updatedAt),\n\t);\n}\n\nfunction computeLegacyDurableGoalGeneration(goal: DurableGoalSnapshot): string {\n\treturn createHash(\"sha256\")\n\t\t.update(JSON.stringify([goal.ref.id, goal.objective, goal.maxRounds, goal.completedRounds]))\n\t\t.digest(\"hex\");\n}\n\nfunction requireText(value: string, label: string): string {\n\tconst normalized = value.trim();\n\tif (normalized.length === 0) throw new DurableGoalError(\"invalid-input\", `${label} must not be empty`);\n\treturn normalized;\n}\n\nfunction requirePositiveInteger(value: number, label: string): number {\n\tif (!Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new DurableGoalError(\"invalid-input\", `${label} must be a positive integer`);\n\t}\n\treturn value;\n}\n\nfunction requireTimestamp(value: string, label: string): string {\n\tif (value.length === 0 || Number.isNaN(Date.parse(value))) {\n\t\tthrow new DurableGoalError(\"invalid-input\", `${label} must be an ISO timestamp`);\n\t}\n\treturn value;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../types.ts";
2
+ export default function goalController(omk: ExtensionAPI): void;
3
+ //# sourceMappingURL=goal-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal-controller.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/goal-controller.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA8BhD,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CA+F9D","sourcesContent":["import { rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { createDurableGoal, DurableGoalError, type DurableGoalSnapshot } from \"../../durable-goal.ts\";\nimport { formatDurableGoalCheckpoint, parseDurableGoalCheckpointCommand } from \"../../durable-goal-checkpoint.ts\";\nimport { DurableGoalStore } from \"../../durable-goal-store.ts\";\nimport { decideGoalContinuation } from \"../../goal-continuation.ts\";\nimport type { ExtensionAPI } from \"../types.ts\";\n\nfunction goalPath(cwd: string): string {\n\treturn join(cwd, \".omk\", \"goals\", \"current.json\");\n}\n\nfunction renderGoal(goal: DurableGoalSnapshot): string {\n\treturn `goal ${goal.ref.id} r${goal.ref.revision} ${goal.status} ${goal.completedRounds}/${goal.maxRounds}\\n${formatDurableGoalCheckpoint(goal)}`;\n}\n\nfunction checkpointPayload(text: string): string | null {\n\tif (text === \"checkpoint\") return \"\";\n\treturn text.startsWith(\"checkpoint \") ? text.slice(\"checkpoint \".length).trim() : null;\n}\n\nfunction unavailableWorkspaceCode(error: unknown): \"ENODEV\" | \"ESTALE\" | \"ENOTCONN\" | undefined {\n\tif (typeof error !== \"object\" || error === null || !(\"code\" in error)) return undefined;\n\tconst code = error.code;\n\treturn code === \"ENODEV\" || code === \"ESTALE\" || code === \"ENOTCONN\" ? code : undefined;\n}\n\nfunction continuationSeam(goal: DurableGoalSnapshot, trustedDigests: ReadonlySet<string>): string {\n\tconst checkpoint = goal.checkpoint;\n\tif (!checkpoint) return \"\";\n\tif (trustedDigests.has(checkpoint.digest)) {\n\t\treturn `\\n\\nSeam checkpoint (explicit user continuity context, not current-round proof):\\n${formatDurableGoalCheckpoint(goal)}`;\n\t}\n\treturn `\\n\\nAn untrusted workspace checkpoint exists at digest ${checkpoint.digest}; its prose was not loaded as user authority.`;\n}\n\nexport default function goalController(omk: ExtensionAPI): void {\n\tconst trustedCheckpointDigests = new Set<string>();\n\tomk.registerCommand(\"goal\", {\n\t\tdescription: \"Show, set, checkpoint, pause, resume, complete, or clear the durable session goal\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst store = new DurableGoalStore(goalPath(ctx.cwd));\n\t\t\tconst text = args.trim();\n\t\t\ttry {\n\t\t\t\tif (text.length === 0) {\n\t\t\t\t\tconst current = await store.current();\n\t\t\t\t\tctx.ui.notify(current ? renderGoal(current) : \"no durable goal\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst existing = await store.current();\n\t\t\t\tif (text === \"pause\" || text === \"resume\" || text === \"complete\" || text === \"clear\") {\n\t\t\t\t\tif (!existing) throw new DurableGoalError(\"store-missing\", \"durable goal does not exist\");\n\t\t\t\t\tconst next = await store.transition({ kind: text, ref: existing.ref }, new Date().toISOString());\n\t\t\t\t\tif (text === \"clear\") trustedCheckpointDigests.clear();\n\t\t\t\t\tctx.ui.notify(renderGoal(next), \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst payload = checkpointPayload(text);\n\t\t\t\tif (payload !== null) {\n\t\t\t\t\tif (!existing) throw new DurableGoalError(\"store-missing\", \"durable goal does not exist\");\n\t\t\t\t\tif (payload.length === 0) {\n\t\t\t\t\t\tthrow new DurableGoalError(\n\t\t\t\t\t\t\t\"invalid-input\",\n\t\t\t\t\t\t\t'usage: /goal checkpoint {\"core\":[],\"verified\":[],\"open\":[],\"next\":\"...\"}',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst now = new Date().toISOString();\n\t\t\t\t\tconst next = await store.transition(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: \"record-checkpoint\",\n\t\t\t\t\t\t\tref: existing.ref,\n\t\t\t\t\t\t\tcheckpoint: parseDurableGoalCheckpointCommand(payload, now),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnow,\n\t\t\t\t\t);\n\t\t\t\t\tconst checkpoint = next.checkpoint;\n\t\t\t\t\tif (!checkpoint) throw new DurableGoalError(\"invalid-store\", \"durable goal journal is invalid\");\n\t\t\t\t\tomk.appendEntry(\"goal_checkpoint\", {\n\t\t\t\t\t\tgoalId: next.ref.id,\n\t\t\t\t\t\tgoalRevision: next.ref.revision,\n\t\t\t\t\t\tcheckpointDigest: checkpoint.digest,\n\t\t\t\t\t});\n\t\t\t\t\ttrustedCheckpointDigests.add(checkpoint.digest);\n\t\t\t\t\tctx.ui.notify(renderGoal(next), \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (existing && existing.status !== \"cleared\" && existing.status !== \"completed\") {\n\t\t\t\t\tconst next = await store.transition(\n\t\t\t\t\t\t{ kind: \"edit\", ref: existing.ref, objective: text },\n\t\t\t\t\t\tnew Date().toISOString(),\n\t\t\t\t\t);\n\t\t\t\t\tctx.ui.notify(renderGoal(next), \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (existing) await rm(goalPath(ctx.cwd), { force: true });\n\t\t\t\tconst created = await store.create(\n\t\t\t\t\tcreateDurableGoal({ id: \"session\", objective: text, maxRounds: 8, now: new Date().toISOString() }),\n\t\t\t\t);\n\t\t\t\tctx.ui.notify(renderGoal(created), \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof DurableGoalError ? error.message : \"goal command failed\";\n\t\t\t\tctx.ui.notify(message, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tomk.on(\"agent_end\", async (_event, ctx) => {\n\t\tconst store = new DurableGoalStore(goalPath(ctx.cwd));\n\t\tlet current: DurableGoalSnapshot | null;\n\t\ttry {\n\t\t\tcurrent = await store.current();\n\t\t} catch (error) {\n\t\t\tconst code = unavailableWorkspaceCode(error);\n\t\t\tif (!code) throw error;\n\t\t\tomk.appendEntry(\"goal_workspace_unavailable\", { code });\n\t\t\treturn;\n\t\t}\n\t\tif (!current) return;\n\t\tconst decision = decideGoalContinuation({\n\t\t\tstatus: current.status,\n\t\t\tcompletedRounds: current.completedRounds,\n\t\t\tmaxRounds: current.maxRounds,\n\t\t\thasQueuedMessages: ctx.hasPendingMessages(),\n\t\t});\n\t\tif (decision.reason === \"queued\" || !decision.continue) return;\n\t\tconst advanced = await store.transition({ kind: \"advance-round\", ref: current.ref }, new Date().toISOString());\n\t\tconst seam = continuationSeam(advanced, trustedCheckpointDigests);\n\t\tomk.sendUserMessage(\n\t\t\t`Continue the active goal (${advanced.completedRounds}/${advanced.maxRounds}): ${advanced.objective}${seam}`,\n\t\t);\n\t});\n}\n"]}
@@ -0,0 +1,125 @@
1
+ import { rm } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { createDurableGoal, DurableGoalError } from "../../durable-goal.js";
4
+ import { formatDurableGoalCheckpoint, parseDurableGoalCheckpointCommand } from "../../durable-goal-checkpoint.js";
5
+ import { DurableGoalStore } from "../../durable-goal-store.js";
6
+ import { decideGoalContinuation } from "../../goal-continuation.js";
7
+ function goalPath(cwd) {
8
+ return join(cwd, ".omk", "goals", "current.json");
9
+ }
10
+ function renderGoal(goal) {
11
+ return `goal ${goal.ref.id} r${goal.ref.revision} ${goal.status} ${goal.completedRounds}/${goal.maxRounds}\n${formatDurableGoalCheckpoint(goal)}`;
12
+ }
13
+ function checkpointPayload(text) {
14
+ if (text === "checkpoint")
15
+ return "";
16
+ return text.startsWith("checkpoint ") ? text.slice("checkpoint ".length).trim() : null;
17
+ }
18
+ function unavailableWorkspaceCode(error) {
19
+ if (typeof error !== "object" || error === null || !("code" in error))
20
+ return undefined;
21
+ const code = error.code;
22
+ return code === "ENODEV" || code === "ESTALE" || code === "ENOTCONN" ? code : undefined;
23
+ }
24
+ function continuationSeam(goal, trustedDigests) {
25
+ const checkpoint = goal.checkpoint;
26
+ if (!checkpoint)
27
+ return "";
28
+ if (trustedDigests.has(checkpoint.digest)) {
29
+ return `\n\nSeam checkpoint (explicit user continuity context, not current-round proof):\n${formatDurableGoalCheckpoint(goal)}`;
30
+ }
31
+ return `\n\nAn untrusted workspace checkpoint exists at digest ${checkpoint.digest}; its prose was not loaded as user authority.`;
32
+ }
33
+ export default function goalController(omk) {
34
+ const trustedCheckpointDigests = new Set();
35
+ omk.registerCommand("goal", {
36
+ description: "Show, set, checkpoint, pause, resume, complete, or clear the durable session goal",
37
+ handler: async (args, ctx) => {
38
+ const store = new DurableGoalStore(goalPath(ctx.cwd));
39
+ const text = args.trim();
40
+ try {
41
+ if (text.length === 0) {
42
+ const current = await store.current();
43
+ ctx.ui.notify(current ? renderGoal(current) : "no durable goal", "info");
44
+ return;
45
+ }
46
+ const existing = await store.current();
47
+ if (text === "pause" || text === "resume" || text === "complete" || text === "clear") {
48
+ if (!existing)
49
+ throw new DurableGoalError("store-missing", "durable goal does not exist");
50
+ const next = await store.transition({ kind: text, ref: existing.ref }, new Date().toISOString());
51
+ if (text === "clear")
52
+ trustedCheckpointDigests.clear();
53
+ ctx.ui.notify(renderGoal(next), "info");
54
+ return;
55
+ }
56
+ const payload = checkpointPayload(text);
57
+ if (payload !== null) {
58
+ if (!existing)
59
+ throw new DurableGoalError("store-missing", "durable goal does not exist");
60
+ if (payload.length === 0) {
61
+ throw new DurableGoalError("invalid-input", 'usage: /goal checkpoint {"core":[],"verified":[],"open":[],"next":"..."}');
62
+ }
63
+ const now = new Date().toISOString();
64
+ const next = await store.transition({
65
+ kind: "record-checkpoint",
66
+ ref: existing.ref,
67
+ checkpoint: parseDurableGoalCheckpointCommand(payload, now),
68
+ }, now);
69
+ const checkpoint = next.checkpoint;
70
+ if (!checkpoint)
71
+ throw new DurableGoalError("invalid-store", "durable goal journal is invalid");
72
+ omk.appendEntry("goal_checkpoint", {
73
+ goalId: next.ref.id,
74
+ goalRevision: next.ref.revision,
75
+ checkpointDigest: checkpoint.digest,
76
+ });
77
+ trustedCheckpointDigests.add(checkpoint.digest);
78
+ ctx.ui.notify(renderGoal(next), "info");
79
+ return;
80
+ }
81
+ if (existing && existing.status !== "cleared" && existing.status !== "completed") {
82
+ const next = await store.transition({ kind: "edit", ref: existing.ref, objective: text }, new Date().toISOString());
83
+ ctx.ui.notify(renderGoal(next), "info");
84
+ return;
85
+ }
86
+ if (existing)
87
+ await rm(goalPath(ctx.cwd), { force: true });
88
+ const created = await store.create(createDurableGoal({ id: "session", objective: text, maxRounds: 8, now: new Date().toISOString() }));
89
+ ctx.ui.notify(renderGoal(created), "info");
90
+ }
91
+ catch (error) {
92
+ const message = error instanceof DurableGoalError ? error.message : "goal command failed";
93
+ ctx.ui.notify(message, "error");
94
+ }
95
+ },
96
+ });
97
+ omk.on("agent_end", async (_event, ctx) => {
98
+ const store = new DurableGoalStore(goalPath(ctx.cwd));
99
+ let current;
100
+ try {
101
+ current = await store.current();
102
+ }
103
+ catch (error) {
104
+ const code = unavailableWorkspaceCode(error);
105
+ if (!code)
106
+ throw error;
107
+ omk.appendEntry("goal_workspace_unavailable", { code });
108
+ return;
109
+ }
110
+ if (!current)
111
+ return;
112
+ const decision = decideGoalContinuation({
113
+ status: current.status,
114
+ completedRounds: current.completedRounds,
115
+ maxRounds: current.maxRounds,
116
+ hasQueuedMessages: ctx.hasPendingMessages(),
117
+ });
118
+ if (decision.reason === "queued" || !decision.continue)
119
+ return;
120
+ const advanced = await store.transition({ kind: "advance-round", ref: current.ref }, new Date().toISOString());
121
+ const seam = continuationSeam(advanced, trustedCheckpointDigests);
122
+ omk.sendUserMessage(`Continue the active goal (${advanced.completedRounds}/${advanced.maxRounds}): ${advanced.objective}${seam}`);
123
+ });
124
+ }
125
+ //# sourceMappingURL=goal-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal-controller.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/goal-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { createDurableGoal, DurableGoalError, type DurableGoalSnapshot } from \"../../durable-goal.ts\";\nimport { formatDurableGoalCheckpoint, parseDurableGoalCheckpointCommand } from \"../../durable-goal-checkpoint.ts\";\nimport { DurableGoalStore } from \"../../durable-goal-store.ts\";\nimport { decideGoalContinuation } from \"../../goal-continuation.ts\";\nimport type { ExtensionAPI } from \"../types.ts\";\n\nfunction goalPath(cwd: string): string {\n\treturn join(cwd, \".omk\", \"goals\", \"current.json\");\n}\n\nfunction renderGoal(goal: DurableGoalSnapshot): string {\n\treturn `goal ${goal.ref.id} r${goal.ref.revision} ${goal.status} ${goal.completedRounds}/${goal.maxRounds}\\n${formatDurableGoalCheckpoint(goal)}`;\n}\n\nfunction checkpointPayload(text: string): string | null {\n\tif (text === \"checkpoint\") return \"\";\n\treturn text.startsWith(\"checkpoint \") ? text.slice(\"checkpoint \".length).trim() : null;\n}\n\nfunction unavailableWorkspaceCode(error: unknown): \"ENODEV\" | \"ESTALE\" | \"ENOTCONN\" | undefined {\n\tif (typeof error !== \"object\" || error === null || !(\"code\" in error)) return undefined;\n\tconst code = error.code;\n\treturn code === \"ENODEV\" || code === \"ESTALE\" || code === \"ENOTCONN\" ? code : undefined;\n}\n\nfunction continuationSeam(goal: DurableGoalSnapshot, trustedDigests: ReadonlySet<string>): string {\n\tconst checkpoint = goal.checkpoint;\n\tif (!checkpoint) return \"\";\n\tif (trustedDigests.has(checkpoint.digest)) {\n\t\treturn `\\n\\nSeam checkpoint (explicit user continuity context, not current-round proof):\\n${formatDurableGoalCheckpoint(goal)}`;\n\t}\n\treturn `\\n\\nAn untrusted workspace checkpoint exists at digest ${checkpoint.digest}; its prose was not loaded as user authority.`;\n}\n\nexport default function goalController(omk: ExtensionAPI): void {\n\tconst trustedCheckpointDigests = new Set<string>();\n\tomk.registerCommand(\"goal\", {\n\t\tdescription: \"Show, set, checkpoint, pause, resume, complete, or clear the durable session goal\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst store = new DurableGoalStore(goalPath(ctx.cwd));\n\t\t\tconst text = args.trim();\n\t\t\ttry {\n\t\t\t\tif (text.length === 0) {\n\t\t\t\t\tconst current = await store.current();\n\t\t\t\t\tctx.ui.notify(current ? renderGoal(current) : \"no durable goal\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst existing = await store.current();\n\t\t\t\tif (text === \"pause\" || text === \"resume\" || text === \"complete\" || text === \"clear\") {\n\t\t\t\t\tif (!existing) throw new DurableGoalError(\"store-missing\", \"durable goal does not exist\");\n\t\t\t\t\tconst next = await store.transition({ kind: text, ref: existing.ref }, new Date().toISOString());\n\t\t\t\t\tif (text === \"clear\") trustedCheckpointDigests.clear();\n\t\t\t\t\tctx.ui.notify(renderGoal(next), \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst payload = checkpointPayload(text);\n\t\t\t\tif (payload !== null) {\n\t\t\t\t\tif (!existing) throw new DurableGoalError(\"store-missing\", \"durable goal does not exist\");\n\t\t\t\t\tif (payload.length === 0) {\n\t\t\t\t\t\tthrow new DurableGoalError(\n\t\t\t\t\t\t\t\"invalid-input\",\n\t\t\t\t\t\t\t'usage: /goal checkpoint {\"core\":[],\"verified\":[],\"open\":[],\"next\":\"...\"}',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst now = new Date().toISOString();\n\t\t\t\t\tconst next = await store.transition(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: \"record-checkpoint\",\n\t\t\t\t\t\t\tref: existing.ref,\n\t\t\t\t\t\t\tcheckpoint: parseDurableGoalCheckpointCommand(payload, now),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnow,\n\t\t\t\t\t);\n\t\t\t\t\tconst checkpoint = next.checkpoint;\n\t\t\t\t\tif (!checkpoint) throw new DurableGoalError(\"invalid-store\", \"durable goal journal is invalid\");\n\t\t\t\t\tomk.appendEntry(\"goal_checkpoint\", {\n\t\t\t\t\t\tgoalId: next.ref.id,\n\t\t\t\t\t\tgoalRevision: next.ref.revision,\n\t\t\t\t\t\tcheckpointDigest: checkpoint.digest,\n\t\t\t\t\t});\n\t\t\t\t\ttrustedCheckpointDigests.add(checkpoint.digest);\n\t\t\t\t\tctx.ui.notify(renderGoal(next), \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (existing && existing.status !== \"cleared\" && existing.status !== \"completed\") {\n\t\t\t\t\tconst next = await store.transition(\n\t\t\t\t\t\t{ kind: \"edit\", ref: existing.ref, objective: text },\n\t\t\t\t\t\tnew Date().toISOString(),\n\t\t\t\t\t);\n\t\t\t\t\tctx.ui.notify(renderGoal(next), \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (existing) await rm(goalPath(ctx.cwd), { force: true });\n\t\t\t\tconst created = await store.create(\n\t\t\t\t\tcreateDurableGoal({ id: \"session\", objective: text, maxRounds: 8, now: new Date().toISOString() }),\n\t\t\t\t);\n\t\t\t\tctx.ui.notify(renderGoal(created), \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof DurableGoalError ? error.message : \"goal command failed\";\n\t\t\t\tctx.ui.notify(message, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tomk.on(\"agent_end\", async (_event, ctx) => {\n\t\tconst store = new DurableGoalStore(goalPath(ctx.cwd));\n\t\tlet current: DurableGoalSnapshot | null;\n\t\ttry {\n\t\t\tcurrent = await store.current();\n\t\t} catch (error) {\n\t\t\tconst code = unavailableWorkspaceCode(error);\n\t\t\tif (!code) throw error;\n\t\t\tomk.appendEntry(\"goal_workspace_unavailable\", { code });\n\t\t\treturn;\n\t\t}\n\t\tif (!current) return;\n\t\tconst decision = decideGoalContinuation({\n\t\t\tstatus: current.status,\n\t\t\tcompletedRounds: current.completedRounds,\n\t\t\tmaxRounds: current.maxRounds,\n\t\t\thasQueuedMessages: ctx.hasPendingMessages(),\n\t\t});\n\t\tif (decision.reason === \"queued\" || !decision.continue) return;\n\t\tconst advanced = await store.transition({ kind: \"advance-round\", ref: current.ref }, new Date().toISOString());\n\t\tconst seam = continuationSeam(advanced, trustedCheckpointDigests);\n\t\tomk.sendUserMessage(\n\t\t\t`Continue the active goal (${advanced.completedRounds}/${advanced.maxRounds}): ${advanced.objective}${seam}`,\n\t\t);\n\t});\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../types.ts";
2
+ export default function identicalLoop(omk: ExtensionAPI): void;
3
+ //# sourceMappingURL=identical-loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identical-loop.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/identical-loop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CA2B7D","sourcesContent":["import { detectIdenticalLoop, type LoopRecord } from \"../../identical-loop.ts\";\nimport type { ExtensionAPI } from \"../types.ts\";\n\nexport default function identicalLoop(omk: ExtensionAPI): void {\n\tconst records: LoopRecord[] = [];\n\n\tomk.on(\"session_start\", () => {\n\t\trecords.length = 0;\n\t});\n\tomk.on(\"input\", (event) => {\n\t\tif (event.source !== \"extension\") records.length = 0;\n\t});\n\tomk.on(\"tool_call\", (event) => {\n\t\trecords.push({ toolName: event.toolName, args: event.input });\n\t\tconst detection = detectIdenticalLoop(records, { warnAfter: 3, stopAfter: 6 });\n\t\tif (!detection) return;\n\t\tif (detection.kind === \"stop\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: `identical loop: ${detection.toolName} repeated ${detection.count} times with the same args`,\n\t\t\t};\n\t\t}\n\t\tomk.sendMessage({\n\t\t\tcustomType: \"identical-loop\",\n\t\t\tcontent: `Same ${detection.toolName} call repeated ${detection.count} times. Change the args or stop.`,\n\t\t\tdisplay: true,\n\t\t\tdetails: detection,\n\t\t});\n\t\treturn undefined;\n\t});\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import { detectIdenticalLoop } from "../../identical-loop.js";
2
+ export default function identicalLoop(omk) {
3
+ const records = [];
4
+ omk.on("session_start", () => {
5
+ records.length = 0;
6
+ });
7
+ omk.on("input", (event) => {
8
+ if (event.source !== "extension")
9
+ records.length = 0;
10
+ });
11
+ omk.on("tool_call", (event) => {
12
+ records.push({ toolName: event.toolName, args: event.input });
13
+ const detection = detectIdenticalLoop(records, { warnAfter: 3, stopAfter: 6 });
14
+ if (!detection)
15
+ return;
16
+ if (detection.kind === "stop") {
17
+ return {
18
+ block: true,
19
+ reason: `identical loop: ${detection.toolName} repeated ${detection.count} times with the same args`,
20
+ };
21
+ }
22
+ omk.sendMessage({
23
+ customType: "identical-loop",
24
+ content: `Same ${detection.toolName} call repeated ${detection.count} times. Change the args or stop.`,
25
+ display: true,
26
+ details: detection,
27
+ });
28
+ return undefined;
29
+ });
30
+ }
31
+ //# sourceMappingURL=identical-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identical-loop.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/identical-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAmB,MAAM,yBAAyB,CAAC;AAG/E,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,GAAiB,EAAQ;IAC9D,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAAA,CACnB,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;QAC1B,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;YAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAAA,CACrD,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/E,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC/B,OAAO;gBACN,KAAK,EAAE,IAAI;gBACX,MAAM,EAAE,mBAAmB,SAAS,CAAC,QAAQ,aAAa,SAAS,CAAC,KAAK,2BAA2B;aACpG,CAAC;QACH,CAAC;QACD,GAAG,CAAC,WAAW,CAAC;YACf,UAAU,EAAE,gBAAgB;YAC5B,OAAO,EAAE,QAAQ,SAAS,CAAC,QAAQ,kBAAkB,SAAS,CAAC,KAAK,kCAAkC;YACtG,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,SAAS;SAClB,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IAAA,CACjB,CAAC,CAAC;AAAA,CACH","sourcesContent":["import { detectIdenticalLoop, type LoopRecord } from \"../../identical-loop.ts\";\nimport type { ExtensionAPI } from \"../types.ts\";\n\nexport default function identicalLoop(omk: ExtensionAPI): void {\n\tconst records: LoopRecord[] = [];\n\n\tomk.on(\"session_start\", () => {\n\t\trecords.length = 0;\n\t});\n\tomk.on(\"input\", (event) => {\n\t\tif (event.source !== \"extension\") records.length = 0;\n\t});\n\tomk.on(\"tool_call\", (event) => {\n\t\trecords.push({ toolName: event.toolName, args: event.input });\n\t\tconst detection = detectIdenticalLoop(records, { warnAfter: 3, stopAfter: 6 });\n\t\tif (!detection) return;\n\t\tif (detection.kind === \"stop\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: `identical loop: ${detection.toolName} repeated ${detection.count} times with the same args`,\n\t\t\t};\n\t\t}\n\t\tomk.sendMessage({\n\t\t\tcustomType: \"identical-loop\",\n\t\t\tcontent: `Same ${detection.toolName} call repeated ${detection.count} times. Change the args or stop.`,\n\t\t\tdisplay: true,\n\t\t\tdetails: detection,\n\t\t});\n\t\treturn undefined;\n\t});\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../types.ts";
2
+ export default function promptPreset(omk: ExtensionAPI): void;
3
+ //# sourceMappingURL=prompt-preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-preset.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/prompt-preset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAS5D","sourcesContent":["import { resolvePromptPreset } from \"../../prompt-preset.ts\";\nimport type { ExtensionAPI } from \"../types.ts\";\n\nexport default function promptPreset(omk: ExtensionAPI): void {\n\tomk.on(\"before_agent_start\", (_event, ctx) => {\n\t\tconst model = ctx.model;\n\t\tconst preset = resolvePromptPreset(model ? `${model.provider}/${model.id}` : undefined);\n\t\tif (!preset) return undefined;\n\t\treturn {\n\t\t\tsystemPrompt: `${_event.systemPrompt}\\n\\n<model_preset id=\"${preset.id}\">\\n${preset.guidelines.map((line) => `- ${line}`).join(\"\\n\")}\\n</model_preset>`,\n\t\t};\n\t});\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { resolvePromptPreset } from "../../prompt-preset.js";
2
+ export default function promptPreset(omk) {
3
+ omk.on("before_agent_start", (_event, ctx) => {
4
+ const model = ctx.model;
5
+ const preset = resolvePromptPreset(model ? `${model.provider}/${model.id}` : undefined);
6
+ if (!preset)
7
+ return undefined;
8
+ return {
9
+ systemPrompt: `${_event.systemPrompt}\n\n<model_preset id="${preset.id}">\n${preset.guidelines.map((line) => `- ${line}`).join("\n")}\n</model_preset>`,
10
+ };
11
+ });
12
+ }
13
+ //# sourceMappingURL=prompt-preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-preset.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/prompt-preset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAG7D,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,GAAiB,EAAQ;IAC7D,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;QACxB,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACxF,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,OAAO;YACN,YAAY,EAAE,GAAG,MAAM,CAAC,YAAY,yBAAyB,MAAM,CAAC,EAAE,OAAO,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB;SACvJ,CAAC;IAAA,CACF,CAAC,CAAC;AAAA,CACH","sourcesContent":["import { resolvePromptPreset } from \"../../prompt-preset.ts\";\nimport type { ExtensionAPI } from \"../types.ts\";\n\nexport default function promptPreset(omk: ExtensionAPI): void {\n\tomk.on(\"before_agent_start\", (_event, ctx) => {\n\t\tconst model = ctx.model;\n\t\tconst preset = resolvePromptPreset(model ? `${model.provider}/${model.id}` : undefined);\n\t\tif (!preset) return undefined;\n\t\treturn {\n\t\t\tsystemPrompt: `${_event.systemPrompt}\\n\\n<model_preset id=\"${preset.id}\">\\n${preset.guidelines.map((line) => `- ${line}`).join(\"\\n\")}\\n</model_preset>`,\n\t\t};\n\t});\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../types.ts";
2
+ export default function toolPairRepair(omk: ExtensionAPI): void;
3
+ //# sourceMappingURL=tool-pair-repair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-pair-repair.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/tool-pair-repair.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoC,YAAY,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAS9D","sourcesContent":["import { applyToolPairRepair } from \"../../tool-pair-repair.ts\";\nimport type { ContextEvent, ContextEventResult, ExtensionAPI } from \"../types.ts\";\n\nexport default function toolPairRepair(omk: ExtensionAPI): void {\n\tomk.on(\"context\", (event: ContextEvent): ContextEventResult | undefined => {\n\t\tconst repaired = applyToolPairRepair(event.messages);\n\t\tconst unchanged =\n\t\t\trepaired.length === event.messages.length &&\n\t\t\trepaired.every((message, index) => message === event.messages[index]);\n\t\tif (unchanged) return undefined;\n\t\treturn { messages: repaired };\n\t});\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { applyToolPairRepair } from "../../tool-pair-repair.js";
2
+ export default function toolPairRepair(omk) {
3
+ omk.on("context", (event) => {
4
+ const repaired = applyToolPairRepair(event.messages);
5
+ const unchanged = repaired.length === event.messages.length &&
6
+ repaired.every((message, index) => message === event.messages[index]);
7
+ if (unchanged)
8
+ return undefined;
9
+ return { messages: repaired };
10
+ });
11
+ }
12
+ //# sourceMappingURL=tool-pair-repair.js.map