oh-my-codex 0.18.9 → 0.18.11
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/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +6 -6
- package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts +2 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts.map +1 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.js +215 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.js.map +1 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js +148 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/deep-interview-gate.d.ts.map +1 -1
- package/dist/autopilot/deep-interview-gate.js +140 -0
- package/dist/autopilot/deep-interview-gate.js.map +1 -1
- package/dist/catalog/__tests__/schema.test.js +6 -0
- package/dist/catalog/__tests__/schema.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +36 -3
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-feature-probe.test.d.ts +2 -0
- package/dist/cli/__tests__/codex-feature-probe.test.d.ts.map +1 -0
- package/dist/cli/__tests__/codex-feature-probe.test.js +46 -0
- package/dist/cli/__tests__/codex-feature-probe.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.js +79 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +2 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +47 -1175
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +276 -6
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +19 -5
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +19 -6
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +6 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-packaging.test.js +45 -2
- package/dist/cli/__tests__/sparkshell-packaging.test.js.map +1 -1
- package/dist/cli/__tests__/team-decompose.test.js +10 -5
- package/dist/cli/__tests__/team-decompose.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +45 -1
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +75 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +25 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +5 -2
- package/dist/cli/codex-feature-probe.d.ts.map +1 -1
- package/dist/cli/codex-feature-probe.js +25 -9
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/doctor.d.ts +17 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +121 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts +2 -21
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +25 -624
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +34 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +166 -89
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +9 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts +4 -0
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +43 -4
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +29 -0
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +8 -10
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +15 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +16 -0
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-routing.test.js +5 -8
- package/dist/hooks/__tests__/explore-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +6 -6
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-guidance-contract.test.js +14 -5
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
- package/dist/hooks/agents-overlay.d.ts.map +1 -1
- package/dist/hooks/agents-overlay.js +2 -1
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/explore-routing.d.ts +1 -1
- package/dist/hooks/explore-routing.d.ts.map +1 -1
- package/dist/hooks/explore-routing.js +3 -8
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +112 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.d.ts +2 -0
- package/dist/hooks/extensibility/plugin-runner-stdin.d.ts.map +1 -0
- package/dist/hooks/extensibility/plugin-runner-stdin.js +16 -0
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -0
- package/dist/hooks/extensibility/plugin-runner.js +2 -4
- package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +23 -2
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +367 -1
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +118 -7
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/constants.d.ts +10 -0
- package/dist/hud/constants.d.ts.map +1 -1
- package/dist/hud/constants.js +19 -0
- package/dist/hud/constants.js.map +1 -1
- package/dist/hud/index.d.ts +6 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +12 -3
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts +10 -2
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +78 -30
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/tmux.d.ts +14 -1
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +129 -15
- package/dist/hud/tmux.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +3 -3
- package/dist/ralplan/consensus-gate.js +9 -1
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +170 -17
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/run-test-files.test.js +115 -1
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +74 -11
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +54 -21
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/run-test-files.js +218 -160
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +463 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/team/__tests__/delivery-log.test.js +18 -0
- package/dist/team/__tests__/delivery-log.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +48 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +107 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.d.ts.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js +14 -2
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js +1 -0
- package/dist/team/__tests__/tmux-test-fixture.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +54 -1
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/delivery-log.d.ts +1 -1
- package/dist/team/delivery-log.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/repo-aware-decomposition.d.ts +4 -0
- package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
- package/dist/team/repo-aware-decomposition.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +78 -9
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts +1 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +16 -5
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/ultragoal-context.d.ts +12 -0
- package/dist/team/ultragoal-context.d.ts.map +1 -1
- package/dist/team/ultragoal-context.js +32 -8
- package/dist/team/ultragoal-context.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +23 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +4 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/toml.d.ts +4 -0
- package/dist/utils/toml.d.ts.map +1 -0
- package/dist/utils/toml.js +75 -0
- package/dist/utils/toml.js.map +1 -0
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +3 -0
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +34 -0
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +32 -17
- package/skills/autopilot/SKILL.md +3 -0
- package/skills/deep-interview/SKILL.md +34 -0
- package/skills/ultrawork/SKILL.md +32 -17
- package/src/scripts/__tests__/codex-native-hook.test.ts +218 -28
- package/src/scripts/__tests__/run-test-files.test.ts +138 -2
- package/src/scripts/codex-native-hook.ts +80 -10
- package/src/scripts/notify-hook/team-worker-stop.ts +58 -18
- package/src/scripts/run-test-files.ts +229 -150
- package/templates/AGENTS.md +39 -199
- package/templates/catalog-manifest.json +7 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
|
-
import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
|
|
2
|
+
import { closeSync, existsSync, openSync, readFileSync, readSync, statSync } from "fs";
|
|
3
3
|
import { appendFile, mkdir, readFile, readdir, stat, writeFile } from "fs/promises";
|
|
4
4
|
import { extname, join, relative, resolve } from "path";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
@@ -216,6 +216,57 @@ function safeContextSnippet(value: unknown, maxLength = 300): string {
|
|
|
216
216
|
return `${text.slice(0, maxLength - 1).trimEnd()}…`;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
const SIDE_CONVERSATION_BOUNDARY_PATTERNS = [
|
|
220
|
+
/side conversation boundary/i,
|
|
221
|
+
/inherited history from the parent thread/i,
|
|
222
|
+
/reference context only/i,
|
|
223
|
+
/only messages submitted after this boundary are active/i,
|
|
224
|
+
/side-conversation assistant/i,
|
|
225
|
+
] as const;
|
|
226
|
+
|
|
227
|
+
function textHasSideConversationBoundary(text: string): boolean {
|
|
228
|
+
return SIDE_CONVERSATION_BOUNDARY_PATTERNS.some((pattern) => pattern.test(text));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function isLikelySideConversationStopPayload(payload: CodexHookPayload): boolean {
|
|
232
|
+
const payloadText = [
|
|
233
|
+
payload.prompt,
|
|
234
|
+
payload.user_prompt,
|
|
235
|
+
payload.userPrompt,
|
|
236
|
+
payload.input,
|
|
237
|
+
payload.last_user_message,
|
|
238
|
+
payload.lastUserMessage,
|
|
239
|
+
payload.last_assistant_message,
|
|
240
|
+
payload.lastAssistantMessage,
|
|
241
|
+
].map(safeString).join("\n");
|
|
242
|
+
if (textHasSideConversationBoundary(payloadText)) return true;
|
|
243
|
+
|
|
244
|
+
const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
|
|
245
|
+
if (!transcriptPath || !existsSync(transcriptPath)) return false;
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const maxBytes = 256 * 1024;
|
|
249
|
+
const stats = statSync(transcriptPath);
|
|
250
|
+
const fd = openSync(transcriptPath, "r");
|
|
251
|
+
try {
|
|
252
|
+
const bytesToRead = Math.min(maxBytes, Math.max(0, stats.size));
|
|
253
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
254
|
+
const position = Math.max(0, stats.size - bytesToRead);
|
|
255
|
+
const bytesRead = readSync(fd, buffer, 0, bytesToRead, position);
|
|
256
|
+
return textHasSideConversationBoundary(buffer.toString("utf-8", 0, bytesRead));
|
|
257
|
+
} finally {
|
|
258
|
+
closeSync(fd);
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function shouldSuppressParentWorkflowStopForSideConversation(payload: CodexHookPayload): boolean {
|
|
266
|
+
if (safeString(payload.hook_event_name ?? payload.hookEventName).trim() !== "Stop") return false;
|
|
267
|
+
return isLikelySideConversationStopPayload(payload);
|
|
268
|
+
}
|
|
269
|
+
|
|
219
270
|
interface NativeSubagentSessionStartMetadata {
|
|
220
271
|
parentThreadId: string;
|
|
221
272
|
agentNickname?: string;
|
|
@@ -2657,9 +2708,23 @@ function readPreToolUsePathCandidates(payload: CodexHookPayload): string[] {
|
|
|
2657
2708
|
return candidates.map((candidate) => safeString(candidate).trim()).filter(Boolean);
|
|
2658
2709
|
}
|
|
2659
2710
|
|
|
2711
|
+
function isNullDeviceRedirectTarget(target: string): boolean {
|
|
2712
|
+
const normalized = target.trim().replace(/^['"]|['"]$/g, "").toLowerCase();
|
|
2713
|
+
return normalized === "/dev/null" || normalized === "nul";
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
function extractDeepInterviewCommandRedirectTargets(command: string): string[] {
|
|
2717
|
+
const targets: string[] = [];
|
|
2718
|
+
for (const match of command.matchAll(/(?:^|[^>])>{1,2}\s*(["']?)([^\s&|;<>]+)\1/g)) {
|
|
2719
|
+
const candidate = safeString(match[2]).trim();
|
|
2720
|
+
if (candidate && !isNullDeviceRedirectTarget(candidate)) targets.push(candidate);
|
|
2721
|
+
}
|
|
2722
|
+
return targets;
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2660
2725
|
function commandHasDeepInterviewWriteIntent(command: string): boolean {
|
|
2661
2726
|
return /\bapply_patch\b/.test(command)
|
|
2662
|
-
||
|
|
2727
|
+
|| extractDeepInterviewCommandRedirectTargets(command).length > 0
|
|
2663
2728
|
|| /\btee\s+(?:-a\s+)?[^\s&|;]+/.test(command)
|
|
2664
2729
|
|| /\bsed\s+(?:[^\n;&|]*\s)?-i(?:\b|['"])/.test(command)
|
|
2665
2730
|
|| /\b(?:python3?|node|perl|ruby)\b[\s\S]{0,260}\b(?:writeFileSync|writeFile|write_text|open\([^)]*["']w|File\.write|Path\()/.test(command)
|
|
@@ -2667,11 +2732,7 @@ function commandHasDeepInterviewWriteIntent(command: string): boolean {
|
|
|
2667
2732
|
}
|
|
2668
2733
|
|
|
2669
2734
|
function extractDeepInterviewCommandWriteTargets(command: string): string[] {
|
|
2670
|
-
const targets
|
|
2671
|
-
for (const match of command.matchAll(/(?:^|[^>])>{1,2}\s*(["']?)([^\s&|;<>]+)\1/g)) {
|
|
2672
|
-
const candidate = safeString(match[2]).trim();
|
|
2673
|
-
if (candidate) targets.push(candidate);
|
|
2674
|
-
}
|
|
2735
|
+
const targets = extractDeepInterviewCommandRedirectTargets(command);
|
|
2675
2736
|
for (const match of command.matchAll(/\btee\s+(?:-a\s+)?(["']?)([^\s&|;<>]+)\1/g)) {
|
|
2676
2737
|
const candidate = safeString(match[2]).trim();
|
|
2677
2738
|
if (candidate) targets.push(candidate);
|
|
@@ -3735,9 +3796,13 @@ async function buildStopHookOutput(
|
|
|
3735
3796
|
const sessionId = readPayloadSessionId(payload);
|
|
3736
3797
|
const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
|
|
3737
3798
|
const threadId = readPayloadThreadId(payload);
|
|
3799
|
+
const suppressParentWorkflowStop = shouldSuppressParentWorkflowStopForSideConversation(payload);
|
|
3738
3800
|
if (canonicalSessionId) {
|
|
3739
3801
|
await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
|
|
3740
3802
|
}
|
|
3803
|
+
if (suppressParentWorkflowStop) {
|
|
3804
|
+
return null;
|
|
3805
|
+
}
|
|
3741
3806
|
const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
|
|
3742
3807
|
if (execFollowupOutput) return execFollowupOutput;
|
|
3743
3808
|
const ralphOwnerContext = {
|
|
@@ -4452,12 +4517,17 @@ function inferHookEventNameFromMalformedInput(raw: string): CodexHookEventName |
|
|
|
4452
4517
|
return readHookEventName({ hook_event_name: value });
|
|
4453
4518
|
}
|
|
4454
4519
|
|
|
4455
|
-
function buildMalformedStdinHookOutput(
|
|
4520
|
+
function buildMalformedStdinHookOutput(
|
|
4521
|
+
parseError: Error,
|
|
4522
|
+
rawInput: string,
|
|
4523
|
+
cwd = process.cwd(),
|
|
4524
|
+
): Record<string, unknown> {
|
|
4456
4525
|
const reason =
|
|
4457
4526
|
"OMX native hook received malformed JSON input. Preserve runtime state, inspect the emitting hook payload yourself, and retry with valid JSON.";
|
|
4458
4527
|
const systemMessage =
|
|
4459
4528
|
`${reason} stdin JSON parsing failed inside codex-native-hook: ${parseError.message}.`;
|
|
4460
|
-
|
|
4529
|
+
const inferredHookEventName = inferHookEventNameFromMalformedInput(rawInput);
|
|
4530
|
+
if (inferredHookEventName === "Stop" || (!inferredHookEventName && hasNativeStopRuntimeSurface(cwd))) {
|
|
4461
4531
|
return {
|
|
4462
4532
|
decision: "block",
|
|
4463
4533
|
reason,
|
|
@@ -4603,7 +4673,7 @@ export async function runCodexNativeHookCli(): Promise<void> {
|
|
|
4603
4673
|
{},
|
|
4604
4674
|
buildRawInputLogFields(rawInput),
|
|
4605
4675
|
);
|
|
4606
|
-
writeNativeHookJsonStdout(buildMalformedStdinHookOutput(parseError, rawInput));
|
|
4676
|
+
writeNativeHookJsonStdout(buildMalformedStdinHookOutput(parseError, rawInput, process.cwd()));
|
|
4607
4677
|
return;
|
|
4608
4678
|
}
|
|
4609
4679
|
|
|
@@ -14,7 +14,7 @@ import { appendTeamDeliveryLog } from '../../team/delivery-log.js';
|
|
|
14
14
|
import { safeString, asNumber, isTerminalPhase } from './utils.js';
|
|
15
15
|
import { readJsonIfExists } from './state-io.js';
|
|
16
16
|
import { logTmuxHookEvent } from './log.js';
|
|
17
|
-
import { evaluatePaneInjectionReadiness,
|
|
17
|
+
import { evaluatePaneInjectionReadiness, sendPaneInput } from './team-tmux-guard.js';
|
|
18
18
|
import { resolvePaneTarget } from './tmux-injection.js';
|
|
19
19
|
import { readTeamWorkersForIdleCheck } from './team-worker.js';
|
|
20
20
|
|
|
@@ -147,6 +147,35 @@ async function resolveCanonicalLeaderPaneId(leaderPaneId) {
|
|
|
147
147
|
return normalizedLeaderPaneId;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
async function recordSuppressedWorkerStopNudge({
|
|
151
|
+
logsDir,
|
|
152
|
+
teamName,
|
|
153
|
+
workerName,
|
|
154
|
+
reason,
|
|
155
|
+
}) {
|
|
156
|
+
const nowIso = new Date().toISOString();
|
|
157
|
+
await logTmuxHookEvent(logsDir, {
|
|
158
|
+
timestamp: nowIso,
|
|
159
|
+
type: 'worker_stop_leader_nudge_suppressed',
|
|
160
|
+
team: teamName,
|
|
161
|
+
worker: workerName,
|
|
162
|
+
to_worker: 'leader-fixed',
|
|
163
|
+
reason,
|
|
164
|
+
tmux_injection_attempted: false,
|
|
165
|
+
source_type: SOURCE_TYPE,
|
|
166
|
+
}).catch(() => {});
|
|
167
|
+
await appendTeamDeliveryLog(logsDir, {
|
|
168
|
+
event: 'nudge_triggered',
|
|
169
|
+
source: SOURCE_TYPE,
|
|
170
|
+
team: teamName,
|
|
171
|
+
from_worker: workerName,
|
|
172
|
+
to_worker: 'leader-fixed',
|
|
173
|
+
transport: 'none',
|
|
174
|
+
result: 'suppressed',
|
|
175
|
+
reason,
|
|
176
|
+
}).catch(() => {});
|
|
177
|
+
}
|
|
178
|
+
|
|
150
179
|
async function recordDeferred({
|
|
151
180
|
stateDir,
|
|
152
181
|
logsDir,
|
|
@@ -229,18 +258,34 @@ export async function maybeNudgeLeaderForAllowedWorkerStop({
|
|
|
229
258
|
};
|
|
230
259
|
let tmuxSession = '';
|
|
231
260
|
let leaderPaneId = '';
|
|
261
|
+
let recordedShutdownSuppression = false;
|
|
262
|
+
const recordShutdownSuppressionOnce = async () => {
|
|
263
|
+
if (recordedShutdownSuppression) return;
|
|
264
|
+
recordedShutdownSuppression = true;
|
|
265
|
+
await recordSuppressedWorkerStopNudge({
|
|
266
|
+
logsDir,
|
|
267
|
+
teamName,
|
|
268
|
+
workerName,
|
|
269
|
+
reason: TEAM_SHUTDOWN_NO_INJECTION_REASON,
|
|
270
|
+
});
|
|
271
|
+
};
|
|
232
272
|
|
|
233
273
|
if (!(await teamStateAllowsWorkerStopNudge(stateDir, teamName))) {
|
|
274
|
+
await recordShutdownSuppressionOnce();
|
|
234
275
|
return { ok: true, result: TEAM_SHUTDOWN_NO_INJECTION_REASON };
|
|
235
276
|
}
|
|
236
277
|
|
|
237
278
|
const lock = await acquireTeamStopNudgeLock(teamDir, nowMs, cooldownMs);
|
|
238
279
|
if (!lock.acquired) {
|
|
280
|
+
if (lock.reason === TEAM_SHUTDOWN_NO_INJECTION_REASON) {
|
|
281
|
+
await recordShutdownSuppressionOnce();
|
|
282
|
+
}
|
|
239
283
|
return { ok: true, result: lock.reason || TEAM_LOCK_HELD_REASON };
|
|
240
284
|
}
|
|
241
285
|
|
|
242
286
|
try {
|
|
243
287
|
if (!(await teamStateAllowsWorkerStopNudge(stateDir, teamName))) {
|
|
288
|
+
await recordShutdownSuppressionOnce();
|
|
244
289
|
return { ok: true, result: TEAM_SHUTDOWN_NO_INJECTION_REASON };
|
|
245
290
|
}
|
|
246
291
|
|
|
@@ -263,6 +308,7 @@ export async function maybeNudgeLeaderForAllowedWorkerStop({
|
|
|
263
308
|
|
|
264
309
|
if (!tmuxTarget) {
|
|
265
310
|
if (!(await teamStateAllowsWorkerStopNudge(stateDir, teamName))) {
|
|
311
|
+
await recordShutdownSuppressionOnce();
|
|
266
312
|
return { ok: true, result: TEAM_SHUTDOWN_NO_INJECTION_REASON };
|
|
267
313
|
}
|
|
268
314
|
await recordDeferred({
|
|
@@ -287,6 +333,7 @@ export async function maybeNudgeLeaderForAllowedWorkerStop({
|
|
|
287
333
|
});
|
|
288
334
|
if (!paneGuard.ok) {
|
|
289
335
|
if (!(await teamStateAllowsWorkerStopNudge(stateDir, teamName))) {
|
|
336
|
+
await recordShutdownSuppressionOnce();
|
|
290
337
|
return { ok: true, result: TEAM_SHUTDOWN_NO_INJECTION_REASON };
|
|
291
338
|
}
|
|
292
339
|
await recordDeferred({
|
|
@@ -305,6 +352,7 @@ export async function maybeNudgeLeaderForAllowedWorkerStop({
|
|
|
305
352
|
}
|
|
306
353
|
|
|
307
354
|
if (!(await teamStateAllowsWorkerStopNudge(stateDir, teamName))) {
|
|
355
|
+
await recordShutdownSuppressionOnce();
|
|
308
356
|
return { ok: true, result: TEAM_SHUTDOWN_NO_INJECTION_REASON };
|
|
309
357
|
}
|
|
310
358
|
|
|
@@ -314,23 +362,14 @@ export async function maybeNudgeLeaderForAllowedWorkerStop({
|
|
|
314
362
|
+ DEFAULT_MARKER;
|
|
315
363
|
|
|
316
364
|
const leaderHasActiveTask = paneHasActiveTask(paneGuard.paneCapture);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
} else {
|
|
326
|
-
const sendResult = await sendPaneInput({
|
|
327
|
-
paneTarget: tmuxTarget,
|
|
328
|
-
prompt,
|
|
329
|
-
submitKeyPresses: 2,
|
|
330
|
-
submitDelayMs: 100,
|
|
331
|
-
});
|
|
332
|
-
if (!sendResult.ok) throw new Error(sendResult.error || sendResult.reason || 'send_failed');
|
|
333
|
-
}
|
|
365
|
+
const sendResult = await sendPaneInput({
|
|
366
|
+
paneTarget: tmuxTarget,
|
|
367
|
+
prompt,
|
|
368
|
+
submitKeyPresses: 2,
|
|
369
|
+
submitDelayMs: 100,
|
|
370
|
+
});
|
|
371
|
+
if (!sendResult.ok) throw new Error(sendResult.error || sendResult.reason || 'send_failed');
|
|
372
|
+
const deliveryMode = leaderHasActiveTask ? 'steered' : 'sent';
|
|
334
373
|
|
|
335
374
|
const deliveryState = {
|
|
336
375
|
...nextState,
|
|
@@ -376,6 +415,7 @@ export async function maybeNudgeLeaderForAllowedWorkerStop({
|
|
|
376
415
|
return { ok: true, result: deliveryMode };
|
|
377
416
|
} catch (err) {
|
|
378
417
|
if (!(await teamStateAllowsWorkerStopNudge(stateDir, teamName))) {
|
|
418
|
+
await recordShutdownSuppressionOnce();
|
|
379
419
|
return { ok: true, result: TEAM_SHUTDOWN_NO_INJECTION_REASON };
|
|
380
420
|
}
|
|
381
421
|
// Worker Stop is already allowed before this helper runs; nudge failures are
|