opensquid 0.5.407 → 0.5.426

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 (154) hide show
  1. package/dist/cli.js +5 -4
  2. package/dist/cli.js.map +1 -1
  3. package/dist/functions/event.d.ts.map +1 -1
  4. package/dist/functions/event.js +30 -0
  5. package/dist/functions/event.js.map +1 -1
  6. package/dist/functions/handoff_session_start.d.ts.map +1 -1
  7. package/dist/functions/handoff_session_start.js +4 -6
  8. package/dist/functions/handoff_session_start.js.map +1 -1
  9. package/dist/functions/index.d.ts +4 -0
  10. package/dist/functions/index.d.ts.map +1 -1
  11. package/dist/functions/index.js +5 -0
  12. package/dist/functions/index.js.map +1 -1
  13. package/dist/functions/read_rubric.d.ts +27 -0
  14. package/dist/functions/read_rubric.d.ts.map +1 -0
  15. package/dist/functions/read_rubric.js +53 -0
  16. package/dist/functions/read_rubric.js.map +1 -0
  17. package/dist/functions/reset_scope_track_state.d.ts +20 -0
  18. package/dist/functions/reset_scope_track_state.d.ts.map +1 -0
  19. package/dist/functions/reset_scope_track_state.js +53 -0
  20. package/dist/functions/reset_scope_track_state.js.map +1 -0
  21. package/dist/functions/rubric_pre_inject.d.ts +22 -0
  22. package/dist/functions/rubric_pre_inject.d.ts.map +1 -0
  23. package/dist/functions/rubric_pre_inject.js +58 -0
  24. package/dist/functions/rubric_pre_inject.js.map +1 -0
  25. package/dist/functions/session_tool_history.d.ts +3 -3
  26. package/dist/functions/session_tool_history.js +1 -1
  27. package/dist/functions/session_tool_history.js.map +1 -1
  28. package/dist/functions/shell_parse.d.ts +41 -0
  29. package/dist/functions/shell_parse.d.ts.map +1 -0
  30. package/dist/functions/shell_parse.js +185 -0
  31. package/dist/functions/shell_parse.js.map +1 -0
  32. package/dist/functions/staged_docs_only.d.ts +23 -0
  33. package/dist/functions/staged_docs_only.d.ts.map +1 -0
  34. package/dist/functions/staged_docs_only.js +57 -0
  35. package/dist/functions/staged_docs_only.js.map +1 -0
  36. package/dist/mcp/server.js +14 -1
  37. package/dist/mcp/server.js.map +1 -1
  38. package/dist/mcp/tools/ralph.d.ts +21 -0
  39. package/dist/mcp/tools/ralph.d.ts.map +1 -0
  40. package/dist/mcp/tools/ralph.js +18 -0
  41. package/dist/mcp/tools/ralph.js.map +1 -0
  42. package/dist/mcp/tools/workgraph.d.ts +11 -0
  43. package/dist/mcp/tools/workgraph.d.ts.map +1 -1
  44. package/dist/mcp/tools/workgraph.js +7 -0
  45. package/dist/mcp/tools/workgraph.js.map +1 -1
  46. package/dist/rag/backend_factory.d.ts.map +1 -1
  47. package/dist/rag/backend_factory.js +4 -0
  48. package/dist/rag/backend_factory.js.map +1 -1
  49. package/dist/rag/backends/libsql_lexical.d.ts.map +1 -1
  50. package/dist/rag/backends/libsql_lexical.js +21 -5
  51. package/dist/rag/backends/libsql_lexical.js.map +1 -1
  52. package/dist/rag/backends/libsql_store.d.ts.map +1 -1
  53. package/dist/rag/backends/libsql_store.js +33 -6
  54. package/dist/rag/backends/libsql_store.js.map +1 -1
  55. package/dist/rag/backends/perfile_source.d.ts.map +1 -1
  56. package/dist/rag/backends/perfile_source.js +3 -0
  57. package/dist/rag/backends/perfile_source.js.map +1 -1
  58. package/dist/rag/memory/consolidate.d.ts +3 -2
  59. package/dist/rag/memory/consolidate.d.ts.map +1 -1
  60. package/dist/rag/memory/consolidate.js +7 -4
  61. package/dist/rag/memory/consolidate.js.map +1 -1
  62. package/dist/rag/types.d.ts +2 -0
  63. package/dist/rag/types.d.ts.map +1 -1
  64. package/dist/rag/types.js.map +1 -1
  65. package/dist/runtime/bootstrap.d.ts.map +1 -1
  66. package/dist/runtime/bootstrap.js +8 -0
  67. package/dist/runtime/bootstrap.js.map +1 -1
  68. package/dist/runtime/coding_flow_keys.d.ts +17 -0
  69. package/dist/runtime/coding_flow_keys.d.ts.map +1 -0
  70. package/dist/runtime/coding_flow_keys.js +21 -0
  71. package/dist/runtime/coding_flow_keys.js.map +1 -0
  72. package/dist/runtime/handoff/collect.d.ts.map +1 -1
  73. package/dist/runtime/handoff/collect.js +3 -1
  74. package/dist/runtime/handoff/collect.js.map +1 -1
  75. package/dist/runtime/hooks/session-start.js +5 -1
  76. package/dist/runtime/hooks/session-start.js.map +1 -1
  77. package/dist/runtime/hooks/session_id.d.ts +7 -0
  78. package/dist/runtime/hooks/session_id.d.ts.map +1 -1
  79. package/dist/runtime/hooks/session_id.js +30 -12
  80. package/dist/runtime/hooks/session_id.js.map +1 -1
  81. package/dist/runtime/protected_paths.d.ts +18 -0
  82. package/dist/runtime/protected_paths.d.ts.map +1 -0
  83. package/dist/runtime/protected_paths.js +18 -0
  84. package/dist/runtime/protected_paths.js.map +1 -0
  85. package/dist/runtime/ralph/decision_classifier.d.ts +18 -0
  86. package/dist/runtime/ralph/decision_classifier.d.ts.map +1 -0
  87. package/dist/runtime/ralph/decision_classifier.js +72 -0
  88. package/dist/runtime/ralph/decision_classifier.js.map +1 -0
  89. package/dist/runtime/ralph/escalate_lap.d.ts +31 -0
  90. package/dist/runtime/ralph/escalate_lap.d.ts.map +1 -0
  91. package/dist/runtime/ralph/escalate_lap.js +22 -0
  92. package/dist/runtime/ralph/escalate_lap.js.map +1 -0
  93. package/dist/runtime/ralph/escalator.d.ts +34 -0
  94. package/dist/runtime/ralph/escalator.d.ts.map +1 -0
  95. package/dist/runtime/ralph/escalator.js +19 -0
  96. package/dist/runtime/ralph/escalator.js.map +1 -0
  97. package/dist/runtime/ralph/lap_outcome.d.ts +43 -0
  98. package/dist/runtime/ralph/lap_outcome.d.ts.map +1 -0
  99. package/dist/runtime/ralph/lap_outcome.js +119 -0
  100. package/dist/runtime/ralph/lap_outcome.js.map +1 -0
  101. package/dist/runtime/ralph/orchestrator.d.ts +71 -0
  102. package/dist/runtime/ralph/orchestrator.d.ts.map +1 -0
  103. package/dist/runtime/ralph/orchestrator.js +74 -0
  104. package/dist/runtime/ralph/orchestrator.js.map +1 -0
  105. package/dist/runtime/ralph/ralph_template.d.ts +18 -0
  106. package/dist/runtime/ralph/ralph_template.d.ts.map +1 -0
  107. package/dist/runtime/ralph/ralph_template.js +61 -0
  108. package/dist/runtime/ralph/ralph_template.js.map +1 -0
  109. package/dist/runtime/ralph/supervisor.d.ts +30 -0
  110. package/dist/runtime/ralph/supervisor.d.ts.map +1 -0
  111. package/dist/runtime/ralph/supervisor.js +24 -0
  112. package/dist/runtime/ralph/supervisor.js.map +1 -0
  113. package/dist/runtime/session_state.d.ts +9 -1
  114. package/dist/runtime/session_state.d.ts.map +1 -1
  115. package/dist/runtime/session_state.js +25 -3
  116. package/dist/runtime/session_state.js.map +1 -1
  117. package/dist/runtime/wedge/compression_deps.d.ts.map +1 -1
  118. package/dist/runtime/wedge/compression_deps.js +9 -1
  119. package/dist/runtime/wedge/compression_deps.js.map +1 -1
  120. package/dist/setup/cli/gate.d.ts +7 -2
  121. package/dist/setup/cli/gate.d.ts.map +1 -1
  122. package/dist/setup/cli/gate.js +7 -3
  123. package/dist/setup/cli/gate.js.map +1 -1
  124. package/dist/setup/cli/ralph.d.ts +20 -0
  125. package/dist/setup/cli/ralph.d.ts.map +1 -0
  126. package/dist/setup/cli/ralph.js +168 -0
  127. package/dist/setup/cli/ralph.js.map +1 -0
  128. package/dist/setup/wizard/ralph_writer.d.ts +98 -0
  129. package/dist/setup/wizard/ralph_writer.d.ts.map +1 -0
  130. package/dist/setup/wizard/ralph_writer.js +114 -0
  131. package/dist/setup/wizard/ralph_writer.js.map +1 -0
  132. package/dist/workgraph/audience.d.ts +12 -0
  133. package/dist/workgraph/audience.d.ts.map +1 -0
  134. package/dist/workgraph/audience.js +10 -0
  135. package/dist/workgraph/audience.js.map +1 -0
  136. package/dist/workgraph/events.d.ts.map +1 -1
  137. package/dist/workgraph/events.js +34 -0
  138. package/dist/workgraph/events.js.map +1 -1
  139. package/dist/workgraph/store.d.ts.map +1 -1
  140. package/dist/workgraph/store.js +86 -12
  141. package/dist/workgraph/store.js.map +1 -1
  142. package/dist/workgraph/types.d.ts +33 -2
  143. package/dist/workgraph/types.d.ts.map +1 -1
  144. package/docs/rubric/author.md +17 -0
  145. package/docs/rubric/scope.md +16 -0
  146. package/package.json +3 -2
  147. package/packs/builtin/coding-flow/skills/entry-and-handoffs/skill.yaml +15 -0
  148. package/packs/builtin/coding-flow/skills/execute-gate/skill.yaml +9 -10
  149. package/packs/builtin/coding-flow/skills/scope-lifecycle/skill.yaml +72 -51
  150. package/packs/builtin/default-discipline/manifest.yaml +6 -3
  151. package/packs/builtin/default-discipline/skills/workflow/skill.yaml +19 -6
  152. package/packs/builtin/pack-architect/SKILL.md +10 -0
  153. package/packs/builtin/pack-architect/skills/skill-yaml-author-walkthrough/skill.yaml +7 -0
  154. package/packs/builtin/scope-architect/team.yaml +5 -2
@@ -0,0 +1,168 @@
1
+ /**
2
+ * GR.4 — the `opensquid loop` CLI: the user-invoked entry that ASSEMBLES the orchestrator's injected deps
3
+ * and runs the gated-ralph loop. A thin wire — all logic lives in the unit-tested pieces it composes
4
+ * (runRalphLoop, chatEscalator, parseLapOutcome, the GR.1–3 store ops). The loop is a CLI COMMAND, not a
5
+ * daemon (opensquid stays an MCP server / tool provider; the agent loop runs inside the spawned harness).
6
+ *
7
+ * Commands:
8
+ * opensquid loop [--once] [--max-budget-usd <n>] — run the loop (read ready → claim → lap → repeat)
9
+ * opensquid loop resolve <itemId> --misclassified — the human-override residual-shrink path (GR.4)
10
+ *
11
+ * Imports from: commander, node:net, ../../runtime/paths.js, ../../runtime/spawn_lifecycle.js,
12
+ * ../../runtime/ralph/*, ../../workgraph/*, ../wizard/ralph_writer.js.
13
+ */
14
+ import { connect } from 'node:net';
15
+ import { join } from 'node:path';
16
+ import { OPENSQUID_HOME, chatDaemonSockPath } from '../../runtime/paths.js';
17
+ import { runOneShotCli } from '../../runtime/spawn_lifecycle.js';
18
+ import { workGraphStore } from '../../workgraph/store.js';
19
+ import { claimAudience } from '../../workgraph/audience.js';
20
+ import { runRalphLoop, resolveParked } from '../../runtime/ralph/orchestrator.js';
21
+ import { parseLapOutcome } from '../../runtime/ralph/lap_outcome.js';
22
+ import { recordMisclassification } from '../../runtime/ralph/decision_classifier.js';
23
+ import { chatEscalator } from '../../runtime/ralph/escalator.js';
24
+ import { readRalphConfig } from '../wizard/ralph_writer.js';
25
+ /** Hydrate the persisted scalar config into the orchestrator's runtime `RalphConfig` (closures rebuilt). */
26
+ export function buildRalphConfig(file, opts) {
27
+ return {
28
+ authMode: file.authMode,
29
+ maxBudgetUsd: opts.maxBudgetUsd ?? file.maxBudgetUsd,
30
+ claimTtlSec: file.claimTtlSec,
31
+ once: opts.once,
32
+ supervise: {
33
+ maxRetries: file.maxRetries,
34
+ backoffMs: (attempt) => file.backoffBaseMs * 2 ** attempt, // exponential from the base
35
+ heartbeat: () => undefined, // a future lease-refresh; liveness tick is a no-op for the CLI run
36
+ },
37
+ };
38
+ }
39
+ /** Build the per-lap runner: spawn `claude -p RALPH.md --item <id>`, parse the typed exit. A deadline
40
+ * overrun (group-SIGKILL) becomes the typed TIMEOUT, NOT a CRASH; a genuine spawn failure rethrows → CRASH. */
41
+ export function makeSpawnLap(cfg, file, runCli = runOneShotCli) {
42
+ return async (item) => {
43
+ let stdout;
44
+ try {
45
+ stdout = await runCli({
46
+ cli: file.harness.cli, // Inv 10 — harness is a parameter
47
+ args: [
48
+ '-p',
49
+ file.harness.ralphMdPath,
50
+ '--item',
51
+ item.id,
52
+ '--output-format',
53
+ 'json',
54
+ '--max-budget-usd',
55
+ String(cfg.maxBudgetUsd),
56
+ '--dangerously-skip-permissions',
57
+ ],
58
+ prompt: '',
59
+ timeoutMs: file.wallClockMs,
60
+ markSubagent: true,
61
+ timeoutError: () => Object.assign(new Error('lap timeout'), { __timeout: true }),
62
+ });
63
+ }
64
+ catch (e) {
65
+ if (e.__timeout === true)
66
+ return { kind: 'TIMEOUT', costUsd: 0 };
67
+ throw e; // genuine spawn/IO failure → superviseLap maps it to CRASH
68
+ }
69
+ const { outcome, costUsd } = parseLapOutcome(stdout);
70
+ return { ...outcome, costUsd };
71
+ };
72
+ }
73
+ /** The real chat transport: a one-shot UDS JSON-RPC `send` to the chat-daemon (the live Telegram path
74
+ * `chat_send` uses). `ok:false` on any unreachable/error so the escalator stays undroppable. */
75
+ export const daemonChatSend = (params) => new Promise((resolve) => {
76
+ const sock = connect(chatDaemonSockPath());
77
+ let buf = '';
78
+ const done = (r) => {
79
+ try {
80
+ sock.end();
81
+ }
82
+ catch {
83
+ /* already closed */
84
+ }
85
+ resolve(r);
86
+ };
87
+ const timer = setTimeout(() => done({ ok: false, reason: 'chat-daemon RPC timeout (5s)' }), 5000);
88
+ sock.on('error', (e) => {
89
+ clearTimeout(timer);
90
+ done({ ok: false, reason: `chat-daemon unreachable: ${e.message}` });
91
+ });
92
+ sock.on('data', (d) => {
93
+ buf += d.toString('utf8');
94
+ const nl = buf.indexOf('\n');
95
+ if (nl === -1)
96
+ return;
97
+ clearTimeout(timer);
98
+ try {
99
+ const res = JSON.parse(buf.slice(0, nl));
100
+ done(res.error ? { ok: false, reason: res.error.message ?? 'send error' } : { ok: true });
101
+ }
102
+ catch (e) {
103
+ done({ ok: false, reason: e instanceof Error ? e.message : 'bad RPC response' });
104
+ }
105
+ });
106
+ sock.write(JSON.stringify({
107
+ jsonrpc: '2.0',
108
+ id: `ralph-${String(Date.now())}`,
109
+ method: 'send',
110
+ params: { channel: params.channel, text: params.text },
111
+ }) + '\n');
112
+ });
113
+ export function registerRalph(program) {
114
+ const loop = program
115
+ .command('loop')
116
+ .description('Run the gated-ralph autonomous loop (composes the work-graph + the coding-flow gate)');
117
+ loop
118
+ .option('--once', 'process a single ready item then stop', false)
119
+ .option('--max-budget-usd <n>', 'API-mode dollar budget for this run (overrides config)')
120
+ .action(async (opts) => {
121
+ const file = await readRalphConfig();
122
+ if (file === null) {
123
+ process.stderr.write('🦑 loop OFF: no ~/.opensquid/ralph.config.json. Run the wizard first.\n');
124
+ process.exitCode = 1;
125
+ return;
126
+ }
127
+ const cfg = buildRalphConfig(file, {
128
+ once: opts.once === true,
129
+ ...(opts.maxBudgetUsd === undefined ? {} : { maxBudgetUsd: Number(opts.maxBudgetUsd) }),
130
+ });
131
+ const wg = workGraphStore({
132
+ dbUrl: `file:${join(OPENSQUID_HOME(), 'workgraph.db')}`,
133
+ sourceDir: join(OPENSQUID_HOME(), 'store', 'issues'),
134
+ });
135
+ await wg.init();
136
+ const result = await runRalphLoop(cfg, {
137
+ wg,
138
+ claimAudience,
139
+ runLap: makeSpawnLap(cfg, file),
140
+ escalate: chatEscalator({ send: daemonChatSend, channel: 'project:telegram' }),
141
+ });
142
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
143
+ });
144
+ loop
145
+ .command('resolve <itemId>')
146
+ .description('Resolve a parked HUMAN_REQUIRED item (the human-override residual-shrink path)')
147
+ .option('--misclassified', 'the escalation was principle-settleable — record + un-wedge for another lap', false)
148
+ .action(async (itemId, opts) => {
149
+ if (opts.misclassified !== true) {
150
+ process.stderr.write('Nothing to do: pass --misclassified to record + un-wedge the item.\n');
151
+ return;
152
+ }
153
+ const wg = workGraphStore({
154
+ dbUrl: `file:${join(OPENSQUID_HOME(), 'workgraph.db')}`,
155
+ sourceDir: join(OPENSQUID_HOME(), 'store', 'issues'),
156
+ });
157
+ await wg.init();
158
+ await resolveParked(itemId, {
159
+ wg,
160
+ recordMisclassification,
161
+ sessionId: process.env.CLAUDE_SESSION_ID ?? '<cli>',
162
+ nowIso: new Date().toISOString(),
163
+ });
164
+ process.stdout.write(`resolved ${itemId}: misclassification recorded, item un-wedged → back in ready.\n`);
165
+ });
166
+ return loop;
167
+ }
168
+ //# sourceMappingURL=ralph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ralph.js","sourceRoot":"","sources":["../../../src/setup/cli/ralph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAoB,MAAM,qCAAqC,CAAC;AAEpG,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AACrF,OAAO,EAAE,aAAa,EAAiB,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAE,eAAe,EAAwB,MAAM,2BAA2B,CAAC;AAElF,4GAA4G;AAC5G,MAAM,UAAU,gBAAgB,CAC9B,IAAqB,EACrB,IAA8C;IAE9C,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY;QACpD,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,SAAS,EAAE;YACT,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,OAAO,EAAE,4BAA4B;YAC/F,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,mEAAmE;SAChG;KACF,CAAC;AACJ,CAAC;AAED;+GAC+G;AAC/G,MAAM,UAAU,YAAY,CAC1B,GAAgB,EAChB,IAAqB,EACrB,SAA+B,aAAa;IAE5C,OAAO,KAAK,EAAE,IAAW,EAAE,EAAE;QAC3B,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,MAAM,CAAC;gBACpB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,kCAAkC;gBACzD,IAAI,EAAE;oBACJ,IAAI;oBACJ,IAAI,CAAC,OAAO,CAAC,WAAW;oBACxB,QAAQ;oBACR,IAAI,CAAC,EAAE;oBACP,iBAAiB;oBACjB,MAAM;oBACN,kBAAkB;oBAClB,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;oBACxB,gCAAgC;iBACjC;gBACD,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,CAAC,WAAW;gBAC3B,YAAY,EAAE,IAAI;gBAClB,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;aACjF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAK,CAA6B,CAAC,SAAS,KAAK,IAAI;gBAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YAC9F,MAAM,CAAC,CAAC,CAAC,2DAA2D;QACtE,CAAC;QACD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QACrD,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC;AAED;gGACgG;AAChG,MAAM,CAAC,MAAM,cAAc,GAAa,CAAC,MAAM,EAAE,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC3C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,MAAM,IAAI,GAAG,CAAC,CAAmC,EAAQ,EAAE;QACzD,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,oBAAoB;QACtB,CAAC;QACD,OAAO,CAAC,CAAC,CAAC,CAAC;IACb,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC,EACjE,IAAI,CACL,CAAC;IACF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;QACrB,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;QAC5B,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,OAAO;QACtB,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAqC,CAAC;YAC7E,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5F,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,KAAK,CACR,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,EAAE,KAAK;QACd,EAAE,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE;QACjC,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;KACvD,CAAC,GAAG,IAAI,CACV,CAAC;AACJ,CAAC,CAAC,CAAC;AAEL,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CACV,sFAAsF,CACvF,CAAC;IAEJ,IAAI;SACD,MAAM,CAAC,QAAQ,EAAE,uCAAuC,EAAE,KAAK,CAAC;SAChE,MAAM,CAAC,sBAAsB,EAAE,wDAAwD,CAAC;SACxF,MAAM,CAAC,KAAK,EAAE,IAA+C,EAAE,EAAE;QAChE,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;QACrC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yEAAyE,CAC1E,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,EAAE;YACjC,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI;YACxB,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;SACxF,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,cAAc,CAAC;YACxB,KAAK,EAAE,QAAQ,IAAI,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,EAAE;YACvD,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC;SACrD,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;YACrC,EAAE;YACF,aAAa;YACb,MAAM,EAAE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC;YAC/B,QAAQ,EAAE,aAAa,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;SAC/E,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEL,IAAI;SACD,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,gFAAgF,CAAC;SAC7F,MAAM,CACL,iBAAiB,EACjB,6EAA6E,EAC7E,KAAK,CACN;SACA,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAiC,EAAE,EAAE;QAClE,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,sEAAsE,CACvE,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAG,cAAc,CAAC;YACxB,KAAK,EAAE,QAAQ,IAAI,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,EAAE;YACvD,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC;SACrD,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,aAAa,CAAC,MAAM,EAAE;YAC1B,EAAE;YACF,uBAAuB;YACvB,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO;YACnD,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACjC,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,YAAY,MAAM,iEAAiE,CACpF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,98 @@
1
+ import { z } from 'zod';
2
+ export declare const RalphConfigFileSchema: z.ZodEffects<z.ZodObject<{
3
+ /** Auth mode resolves the per-lap bound (Inv 11): API → dollar budget; subscription → wall-clock W. */
4
+ authMode: z.ZodEnum<["api", "subscription"]>;
5
+ /** API dollar budget (running sum of the verified total_cost_usd). Ignored in subscription mode. */
6
+ maxBudgetUsd: z.ZodNumber;
7
+ /** Per-item claim TTL (GR.1). */
8
+ claimTtlSec: z.ZodNumber;
9
+ /** Per-lap wall-clock deadline W (the subscription bound + the TIMEOUT trigger). */
10
+ wallClockMs: z.ZodNumber;
11
+ /** Supervisor retry cap R (CRASH/TIMEOUT only) and the backoff base for exponential backoff. */
12
+ maxRetries: z.ZodNumber;
13
+ backoffBaseMs: z.ZodNumber;
14
+ /** Harness is a PARAMETER (Inv 10): the lap CLI + the RALPH.md path it reads. */
15
+ harness: z.ZodObject<{
16
+ cli: z.ZodString;
17
+ ralphMdPath: z.ZodString;
18
+ }, "strip", z.ZodTypeAny, {
19
+ cli: string;
20
+ ralphMdPath: string;
21
+ }, {
22
+ cli: string;
23
+ ralphMdPath: string;
24
+ }>;
25
+ }, "strip", z.ZodTypeAny, {
26
+ authMode: "subscription" | "api";
27
+ maxBudgetUsd: number;
28
+ claimTtlSec: number;
29
+ wallClockMs: number;
30
+ maxRetries: number;
31
+ backoffBaseMs: number;
32
+ harness: {
33
+ cli: string;
34
+ ralphMdPath: string;
35
+ };
36
+ }, {
37
+ authMode: "subscription" | "api";
38
+ maxBudgetUsd: number;
39
+ claimTtlSec: number;
40
+ wallClockMs: number;
41
+ maxRetries: number;
42
+ backoffBaseMs: number;
43
+ harness: {
44
+ cli: string;
45
+ ralphMdPath: string;
46
+ };
47
+ }>, {
48
+ authMode: "subscription" | "api";
49
+ maxBudgetUsd: number;
50
+ claimTtlSec: number;
51
+ wallClockMs: number;
52
+ maxRetries: number;
53
+ backoffBaseMs: number;
54
+ harness: {
55
+ cli: string;
56
+ ralphMdPath: string;
57
+ };
58
+ }, {
59
+ authMode: "subscription" | "api";
60
+ maxBudgetUsd: number;
61
+ claimTtlSec: number;
62
+ wallClockMs: number;
63
+ maxRetries: number;
64
+ backoffBaseMs: number;
65
+ harness: {
66
+ cli: string;
67
+ ralphMdPath: string;
68
+ };
69
+ }>;
70
+ export type RalphConfigFile = z.infer<typeof RalphConfigFileSchema>;
71
+ export declare const ralphMdPath: (home?: string) => string;
72
+ export declare const ralphConfigPath: (home?: string) => string;
73
+ /** Sensible defaults — subscription mode (W-bounded), conservative caps. Overridable by the wizard. */
74
+ export declare function defaultRalphConfig(home?: string): RalphConfigFile;
75
+ type WriteOutcome = 'created' | 'unchanged' | 'replaced';
76
+ export interface RalphInstallResult {
77
+ home: string;
78
+ ralphMd: {
79
+ path: string;
80
+ outcome: WriteOutcome;
81
+ };
82
+ config: {
83
+ path: string;
84
+ outcome: WriteOutcome;
85
+ };
86
+ }
87
+ /**
88
+ * Install/refresh the RALPH.md directive + loop config. Idempotent + re-runnable (the wizard calls this);
89
+ * a second run with the same inputs is a no-op diff. Merges `overrides` over the defaults.
90
+ */
91
+ export declare function installRalph(opts?: {
92
+ home?: string;
93
+ overrides?: Partial<RalphConfigFile>;
94
+ }): Promise<RalphInstallResult>;
95
+ /** Read + validate the loop config (fail-loud per the project Zod invariant). Null if absent (loop OFF). */
96
+ export declare function readRalphConfig(home?: string): Promise<RalphConfigFile | null>;
97
+ export {};
98
+ //# sourceMappingURL=ralph_writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ralph_writer.d.ts","sourceRoot":"","sources":["../../../src/setup/wizard/ralph_writer.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,qBAAqB;IAE9B,uGAAuG;;IAEvG,oGAAoG;;IAEpG,iCAAiC;;IAEjC,oFAAoF;;IAEpF,gGAAgG;;;IAGhG,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUjF,CAAC;AACL,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,WAAW,GAAI,OAAM,MAAyB,KAAG,MAAgC,CAAC;AAC/F,eAAO,MAAM,eAAe,GAAI,OAAM,MAAyB,KAAG,MACjC,CAAC;AAElC,uGAAuG;AACvG,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,MAAyB,GAAG,eAAe,CAUnF;AAED,KAAK,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAgBzD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,CAAA;KAAE,CAAC;IACjD,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,YAAY,CAAA;KAAE,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,GAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CACjC,GACL,OAAO,CAAC,kBAAkB,CAAC,CAiB7B;AAED,4GAA4G;AAC5G,wBAAsB,eAAe,CACnC,IAAI,GAAE,MAAyB,GAC9B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CASjC"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * GR.4 — the gated-ralph wizard writer (Inv 12: wizard-configured, never hand-wired).
3
+ *
4
+ * Installs the two on-disk artifacts the `opensquid loop` orchestrator reads:
5
+ * 1. `~/.opensquid/RALPH.md` — the stable per-lap directive (the `RALPH_MD` constant).
6
+ * 2. `~/.opensquid/ralph.config.json` — the loop config (auth-mode, budget/rate caps, supervisor
7
+ * bounds, harness), validated by `RalphConfigFileSchema` on read (fail-loud, the project invariant).
8
+ *
9
+ * Both writes are IDEMPOTENT: an identical existing file is a no-op; a divergent one is snapshotted to
10
+ * `<file>.bak` before the atomic overwrite (same contract as settings-writer). Absent config ⇒ the loop
11
+ * is OFF (the CLI refuses to run without it) ⇒ today's behavior is unchanged (additive, Inv 12).
12
+ *
13
+ * Persisted config stores only SCALARS (no functions) — the CLI reconstructs the orchestrator's
14
+ * `RalphConfig` (the `backoffMs`/`heartbeat`/`sleep` closures) from these at launch.
15
+ *
16
+ * Imports from: node:fs/promises, ../../runtime/atomic_write.js, ../../runtime/paths.js,
17
+ * ../../runtime/ralph/ralph_template.js, zod.
18
+ */
19
+ import { readFile, writeFile } from 'node:fs/promises';
20
+ import { join } from 'node:path';
21
+ import { z } from 'zod';
22
+ import { atomicWriteFile } from '../../runtime/atomic_write.js';
23
+ import { OPENSQUID_HOME } from '../../runtime/paths.js';
24
+ import { RALPH_MD } from '../../runtime/ralph/ralph_template.js';
25
+ export const RalphConfigFileSchema = z
26
+ .object({
27
+ /** Auth mode resolves the per-lap bound (Inv 11): API → dollar budget; subscription → wall-clock W. */
28
+ authMode: z.enum(['api', 'subscription']),
29
+ /** API dollar budget (running sum of the verified total_cost_usd). Ignored in subscription mode. */
30
+ maxBudgetUsd: z.number().positive(),
31
+ /** Per-item claim TTL (GR.1). */
32
+ claimTtlSec: z.number().int().positive(),
33
+ /** Per-lap wall-clock deadline W (the subscription bound + the TIMEOUT trigger). */
34
+ wallClockMs: z.number().int().positive(),
35
+ /** Supervisor retry cap R (CRASH/TIMEOUT only) and the backoff base for exponential backoff. */
36
+ maxRetries: z.number().int().nonnegative(),
37
+ backoffBaseMs: z.number().int().positive(),
38
+ /** Harness is a PARAMETER (Inv 10): the lap CLI + the RALPH.md path it reads. */
39
+ harness: z.object({ cli: z.string().min(1), ralphMdPath: z.string().min(1) }),
40
+ })
41
+ .refine((c) => c.claimTtlSec * 1000 > c.wallClockMs, {
42
+ // HARD INVARIANT (S7): the claim TTL T must exceed the lap deadline W — else a legitimately long lap
43
+ // outruns its own claim, ready() re-surfaces the item mid-run, a second runner's CAS succeeds, and the
44
+ // loop DOUBLE-SHIPS (the wg-c34349377f81 hazard the claim layer exists to prevent). Fail-loud, not the operator's job.
45
+ message: 'claimTtlSec*1000 must exceed wallClockMs (T > W) — else a long lap outruns its claim → double-ship',
46
+ path: ['claimTtlSec'],
47
+ });
48
+ export const ralphMdPath = (home = OPENSQUID_HOME()) => join(home, 'RALPH.md');
49
+ export const ralphConfigPath = (home = OPENSQUID_HOME()) => join(home, 'ralph.config.json');
50
+ /** Sensible defaults — subscription mode (W-bounded), conservative caps. Overridable by the wizard. */
51
+ export function defaultRalphConfig(home = OPENSQUID_HOME()) {
52
+ return {
53
+ authMode: 'subscription',
54
+ maxBudgetUsd: 10,
55
+ claimTtlSec: 3600, // T = 1h claim TTL — MUST exceed wallClockMs (W = 30m deadline) per S7 (T > W)
56
+ wallClockMs: 30 * 60 * 1000,
57
+ maxRetries: 2,
58
+ backoffBaseMs: 2000,
59
+ harness: { cli: 'claude', ralphMdPath: ralphMdPath(home) },
60
+ };
61
+ }
62
+ /** Idempotent atomic write: identical → no-op; divergent → snapshot the old to `<path>.bak` then rename. */
63
+ async function idempotentWrite(path, content) {
64
+ let existing = null;
65
+ try {
66
+ existing = await readFile(path, 'utf8');
67
+ }
68
+ catch (e) {
69
+ if (e.code !== 'ENOENT')
70
+ throw e;
71
+ }
72
+ if (existing === content)
73
+ return 'unchanged';
74
+ if (existing !== null)
75
+ await writeFile(`${path}.bak`, existing); // last line of defense before overwrite
76
+ await atomicWriteFile(path, content);
77
+ return existing === null ? 'created' : 'replaced';
78
+ }
79
+ /**
80
+ * Install/refresh the RALPH.md directive + loop config. Idempotent + re-runnable (the wizard calls this);
81
+ * a second run with the same inputs is a no-op diff. Merges `overrides` over the defaults.
82
+ */
83
+ export async function installRalph(opts = {}) {
84
+ const home = opts.home ?? OPENSQUID_HOME();
85
+ const config = RalphConfigFileSchema.parse({
86
+ ...defaultRalphConfig(home),
87
+ ...opts.overrides,
88
+ // a partial harness override must not drop the sibling field
89
+ harness: { ...defaultRalphConfig(home).harness, ...opts.overrides?.harness },
90
+ });
91
+ const mdPath = ralphMdPath(home);
92
+ const cfgPath = ralphConfigPath(home);
93
+ const mdOutcome = await idempotentWrite(mdPath, RALPH_MD);
94
+ const cfgOutcome = await idempotentWrite(cfgPath, `${JSON.stringify(config, null, 2)}\n`);
95
+ return {
96
+ home,
97
+ ralphMd: { path: mdPath, outcome: mdOutcome },
98
+ config: { path: cfgPath, outcome: cfgOutcome },
99
+ };
100
+ }
101
+ /** Read + validate the loop config (fail-loud per the project Zod invariant). Null if absent (loop OFF). */
102
+ export async function readRalphConfig(home = OPENSQUID_HOME()) {
103
+ let raw;
104
+ try {
105
+ raw = await readFile(ralphConfigPath(home), 'utf8');
106
+ }
107
+ catch (e) {
108
+ if (e.code === 'ENOENT')
109
+ return null; // not configured ⇒ loop OFF
110
+ throw e;
111
+ }
112
+ return RalphConfigFileSchema.parse(JSON.parse(raw));
113
+ }
114
+ //# sourceMappingURL=ralph_writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ralph_writer.js","sourceRoot":"","sources":["../../../src/setup/wizard/ralph_writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Derive a claim's audience from the GDC env markers the gate already trusts (the same
3
+ * `AGENT_ENV_MARKERS` as `setup/cli/gate.ts`: CLAUDECODE / CODEX_THREAD_ID / AI_AGENT). The audience
4
+ * is stamped at claim time, NEVER taken from caller input — so it reflects the actual harness that
5
+ * ran the claim. (GR.1 of the gated-ralph loop; the work-graph-item instance of the claim/audience
6
+ * pattern from wg-c34349377f81.)
7
+ *
8
+ * Imported by: src/mcp/tools/workgraph.ts.
9
+ */
10
+ import type { ClaimAudience } from './types.js';
11
+ export declare function claimAudience(env?: NodeJS.ProcessEnv): ClaimAudience;
12
+ //# sourceMappingURL=audience.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audience.d.ts","sourceRoot":"","sources":["../../src/workgraph/audience.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,aAAa,CAMjF"}
@@ -0,0 +1,10 @@
1
+ export function claimAudience(env = process.env) {
2
+ const claude = env.CLAUDECODE;
3
+ if (claude !== undefined && claude !== '')
4
+ return { source: 'claudecode', version: claude };
5
+ const codex = env.CODEX_THREAD_ID;
6
+ if (codex !== undefined && codex !== '')
7
+ return { source: 'codex', threadId: codex };
8
+ return { source: 'unknown' };
9
+ }
10
+ //# sourceMappingURL=audience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audience.js","sourceRoot":"","sources":["../../src/workgraph/audience.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IAChE,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC;IAC9B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC5F,MAAM,KAAK,GAAG,GAAG,CAAC,eAAe,CAAC;IAClC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACrF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/workgraph/events.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAevC,gGAAgG;AAChG,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MACgC,CAAC;AAExF,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,SAAS,OAAO,EAAE,SAAS,MAAM,KAAG,MAK1D,CAAC;AAIlB;;;GAGG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CrE"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/workgraph/events.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAevC,gGAAgG;AAChG,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MACgC,CAAC;AAExF,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,SAAS,OAAO,EAAE,SAAS,MAAM,KAAG,MAK1D,CAAC;AAIlB;;;GAGG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA+ErE"}
@@ -85,6 +85,40 @@ export async function applyOp(client, op) {
85
85
  args: [edgeKey(s(p.from), s(p.to))],
86
86
  });
87
87
  return;
88
+ case 'claim_acquired':
89
+ // GR.1 — exactly-once CAS at the projection: the claim lands ONLY if the item is currently
90
+ // unclaimed OR its prior claim already expired (claim_expires_at <= this op's ts). Replaying
91
+ // in lamport order makes exactly one concurrent claim win; the loser's UPDATE matches 0 rows.
92
+ // Expiry is read at query time (listReady) — no reaper. claim_token is the unique winner mark.
93
+ await client.execute({
94
+ sql: `UPDATE wg_issues
95
+ SET claim_token = ?, claim_audience = ?, claim_expires_at = ?, updated_at = ?
96
+ WHERE id = ? AND status = 'open'
97
+ AND (claim_token IS NULL OR claim_expires_at <= ?)`,
98
+ args: [
99
+ s(p.claimToken),
100
+ s(p.audience === undefined ? '' : JSON.stringify(p.audience)),
101
+ s(p.expiresAt),
102
+ s(p.ts),
103
+ op.issueId,
104
+ s(p.ts),
105
+ ],
106
+ });
107
+ return;
108
+ case 'wedge_marked':
109
+ // GR.3 — record the wedge reason; listReady excludes wedge-marked items (escalate, not re-attempt).
110
+ await client.execute({
111
+ sql: `UPDATE wg_issues SET wedge_reason = ?, updated_at = ? WHERE id = ?`,
112
+ args: [s(p.reason), s(p.ts), op.issueId],
113
+ });
114
+ return;
115
+ case 'wedge_cleared':
116
+ // GR.4 — un-wedge (human-override resolution): the item re-enters listReady for another lap.
117
+ await client.execute({
118
+ sql: `UPDATE wg_issues SET wedge_reason = NULL, updated_at = ? WHERE id = ?`,
119
+ args: [s(p.ts), op.issueId],
120
+ });
121
+ return;
88
122
  }
89
123
  }
90
124
  //# sourceMappingURL=events.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/workgraph/events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/workgraph/events.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/workgraph/store.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAsC,cAAc,EAAE,MAAM,YAAY,CAAC;AAoCrF,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAqH1F;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoClB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/workgraph/store.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAqD,cAAc,EAAE,MAAM,YAAY,CAAC;AAyEpG,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAwJ1F;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoClB"}
@@ -24,14 +24,39 @@ const newIssueId = (title) => 'wg-' +
24
24
  const str = (r, k) => (typeof r[k] === 'string' ? r[k] : '');
25
25
  const num = (v) => (typeof v === 'number' ? v : Number(v ?? 0));
26
26
  const toStatus = (s) => (s === 'in_progress' || s === 'closed' ? s : 'open');
27
- const rowToIssue = (r) => ({
28
- id: str(r, 'id'),
29
- title: str(r, 'title'),
30
- body: str(r, 'body'),
31
- status: toStatus(str(r, 'status')),
32
- createdAt: str(r, 'created_at'),
33
- updatedAt: str(r, 'updated_at'),
34
- });
27
+ const optStr = (r, k) => {
28
+ const v = r[k];
29
+ return typeof v === 'string' && v !== '' ? v : undefined;
30
+ };
31
+ const parseAudience = (r) => {
32
+ const raw = optStr(r, 'claim_audience');
33
+ if (raw === undefined)
34
+ return undefined;
35
+ try {
36
+ return JSON.parse(raw);
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ };
42
+ const rowToIssue = (r) => {
43
+ const claimToken = optStr(r, 'claim_token');
44
+ const claimAudience = parseAudience(r);
45
+ const claimExpiresAt = optStr(r, 'claim_expires_at');
46
+ const wedgeReason = optStr(r, 'wedge_reason');
47
+ return {
48
+ id: str(r, 'id'),
49
+ title: str(r, 'title'),
50
+ body: str(r, 'body'),
51
+ status: toStatus(str(r, 'status')),
52
+ createdAt: str(r, 'created_at'),
53
+ updatedAt: str(r, 'updated_at'),
54
+ ...(claimToken === undefined ? {} : { claimToken }),
55
+ ...(claimAudience === undefined ? {} : { claimAudience }),
56
+ ...(claimExpiresAt === undefined ? {} : { claimExpiresAt }),
57
+ ...(wedgeReason === undefined ? {} : { wedgeReason }),
58
+ };
59
+ };
35
60
  async function createSchema(client) {
36
61
  await client.execute(`CREATE TABLE IF NOT EXISTS wg_ops (
37
62
  id TEXT PRIMARY KEY, issue_id TEXT NOT NULL, lamport INTEGER NOT NULL,
@@ -39,9 +64,24 @@ async function createSchema(client) {
39
64
  await client.execute(`CREATE TABLE IF NOT EXISTS wg_issues (
40
65
  id TEXT PRIMARY KEY, title TEXT NOT NULL, body TEXT NOT NULL DEFAULT '',
41
66
  status TEXT NOT NULL DEFAULT 'open', created_at TEXT NOT NULL, updated_at TEXT NOT NULL,
42
- lww INTEGER NOT NULL DEFAULT 0);`);
67
+ lww INTEGER NOT NULL DEFAULT 0,
68
+ claim_token TEXT, claim_audience TEXT, claim_expires_at TEXT, wedge_reason TEXT);`);
43
69
  await client.execute(`CREATE TABLE IF NOT EXISTS wg_edges (
44
70
  edge_key TEXT PRIMARY KEY, from_id TEXT NOT NULL, to_id TEXT NOT NULL, type TEXT NOT NULL);`);
71
+ // GR.1/GR.3 — additive claim + wedge columns for a pre-existing wg_issues (idempotent; already-migrated throws).
72
+ for (const ddl of [
73
+ `ALTER TABLE wg_issues ADD COLUMN claim_token TEXT`,
74
+ `ALTER TABLE wg_issues ADD COLUMN claim_audience TEXT`,
75
+ `ALTER TABLE wg_issues ADD COLUMN claim_expires_at TEXT`,
76
+ `ALTER TABLE wg_issues ADD COLUMN wedge_reason TEXT`,
77
+ ]) {
78
+ try {
79
+ await client.execute(ddl);
80
+ }
81
+ catch {
82
+ /* column already exists */
83
+ }
84
+ }
45
85
  await client.execute(`DROP TABLE IF EXISTS wg_events;`); // clean cutover from the 1c state-primary store
46
86
  }
47
87
  export function workGraphStore(opts) {
@@ -131,11 +171,45 @@ export function workGraphStore(opts) {
131
171
  await appendOp(fromId, 'dep_added', { from: fromId, to: toId, type });
132
172
  },
133
173
  async listReady() {
134
- const rs = await db().execute(`SELECT * FROM wg_issues WHERE status = 'open' AND id NOT IN (
135
- SELECT e.to_id FROM wg_edges e JOIN wg_issues x ON x.id = e.from_id
136
- WHERE e.type = 'blocks' AND x.status != 'closed') ORDER BY created_at`);
174
+ // Open, unblocked, AND not live-claimed. A claim with claim_expires_at <= now is treated as
175
+ // unclaimed (query-time expiry no reaper). ISO-8601 UTC sorts lexically == chronologically.
176
+ const now = new Date().toISOString();
177
+ const rs = await db().execute({
178
+ sql: `SELECT * FROM wg_issues WHERE status = 'open'
179
+ AND (claim_token IS NULL OR claim_expires_at <= ?)
180
+ AND wedge_reason IS NULL
181
+ AND id NOT IN (
182
+ SELECT e.to_id FROM wg_edges e JOIN wg_issues x ON x.id = e.from_id
183
+ WHERE e.type = 'blocks' AND x.status != 'closed') ORDER BY created_at`,
184
+ args: [now],
185
+ });
137
186
  return rs.rows.map(rowToIssue);
138
187
  },
188
+ async wedgeMark(id, reason) {
189
+ if ((await getIssue(id)) === null)
190
+ throw new Error(`workgraph: no issue ${id}`);
191
+ await appendOp(id, 'wedge_marked', { reason });
192
+ },
193
+ async clearWedge(id) {
194
+ if ((await getIssue(id)) === null)
195
+ throw new Error(`workgraph: no issue ${id}`);
196
+ await appendOp(id, 'wedge_cleared', {});
197
+ },
198
+ async claimIssue(id, audience, ttlSec) {
199
+ if ((await getIssue(id)) === null)
200
+ throw new Error(`workgraph: no issue ${id}`);
201
+ const expiresAt = new Date(Date.now() + ttlSec * 1000).toISOString();
202
+ // Unique per attempt → robust read-back (no two claims collide even at the same ms/expiry).
203
+ const claimToken = 'clm-' +
204
+ createHash('sha256')
205
+ .update(`${id}\n${String(Date.now())}\n${String(Math.random())}`)
206
+ .digest('hex')
207
+ .slice(0, 16);
208
+ await appendOp(id, 'claim_acquired', { claimToken, audience, expiresAt });
209
+ // applyOp ran the conditional CAS; we won iff OUR token is the one that landed.
210
+ const cur = await getIssue(id);
211
+ return { won: cur?.claimToken === claimToken, expiresAt };
212
+ },
139
213
  async listEvents(issueId) {
140
214
  const rs = await db().execute({
141
215
  sql: 'SELECT id, issue_id, lamport, type, payload FROM wg_ops WHERE issue_id = ? ORDER BY lamport, id',