@eventmodelers/cli 1.0.163 → 2.0.2

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 (128) hide show
  1. package/README.md +48 -36
  2. package/RELEASE_NOTES.md +20 -2
  3. package/cli.js +774 -247
  4. package/lib/adapters/spec-kitty-adapter.js +3 -7
  5. package/lib/build-kits.js +23 -0
  6. package/lib/global-agent-id.js +45 -0
  7. package/lib/modeling-local-ai.js +4 -2
  8. package/lib/scaffold-model.js +71 -0
  9. package/lib/scaffold.js +224 -0
  10. package/lib/supervise.js +60 -0
  11. package/lib/ui-baseline.js +123 -0
  12. package/package.json +1 -1
  13. package/shared/build-kit/README.md +4 -19
  14. package/shared/build-kit/lib/agent-lock.js +75 -0
  15. package/shared/build-kit/lib/agent-name.js +27 -0
  16. package/shared/build-kit/lib/event-prune.js +58 -0
  17. package/shared/build-kit/lib/events-view.js +134 -0
  18. package/shared/build-kit/lib/local-ai-agent.js +14 -26
  19. package/shared/build-kit/lib/mcp-register.js +17 -1
  20. package/shared/build-kit/lib/prompt-journal.js +191 -0
  21. package/shared/build-kit/lib/prompt-replay.js +35 -0
  22. package/shared/build-kit/lib/ralph.js +218 -169
  23. package/shared/build-kit/lib/slice-curation.js +40 -0
  24. package/shared/build-kit/lib/slice-events.js +93 -0
  25. package/shared/build-kit/lib/slice-git.js +86 -0
  26. package/shared/build-kit/lib/slice-learnings.js +197 -0
  27. package/shared/build-kit/lib/slice-projection.js +101 -0
  28. package/shared/build-kit/lib/slice-run.js +181 -0
  29. package/shared/build-kit/lib/slice-state.js +184 -0
  30. package/shared/build-kit/lib/slice-tasks.js +35 -0
  31. package/shared/build-kit/ralph-claude.js +4 -2
  32. package/shared/build-kit/ralph-exec.js +4 -2
  33. package/shared/build-kit/ralph-local-ai.js +5 -3
  34. package/shared/scaffold/LICENSE-em-scaffold +21 -0
  35. package/shared/scaffold/supabase/generate.mjs +290 -0
  36. package/shared/scaffold/supabase/template/scripts/create-user.mjs.tmpl +29 -0
  37. package/shared/scaffold/supabase/template/scripts/dev.mjs.tmpl +145 -0
  38. package/shared/scaffold/supabase/template/scripts/write-env.mjs.tmpl +44 -0
  39. package/shared/scaffold/supabase/template/server.ts.tmpl +168 -0
  40. package/shared/scaffold/supabase/template/src/common/extraEndpoints.ts.tmpl +5 -0
  41. package/shared/scaffold/supabase/template/src/common/notImplemented.test.ts.tmpl +58 -0
  42. package/shared/scaffold/supabase/template/src/common/notImplemented.ts.tmpl +29 -0
  43. package/shared/scaffold/supabase/template/supabase/migrations/_V0__supabase_stubs.sql.tmpl +34 -0
  44. package/shared/scaffold/supabase/template/web/src/App.tsx.tmpl +38 -0
  45. package/shared/scaffold/supabase/template/web/src/app/Layout.tsx.tmpl +48 -0
  46. package/shared/scaffold/supabase/template/web/src/app/NotFound.tsx.tmpl +12 -0
  47. package/shared/scaffold/supabase/template/web/src/app/SignIn.tsx.tmpl +42 -0
  48. package/shared/scaffold/supabase/template/web/src/app/TimelinePage.tsx.tmpl +73 -0
  49. package/shared/scaffold/supabase/template/web/src/app/pages.ts.tmpl +26 -0
  50. package/shared/scaffold/supabase/template/web/src/app/skeleton.css.tmpl +25 -0
  51. package/shared/scaffold/supabase/template/web/src/lib/NotBuilt.tsx.tmpl +12 -0
  52. package/shared/scaffold/supabase/template/web/src/lib/api.ts.tmpl +226 -0
  53. package/shared/scaffold/supabase/template/web/src/main.tsx.tmpl +13 -0
  54. package/shared/skills/learn-eventmodelers-api/SKILL.md +17 -4
  55. package/shared/skills/request-feedback/SKILL.md +1 -2
  56. package/shared/skills/ui-contract/SKILL.md +7 -5
  57. package/shared/skills/update-slice-status/SKILL.md +1 -1
  58. package/stacks/axon/templates/build-kit/CLAUDE.md +7 -6
  59. package/stacks/axon/templates/build-kit/lib/AGENT.md +6 -7
  60. package/stacks/axon/templates/build-kit/lib/backend-prompt.md +20 -42
  61. package/stacks/axon/templates/build-kit/lib/prompt.md +32 -41
  62. package/stacks/blank/templates/build-kit/CLAUDE.md +7 -6
  63. package/stacks/blank/templates/build-kit/lib/AGENT.md +6 -7
  64. package/stacks/blank/templates/build-kit/lib/backend-prompt.md +20 -37
  65. package/stacks/blank/templates/build-kit/lib/prompt.md +33 -42
  66. package/stacks/classic/templates/.claude/skills/build-automation/SKILL.md +1 -1
  67. package/stacks/classic/templates/.claude/skills/build-state-change/SKILL.md +1 -1
  68. package/stacks/classic/templates/.claude/skills/build-state-view/SKILL.md +2 -2
  69. package/stacks/classic/templates/.claude/skills/record-evidence/SKILL.md +2 -2
  70. package/stacks/classic/templates/build-kit/CLAUDE.md +9 -8
  71. package/stacks/classic/templates/build-kit/lib/AGENT.md +6 -7
  72. package/stacks/classic/templates/build-kit/lib/backend-prompt.md +20 -38
  73. package/stacks/classic/templates/build-kit/lib/prompt.md +33 -42
  74. package/stacks/kurrent/templates/build-kit/CLAUDE.md +7 -7
  75. package/stacks/kurrent/templates/build-kit/lib/AGENT.md +6 -7
  76. package/stacks/kurrent/templates/build-kit/lib/backend-prompt.md +20 -42
  77. package/stacks/kurrent/templates/build-kit/lib/prompt.md +32 -41
  78. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +1 -1
  79. package/stacks/modeling-kit/templates/.claude/skills/detect-model-drift/SKILL.md +1 -1
  80. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +2 -0
  81. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +7 -3
  82. package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +1 -1
  83. package/stacks/modeling-kit/templates/kit/CLAUDE-STANDALONE.md +3 -4
  84. package/stacks/modeling-kit/templates/kit/CLAUDE.md +18 -28
  85. package/stacks/modeling-kit/templates/kit/README.md +1 -1
  86. package/stacks/modeling-kit/templates/kit/lib/config.js +1 -1
  87. package/stacks/node/templates/build-kit/CLAUDE.md +7 -6
  88. package/stacks/node/templates/build-kit/lib/AGENT.md +6 -7
  89. package/stacks/node/templates/build-kit/lib/backend-prompt.md +20 -42
  90. package/stacks/node/templates/build-kit/lib/prompt.md +18 -41
  91. package/stacks/opencqrs/templates/build-kit/CLAUDE.md +7 -7
  92. package/stacks/opencqrs/templates/build-kit/lib/AGENT.md +6 -7
  93. package/stacks/opencqrs/templates/build-kit/lib/backend-prompt.md +20 -42
  94. package/stacks/opencqrs/templates/build-kit/lib/prompt.md +32 -41
  95. package/stacks/react/templates/.claude/skills/build-state-change/SKILL.md +1 -1
  96. package/stacks/react/templates/.claude/skills/build-state-view/SKILL.md +1 -1
  97. package/stacks/react/templates/build-kit/CLAUDE.md +7 -6
  98. package/stacks/react/templates/build-kit/lib/AGENT.md +6 -7
  99. package/stacks/react/templates/build-kit/lib/backend-prompt.md +25 -42
  100. package/stacks/react/templates/build-kit/lib/kit.json +1 -1
  101. package/stacks/react/templates/build-kit/lib/prompt.md +47 -43
  102. package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +15 -0
  103. package/stacks/supabase/templates/build-kit/CLAUDE.md +7 -6
  104. package/stacks/supabase/templates/build-kit/lib/AGENT.md +6 -7
  105. package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +20 -42
  106. package/stacks/supabase/templates/build-kit/lib/prompt.md +18 -41
  107. package/stacks/supabase-react/templates/.claude/skills/build-state-change/SKILL.md +80 -8
  108. package/stacks/supabase-react/templates/.claude/skills/build-state-view/SKILL.md +66 -13
  109. package/stacks/supabase-react/templates/build-kit/CLAUDE.md +8 -7
  110. package/stacks/supabase-react/templates/build-kit/lib/AGENT.md +6 -7
  111. package/stacks/supabase-react/templates/build-kit/lib/backend-prompt.md +25 -42
  112. package/stacks/supabase-react/templates/build-kit/lib/kit.json +1 -1
  113. package/stacks/supabase-react/templates/build-kit/lib/prompt.md +48 -44
  114. package/stacks/umadb/templates/build-kit/CLAUDE.md +7 -6
  115. package/stacks/umadb/templates/build-kit/lib/AGENT.md +6 -7
  116. package/stacks/umadb/templates/build-kit/lib/backend-prompt.md +20 -42
  117. package/stacks/umadb/templates/build-kit/lib/prompt.md +32 -41
  118. package/shared/bridge/spec-kitty/bridge-spec-kitty-specify/SKILL.md +0 -125
  119. package/shared/bridge/spec-kitty/bridge-spec-kitty-tasks/SKILL.md +0 -95
  120. package/shared/build-kit/lib/agent.sh +0 -20
  121. package/shared/build-kit/ralph.sh +0 -111
  122. package/shared/build-kit/realtime-agent.js +0 -20
  123. package/stacks/bridge/templates/bridge/lib/AGENT.md +0 -47
  124. package/stacks/bridge/templates/bridge/lib/prompt.md +0 -111
  125. package/stacks/bridge/templates/bridge/ralph-claude.js +0 -50
  126. package/stacks/bridge/templates/bridge/ralph-hook.js +0 -103
  127. package/stacks/bridge/templates/bridge/ralph-local-ai.js +0 -43
  128. package/stacks/bridge/templates/bridge/ralph-static.js +0 -90
@@ -1,47 +0,0 @@
1
- # Agent Learnings
2
-
3
- Patterns and gotchas discovered during task processing. Update this file
4
- whenever you encounter something reusable.
5
-
6
- ## tasks.json
7
-
8
- - Tasks are objects with `id`, `createdAt`, and `payload` (a
9
- `SliceChangedPayload`).
10
- - Unlike build-kit, every status change is queued (not just non-`Planned`
11
- ones) — see `queueAllStatuses` in `lib/ralph.js`.
12
- - After completing a task, remove it from the array entirely — do not add a
13
- status field.
14
- - Write `[]` to `tasks.json` if the last task is completed.
15
-
16
- ## SliceChangedPayload fields
17
-
18
- ```
19
- event always "slice:changed"
20
- organizationId org UUID or null
21
- boardId board UUID
22
- sliceId SLICE_BORDER node UUID
23
- sliceTitle human-readable slice name (may be null)
24
- sliceStatus e.g. "Created", "Planned", "InProgress", "Done" (may be null)
25
- timestamp unix ms when the change was emitted
26
- ```
27
-
28
- ## Bridge target
29
-
30
- - The active target framework lives in `.bridge-kit/bridge.json`'s `target`
31
- field, written at `init --bridge --target <name>` time. This file is
32
- committed (unlike `.eventmodelers/config.json`, which is gitignored) since
33
- it's project policy shared by every teammate and CI runner, not a
34
- per-machine credential.
35
- - Skill naming convention: `bridge-<target>-specify` (kept in sync every
36
- task) and `bridge-<target>-tasks` (invoked separately, by that framework's
37
- own task-planning phase — not from this loop).
38
-
39
- ## Executors
40
-
41
- - Claude (`ralph-claude.js`, this prompt) is the default. `bridge --local-ai`
42
- swaps in a local model instead — same prompt, different executor.
43
- - `bridge --hook "<command>"` (or a `hookCommand` persisted in
44
- `bridge.json`) bypasses this prompt entirely: `ralph-hook.js` runs an
45
- arbitrary shell command per batch of changes instead of any AI agent — e.g.
46
- commit + push `.slices/` and let a CI pipeline do the actual translation.
47
- If you're reading this file, a hook wasn't configured for this run.
@@ -1,111 +0,0 @@
1
- # Bridge Task Instructions
2
-
3
- You are an autonomous agent reacting to slice status change events on an
4
- Eventmodelers board. Unlike a build-kit agent, you do **not** write
5
- application code — you translate the board's event model into artifacts for
6
- another spec framework (e.g. Spec Kitty), keeping that framework's files in
7
- sync with the board as it changes.
8
-
9
- ## Your Loop
10
-
11
- 1. Read `AGENT.md` to load accumulated learnings before doing anything else.
12
- 2. Read `.bridge-kit/tasks.json`.
13
- 3. If `tasks.json` is empty or missing, reply with:
14
- <promise>IDLE</promise>
15
- and stop.
16
- 4. Pick the **oldest task** (earliest `createdAt`).
17
- 5. Execute the task — see the Execution section below.
18
- 6. After execution, remove that task from the array and write
19
- `.bridge-kit/tasks.json` back.
20
- 7. Append a progress entry to `progress.txt` (create if missing).
21
- 8. Update `AGENT.md` with any new reusable learnings discovered this
22
- iteration.
23
- 9. Reply normally so the next iteration can pick up the next task.
24
-
25
- ## Execution
26
-
27
- Each task has a single `payload` of type `SliceChangedPayload`:
28
-
29
- ```
30
- {
31
- event: "slice:changed"
32
- organizationId: string | null
33
- boardId: string
34
- sliceId: string ← SLICE_BORDER node UUID
35
- sliceTitle: string | null
36
- sliceStatus: string | null ← e.g. "Planned", "InProgress", "Done"
37
- timestamp: number
38
- }
39
- ```
40
-
41
- Unlike a build-kit agent, a bridge agent reacts to **every** status change
42
- (including `Planned`) — a task is queued regardless of `sliceStatus`. There
43
- is no separate "claim and build" step, so don't invoke `/update-slice-status`
44
- here; translation doesn't take ownership of a slice the way building does.
45
-
46
- ### Step 1 — Load credentials
47
-
48
- Run `/connect` to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL` from
49
- `.eventmodelers/config.json`.
50
-
51
- ### Step 2 — Resolve the bridge target
52
-
53
- Read `.bridge-kit/bridge.json`'s `target` field (e.g. `"spec-kitty"`). The
54
- matching translation skill is named `bridge-<target>-specify`.
55
-
56
- ### Step 3 — Translate
57
-
58
- Invoke the `bridge-<target>-specify` skill. It reads `.slices/` (written by
59
- `npx @eventmodelers/cli listen`, which must be running separately — see that
60
- skill's own guardrail if `.slices/` doesn't exist yet) and regenerates that
61
- framework's spec artifacts **wholesale** from the current board state. Do
62
- not hand-author or patch those artifacts yourself — if they're wrong, the
63
- event model is wrong; fix it on the board and let the next slice change
64
- re-trigger this skill.
65
-
66
- Do **not** also invoke `bridge-<target>-tasks` from this loop. That
67
- companion skill enforces the 1:1 slice-to-work-package mapping during that
68
- framework's own task-planning phase (e.g. Spec Kitty's
69
- `/spec-kitty.tasks-outline`) — it's triggered by that framework's own
70
- tooling when the user reaches that phase, not by every board change.
71
-
72
- ## Updating tasks.json
73
-
74
- After completing a task, remove it from the array and write the updated
75
- array back to `.bridge-kit/tasks.json`. If the array is now empty, write
76
- `[]`.
77
-
78
- ## Progress Report Format
79
-
80
- APPEND to `progress.txt` (never replace):
81
- ```
82
- ## [ISO timestamp] — Task [task.id]
83
-
84
- Slice: [sliceTitle] ([sliceId])
85
- Status change: [sliceStatus]
86
-
87
- Action taken:
88
- - [what was translated / regenerated in response to the slice change]
89
-
90
- Learnings:
91
- - [any patterns, gotchas, or reusable knowledge discovered]
92
- ---
93
- ```
94
-
95
- ## Stop Condition
96
-
97
- If `.bridge-kit/tasks.json` is empty (`[]`) or does not exist, reply with:
98
- <promise>IDLE</promise>
99
-
100
- ## Updating AGENT.md
101
-
102
- After completing a task, add any **reusable** learnings to `AGENT.md` —
103
- patterns, gotchas, or skill behaviour that future iterations should know.
104
- Only add things that are general and applicable beyond this single task. Do
105
- not duplicate what is already there.
106
-
107
- ## Important
108
-
109
- - Process **one task per iteration**.
110
- - Read `AGENT.md` first — it contains patterns from previous iterations.
111
- - Always start with `/connect` if credentials are not yet loaded.
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env node
2
- // Bridge loop using Claude Code as the executor. Unlike build-kit's
3
- // ralph-claude.js, there is no onPlannedSlice consumer — a bridge agent
4
- // doesn't "build" a Planned slice, it just translates every slice change as
5
- // it arrives via tasks.json (see lib/prompt.md and queueAllStatuses below).
6
- // Usage: node ralph-claude.js [project_dir]
7
-
8
- import { startRalph, loadLocalConfig } from './lib/ralph.js';
9
- import { spawn } from 'child_process';
10
- import { dirname, resolve } from 'path';
11
- import { fileURLToPath } from 'url';
12
-
13
- const kitDir = dirname(fileURLToPath(import.meta.url));
14
- const projectDir = process.argv[2] ? resolve(process.argv[2]) : resolve(kitDir, '..');
15
-
16
- const cfg = loadLocalConfig(kitDir);
17
- const inlineHeader = cfg.boardId
18
- ? `board=${cfg.boardId} token=${cfg.token} org=${cfg.organizationId} baseUrl=${cfg.baseUrl}\n\n`
19
- : '';
20
-
21
- const claudeArgs = ['--dangerously-skip-permissions'];
22
- if (cfg.model) claudeArgs.push('--model', cfg.model);
23
- const claudeEnv = cfg.anthropicBaseUrl
24
- ? { ...process.env, ANTHROPIC_BASE_URL: cfg.anthropicBaseUrl }
25
- : process.env;
26
-
27
- function runClaude(prompt) {
28
- return new Promise((resolve, reject) => {
29
- // Prompt on stdin, not as a `-p` argument — Windows cuts a multi-line argv entry at its first newline.
30
- const proc = spawn('claude', [...claudeArgs, '-p'], {
31
- cwd: projectDir,
32
- stdio: ['pipe', 'inherit', 'inherit'],
33
- env: claudeEnv,
34
- });
35
- proc.stdin.end(inlineHeader + prompt);
36
- proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`Claude exited ${code}`))));
37
- proc.on('error', reject);
38
- });
39
- }
40
-
41
- startRalph({
42
- kitDir,
43
- projectDir,
44
- onTask: runClaude,
45
- agentType: 'BRIDGE',
46
- queueAllStatuses: true,
47
- }).catch((err) => {
48
- console.error('[ralph] Fatal:', err);
49
- process.exit(1);
50
- });
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env node
2
- // Bridge loop that hands each batch of slice changes to an arbitrary external
3
- // command instead of an AI agent — e.g. commit + push .slices/ and let a CI
4
- // pipeline take it from there. No Claude/Ollama call happens in this mode.
5
- //
6
- // Configure the hook with `bridge --hook "<command>"` (one-off) or persist a
7
- // default with `init --bridge --target <name> --hook "<command>"`.
8
- //
9
- // Usage: node ralph-hook.js [project_dir]
10
- // BRIDGE_HOOK_CMD="git add .slices && git commit -m sync && git push" node ralph-hook.js
11
-
12
- import { startRalph } from './lib/ralph.js';
13
- import { spawn } from 'child_process';
14
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
15
- import { dirname, join, resolve } from 'path';
16
- import { fileURLToPath } from 'url';
17
-
18
- const kitDir = dirname(fileURLToPath(import.meta.url));
19
- const projectDir = process.argv[2] ? resolve(process.argv[2]) : resolve(kitDir, '..');
20
-
21
- // bridge.json (not .eventmodelers/config.json) — a plain, committed sibling
22
- // file, since target/hookCommand are project policy meant to be shared with
23
- // every teammate and CI runner, not gitignored per-machine state.
24
- function loadBridgeConfig() {
25
- const p = join(kitDir, 'bridge.json');
26
- if (!existsSync(p)) return {};
27
- try { return JSON.parse(readFileSync(p, 'utf-8')); } catch { return {}; }
28
- }
29
-
30
- const hookCmd = process.env.BRIDGE_HOOK_CMD || loadBridgeConfig().hookCommand;
31
- if (!hookCmd) {
32
- console.error('[bridge-hook] No hook command configured.');
33
- console.error(' Set one for this run: eventmodelers bridge --hook "<command>"');
34
- console.error(' Or persist a default: eventmodelers init --bridge --target <name> --hook "<command>"');
35
- process.exit(1);
36
- }
37
-
38
- const tasksPath = join(kitDir, 'tasks.json');
39
-
40
- function readTasks() {
41
- try {
42
- return JSON.parse(readFileSync(tasksPath, 'utf-8'));
43
- } catch {
44
- return [];
45
- }
46
- }
47
-
48
- // Batched, not one-task-at-a-time: a hook like "commit + push .slices/" acts
49
- // on the whole current board export in one shot (already fresh — lib/ralph.js
50
- // re-syncs .slices/ before every task is queued), not on a single slice's
51
- // translation the way an AI agent does. Only the tasks present at invocation
52
- // time are cleared afterward — anything the realtime agent queues *while* the
53
- // hook is still running is left in place for the next tick, so a slice change
54
- // arriving mid-run is never silently dropped.
55
- function runHook() {
56
- const batch = readTasks();
57
- if (!batch.length) return Promise.resolve();
58
-
59
- const batchFilePath = join(kitDir, 'last-hook-batch.json');
60
- mkdirSync(kitDir, { recursive: true });
61
- writeFileSync(batchFilePath, JSON.stringify(batch, null, 2));
62
-
63
- const latest = batch[batch.length - 1]?.payload ?? {};
64
-
65
- return new Promise((resolvePromise, reject) => {
66
- console.log(`[bridge-hook] Running hook for ${batch.length} change(s): ${hookCmd}`);
67
- const proc = spawn(hookCmd, {
68
- cwd: projectDir,
69
- shell: true,
70
- stdio: 'inherit',
71
- env: {
72
- ...process.env,
73
- BRIDGE_BATCH_FILE: batchFilePath,
74
- BRIDGE_TASK_COUNT: String(batch.length),
75
- BRIDGE_SLICE_ID: latest.sliceId ?? '',
76
- BRIDGE_SLICE_TITLE: latest.sliceTitle ?? '',
77
- BRIDGE_SLICE_STATUS: latest.sliceStatus ?? '',
78
- BRIDGE_BOARD_ID: latest.boardId ?? '',
79
- BRIDGE_ORGANIZATION_ID: latest.organizationId ?? '',
80
- },
81
- });
82
- proc.on('close', (code) => {
83
- if (code !== 0) return reject(new Error(`hook exited ${code}`));
84
- const handledIds = new Set(batch.map((t) => t.id));
85
- const remaining = readTasks().filter((t) => !handledIds.has(t.id));
86
- writeFileSync(tasksPath, JSON.stringify(remaining, null, 2), 'utf-8');
87
- resolvePromise();
88
- });
89
- proc.on('error', reject);
90
- });
91
- }
92
-
93
- startRalph({
94
- kitDir,
95
- projectDir,
96
- onTask: runHook,
97
- // onPlannedSlice omitted — see stacks/bridge/templates/bridge/ralph-claude.js
98
- agentType: 'BRIDGE',
99
- queueAllStatuses: true,
100
- }).catch((err) => {
101
- console.error('[ralph] Fatal:', err);
102
- process.exit(1);
103
- });
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env node
2
- // Bridge loop using a local AI model as the executor. Same caveats as
3
- // build-kit's ralph-local-ai.js — lib/local-ai-agent.js is shared as-is (see
4
- // useShared in cli.js), unmodified for bridge.
5
- // Backend is selected by dialect, not by a separate runner: Ollama (native
6
- // /api/chat) or any OpenAI-compatible server (vLLM, LM Studio, llama.cpp, TGI).
7
- //
8
- // Usage: node ralph-local-ai.js [project_dir]
9
- // LOCAL_AI_TARGET=ollama node ralph-local-ai.js # run `ollama serve` first
10
- // LOCAL_AI_TARGET=vllm node ralph-local-ai.js
11
- // LOCAL_AI_URL=http://gpu-box:8000/v1 LOCAL_AI_MODEL=Qwen/Qwen3-8B node ralph-local-ai.js
12
- import { startRalph } from './lib/ralph.js';
13
- import { spawn } from 'child_process';
14
- import { dirname, join, resolve } from 'path';
15
- import { fileURLToPath } from 'url';
16
-
17
- const kitDir = dirname(fileURLToPath(import.meta.url));
18
- const projectDir = process.argv[2] ? resolve(process.argv[2]) : resolve(kitDir, '..');
19
-
20
-
21
- function runLocalAi() {
22
- return new Promise((resolve, reject) => {
23
- const proc = spawn('node', [join(kitDir, 'lib', 'local-ai-agent.js')], {
24
- cwd: projectDir,
25
- stdio: 'inherit',
26
- env: process.env,
27
- });
28
- proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`local-ai-agent exited ${code}`))));
29
- proc.on('error', reject);
30
- });
31
- }
32
-
33
- startRalph({
34
- kitDir,
35
- projectDir,
36
- onTask: runLocalAi,
37
- // onPlannedSlice omitted — local-ai-agent manages its own task queue
38
- agentType: 'BRIDGE',
39
- queueAllStatuses: true,
40
- }).catch((err) => {
41
- console.error('[ralph] Fatal:', err);
42
- process.exit(1);
43
- });
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
- // Bridge loop that hands each batch of slice changes to a deterministic JS
3
- // adapter instead of an AI agent or an arbitrary shell hook — no LLM call
4
- // happens in this mode. Which adapter runs is picked by bridge.json's target
5
- // (adapters/<target>-adapter.js); if the installed target has no adapter file
6
- // yet, this exits with a clear error rather than silently doing nothing.
7
- //
8
- // Usage: node ralph-static.js [project_dir]
9
-
10
- import { startRalph, loadLocalConfig, fetchPlatformConfig } from './lib/ralph.js';
11
- import { existsSync, readFileSync } from 'fs';
12
- import { dirname, join, resolve } from 'path';
13
- import { fileURLToPath, pathToFileURL } from 'url';
14
-
15
- const kitDir = dirname(fileURLToPath(import.meta.url));
16
- const projectDir = process.argv[2] ? resolve(process.argv[2]) : resolve(kitDir, '..');
17
-
18
- function loadBridgeConfig() {
19
- const p = join(kitDir, 'bridge.json');
20
- if (!existsSync(p)) return {};
21
- try {
22
- return JSON.parse(readFileSync(p, 'utf-8'));
23
- } catch {
24
- return {};
25
- }
26
- }
27
-
28
- const target = loadBridgeConfig().target;
29
- if (!target) {
30
- console.error('[bridge-static] No target configured in bridge.json — run `eventmodelers init --bridge --target <name>` first.');
31
- process.exit(1);
32
- }
33
-
34
- const adapterPath = join(kitDir, 'adapters', `${target}-adapter.js`);
35
- if (!existsSync(adapterPath)) {
36
- console.error(`[bridge-static] No static adapter for target "${target}" (expected ${adapterPath}).`);
37
- console.error(' Use the default Claude runner for this target instead: `eventmodelers bridge`.');
38
- process.exit(1);
39
- }
40
-
41
- const local = loadLocalConfig(kitDir);
42
-
43
- // The adapter itself doesn't know about the bridge loop's .slices/ convention
44
- // (fetch --spec-kitty calls the same run() with a context name of its own) —
45
- // this is the one place that convention still applies, so resolve it here.
46
- function readCurrentContext() {
47
- const ctxPath = join(kitDir, '.slices', 'current_context.json');
48
- if (!existsSync(ctxPath)) return null;
49
- try {
50
- return JSON.parse(readFileSync(ctxPath, 'utf-8')).name || null;
51
- } catch {
52
- return null;
53
- }
54
- }
55
-
56
- async function runAdapter() {
57
- const contextName = readCurrentContext();
58
- if (!contextName) {
59
- console.log('[bridge-static] No .slices/current_context.json yet — waiting for the first board sync.');
60
- return;
61
- }
62
-
63
- const { run } = await import(pathToFileURL(adapterPath).href);
64
- const cfg = await fetchPlatformConfig(local);
65
- try {
66
- await run({ cfg, projectDir, contextName });
67
- } catch (err) {
68
- // lib/ralph.js retries any onTask failure after 60s forever — right for
69
- // transient errors (network blips, a slow spec-kitty command), wrong for
70
- // a missing one-time setup step that retrying can never fix on its own.
71
- // Adapters flag those with `err.fatal` so we stop instead of looping.
72
- if (err.fatal) {
73
- console.error(`[bridge-static] ${err.message}`);
74
- process.exit(1);
75
- }
76
- throw err;
77
- }
78
- }
79
-
80
- startRalph({
81
- kitDir,
82
- projectDir,
83
- onTask: runAdapter,
84
- // onPlannedSlice omitted — see ralph-claude.js in this same directory.
85
- agentType: 'BRIDGE',
86
- queueAllStatuses: true,
87
- }).catch((err) => {
88
- console.error('[ralph] Fatal:', err);
89
- process.exit(1);
90
- });