oh-my-codex 0.10.2 → 0.10.3
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/README.de.md +4 -4
- package/README.es.md +4 -4
- package/README.fr.md +4 -4
- package/README.it.md +4 -4
- package/README.ja.md +4 -4
- package/README.ko.md +4 -4
- package/README.md +13 -7
- package/README.pt.md +4 -4
- package/README.ru.md +4 -4
- package/README.tr.md +4 -4
- package/README.vi.md +4 -4
- package/README.zh-TW.md +4 -4
- package/README.zh.md +4 -4
- package/dist/agents/__tests__/native-config.test.js +37 -33
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/__tests__/skill-bridge.test.d.ts +2 -0
- package/dist/agents/__tests__/skill-bridge.test.d.ts.map +1 -0
- package/dist/agents/__tests__/skill-bridge.test.js +71 -0
- package/dist/agents/__tests__/skill-bridge.test.js.map +1 -0
- package/dist/agents/native-config.d.ts +18 -6
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +109 -92
- package/dist/agents/native-config.js.map +1 -1
- package/dist/agents/skill-bridge.d.ts +20 -0
- package/dist/agents/skill-bridge.d.ts.map +1 -0
- package/dist/agents/skill-bridge.js +150 -0
- package/dist/agents/skill-bridge.js.map +1 -0
- package/dist/autoresearch/__tests__/contracts.test.js +37 -1
- package/dist/autoresearch/__tests__/contracts.test.js.map +1 -1
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +10 -10
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +1 -1
- package/dist/autoresearch/__tests__/runtime.test.js +2 -2
- package/dist/autoresearch/__tests__/runtime.test.js.map +1 -1
- package/dist/autoresearch/contracts.d.ts.map +1 -1
- package/dist/autoresearch/contracts.js +17 -10
- package/dist/autoresearch/contracts.js.map +1 -1
- package/dist/autoresearch/runtime.d.ts.map +1 -1
- package/dist/autoresearch/runtime.js +71 -96
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js +2 -0
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/agents.test.d.ts +2 -0
- package/dist/cli/__tests__/agents.test.d.ts.map +1 -0
- package/dist/cli/__tests__/agents.test.js +114 -0
- package/dist/cli/__tests__/agents.test.js.map +1 -0
- package/dist/cli/__tests__/autoresearch-guided.test.js +156 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js +195 -24
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/cleanup.test.d.ts +2 -0
- package/dist/cli/__tests__/cleanup.test.d.ts.map +1 -0
- package/dist/cli/__tests__/cleanup.test.js +213 -0
- package/dist/cli/__tests__/cleanup.test.js.map +1 -0
- package/dist/cli/__tests__/error-handling-warnings.test.js +1 -1
- package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +3 -3
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +521 -401
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/native-assets.test.js +72 -9
- package/dist/cli/__tests__/native-assets.test.js.map +1 -1
- package/dist/cli/__tests__/ralphthon.test.d.ts +2 -0
- package/dist/cli/__tests__/ralphthon.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralphthon.test.js +28 -0
- package/dist/cli/__tests__/ralphthon.test.js.map +1 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +36 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +35 -5
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +2 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +131 -161
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +10 -10
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +28 -2
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +1 -112
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +7 -20
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/agents-init.d.ts.map +1 -1
- package/dist/cli/agents-init.js +99 -95
- package/dist/cli/agents-init.js.map +1 -1
- package/dist/cli/agents.d.ts +14 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +261 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/autoresearch-guided.d.ts +8 -0
- package/dist/cli/autoresearch-guided.d.ts.map +1 -1
- package/dist/cli/autoresearch-guided.js +104 -37
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch-intake.d.ts +60 -0
- package/dist/cli/autoresearch-intake.d.ts.map +1 -0
- package/dist/cli/autoresearch-intake.js +318 -0
- package/dist/cli/autoresearch-intake.js.map +1 -0
- package/dist/cli/autoresearch.d.ts +3 -1
- package/dist/cli/autoresearch.d.ts.map +1 -1
- package/dist/cli/autoresearch.js +64 -10
- package/dist/cli/autoresearch.js.map +1 -1
- package/dist/cli/cleanup.d.ts +52 -0
- package/dist/cli/cleanup.d.ts.map +1 -0
- package/dist/cli/cleanup.js +302 -0
- package/dist/cli/cleanup.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +9 -37
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +5 -4
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +5 -7
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +610 -427
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/native-assets.d.ts +15 -1
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +134 -32
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +38 -1
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralphthon.d.ts +14 -0
- package/dist/cli/ralphthon.d.ts.map +1 -0
- package/dist/cli/ralphthon.js +234 -0
- package/dist/cli/ralphthon.js.map +1 -0
- package/dist/cli/setup.d.ts +1 -4
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +111 -76
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts +3 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +35 -16
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +1 -0
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/uninstall.d.ts +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +82 -64
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +10 -10
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +15 -0
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/generator.d.ts +0 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +53 -42
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +295 -230
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +49 -24
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.js +193 -0
- package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.js.map +1 -0
- package/dist/hooks/agents-overlay.d.ts +1 -1
- package/dist/hooks/agents-overlay.d.ts.map +1 -1
- package/dist/hooks/agents-overlay.js +109 -106
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/modes/base.d.ts +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +1 -1
- package/dist/modes/base.js.map +1 -1
- package/dist/ralphthon/__tests__/bootstrap.test.d.ts +2 -0
- package/dist/ralphthon/__tests__/bootstrap.test.d.ts.map +1 -0
- package/dist/ralphthon/__tests__/bootstrap.test.js +23 -0
- package/dist/ralphthon/__tests__/bootstrap.test.js.map +1 -0
- package/dist/ralphthon/__tests__/orchestrator.test.d.ts +2 -0
- package/dist/ralphthon/__tests__/orchestrator.test.d.ts.map +1 -0
- package/dist/ralphthon/__tests__/orchestrator.test.js +309 -0
- package/dist/ralphthon/__tests__/orchestrator.test.js.map +1 -0
- package/dist/ralphthon/__tests__/prd.test.d.ts +2 -0
- package/dist/ralphthon/__tests__/prd.test.d.ts.map +1 -0
- package/dist/ralphthon/__tests__/prd.test.js +133 -0
- package/dist/ralphthon/__tests__/prd.test.js.map +1 -0
- package/dist/ralphthon/bootstrap.d.ts +3 -0
- package/dist/ralphthon/bootstrap.d.ts.map +1 -0
- package/dist/ralphthon/bootstrap.js +84 -0
- package/dist/ralphthon/bootstrap.js.map +1 -0
- package/dist/ralphthon/orchestrator.d.ts +50 -0
- package/dist/ralphthon/orchestrator.d.ts.map +1 -0
- package/dist/ralphthon/orchestrator.js +362 -0
- package/dist/ralphthon/orchestrator.js.map +1 -0
- package/dist/ralphthon/prd.d.ts +191 -0
- package/dist/ralphthon/prd.d.ts.map +1 -0
- package/dist/ralphthon/prd.js +355 -0
- package/dist/ralphthon/prd.js.map +1 -0
- package/dist/ralphthon/runtime.d.ts +31 -0
- package/dist/ralphthon/runtime.d.ts.map +1 -0
- package/dist/ralphthon/runtime.js +104 -0
- package/dist/ralphthon/runtime.js.map +1 -0
- package/dist/ralphthon/tmux.d.ts +3 -0
- package/dist/ralphthon/tmux.d.ts.map +1 -0
- package/dist/ralphthon/tmux.js +39 -0
- package/dist/ralphthon/tmux.js.map +1 -0
- package/dist/subagents/__tests__/tracker.test.d.ts +2 -0
- package/dist/subagents/__tests__/tracker.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/tracker.test.js +47 -0
- package/dist/subagents/__tests__/tracker.test.js.map +1 -0
- package/dist/subagents/tracker.d.ts +52 -0
- package/dist/subagents/tracker.d.ts.map +1 -0
- package/dist/subagents/tracker.js +175 -0
- package/dist/subagents/tracker.js.map +1 -0
- package/dist/team/__tests__/worker-bootstrap.test.js +189 -163
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/__tests__/worktree.test.js +1 -1
- package/dist/team/__tests__/worktree.test.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +1 -1
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +58 -63
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/team/worktree.js +1 -1
- package/dist/team/worktree.js.map +1 -1
- package/dist/utils/__tests__/agents-md.test.d.ts +2 -0
- package/dist/utils/__tests__/agents-md.test.d.ts.map +1 -0
- package/dist/utils/__tests__/agents-md.test.js +32 -0
- package/dist/utils/__tests__/agents-md.test.js.map +1 -0
- package/dist/utils/__tests__/agents-model-table.test.d.ts +2 -0
- package/dist/utils/__tests__/agents-model-table.test.d.ts.map +1 -0
- package/dist/utils/__tests__/agents-model-table.test.js +84 -0
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.js +78 -83
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +10 -0
- package/dist/utils/agents-md.js.map +1 -1
- package/dist/utils/agents-model-table.d.ts +16 -0
- package/dist/utils/agents-model-table.d.ts.map +1 -0
- package/dist/utils/agents-model-table.js +83 -0
- package/dist/utils/agents-model-table.js.map +1 -0
- package/dist/utils/paths.d.ts +6 -6
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +31 -31
- package/dist/utils/paths.js.map +1 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +21 -3
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/dist/verification/__tests__/native-release-manifest.test.d.ts +2 -0
- package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +1 -0
- package/dist/verification/__tests__/native-release-manifest.test.js +80 -0
- package/dist/verification/__tests__/native-release-manifest.test.js.map +1 -0
- package/package.json +1 -1
- package/prompts/executor.md +15 -0
- package/scripts/__tests__/smoke-packed-install.test.mjs +137 -8
- package/scripts/eval-adaptive-sort-optimization.py +24 -0
- package/scripts/eval-in-action-cat-shellout-demo.js +31 -0
- package/scripts/eval-ml-kaggle-model-optimization.py +29 -0
- package/scripts/eval-noisy-bayesopt-highdim.py +44 -0
- package/scripts/eval-noisy-latent-subspace-discovery.py +44 -0
- package/scripts/generate-native-release-manifest.mjs +14 -3
- package/scripts/notify-fallback-watcher.js +308 -6
- package/scripts/notify-hook.js +20 -0
- package/scripts/run-autoresearch-showcase.sh +75 -0
- package/scripts/smoke-packed-install.mjs +142 -10
- package/skills/deep-interview/SKILL.md +30 -1
- package/skills/omx-setup/SKILL.md +2 -2
- package/skills/skill/SKILL.md +32 -32
- package/skills/team/SKILL.md +6 -0
- package/skills/worker/SKILL.md +2 -2
- package/templates/AGENTS.md +97 -16
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
import { appendFile, mkdir, readFile, readdir, stat, unlink, writeFile } from 'fs/promises';
|
|
5
|
-
import { spawnSync } from 'child_process';
|
|
5
|
+
import { spawn, spawnSync } from 'child_process';
|
|
6
6
|
import { dirname, join, resolve } from 'path';
|
|
7
7
|
import { homedir } from 'os';
|
|
8
8
|
import { drainPendingTeamDispatch } from './notify-hook/team-dispatch.js';
|
|
@@ -14,6 +14,9 @@ import {
|
|
|
14
14
|
resolveLeaderStalenessThresholdMs,
|
|
15
15
|
} from './notify-hook/team-leader-nudge.js';
|
|
16
16
|
import { DEFAULT_MARKER } from './tmux-hook-engine.js';
|
|
17
|
+
import { RalphthonOrchestrator } from '../dist/ralphthon/orchestrator.js';
|
|
18
|
+
import { readRalphthonPrd, writeRalphthonPrd } from '../dist/ralphthon/prd.js';
|
|
19
|
+
import { createRalphthonRuntimeState, readRalphthonRuntimeState, writeRalphthonRuntimeState } from '../dist/ralphthon/runtime.js';
|
|
17
20
|
|
|
18
21
|
function argValue(name, fallback = '') {
|
|
19
22
|
const idx = process.argv.indexOf(name);
|
|
@@ -83,6 +86,8 @@ const logPath = join(logsDir, `notify-fallback-${new Date().toISOString().split(
|
|
|
83
86
|
const RALPH_CONTINUE_TEXT = 'Ralph loop active continue';
|
|
84
87
|
const RALPH_CONTINUE_CADENCE_MS = 60_000;
|
|
85
88
|
const RALPH_TERMINAL_PHASES = new Set(['complete', 'failed', 'cancelled']);
|
|
89
|
+
const RALPHTHON_WATCHDOG_RESTART_LIMIT = 3;
|
|
90
|
+
const RALPHTHON_WATCHDOG_RESTART_WINDOW_MS = 5 * 60 * 1000;
|
|
86
91
|
|
|
87
92
|
const fileState = new Map();
|
|
88
93
|
const seenTurnKeys = new Set();
|
|
@@ -124,6 +129,17 @@ let lastParentGuard = {
|
|
|
124
129
|
state_path: '',
|
|
125
130
|
current_phase: '',
|
|
126
131
|
};
|
|
132
|
+
let lastRalphthonWatchdog = {
|
|
133
|
+
active: false,
|
|
134
|
+
restart_count: 0,
|
|
135
|
+
restart_window_started_at: '',
|
|
136
|
+
last_tick_at: null,
|
|
137
|
+
last_error: null,
|
|
138
|
+
last_result: null,
|
|
139
|
+
};
|
|
140
|
+
let ralphthonRestartWindowStartedAt = 0;
|
|
141
|
+
let ralphthonRestartCount = 0;
|
|
142
|
+
let ralphthonOrchestrator = null;
|
|
127
143
|
|
|
128
144
|
function eventLog(event) {
|
|
129
145
|
return appendFile(logPath, `${JSON.stringify({ timestamp: new Date().toISOString(), ...event })}\n`).catch(() => {});
|
|
@@ -161,9 +177,23 @@ async function loadPersistedWatcherState() {
|
|
|
161
177
|
.then((content) => JSON.parse(content))
|
|
162
178
|
.catch(() => null);
|
|
163
179
|
lastRalphContinueSteer = normalizeRalphContinueSteerState(persisted?.ralph_continue_steer);
|
|
180
|
+
if (persisted?.ralphthon_watchdog && typeof persisted.ralphthon_watchdog === 'object') {
|
|
181
|
+
lastRalphthonWatchdog = {
|
|
182
|
+
...lastRalphthonWatchdog,
|
|
183
|
+
...persisted.ralphthon_watchdog,
|
|
184
|
+
};
|
|
185
|
+
const persistedRestartCount = Number(persisted.ralphthon_watchdog.restart_count);
|
|
186
|
+
if (Number.isFinite(persistedRestartCount) && persistedRestartCount >= 0) {
|
|
187
|
+
ralphthonRestartCount = Math.floor(persistedRestartCount);
|
|
188
|
+
}
|
|
189
|
+
const persistedWindowStart = Date.parse(safeString(persisted.ralphthon_watchdog.restart_window_started_at));
|
|
190
|
+
if (Number.isFinite(persistedWindowStart) && persistedWindowStart > 0) {
|
|
191
|
+
ralphthonRestartWindowStartedAt = persistedWindowStart;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
164
194
|
}
|
|
165
195
|
|
|
166
|
-
async function
|
|
196
|
+
async function resolveActiveModeState(mode) {
|
|
167
197
|
const candidateDirs = [];
|
|
168
198
|
const sessionPath = join(stateDir, 'session.json');
|
|
169
199
|
try {
|
|
@@ -178,7 +208,7 @@ async function resolveActiveRalphState() {
|
|
|
178
208
|
if (!candidateDirs.includes(stateDir)) candidateDirs.push(stateDir);
|
|
179
209
|
|
|
180
210
|
for (const dir of candidateDirs) {
|
|
181
|
-
const path = join(dir,
|
|
211
|
+
const path = join(dir, `${mode}-state.json`);
|
|
182
212
|
if (!existsSync(path)) continue;
|
|
183
213
|
const parsed = await readFile(path, 'utf-8')
|
|
184
214
|
.then((content) => JSON.parse(content))
|
|
@@ -208,6 +238,14 @@ async function resolveActiveRalphState() {
|
|
|
208
238
|
};
|
|
209
239
|
}
|
|
210
240
|
|
|
241
|
+
async function resolveActiveRalphState() {
|
|
242
|
+
return resolveActiveModeState('ralph');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function resolveActiveRalphthonState() {
|
|
246
|
+
return resolveActiveModeState('ralphthon');
|
|
247
|
+
}
|
|
248
|
+
|
|
211
249
|
async function emitRalphContinueSteer(paneId, message) {
|
|
212
250
|
const markedText = `${message} ${DEFAULT_MARKER}`;
|
|
213
251
|
await new Promise((resolve) => {
|
|
@@ -226,6 +264,34 @@ async function emitRalphContinueSteer(paneId, message) {
|
|
|
226
264
|
}
|
|
227
265
|
}
|
|
228
266
|
|
|
267
|
+
function resolveSessionLeaderPaneId(sessionName) {
|
|
268
|
+
const normalized = safeString(sessionName).trim();
|
|
269
|
+
if (!normalized) return '';
|
|
270
|
+
const listed = spawnSync('tmux', ['list-panes', '-t', normalized, '-F', '#{pane_id}\t#{pane_start_command}\t#{pane_current_command}'], { encoding: 'utf-8' });
|
|
271
|
+
if (listed.status !== 0) return '';
|
|
272
|
+
const lines = safeString(listed.stdout).split('\n').map((line) => line.trim()).filter(Boolean);
|
|
273
|
+
for (const line of lines) {
|
|
274
|
+
const [paneId = '', startCommand = '', currentCommand = ''] = line.split('\t');
|
|
275
|
+
if (!paneId.startsWith('%')) continue;
|
|
276
|
+
const combined = `${startCommand} ${currentCommand}`.toLowerCase();
|
|
277
|
+
if (/\bomx(?:\.js)?\b/.test(combined) && /\bhud\b/.test(combined) && /--watch\b/.test(combined)) continue;
|
|
278
|
+
return paneId;
|
|
279
|
+
}
|
|
280
|
+
return '';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function resolveRalphthonPaneTarget(activeRalphthon) {
|
|
284
|
+
const state = activeRalphthon?.state && typeof activeRalphthon.state === 'object' ? activeRalphthon.state : {};
|
|
285
|
+
const leaderPaneId = safeString(state.leader_pane_id).trim();
|
|
286
|
+
if (leaderPaneId.startsWith('%')) return leaderPaneId;
|
|
287
|
+
const tmuxPaneId = safeString(state.tmux_pane_id).trim();
|
|
288
|
+
if (tmuxPaneId.startsWith('%')) return tmuxPaneId;
|
|
289
|
+
const sessionName = safeString(state.tmux_session).trim();
|
|
290
|
+
const sessionPane = resolveSessionLeaderPaneId(sessionName);
|
|
291
|
+
if (sessionPane) return sessionPane;
|
|
292
|
+
return '';
|
|
293
|
+
}
|
|
294
|
+
|
|
229
295
|
async function runRalphContinueSteerTick() {
|
|
230
296
|
const now = Date.now();
|
|
231
297
|
const nowIso = new Date(now).toISOString();
|
|
@@ -395,6 +461,9 @@ async function writeState(extra = {}) {
|
|
|
395
461
|
cadence_ms: RALPH_CONTINUE_CADENCE_MS,
|
|
396
462
|
message: RALPH_CONTINUE_TEXT,
|
|
397
463
|
},
|
|
464
|
+
ralphthon_watchdog: {
|
|
465
|
+
...lastRalphthonWatchdog,
|
|
466
|
+
},
|
|
398
467
|
...extra,
|
|
399
468
|
};
|
|
400
469
|
await writeFile(statePath, JSON.stringify(state, null, 2)).catch(() => {});
|
|
@@ -422,11 +491,13 @@ async function enforceLifecycleGuards() {
|
|
|
422
491
|
if (runOnce) return false;
|
|
423
492
|
if (parentIsGone()) {
|
|
424
493
|
const activeRalph = await resolveActiveRalphState();
|
|
425
|
-
|
|
426
|
-
|
|
494
|
+
const activeRalphthon = await resolveActiveRalphthonState();
|
|
495
|
+
const activeMode = activeRalph.active ? activeRalph : activeRalphthon;
|
|
496
|
+
if (activeMode.active) {
|
|
497
|
+
const currentPhase = safeString(activeMode.state?.current_phase);
|
|
427
498
|
const nextParentGuard = {
|
|
428
499
|
reason: 'parent_gone_deferred_for_active_ralph',
|
|
429
|
-
state_path:
|
|
500
|
+
state_path: activeMode.path,
|
|
430
501
|
current_phase: currentPhase,
|
|
431
502
|
};
|
|
432
503
|
if (
|
|
@@ -716,11 +787,216 @@ async function pumpTeamControlPlaneTick() {
|
|
|
716
787
|
await runLeaderNudgeTick();
|
|
717
788
|
}
|
|
718
789
|
|
|
790
|
+
|
|
791
|
+
async function updateRalphthonModePatch(patch) {
|
|
792
|
+
try {
|
|
793
|
+
const sessionPath = join(stateDir, 'session.json');
|
|
794
|
+
let stateFile = join(stateDir, 'ralphthon-state.json');
|
|
795
|
+
try {
|
|
796
|
+
const session = JSON.parse(await readFile(sessionPath, 'utf-8'));
|
|
797
|
+
const sessionId = safeString(session?.session_id).trim();
|
|
798
|
+
if (sessionId) {
|
|
799
|
+
const scoped = join(stateDir, 'sessions', sessionId, 'ralphthon-state.json');
|
|
800
|
+
if (existsSync(scoped)) stateFile = scoped;
|
|
801
|
+
}
|
|
802
|
+
} catch {}
|
|
803
|
+
|
|
804
|
+
if (!existsSync(stateFile)) return;
|
|
805
|
+
const parsed = JSON.parse(await readFile(stateFile, 'utf-8'));
|
|
806
|
+
const next = { ...parsed, ...patch };
|
|
807
|
+
await writeFile(stateFile, `${JSON.stringify(next, null, 2)}\n`);
|
|
808
|
+
} catch {}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
async function readActiveSessionId() {
|
|
812
|
+
try {
|
|
813
|
+
const session = JSON.parse(await readFile(join(stateDir, 'session.json'), 'utf-8'));
|
|
814
|
+
const sessionId = safeString(session?.session_id).trim();
|
|
815
|
+
return sessionId || 'ralphthon-watchdog';
|
|
816
|
+
} catch {
|
|
817
|
+
return 'ralphthon-watchdog';
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
async function notifyRalphthonWatchdogFailure(message) {
|
|
822
|
+
const sessionId = await readActiveSessionId();
|
|
823
|
+
try {
|
|
824
|
+
const { notifyLifecycle } = await import('../dist/notifications/index.js');
|
|
825
|
+
const result = await notifyLifecycle('session-stop', {
|
|
826
|
+
sessionId,
|
|
827
|
+
projectPath: cwd,
|
|
828
|
+
projectName: cwd.split('/').filter(Boolean).at(-1) || 'unknown',
|
|
829
|
+
activeMode: 'ralphthon',
|
|
830
|
+
reason: 'ralphthon_watchdog_restart_limit_reached',
|
|
831
|
+
tmuxTail: message,
|
|
832
|
+
contextSummary: message,
|
|
833
|
+
});
|
|
834
|
+
await eventLog({
|
|
835
|
+
type: 'ralphthon_alert_notification',
|
|
836
|
+
status: result ? 'delivered' : 'skipped',
|
|
837
|
+
session_id: sessionId,
|
|
838
|
+
message,
|
|
839
|
+
});
|
|
840
|
+
} catch (error) {
|
|
841
|
+
await eventLog({
|
|
842
|
+
type: 'ralphthon_alert_notification',
|
|
843
|
+
status: 'failed',
|
|
844
|
+
session_id: sessionId,
|
|
845
|
+
message,
|
|
846
|
+
error: error instanceof Error ? error.message : safeString(error),
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function shouldRestartRalphthonWatchdog(nowMs) {
|
|
852
|
+
if (!ralphthonRestartWindowStartedAt || (nowMs - ralphthonRestartWindowStartedAt) > RALPHTHON_WATCHDOG_RESTART_WINDOW_MS) {
|
|
853
|
+
ralphthonRestartWindowStartedAt = nowMs;
|
|
854
|
+
ralphthonRestartCount = 0;
|
|
855
|
+
}
|
|
856
|
+
return ralphthonRestartCount < RALPHTHON_WATCHDOG_RESTART_LIMIT;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
async function runRalphthonWatchdogTick() {
|
|
860
|
+
const now = Date.now();
|
|
861
|
+
const nowIso = new Date(now).toISOString();
|
|
862
|
+
const activeRalphthon = await resolveActiveRalphthonState();
|
|
863
|
+
const paneTarget = resolveRalphthonPaneTarget(activeRalphthon) || await resolveNudgePaneTarget(stateDir);
|
|
864
|
+
let runtime = await readRalphthonRuntimeState(cwd).catch(() => null);
|
|
865
|
+
|
|
866
|
+
if (!activeRalphthon.active) {
|
|
867
|
+
lastRalphthonWatchdog = {
|
|
868
|
+
...lastRalphthonWatchdog,
|
|
869
|
+
active: false,
|
|
870
|
+
last_tick_at: nowIso,
|
|
871
|
+
last_result: 'inactive',
|
|
872
|
+
last_error: null,
|
|
873
|
+
state_path: activeRalphthon.path,
|
|
874
|
+
runtime_path: runtime ? join(cwd, '.omx', 'ralphthon', 'runtime.json') : '',
|
|
875
|
+
};
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (!runtime) {
|
|
879
|
+
runtime = createRalphthonRuntimeState(paneTarget);
|
|
880
|
+
}
|
|
881
|
+
if (!paneTarget) {
|
|
882
|
+
lastRalphthonWatchdog = {
|
|
883
|
+
...lastRalphthonWatchdog,
|
|
884
|
+
active: true,
|
|
885
|
+
last_tick_at: nowIso,
|
|
886
|
+
last_result: 'pane_missing',
|
|
887
|
+
last_error: null,
|
|
888
|
+
state_path: activeRalphthon.path,
|
|
889
|
+
runtime_path: join(cwd, '.omx', 'ralphthon', 'runtime.json'),
|
|
890
|
+
pane_id: '',
|
|
891
|
+
};
|
|
892
|
+
await writeRalphthonRuntimeState(cwd, runtime).catch(() => {});
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (safeString(runtime.leaderTarget).trim() !== paneTarget) {
|
|
896
|
+
runtime = { ...runtime, leaderTarget: paneTarget };
|
|
897
|
+
await writeRalphthonRuntimeState(cwd, runtime).catch(() => {});
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
if (!ralphthonOrchestrator) {
|
|
901
|
+
ralphthonOrchestrator = new RalphthonOrchestrator({
|
|
902
|
+
readPrd: async () => readRalphthonPrd(cwd),
|
|
903
|
+
writePrd: async (prd) => { await writeRalphthonPrd(cwd, prd); },
|
|
904
|
+
readRuntime: async () => readRalphthonRuntimeState(cwd),
|
|
905
|
+
writeRuntime: async (next) => { await writeRalphthonRuntimeState(cwd, next); },
|
|
906
|
+
capturePane: async (leaderTarget) => {
|
|
907
|
+
const result = spawnSync('tmux', ['capture-pane', '-t', leaderTarget, '-p', '-S', '-120'], { encoding: 'utf-8' });
|
|
908
|
+
return result.status === 0 ? safeString(result.stdout) : '';
|
|
909
|
+
},
|
|
910
|
+
injectPrompt: async (leaderTarget, prompt) => {
|
|
911
|
+
const paneGuard = await checkPaneReadyForTeamSendKeys(leaderTarget);
|
|
912
|
+
if (!paneGuard.ok) {
|
|
913
|
+
await eventLog({
|
|
914
|
+
type: 'ralphthon_injection_skipped',
|
|
915
|
+
pane_id: leaderTarget,
|
|
916
|
+
reason: paneGuard.reason || 'pane_guard_blocked',
|
|
917
|
+
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
918
|
+
});
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
const marked = `${prompt} ${DEFAULT_MARKER}`;
|
|
922
|
+
const send = spawnSync('tmux', ['send-keys', '-t', leaderTarget, '-l', marked], { encoding: 'utf-8' });
|
|
923
|
+
if (send.status !== 0) throw new Error((send.stderr || send.stdout || '').trim() || 'tmux send-keys failed');
|
|
924
|
+
spawnSync('tmux', ['send-keys', '-t', leaderTarget, 'C-m'], { encoding: 'utf-8' });
|
|
925
|
+
spawnSync('tmux', ['send-keys', '-t', leaderTarget, 'C-m'], { encoding: 'utf-8' });
|
|
926
|
+
return true;
|
|
927
|
+
},
|
|
928
|
+
updateModeState: updateRalphthonModePatch,
|
|
929
|
+
alert: async (message) => { await eventLog({ type: 'ralphthon_alert', message }); },
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
try {
|
|
934
|
+
const result = await ralphthonOrchestrator.tick();
|
|
935
|
+
lastRalphthonWatchdog = {
|
|
936
|
+
...lastRalphthonWatchdog,
|
|
937
|
+
active: true,
|
|
938
|
+
last_tick_at: nowIso,
|
|
939
|
+
last_result: result,
|
|
940
|
+
last_error: null,
|
|
941
|
+
state_path: activeRalphthon.path,
|
|
942
|
+
runtime_path: join(cwd, '.omx', 'ralphthon', 'runtime.json'),
|
|
943
|
+
pane_id: paneTarget,
|
|
944
|
+
restart_count: ralphthonRestartCount,
|
|
945
|
+
restart_window_started_at: ralphthonRestartWindowStartedAt ? new Date(ralphthonRestartWindowStartedAt).toISOString() : '',
|
|
946
|
+
};
|
|
947
|
+
} catch (error) {
|
|
948
|
+
const message = error instanceof Error ? error.message : safeString(error);
|
|
949
|
+
if (shouldRestartRalphthonWatchdog(now)) {
|
|
950
|
+
ralphthonRestartCount += 1;
|
|
951
|
+
ralphthonOrchestrator = null;
|
|
952
|
+
lastRalphthonWatchdog = {
|
|
953
|
+
...lastRalphthonWatchdog,
|
|
954
|
+
active: true,
|
|
955
|
+
last_tick_at: nowIso,
|
|
956
|
+
last_result: 'restart_scheduled',
|
|
957
|
+
last_error: message,
|
|
958
|
+
state_path: activeRalphthon.path,
|
|
959
|
+
runtime_path: join(cwd, '.omx', 'ralphthon', 'runtime.json'),
|
|
960
|
+
pane_id: paneTarget,
|
|
961
|
+
restart_count: ralphthonRestartCount,
|
|
962
|
+
restart_window_started_at: new Date(ralphthonRestartWindowStartedAt).toISOString(),
|
|
963
|
+
};
|
|
964
|
+
await eventLog({ type: 'ralphthon_watchdog_restart', restart_count: ralphthonRestartCount, error: message });
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
lastRalphthonWatchdog = {
|
|
968
|
+
...lastRalphthonWatchdog,
|
|
969
|
+
active: false,
|
|
970
|
+
last_tick_at: nowIso,
|
|
971
|
+
last_result: 'restart_limit_reached',
|
|
972
|
+
last_error: message,
|
|
973
|
+
state_path: activeRalphthon.path,
|
|
974
|
+
runtime_path: join(cwd, '.omx', 'ralphthon', 'runtime.json'),
|
|
975
|
+
pane_id: paneTarget,
|
|
976
|
+
restart_count: ralphthonRestartCount,
|
|
977
|
+
restart_window_started_at: ralphthonRestartWindowStartedAt ? new Date(ralphthonRestartWindowStartedAt).toISOString() : '',
|
|
978
|
+
};
|
|
979
|
+
await updateRalphthonModePatch({
|
|
980
|
+
active: false,
|
|
981
|
+
current_phase: 'failed',
|
|
982
|
+
completed_at: nowIso,
|
|
983
|
+
error: message || 'ralphthon_watchdog_restart_limit_reached',
|
|
984
|
+
stop_reason: 'ralphthon_watchdog_restart_limit_reached',
|
|
985
|
+
});
|
|
986
|
+
await eventLog({ type: 'ralphthon_watchdog_failed', restart_count: ralphthonRestartCount, error: message });
|
|
987
|
+
const notifyLine = `[ralphthon] watchdog failed permanently after ${ralphthonRestartCount} restarts: ${message || 'unknown error'}`;
|
|
988
|
+
process.stderr.write(`${notifyLine}\n`);
|
|
989
|
+
await eventLog({ type: 'ralphthon_alert', message: notifyLine, user_visible: true });
|
|
990
|
+
await notifyRalphthonWatchdogFailure(notifyLine);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
719
994
|
async function runWatcherCycle() {
|
|
720
995
|
await ensureTrackedFiles();
|
|
721
996
|
await pollFiles();
|
|
722
997
|
await pumpTeamControlPlaneTick();
|
|
723
998
|
await runRalphWatcherBehaviorTick();
|
|
999
|
+
await runRalphthonWatchdogTick();
|
|
724
1000
|
await writeState();
|
|
725
1001
|
}
|
|
726
1002
|
|
|
@@ -775,10 +1051,36 @@ async function main() {
|
|
|
775
1051
|
|
|
776
1052
|
main().catch(async (err) => {
|
|
777
1053
|
await mkdir(dirname(logPath), { recursive: true }).catch(() => {});
|
|
1054
|
+
const restartCount = Math.max(0, asNumber(process.env.OMX_RALPHTHON_WATCHDOG_PROC_RESTART_COUNT || '0', 0));
|
|
1055
|
+
const activeRalphthon = await resolveActiveRalphthonState().catch(() => ({ active: false, path: '', state: null }));
|
|
778
1056
|
await eventLog({
|
|
779
1057
|
type: 'watcher_error',
|
|
780
1058
|
reason: 'fatal',
|
|
781
1059
|
error: err instanceof Error ? err.message : safeString(err),
|
|
1060
|
+
ralphthon_active: activeRalphthon.active === true,
|
|
1061
|
+
restart_count: restartCount,
|
|
782
1062
|
});
|
|
1063
|
+
if (!runOnce && activeRalphthon.active === true && restartCount < RALPHTHON_WATCHDOG_RESTART_LIMIT) {
|
|
1064
|
+
const child = spawn(
|
|
1065
|
+
process.execPath,
|
|
1066
|
+
[process.argv[1], ...process.argv.slice(2)],
|
|
1067
|
+
{
|
|
1068
|
+
cwd,
|
|
1069
|
+
detached: true,
|
|
1070
|
+
stdio: 'ignore',
|
|
1071
|
+
env: {
|
|
1072
|
+
...process.env,
|
|
1073
|
+
OMX_RALPHTHON_WATCHDOG_PROC_RESTART_COUNT: String(restartCount + 1),
|
|
1074
|
+
},
|
|
1075
|
+
},
|
|
1076
|
+
);
|
|
1077
|
+
child.unref();
|
|
1078
|
+
await eventLog({
|
|
1079
|
+
type: 'watcher_restart_spawned',
|
|
1080
|
+
reason: 'fatal_recovery',
|
|
1081
|
+
restart_count: restartCount + 1,
|
|
1082
|
+
spawned_pid: child.pid ?? null,
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
783
1085
|
process.exit(1);
|
|
784
1086
|
});
|
package/scripts/notify-hook.js
CHANGED
|
@@ -124,6 +124,26 @@ async function main() {
|
|
|
124
124
|
// Non-critical
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// 0.5. Track leader + native subagent thread activity (lead session only)
|
|
128
|
+
if (!isTeamWorker) {
|
|
129
|
+
try {
|
|
130
|
+
const threadId = safeString(payload['thread-id'] || payload.thread_id || '');
|
|
131
|
+
const turnId = safeString(payload['turn-id'] || payload.turn_id || '');
|
|
132
|
+
if (payloadSessionId && threadId) {
|
|
133
|
+
const { recordSubagentTurnForSession } = await import('../dist/subagents/tracker.js');
|
|
134
|
+
await recordSubagentTurnForSession(cwd, {
|
|
135
|
+
sessionId: payloadSessionId,
|
|
136
|
+
threadId,
|
|
137
|
+
...(turnId ? { turnId } : {}),
|
|
138
|
+
timestamp: new Date().toISOString(),
|
|
139
|
+
mode: safeString(payload.mode || ''),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
// Non-critical: tracking must never block the hook
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
127
147
|
// 1. Log the turn
|
|
128
148
|
const logEntry = {
|
|
129
149
|
timestamp: new Date().toISOString(),
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
show_usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
scripts/run-autoresearch-showcase.sh --list
|
|
8
|
+
scripts/run-autoresearch-showcase.sh <showcase> [<showcase> ...]
|
|
9
|
+
|
|
10
|
+
Available showcases:
|
|
11
|
+
omx-self -> missions/in-action-cat-shellout-demo
|
|
12
|
+
ml-tabular -> missions/ml-kaggle-model-optimization
|
|
13
|
+
bayesopt -> missions/noisy-bayesopt-highdim
|
|
14
|
+
latent -> missions/noisy-latent-subspace-discovery
|
|
15
|
+
sorting -> missions/adaptive-sort-optimization
|
|
16
|
+
all -> omx-self ml-tabular bayesopt latent sorting
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
scripts/run-autoresearch-showcase.sh --list
|
|
20
|
+
scripts/run-autoresearch-showcase.sh bayesopt
|
|
21
|
+
scripts/run-autoresearch-showcase.sh omx-self ml-tabular
|
|
22
|
+
USAGE
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
mission_for() {
|
|
26
|
+
case "$1" in
|
|
27
|
+
omx-self) printf '%s' 'missions/in-action-cat-shellout-demo' ;;
|
|
28
|
+
ml-tabular) printf '%s' 'missions/ml-kaggle-model-optimization' ;;
|
|
29
|
+
bayesopt) printf '%s' 'missions/noisy-bayesopt-highdim' ;;
|
|
30
|
+
latent) printf '%s' 'missions/noisy-latent-subspace-discovery' ;;
|
|
31
|
+
sorting) printf '%s' 'missions/adaptive-sort-optimization' ;;
|
|
32
|
+
*) return 1 ;;
|
|
33
|
+
esac
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
list_showcases() {
|
|
37
|
+
cat <<'LIST'
|
|
38
|
+
omx-self missions/in-action-cat-shellout-demo
|
|
39
|
+
ml-tabular missions/ml-kaggle-model-optimization
|
|
40
|
+
bayesopt missions/noisy-bayesopt-highdim
|
|
41
|
+
latent missions/noisy-latent-subspace-discovery
|
|
42
|
+
sorting missions/adaptive-sort-optimization
|
|
43
|
+
LIST
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if [[ $# -eq 0 ]]; then
|
|
47
|
+
show_usage
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
|
52
|
+
show_usage
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if [[ "$1" == "--list" ]]; then
|
|
57
|
+
list_showcases
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
args=("$@")
|
|
62
|
+
if [[ " ${args[*]} " == *" all "* ]]; then
|
|
63
|
+
args=(omx-self ml-tabular bayesopt latent sorting)
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
for showcase in "${args[@]}"; do
|
|
67
|
+
mission="$(mission_for "$showcase")" || {
|
|
68
|
+
printf 'Unknown showcase: %s\n\n' "$showcase" >&2
|
|
69
|
+
show_usage >&2
|
|
70
|
+
exit 1
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
printf '\n==> Running showcase %s (%s)\n' "$showcase" "$mission"
|
|
74
|
+
omx autoresearch "$mission"
|
|
75
|
+
done
|