@eventmodelers/cli 0.0.17 → 0.0.19
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.
- package/cli.js +40 -2
- package/package.json +1 -1
- package/shared/build-kit/lib/ralph.js +26 -1
package/cli.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { execSync, spawn } from 'child_process';
|
|
18
18
|
import { createInterface, emitKeypressEvents, moveCursor, clearScreenDown } from 'readline';
|
|
19
19
|
import { homedir } from 'os';
|
|
20
|
+
import { randomUUID } from 'crypto';
|
|
20
21
|
|
|
21
22
|
const __filename = fileURLToPath(import.meta.url);
|
|
22
23
|
const __dirname = dirname(__filename);
|
|
@@ -437,6 +438,23 @@ function readJsonSafe(path) {
|
|
|
437
438
|
}
|
|
438
439
|
}
|
|
439
440
|
|
|
441
|
+
// Distinguishes this agent process from any other agent pinging the same
|
|
442
|
+
// token/board — e.g. a build-kit and a modeling-kit install in the same project
|
|
443
|
+
// share one root config.json, and without a per-agent id both would upsert the
|
|
444
|
+
// same alive row and race each other. Written to the kit's OWN config.json
|
|
445
|
+
// (inside kitDir, not the shared root one credentials live in) so a build agent
|
|
446
|
+
// and a modeling agent never end up with the same id, and persisted so restarts
|
|
447
|
+
// of this same kit keep reporting under the same identity.
|
|
448
|
+
function ensureAgentId(kitDir) {
|
|
449
|
+
const kitConfigPath = join(kitDir, '.eventmodelers', 'config.json');
|
|
450
|
+
const existing = readJsonSafe(kitConfigPath);
|
|
451
|
+
if (existing.agentId) return existing.agentId;
|
|
452
|
+
const agentId = randomUUID();
|
|
453
|
+
mkdirSync(dirname(kitConfigPath), { recursive: true });
|
|
454
|
+
writeFileSync(kitConfigPath, JSON.stringify({ ...existing, agentId }, null, 2));
|
|
455
|
+
return agentId;
|
|
456
|
+
}
|
|
457
|
+
|
|
440
458
|
// Hierarchical resolution: a shared config higher up the directory tree (e.g. the
|
|
441
459
|
// project root's own .eventmodelers/config.json, or ~/.eventmodelers/config.json for
|
|
442
460
|
// defaults shared across every project) provides the base values — this is where
|
|
@@ -828,6 +846,7 @@ async function runModeling(kitDir, projectDir) {
|
|
|
828
846
|
const { createClient } = await import('@supabase/supabase-js');
|
|
829
847
|
|
|
830
848
|
const local = loadLocalConfig(kitDir);
|
|
849
|
+
local.agentId = local.agentId ?? ensureAgentId(kitDir);
|
|
831
850
|
if (!local.token || !local.organizationId) {
|
|
832
851
|
console.error('❌ --modeling needs platform credentials in .eventmodelers/config.json (token + organizationId) — run `/connect` once or paste your config first.');
|
|
833
852
|
process.exit(1);
|
|
@@ -873,6 +892,25 @@ async function runModeling(kitDir, projectDir) {
|
|
|
873
892
|
let stdoutBuffer = '';
|
|
874
893
|
let pending = null; // one in-flight turn at a time
|
|
875
894
|
|
|
895
|
+
// Bare tool names (`→ Bash`, `→ Skill`) tell you nothing happened worth
|
|
896
|
+
// reading — this pulls out the one input field that actually says what the
|
|
897
|
+
// tool did, so the trace is skimmable without the interactive TUI.
|
|
898
|
+
function describeToolUse(block) {
|
|
899
|
+
const input = block.input ?? {};
|
|
900
|
+
switch (block.name) {
|
|
901
|
+
case 'Bash': return `Bash: ${input.command}`;
|
|
902
|
+
case 'Skill': return `Skill: ${input.skill}${input.args ? ` ${input.args}` : ''}`;
|
|
903
|
+
case 'Read': return `Read: ${input.file_path}`;
|
|
904
|
+
case 'Edit': return `Edit: ${input.file_path}`;
|
|
905
|
+
case 'Write': return `Write: ${input.file_path}`;
|
|
906
|
+
case 'Grep': return `Grep: ${input.pattern}`;
|
|
907
|
+
case 'Glob': return `Glob: ${input.pattern}`;
|
|
908
|
+
case 'WebFetch': return `WebFetch: ${input.url}`;
|
|
909
|
+
case 'Agent': return `Agent: ${input.description ?? input.subagent_type ?? ''}`;
|
|
910
|
+
default: return block.name;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
876
914
|
// stream-json output loses the normal interactive TUI (tool cards, live diffs) —
|
|
877
915
|
// this is a plain-text approximation, good enough for a headless/voice runner.
|
|
878
916
|
function handleLine(line) {
|
|
@@ -883,7 +921,7 @@ async function runModeling(kitDir, projectDir) {
|
|
|
883
921
|
if (msg.type === 'assistant') {
|
|
884
922
|
for (const block of msg.message?.content ?? []) {
|
|
885
923
|
if (block.type === 'text' && block.text) log(block.text);
|
|
886
|
-
if (block.type === 'tool_use') log(`→ ${block
|
|
924
|
+
if (block.type === 'tool_use') log(`→ ${describeToolUse(block)}`);
|
|
887
925
|
}
|
|
888
926
|
return;
|
|
889
927
|
}
|
|
@@ -1001,7 +1039,7 @@ async function runModeling(kitDir, projectDir) {
|
|
|
1001
1039
|
const res = await fetch(`${cfg.baseUrl}/api/agent-alive`, {
|
|
1002
1040
|
method: 'POST',
|
|
1003
1041
|
headers: { Authorization: `Bearer ${realtimeToken}`, 'Content-Type': 'application/json' },
|
|
1004
|
-
body: JSON.stringify({ token: cfg.token, board_id: cfg.boardId, agent_type: 'MODELING' }),
|
|
1042
|
+
body: JSON.stringify({ token: cfg.token, board_id: cfg.boardId, agent_type: 'MODELING', agent_id: cfg.agentId }),
|
|
1005
1043
|
signal: AbortSignal.timeout(10_000),
|
|
1006
1044
|
});
|
|
1007
1045
|
if (!res.ok) log(`ping failed: ${res.status}`);
|
package/package.json
CHANGED
|
@@ -108,6 +108,30 @@ function hasCredentials(cfg) {
|
|
|
108
108
|
return !!(cfg.token && cfg.organizationId && cfg.boardId && cfg.baseUrl);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// Distinguishes this agent process from any other agent pinging the same
|
|
112
|
+
// token/board — e.g. a build-kit and a modeling-kit install in the same project
|
|
113
|
+
// share one root config.json, and without a per-agent id both would upsert the
|
|
114
|
+
// same alive row and race each other. Written to the kit's OWN config.json
|
|
115
|
+
// (inside kitDir, not the shared root one credentials live in) so a build agent
|
|
116
|
+
// and a modeling agent never end up with the same id, and persisted so restarts
|
|
117
|
+
// of this same kit keep reporting under the same identity.
|
|
118
|
+
function ensureAgentId(kitDir) {
|
|
119
|
+
const kitConfigPath = join(kitDir, '.eventmodelers', 'config.json');
|
|
120
|
+
let existing = {};
|
|
121
|
+
if (existsSync(kitConfigPath)) {
|
|
122
|
+
try {
|
|
123
|
+
existing = JSON.parse(readFileSync(kitConfigPath, 'utf-8'));
|
|
124
|
+
} catch {
|
|
125
|
+
console.warn(`[ralph] Skipping invalid config at ${kitConfigPath}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (existing.agentId) return existing.agentId;
|
|
129
|
+
const agentId = randomUUID();
|
|
130
|
+
mkdirSync(dirname(kitConfigPath), { recursive: true });
|
|
131
|
+
writeFileSync(kitConfigPath, JSON.stringify({ ...existing, agentId }, null, 2));
|
|
132
|
+
return agentId;
|
|
133
|
+
}
|
|
134
|
+
|
|
111
135
|
async function fetchPlatformConfig(local) {
|
|
112
136
|
const remote = await fetchJSON(`${local.baseUrl}/api/config`, {
|
|
113
137
|
headers: { 'x-token': local.token },
|
|
@@ -252,7 +276,7 @@ async function startRealtimeAgent(cfg, kitDir) {
|
|
|
252
276
|
const res = await fetch(`${cfg.baseUrl}/api/agent-alive`, {
|
|
253
277
|
method: 'POST',
|
|
254
278
|
headers: { Authorization: `Bearer ${realtimeToken}`, 'Content-Type': 'application/json' },
|
|
255
|
-
body: JSON.stringify({ token: cfg.token, board_id: cfg.boardId, agent_type: 'BUILD' }),
|
|
279
|
+
body: JSON.stringify({ token: cfg.token, board_id: cfg.boardId, agent_type: 'BUILD', agent_id: cfg.agentId }),
|
|
256
280
|
signal: AbortSignal.timeout(10_000),
|
|
257
281
|
});
|
|
258
282
|
if (!res.ok) console.error(`[agent] Ping failed: ${res.status}`);
|
|
@@ -357,6 +381,7 @@ export { loadLocalConfig, fetchPlatformConfig, retryOn401, startRealtimeAgent };
|
|
|
357
381
|
|
|
358
382
|
export async function startRalph({ kitDir, projectDir, onTask, onPlannedSlice }) {
|
|
359
383
|
const local = loadLocalConfig(kitDir);
|
|
384
|
+
local.agentId = local.agentId ?? ensureAgentId(kitDir);
|
|
360
385
|
|
|
361
386
|
console.log(`Ralph — kit: ${kitDir}`);
|
|
362
387
|
console.log(` project: ${projectDir}`);
|