@agents-ensemble/core 0.20.0 → 0.22.0
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/assets/pi/pi-cli-env-wrapper.cmd +28 -0
- package/assets/pi/pi-cli-env-wrapper.sh +19 -0
- package/assets/pi/settings.json +4 -0
- package/dist/acp/acp-preset-bins.d.ts +3 -3
- package/dist/acp/acp-preset-bins.d.ts.map +1 -1
- package/dist/acp/acp-preset-bins.js +3 -3
- package/dist/acp/acp-preset-bins.js.map +1 -1
- package/dist/acp/index.d.ts +3 -1
- package/dist/acp/index.d.ts.map +1 -1
- package/dist/acp/index.js +2 -1
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/pi-acp-wrapper.d.ts +3 -0
- package/dist/acp/pi-acp-wrapper.d.ts.map +1 -0
- package/dist/acp/pi-acp-wrapper.js +41 -0
- package/dist/acp/pi-acp-wrapper.js.map +1 -0
- package/dist/acp/pi-builtin-config.d.ts +10 -0
- package/dist/acp/pi-builtin-config.d.ts.map +1 -0
- package/dist/acp/pi-builtin-config.js +36 -0
- package/dist/acp/pi-builtin-config.js.map +1 -0
- package/dist/acp/pi-runtime.d.ts +23 -0
- package/dist/acp/pi-runtime.d.ts.map +1 -0
- package/dist/acp/pi-runtime.js +160 -0
- package/dist/acp/pi-runtime.js.map +1 -0
- package/dist/acp/pi-session-map.d.ts +36 -0
- package/dist/acp/pi-session-map.d.ts.map +1 -0
- package/dist/acp/pi-session-map.js +266 -0
- package/dist/acp/pi-session-map.js.map +1 -0
- package/dist/acp/resolve-acp-spawn.d.ts +9 -3
- package/dist/acp/resolve-acp-spawn.d.ts.map +1 -1
- package/dist/acp/resolve-acp-spawn.js +41 -9
- package/dist/acp/resolve-acp-spawn.js.map +1 -1
- package/dist/acp/resolve-bundled-acp-bin.d.ts +2 -2
- package/dist/acp/resolve-bundled-acp-bin.d.ts.map +1 -1
- package/dist/acp/resolve-bundled-acp-bin.js +4 -4
- package/dist/acp/resolve-bundled-acp-bin.js.map +1 -1
- package/dist/acp/validate-acp-preset-prerequisites.d.ts +1 -1
- package/dist/acp/validate-acp-preset-prerequisites.d.ts.map +1 -1
- package/dist/acp/validate-acp-preset-prerequisites.js +30 -10
- package/dist/acp/validate-acp-preset-prerequisites.js.map +1 -1
- package/dist/conductor/conductor-agent.d.ts +15 -3
- package/dist/conductor/conductor-agent.d.ts.map +1 -1
- package/dist/conductor/conductor-auth.d.ts +4 -3
- package/dist/conductor/conductor-auth.d.ts.map +1 -1
- package/dist/conductor/conductor-auth.js +20 -4
- package/dist/conductor/conductor-auth.js.map +1 -1
- package/dist/conductor/conductor-dispatch-lifecycle.d.ts +85 -0
- package/dist/conductor/conductor-dispatch-lifecycle.d.ts.map +1 -0
- package/dist/conductor/conductor-dispatch-lifecycle.js +190 -0
- package/dist/conductor/conductor-dispatch-lifecycle.js.map +1 -0
- package/dist/conductor/conductor-history.d.ts +15 -0
- package/dist/conductor/conductor-history.d.ts.map +1 -1
- package/dist/conductor/conductor-history.js +38 -7
- package/dist/conductor/conductor-history.js.map +1 -1
- package/dist/conductor/conductor-path-safety.d.ts +23 -0
- package/dist/conductor/conductor-path-safety.d.ts.map +1 -0
- package/dist/conductor/conductor-path-safety.js +319 -0
- package/dist/conductor/conductor-path-safety.js.map +1 -0
- package/dist/conductor/conductor-pi-auth.d.ts +57 -2
- package/dist/conductor/conductor-pi-auth.d.ts.map +1 -1
- package/dist/conductor/conductor-pi-auth.js +718 -40
- package/dist/conductor/conductor-pi-auth.js.map +1 -1
- package/dist/conductor/conductor-recovery-inbox.d.ts +73 -0
- package/dist/conductor/conductor-recovery-inbox.d.ts.map +1 -0
- package/dist/conductor/conductor-recovery-inbox.js +181 -0
- package/dist/conductor/conductor-recovery-inbox.js.map +1 -0
- package/dist/conductor/conductor-send-reconnect.d.ts +33 -4
- package/dist/conductor/conductor-send-reconnect.d.ts.map +1 -1
- package/dist/conductor/conductor-send-reconnect.js +89 -24
- package/dist/conductor/conductor-send-reconnect.js.map +1 -1
- package/dist/conductor/conductor-session-driver.d.ts +34 -1
- package/dist/conductor/conductor-session-driver.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.js +529 -75
- package/dist/conductor/conductor-session-driver.js.map +1 -1
- package/dist/conductor/conductor-session.d.ts +4 -0
- package/dist/conductor/conductor-session.d.ts.map +1 -1
- package/dist/conductor/conductor-session.js +416 -145
- package/dist/conductor/conductor-session.js.map +1 -1
- package/dist/conductor/conductor-setup.d.ts +30 -0
- package/dist/conductor/conductor-setup.d.ts.map +1 -0
- package/dist/conductor/conductor-setup.js +243 -0
- package/dist/conductor/conductor-setup.js.map +1 -0
- package/dist/conductor/cursor-bootstrap-state.d.ts +9 -0
- package/dist/conductor/cursor-bootstrap-state.d.ts.map +1 -0
- package/dist/conductor/cursor-bootstrap-state.js +11 -0
- package/dist/conductor/cursor-bootstrap-state.js.map +1 -0
- package/dist/conductor/cursor-run-snapshots.d.ts +30 -0
- package/dist/conductor/cursor-run-snapshots.d.ts.map +1 -0
- package/dist/conductor/cursor-run-snapshots.js +120 -0
- package/dist/conductor/cursor-run-snapshots.js.map +1 -0
- package/dist/conductor/index.d.ts +18 -7
- package/dist/conductor/index.d.ts.map +1 -1
- package/dist/conductor/index.js +9 -4
- package/dist/conductor/index.js.map +1 -1
- package/dist/conductor/operator-command.d.ts +5 -0
- package/dist/conductor/operator-command.d.ts.map +1 -1
- package/dist/conductor/operator-command.js +6 -0
- package/dist/conductor/operator-command.js.map +1 -1
- package/dist/conductor/operator-input-binding.d.ts +17 -0
- package/dist/conductor/operator-input-binding.d.ts.map +1 -1
- package/dist/conductor/pi-auth-recovery-snapshot-store.d.ts +45 -0
- package/dist/conductor/pi-auth-recovery-snapshot-store.d.ts.map +1 -0
- package/dist/conductor/pi-auth-recovery-snapshot-store.js +116 -0
- package/dist/conductor/pi-auth-recovery-snapshot-store.js.map +1 -0
- package/dist/conductor/pi-conductor-agent.d.ts +6 -3
- package/dist/conductor/pi-conductor-agent.d.ts.map +1 -1
- package/dist/conductor/pi-conductor-agent.js +276 -53
- package/dist/conductor/pi-conductor-agent.js.map +1 -1
- package/dist/conductor/pi-conductor-session-file.d.ts +13 -0
- package/dist/conductor/pi-conductor-session-file.d.ts.map +1 -0
- package/dist/conductor/pi-conductor-session-file.js +21 -0
- package/dist/conductor/pi-conductor-session-file.js.map +1 -0
- package/dist/conductor/pi-resource-loader.d.ts +6 -0
- package/dist/conductor/pi-resource-loader.d.ts.map +1 -1
- package/dist/conductor/pi-resource-loader.js +26 -12
- package/dist/conductor/pi-resource-loader.js.map +1 -1
- package/dist/conductor/pi-user-root-lock.d.ts +8 -0
- package/dist/conductor/pi-user-root-lock.d.ts.map +1 -0
- package/dist/conductor/pi-user-root-lock.js +53 -0
- package/dist/conductor/pi-user-root-lock.js.map +1 -0
- package/dist/conductor/recovery-inbox-command.d.ts +29 -0
- package/dist/conductor/recovery-inbox-command.d.ts.map +1 -0
- package/dist/conductor/recovery-inbox-command.js +248 -0
- package/dist/conductor/recovery-inbox-command.js.map +1 -0
- package/dist/conductor/session/events/index.d.ts +1 -1
- package/dist/conductor/session/events/index.d.ts.map +1 -1
- package/dist/conductor/session/events/index.js.map +1 -1
- package/dist/conductor/session/events/session-event.d.ts +43 -1
- package/dist/conductor/session/events/session-event.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event-groups.d.ts +1 -1
- package/dist/conductor/session/events/session-log-event-groups.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event-groups.js +2 -0
- package/dist/conductor/session/events/session-log-event-groups.js.map +1 -1
- package/dist/conductor/session/events/session-log-event.d.ts +4 -0
- package/dist/conductor/session/events/session-log-event.d.ts.map +1 -1
- package/dist/conductor/session/format-session-event.js +57 -5
- package/dist/conductor/session/format-session-event.js.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.d.ts +2 -0
- package/dist/conductor/session/select-dispatch-batch.d.ts.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.js +36 -2
- package/dist/conductor/session/select-dispatch-batch.js.map +1 -1
- package/dist/conductor/session/session-event-queue.d.ts +14 -0
- package/dist/conductor/session/session-event-queue.d.ts.map +1 -1
- package/dist/conductor/session/session-event-queue.js +82 -10
- package/dist/conductor/session/session-event-queue.js.map +1 -1
- package/dist/conductor/session/session-event.d.ts +1 -1
- package/dist/conductor/session/session-event.d.ts.map +1 -1
- package/dist/conductor/session-policy.d.ts.map +1 -1
- package/dist/conductor/session-policy.js +8 -4
- package/dist/conductor/session-policy.js.map +1 -1
- package/dist/conductor/submit-operator-input.d.ts +3 -0
- package/dist/conductor/submit-operator-input.d.ts.map +1 -1
- package/dist/conductor/submit-operator-input.js +21 -0
- package/dist/conductor/submit-operator-input.js.map +1 -1
- package/dist/config/deep-merge.d.ts.map +1 -1
- package/dist/config/deep-merge.js +13 -3
- package/dist/config/deep-merge.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +1 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/doctor-settings.d.ts +59 -0
- package/dist/config/doctor-settings.d.ts.map +1 -0
- package/dist/config/doctor-settings.js +343 -0
- package/dist/config/doctor-settings.js.map +1 -0
- package/dist/config/ensemble-config-digest.d.ts +2 -4
- package/dist/config/ensemble-config-digest.d.ts.map +1 -1
- package/dist/config/ensemble-config-digest.js +2 -4
- package/dist/config/ensemble-config-digest.js.map +1 -1
- package/dist/config/index.d.ts +3 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/load-ensemble-config.d.ts.map +1 -1
- package/dist/config/load-ensemble-config.js +8 -1
- package/dist/config/load-ensemble-config.js.map +1 -1
- package/dist/config/parse-config.d.ts.map +1 -1
- package/dist/config/parse-config.js +34 -14
- package/dist/config/parse-config.js.map +1 -1
- package/dist/config/resolve-settings.d.ts +3 -1
- package/dist/config/resolve-settings.d.ts.map +1 -1
- package/dist/config/resolve-settings.js +7 -4
- package/dist/config/resolve-settings.js.map +1 -1
- package/dist/config/types.d.ts +14 -5
- package/dist/config/types.d.ts.map +1 -1
- package/dist/dispatch/attach-worker.js +1 -1
- package/dist/dispatch/attach-worker.js.map +1 -1
- package/dist/dispatch/worker-acp-session.d.ts +21 -3
- package/dist/dispatch/worker-acp-session.d.ts.map +1 -1
- package/dist/dispatch/worker-acp-session.js +50 -13
- package/dist/dispatch/worker-acp-session.js.map +1 -1
- package/dist/ensemble-paths.d.ts +19 -19
- package/dist/ensemble-paths.d.ts.map +1 -1
- package/dist/ensemble-paths.js +40 -22
- package/dist/ensemble-paths.js.map +1 -1
- package/dist/issue/resolve-issue-url.d.ts +4 -0
- package/dist/issue/resolve-issue-url.d.ts.map +1 -1
- package/dist/issue/resolve-issue-url.js +2 -2
- package/dist/issue/resolve-issue-url.js.map +1 -1
- package/dist/operator-runtime.d.ts +19 -4
- package/dist/operator-runtime.d.ts.map +1 -1
- package/dist/operator-runtime.js +13 -2
- package/dist/operator-runtime.js.map +1 -1
- package/dist/profile/types.d.ts +4 -0
- package/dist/profile/types.d.ts.map +1 -1
- package/dist/profile/types.js +29 -12
- package/dist/profile/types.js.map +1 -1
- package/dist/representation/escape-terminal-control-characters.d.ts +9 -0
- package/dist/representation/escape-terminal-control-characters.d.ts.map +1 -0
- package/dist/representation/escape-terminal-control-characters.js +34 -0
- package/dist/representation/escape-terminal-control-characters.js.map +1 -0
- package/dist/representation/index.d.ts +1 -0
- package/dist/representation/index.d.ts.map +1 -1
- package/dist/representation/index.js +1 -0
- package/dist/representation/index.js.map +1 -1
- package/dist/runtime/types.d.ts +9 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.d.ts +14 -1
- package/dist/runtime/worker-runtime.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.js +197 -50
- package/dist/runtime/worker-runtime.js.map +1 -1
- package/dist/runtime/worker-session.d.ts +2 -1
- package/dist/runtime/worker-session.d.ts.map +1 -1
- package/dist/runtime/worker-session.js +1 -0
- package/dist/runtime/worker-session.js.map +1 -1
- package/dist/session/export-session-bundle.d.ts +77 -0
- package/dist/session/export-session-bundle.d.ts.map +1 -0
- package/dist/session/export-session-bundle.js +640 -0
- package/dist/session/export-session-bundle.js.map +1 -0
- package/dist/session/index.d.ts +6 -3
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +4 -1
- package/dist/session/index.js.map +1 -1
- package/dist/session/open-question-control.d.ts +9 -0
- package/dist/session/open-question-control.d.ts.map +1 -1
- package/dist/session/open-question-control.js +26 -1
- package/dist/session/open-question-control.js.map +1 -1
- package/dist/session/open-questions-store.d.ts +1 -1
- package/dist/session/open-questions-store.d.ts.map +1 -1
- package/dist/session/open-questions-store.js +3 -6
- package/dist/session/open-questions-store.js.map +1 -1
- package/dist/session/persisted-file.d.ts +5 -0
- package/dist/session/persisted-file.d.ts.map +1 -0
- package/dist/session/persisted-file.js +56 -0
- package/dist/session/persisted-file.js.map +1 -0
- package/dist/session/session-resume-store.d.ts +79 -10
- package/dist/session/session-resume-store.d.ts.map +1 -1
- package/dist/session/session-resume-store.js +353 -83
- package/dist/session/session-resume-store.js.map +1 -1
- package/dist/session/session-snapshot-paths.d.ts +11 -0
- package/dist/session/session-snapshot-paths.d.ts.map +1 -0
- package/dist/session/session-snapshot-paths.js +41 -0
- package/dist/session/session-snapshot-paths.js.map +1 -0
- package/dist/session/session-state-store.d.ts +2 -2
- package/dist/session/session-state-store.d.ts.map +1 -1
- package/dist/session/session-state-store.js +5 -16
- package/dist/session/session-state-store.js.map +1 -1
- package/dist/session/tool-call-snapshot-history.d.ts +12 -1
- package/dist/session/tool-call-snapshot-history.d.ts.map +1 -1
- package/dist/session/tool-call-snapshot-history.js +75 -70
- package/dist/session/tool-call-snapshot-history.js.map +1 -1
- package/dist/session/worker-session-history.d.ts +51 -0
- package/dist/session/worker-session-history.d.ts.map +1 -0
- package/dist/session/worker-session-history.js +654 -0
- package/dist/session/worker-session-history.js.map +1 -0
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/worktree/worktree.d.ts +6 -1
- package/dist/worktree/worktree.d.ts.map +1 -1
- package/dist/worktree/worktree.js +123 -2
- package/dist/worktree/worktree.js.map +1 -1
- package/package.json +9 -4
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { resolve as resolvePath } from 'node:path';
|
|
1
3
|
import { computeAcpModelConfigDigest, computeEnsembleConfigDigest, computeResumeFeasibilityConfigDigest, } from '../config/ensemble-config-digest.js';
|
|
2
4
|
import { loadEnsembleConfig } from '../config/load-ensemble-config.js';
|
|
3
5
|
import { computeMcpConfigDigest, resolveMcpServers, } from '../mcp/load-mcp-config.js';
|
|
@@ -12,6 +14,7 @@ import { createPermissionDeadlockMonitor, } from '../permission/permission-deadl
|
|
|
12
14
|
import { createResolvePermissionTool } from '../permission/resolve-permission-tool.js';
|
|
13
15
|
import { buildPermissionBrief, getPermissionToolCallId, } from '../permission/permission-brief.js';
|
|
14
16
|
import { acpSpawnFingerprint, resolveWorkerAcpSpawn, resolvedAcpSpawnToOptions, } from '../acp/resolve-acp-spawn.js';
|
|
17
|
+
import { configurePiWorkerRuntime } from '../acp/pi-runtime.js';
|
|
15
18
|
import { finalizeResolvedAcpSpawn, validateWorkerAcpPrerequisites, } from '../acp/validate-acp-preset-prerequisites.js';
|
|
16
19
|
import { profileWorkersToSessionSpecs, sessionStateFromProfile, resolveAgentPromptModule, } from '../profile/types.js';
|
|
17
20
|
import { WorkerSession } from '../runtime/worker-session.js';
|
|
@@ -31,25 +34,31 @@ import { createConductorAgentFactory } from './conductor-agent-factory.js';
|
|
|
31
34
|
import { resolveConductorReasoning } from './resolve-conductor-reasoning.js';
|
|
32
35
|
import { formatConductorAuthRecoveryHint, isConductorSendAuthError, } from './conductor-auth.js';
|
|
33
36
|
import { resolvePiConductorProvider } from './conductor-pi-auth.js';
|
|
37
|
+
import { closeConductorAgentOnce } from './conductor-send-reconnect.js';
|
|
38
|
+
import { escapeTerminalControlCharacters } from '../representation/escape-terminal-control-characters.js';
|
|
39
|
+
import { cursorBootstrapCompleteForStore } from './cursor-bootstrap-state.js';
|
|
34
40
|
import { SessionLogger } from './session/session-logger.js';
|
|
35
41
|
import { SessionEventQueue } from './session/session-event-queue.js';
|
|
36
42
|
import { bufferDispatchHoldEvents, createDispatchHoldState, pruneStalePermissionEvents, } from './session/dispatch-hold.js';
|
|
37
43
|
import { createDispatchHoldReminderMonitor, formatDispatchHoldReminderMessage, } from './session/dispatch-hold-reminder-monitor.js';
|
|
38
44
|
import { operatorInputMaxTurns, resolveMaxTurns, } from './session-policy.js';
|
|
39
|
-
import { runConductorSessionDriver } from './conductor-session-driver.js';
|
|
45
|
+
import { runConductorSessionDriver, } from './conductor-session-driver.js';
|
|
40
46
|
import { isOperatorExitCommand } from './operator-exit.js';
|
|
41
47
|
import { isOperatorCloseCommand } from './operator-close.js';
|
|
42
48
|
import { isOperatorReconnectCommand } from './operator-reconnect.js';
|
|
43
49
|
import { parseOperatorMessageDelivery } from './operator-command.js';
|
|
44
|
-
import { assertSessionResumeStoreMatches, requireLocatedSessionResumeStoreForResume, saveSessionResumeStore, SESSION_RESUME_STORE_VERSION,
|
|
50
|
+
import { assertSessionResumeStoreMatches, canonicalSessionResumeStorePath, requireLocatedSessionResumeStoreForResume, saveSessionResumeStore, SESSION_RESUME_STORE_VERSION, } from '../session/session-resume-store.js';
|
|
45
51
|
import { buildSessionModelsSummary, } from '../session/build-session-models-summary.js';
|
|
46
|
-
import { saveSessionStatusLine, sessionStateStorePath, loadSessionStateStore,
|
|
52
|
+
import { saveSessionStatusLine, sessionStateStorePath, loadSessionStateStore, } from '../session/session-state-store.js';
|
|
47
53
|
import { loadToolCallSnapshotHistory, pruneExpiredToolCallSnapshotHistoryFiles, saveToolCallSnapshotHistory, toolCallSnapshotHistoryPath, } from '../session/tool-call-snapshot-history.js';
|
|
48
|
-
import { loadOpenQuestionsStore,
|
|
54
|
+
import { loadOpenQuestionsStore, openQuestionsStorePath, saveOpenQuestionsStore, } from '../session/open-questions-store.js';
|
|
55
|
+
import { sessionSnapshotPaths } from '../session/session-snapshot-paths.js';
|
|
49
56
|
import { CONDUCTOR_MESSAGE_HISTORY_MAX_ENTRIES, OpenQuestionControlOperationError, startOpenQuestionControlServer, } from '../session/open-question-control.js';
|
|
50
57
|
import { formatPermissionSummaryForOperator } from '../permission/format-permission-summary-for-operator.js';
|
|
51
58
|
import { enrichSessionUsageWithCost } from '../usage/enrich-session-usage-cost.js';
|
|
52
59
|
import { SessionUsageTracker } from '../usage/session-usage-tracker.js';
|
|
60
|
+
import { ConductorDispatchLifecycle } from './conductor-dispatch-lifecycle.js';
|
|
61
|
+
import { ConductorRecoveryInbox } from './conductor-recovery-inbox.js';
|
|
53
62
|
import { enqueueOperatorMessage as enqueueOperatorMessageEvent, submitOperatorInput, } from './submit-operator-input.js';
|
|
54
63
|
import { createGitHubMonitor, } from '../github/github-monitor.js';
|
|
55
64
|
import { resolveConductorBackendSetting, resolveConductorPiResourcePaths, resolveGitHubMonitorEnabled, } from '../config/resolve-settings.js';
|
|
@@ -63,7 +72,6 @@ import { createRegisterGitHubWatchTool } from '../github/register-github-watch-t
|
|
|
63
72
|
import { createUnregisterGitHubWatchTool } from '../github/unregister-github-watch-tool.js';
|
|
64
73
|
import { compileConductorSystemPrompt } from '../prompt/compile-system-prompt.js';
|
|
65
74
|
import { loadUserInstructions } from '../prompt/load-user-instructions.js';
|
|
66
|
-
import { resolveEnsemblePaths } from '../ensemble-paths.js';
|
|
67
75
|
const OPEN_QUESTION_CONTROL_DRAIN_TIMEOUT_MS = 5_000;
|
|
68
76
|
const RECORDED_ANSWER_UNKNOWN_DISPATCH = {
|
|
69
77
|
outcome: 'unknown',
|
|
@@ -168,7 +176,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
168
176
|
});
|
|
169
177
|
});
|
|
170
178
|
attachLegacySessionCallbacks(sessionLogger, options);
|
|
171
|
-
const expiredHistory = await pruneExpiredToolCallSnapshotHistoryFiles(options.repoRoot);
|
|
179
|
+
const expiredHistory = await pruneExpiredToolCallSnapshotHistoryFiles({ repoRoot: options.repoRoot, issueUrl: options.issueUrl });
|
|
172
180
|
if (expiredHistory.failedCount > 0) {
|
|
173
181
|
sessionLogger.emit({
|
|
174
182
|
type: 'harness.warning',
|
|
@@ -185,6 +193,16 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
185
193
|
let lastConductorMessage = null;
|
|
186
194
|
const conductorMessages = [];
|
|
187
195
|
const eventQueue = new SessionEventQueue();
|
|
196
|
+
const resumeNoticeDetails = new Set();
|
|
197
|
+
const reportResumeNotice = (message) => {
|
|
198
|
+
if (resumeNoticeDetails.has(message))
|
|
199
|
+
return;
|
|
200
|
+
resumeNoticeDetails.add(message);
|
|
201
|
+
sessionLogger.emit({ type: 'harness.warning', message });
|
|
202
|
+
};
|
|
203
|
+
const recoveryInbox = new ConductorRecoveryInbox();
|
|
204
|
+
const dispatchLifecycle = new ConductorDispatchLifecycle();
|
|
205
|
+
startupCleanup.add(() => recoveryInbox.dispose());
|
|
188
206
|
const openQuestionDispatchReceipts = new WeakMap();
|
|
189
207
|
const pendingOpenQuestionDispatchReceipts = new Set();
|
|
190
208
|
const dispatchHoldState = createDispatchHoldState();
|
|
@@ -207,11 +225,13 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
207
225
|
let githubMonitorCursor;
|
|
208
226
|
let githubMonitor;
|
|
209
227
|
let activeResumeStorePath;
|
|
210
|
-
let
|
|
228
|
+
let activeLocatedResumeStore;
|
|
229
|
+
let createdHarnessCliVersion = options.cliPackageVersion;
|
|
211
230
|
let drainStartupResumeStoreWrites = async () => { };
|
|
212
231
|
const pendingGitHubRecoveries = [];
|
|
213
232
|
const conductorCwd = options.conductorCwd ?? process.cwd();
|
|
214
233
|
let cursorBootstrapRunId;
|
|
234
|
+
const cursorBootstrapState = conductorBackend === 'cursor' ? { status: 'incomplete' } : undefined;
|
|
215
235
|
const mcpServers = await resolveMcpServers(options.repoRoot, options.mcpConfigOptions);
|
|
216
236
|
const mcpConfigDigest = computeMcpConfigDigest(mcpServers);
|
|
217
237
|
const mcpConfigConfigured = Object.keys(mcpServers).length > 0;
|
|
@@ -221,10 +241,13 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
221
241
|
const locatedResumeStore = await requireLocatedSessionResumeStoreForResume({
|
|
222
242
|
repoRoot: options.repoRoot,
|
|
223
243
|
conductorAgentId: options.resumeAgentId,
|
|
244
|
+
issueUrl: options.issueUrl,
|
|
224
245
|
});
|
|
225
246
|
const loadedResumeStore = locatedResumeStore.resumeStore;
|
|
247
|
+
activeLocatedResumeStore = locatedResumeStore;
|
|
248
|
+
// A resume keeps its origin version; a legacy store stays without one.
|
|
249
|
+
createdHarnessCliVersion = loadedResumeStore.createdHarnessCliVersion;
|
|
226
250
|
activeResumeStorePath = locatedResumeStore.path;
|
|
227
|
-
activeStoreLocation = locatedResumeStore.location;
|
|
228
251
|
const savedConfigDigestScheme = loadedResumeStore.ensembleConfigDigestScheme;
|
|
229
252
|
const effectiveConfigDigestScheme = savedConfigDigestScheme ?? 'full';
|
|
230
253
|
const currentEnsembleConfigDigest = effectiveConfigDigestScheme === 'resume-feasibility'
|
|
@@ -233,17 +256,39 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
233
256
|
assertSessionResumeStoreMatches(loadedResumeStore, {
|
|
234
257
|
conductorAgentId: options.resumeAgentId,
|
|
235
258
|
issueUrl: options.issueUrl,
|
|
236
|
-
repoRoot: options.repoRoot,
|
|
237
|
-
conductorBackend,
|
|
238
|
-
mcpConfigDigest,
|
|
239
|
-
mcpConfigConfigured,
|
|
240
|
-
ensembleConfigDigest: currentEnsembleConfigDigest,
|
|
241
259
|
});
|
|
242
|
-
if (loadedResumeStore.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
260
|
+
if (resolvePath(loadedResumeStore.repoRoot) !== resolvePath(options.repoRoot)) {
|
|
261
|
+
reportResumeNotice(`保存時の repoRoot ${loadedResumeStore.repoRoot} と現在の repoRoot ${options.repoRoot} が異なります。現在の clone を使って再開します。Store に commit SHA がないため、保存時 clone にだけある local commit / 未コミット変更は照合・復元できません。`);
|
|
262
|
+
if (!(await pathExists(loadedResumeStore.repoRoot))) {
|
|
263
|
+
reportResumeNotice(`保存時の clone ${loadedResumeStore.repoRoot} は現在参照できません。そこにだけあった未コミット変更は復元できず、Store に commit SHA がないため欠落した commit の有無も照合できません。`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (loadedResumeStore.conductorCwd !== undefined &&
|
|
267
|
+
resolvePath(loadedResumeStore.conductorCwd) !== resolvePath(conductorCwd)) {
|
|
268
|
+
reportResumeNotice(`保存時の conductor cwd ${loadedResumeStore.conductorCwd} は現在の cwd ${conductorCwd} とは異なります。現在の cwd で backend resume を試みます。以前の cwd にだけある local state は引き継がれず、Store に commit SHA がないため commit の差も照合できません。`);
|
|
269
|
+
if (!(await pathExists(loadedResumeStore.conductorCwd))) {
|
|
270
|
+
reportResumeNotice(`保存時の conductor cwd ${loadedResumeStore.conductorCwd} は見つからないため、以前の workspace のローカル状態は復元できません。`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const savedBackend = loadedResumeStore.conductorBackend ?? 'cursor';
|
|
274
|
+
if (savedBackend !== conductorBackend) {
|
|
275
|
+
reportResumeNotice(`保存時の conductor backend は ${savedBackend}、現在の設定は ${conductorBackend} です。現在の backend で復元を試みます。復元できなければ session は失敗として扱います。`);
|
|
276
|
+
}
|
|
277
|
+
if (loadedResumeStore.ensembleConfigDigest !== undefined &&
|
|
278
|
+
loadedResumeStore.ensembleConfigDigest !== currentEnsembleConfigDigest) {
|
|
279
|
+
reportResumeNotice('保存時と現在の Ensemble config が異なります。保存時の設定には戻さず、現在の clone の config で復元を試みます。');
|
|
280
|
+
}
|
|
281
|
+
else if (loadedResumeStore.ensembleConfigDigest === undefined) {
|
|
282
|
+
reportResumeNotice('SessionResumeStore に config digest がないため差分を比較できません。現在の clone の config で復元します。');
|
|
283
|
+
}
|
|
284
|
+
if (loadedResumeStore.mcpConfigDigest === undefined
|
|
285
|
+
? mcpConfigConfigured
|
|
286
|
+
: loadedResumeStore.mcpConfigDigest !== mcpConfigDigest) {
|
|
287
|
+
reportResumeNotice('保存時と現在の MCP config が異なるか、保存時の digest がありません。現在の clone の MCP config を使って復元を試みます。');
|
|
288
|
+
}
|
|
289
|
+
if (JSON.stringify(loadedResumeStore.profile) !==
|
|
290
|
+
JSON.stringify(options.profile)) {
|
|
291
|
+
reportResumeNotice('保存時の team profile と現在の clone で解決した profile が異なります。以降は現在の profile を使います。');
|
|
247
292
|
}
|
|
248
293
|
const hasComparableLegacyFullDigest = effectiveConfigDigestScheme === 'full' &&
|
|
249
294
|
loadedResumeStore.ensembleConfigDigest !== undefined;
|
|
@@ -270,6 +315,35 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
270
315
|
// acquired resource is released successfully; otherwise keep this record
|
|
271
316
|
// marked unknown/running so it does not claim a possibly active session is
|
|
272
317
|
// closed.
|
|
318
|
+
cursorBootstrapRunId = loadedResumeStore.cursorBootstrapRunId;
|
|
319
|
+
if (cursorBootstrapState) {
|
|
320
|
+
const savedBootstrapComplete = loadedResumeStore.cursorBootstrapComplete;
|
|
321
|
+
cursorBootstrapState.status =
|
|
322
|
+
savedBootstrapComplete === undefined
|
|
323
|
+
? 'unknown'
|
|
324
|
+
: savedBootstrapComplete
|
|
325
|
+
? 'complete'
|
|
326
|
+
: 'incomplete';
|
|
327
|
+
if (cursorBootstrapState.status === 'unknown') {
|
|
328
|
+
if (options.operatorCanInspectRecovery !== true ||
|
|
329
|
+
!options.bindOperatorInput) {
|
|
330
|
+
throw new Error([
|
|
331
|
+
'旧 Cursor session の SessionResumeStore に bootstrap 状態がなく、compiled prompt が provider に届いたか判定できません。',
|
|
332
|
+
'安全のため backend resume と event dispatch は開始しませんでした。',
|
|
333
|
+
'stdin / stdout / stderr がすべて対話 TTY の環境で `--continue` し、`/recovery bootstrap assume-complete` または `/recovery bootstrap assume-incomplete` を明示してください。',
|
|
334
|
+
'complete は prompt を再送せず、incomplete は次の新しい event に prompt を添えます。どちらも失敗 input や旧 queue は再送しません。',
|
|
335
|
+
].join('\n'));
|
|
336
|
+
}
|
|
337
|
+
sessionLogger.emit({
|
|
338
|
+
type: 'harness.warning',
|
|
339
|
+
message: [
|
|
340
|
+
'旧 Cursor session の SessionResumeStore に bootstrap 状態がなく、compiled prompt が provider に届いたか判定できません。',
|
|
341
|
+
'operator が `/recovery bootstrap assume-complete` または `/recovery bootstrap assume-incomplete` を選んで判断を保存するまで、すべての event dispatch を停止します。',
|
|
342
|
+
'どちらの選択も失敗 input や旧 queue を復元・再送しません。',
|
|
343
|
+
].join(' '),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
273
347
|
const resumeStore = {
|
|
274
348
|
...loadedResumeStore,
|
|
275
349
|
lifecycle: 'unknown',
|
|
@@ -278,7 +352,6 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
278
352
|
harnessSocketPath: undefined,
|
|
279
353
|
updatedAt: Date.now(),
|
|
280
354
|
};
|
|
281
|
-
cursorBootstrapRunId = loadedResumeStore.cursorBootstrapRunId;
|
|
282
355
|
harnessPhase = 'running';
|
|
283
356
|
harnessModifiedAt = resumeStore.modifiedAt;
|
|
284
357
|
let resumeStoreActivationCommitted = false;
|
|
@@ -300,6 +373,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
300
373
|
const history = await loadToolCallSnapshotHistory({
|
|
301
374
|
repoRoot: options.repoRoot,
|
|
302
375
|
conductorAgentId: options.resumeAgentId,
|
|
376
|
+
issueUrl: options.issueUrl,
|
|
303
377
|
});
|
|
304
378
|
resumeToolCallSnapshots = history.entries;
|
|
305
379
|
toolCallHistoryNeedsRewrite = history.needsRewrite;
|
|
@@ -309,47 +383,8 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
309
383
|
message: `${history.warning}; the session will continue without affected history`,
|
|
310
384
|
});
|
|
311
385
|
}
|
|
312
|
-
const openQuestionsPath =
|
|
313
|
-
repoRoot: options.repoRoot,
|
|
314
|
-
conductorAgentId: options.resumeAgentId,
|
|
315
|
-
issueUrl: options.issueUrl,
|
|
316
|
-
location: activeStoreLocation,
|
|
317
|
-
});
|
|
386
|
+
const openQuestionsPath = sessionSnapshotPaths(options.repoRoot, locatedResumeStore, 'open-questions')[0];
|
|
318
387
|
let openQuestionsSnapshot = await loadOpenQuestionsStore(openQuestionsPath);
|
|
319
|
-
if (!openQuestionsSnapshot) {
|
|
320
|
-
const fallbackPaths = [
|
|
321
|
-
...(activeStoreLocation === 'canonical-slug'
|
|
322
|
-
? [
|
|
323
|
-
openQuestionsStorePath({
|
|
324
|
-
repoRoot: options.repoRoot,
|
|
325
|
-
conductorAgentId: options.resumeAgentId,
|
|
326
|
-
location: 'user-path-hash',
|
|
327
|
-
}),
|
|
328
|
-
]
|
|
329
|
-
: []),
|
|
330
|
-
legacyOpenQuestionsStorePath({
|
|
331
|
-
repoRoot: options.repoRoot,
|
|
332
|
-
conductorAgentId: options.resumeAgentId,
|
|
333
|
-
}),
|
|
334
|
-
];
|
|
335
|
-
for (const fallbackPath of fallbackPaths) {
|
|
336
|
-
openQuestionsSnapshot = await loadOpenQuestionsStore(fallbackPath);
|
|
337
|
-
if (openQuestionsSnapshot)
|
|
338
|
-
break;
|
|
339
|
-
}
|
|
340
|
-
if (openQuestionsSnapshot) {
|
|
341
|
-
try {
|
|
342
|
-
await saveOpenQuestionsStore(openQuestionsPath, openQuestionsSnapshot);
|
|
343
|
-
}
|
|
344
|
-
catch (error) {
|
|
345
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
346
|
-
sessionLogger.emit({
|
|
347
|
-
type: 'harness.warning',
|
|
348
|
-
message: `旧保存先の open question を user 保存先へ移行できませんでした。今回のセッションでは旧 YAML を読み込みます。 error=${detail}`,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
388
|
if (openQuestionsSnapshot) {
|
|
354
389
|
openQuestions.restore(openQuestionsSnapshot);
|
|
355
390
|
}
|
|
@@ -370,9 +405,6 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
370
405
|
});
|
|
371
406
|
}
|
|
372
407
|
}
|
|
373
|
-
activeProfile = resumeStore.profile;
|
|
374
|
-
// ResumeStores written before this setting always started every worker eagerly.
|
|
375
|
-
activeLazyWorkers = resumeStore.lazyWorkers ?? false;
|
|
376
408
|
githubMonitorCursor = resumeStore.githubMonitor;
|
|
377
409
|
for (const [name, worker] of Object.entries(resumeStore.workers)) {
|
|
378
410
|
workerSessions.set(name, {
|
|
@@ -499,23 +531,70 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
499
531
|
});
|
|
500
532
|
},
|
|
501
533
|
};
|
|
534
|
+
const piAgentDir = resolveConductorPiResourcePaths({
|
|
535
|
+
repoRoot: options.repoRoot,
|
|
536
|
+
config: ensembleConfig,
|
|
537
|
+
}).agentDir;
|
|
502
538
|
const workers = profileWorkersToSessionSpecs(activeProfile, {
|
|
503
539
|
defaultAcp: options.defaultAcp,
|
|
504
540
|
spawnBase,
|
|
541
|
+
repoRoot: options.repoRoot,
|
|
542
|
+
issueNumber: issue.number,
|
|
543
|
+
...(piAgentDir ? { piAgentDir } : {}),
|
|
544
|
+
onWarning: (message) => sessionLogger.emit({ type: 'harness.warning', message }),
|
|
505
545
|
});
|
|
506
546
|
if (workers.length > 0) {
|
|
507
547
|
validateWorkerAcpPrerequisites(workers.map((worker) => resolveWorkerAcpSpawn({
|
|
508
548
|
defaultOptions: options.defaultAcp,
|
|
509
549
|
modelTag: worker.modelTag,
|
|
510
550
|
})));
|
|
511
|
-
finalizeSessionWorkerSpecs(workers, options.defaultAcp);
|
|
551
|
+
finalizeSessionWorkerSpecs(workers, options.repoRoot, issue.number, options.defaultAcp, piAgentDir);
|
|
512
552
|
}
|
|
513
553
|
const workerAcpFingerprints = new Map(workers.map((worker) => [worker.name, worker.acpFingerprint]));
|
|
514
554
|
let teardownStarted = false;
|
|
515
555
|
const workerWorktree = options.workerWorktree ??
|
|
516
556
|
(workers.length > 0
|
|
517
|
-
? await resolveWorkerWorkspace(options.repoRoot, issue, options.workerWorktreeMode ?? 'isolated'
|
|
557
|
+
? await resolveWorkerWorkspace(options.repoRoot, issue, options.workerWorktreeMode ?? 'isolated', {
|
|
558
|
+
resume: Boolean(options.resumeAgentId),
|
|
559
|
+
onNotice: reportResumeNotice,
|
|
560
|
+
})
|
|
518
561
|
: undefined);
|
|
562
|
+
if (options.resumeAgentId) {
|
|
563
|
+
const currentWorkers = new Map(workers.map((worker) => [worker.name, worker]));
|
|
564
|
+
for (const [name, savedWorker] of workerSessions) {
|
|
565
|
+
if (!currentWorkers.has(name)) {
|
|
566
|
+
reportResumeNotice(`保存 session に worker「${name}」がありますが、現在の profile には定義がありません。この worker session は復元対象から外れます。`);
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
const currentWorker = currentWorkers.get(name);
|
|
570
|
+
const savedAcpSpawn = savedWorker.acpSpawn;
|
|
571
|
+
const currentAcpSpawn = currentWorker.acpFingerprint;
|
|
572
|
+
if (savedAcpSpawn &&
|
|
573
|
+
currentAcpSpawn &&
|
|
574
|
+
(savedAcpSpawn.preset !== currentAcpSpawn.preset ||
|
|
575
|
+
(savedAcpSpawn.preset === 'pi' &&
|
|
576
|
+
currentAcpSpawn.preset === 'pi' &&
|
|
577
|
+
(savedAcpSpawn.piRuntime ?? 'byo') !==
|
|
578
|
+
(currentAcpSpawn.piRuntime ?? 'byo')) ||
|
|
579
|
+
(savedAcpSpawn.preset === 'custom' &&
|
|
580
|
+
currentAcpSpawn.preset === 'custom' &&
|
|
581
|
+
(savedAcpSpawn.command !== currentAcpSpawn.command ||
|
|
582
|
+
JSON.stringify(savedAcpSpawn.args) !==
|
|
583
|
+
JSON.stringify(currentAcpSpawn.args))))) {
|
|
584
|
+
reportResumeNotice(`worker「${name}」の保存時 ACP preset/runtime と現在の設定が異なります。現在の設定で ACP session/load を試みます。`);
|
|
585
|
+
}
|
|
586
|
+
if (!savedWorker.acpCwd)
|
|
587
|
+
continue;
|
|
588
|
+
const currentCwd = currentWorker.resolvedWorkspacePath ?? workerWorktree?.path;
|
|
589
|
+
if (currentCwd &&
|
|
590
|
+
resolvePath(savedWorker.acpCwd) !== resolvePath(currentCwd)) {
|
|
591
|
+
reportResumeNotice(`worker「${name}」の保存時 ACP cwd ${savedWorker.acpCwd} と現在の workspace ${currentCwd} が異なります。現在の workspace で ACP session/load を試みます。以前の cwd にだけある local changes はコピーされず、Store に commit SHA がないため commit の差も照合できません。`);
|
|
592
|
+
if (!(await pathExists(savedWorker.acpCwd))) {
|
|
593
|
+
reportResumeNotice(`worker「${name}」の保存時 ACP cwd ${savedWorker.acpCwd} は見つかりません。そこにだけあった未コミット変更は復元できず、保存 Store に commit SHA がないため欠落 commit の有無も照合できません。`);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
519
598
|
if (workerWorktree) {
|
|
520
599
|
sessionLogger.emit({
|
|
521
600
|
type: 'harness.worktree',
|
|
@@ -627,6 +706,34 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
627
706
|
eventQueue.enqueue({ type: 'worker.completed', result });
|
|
628
707
|
scheduleSessionResumeStoreFlush();
|
|
629
708
|
},
|
|
709
|
+
onWorkerSessionRecovered: async (notification) => {
|
|
710
|
+
workerSessions.set(notification.name, {
|
|
711
|
+
acpSessionId: notification.acpSessionId,
|
|
712
|
+
acpCwd: notification.acpCwd,
|
|
713
|
+
...(workerAcpFingerprints.get(notification.name)
|
|
714
|
+
? { acpSpawn: workerAcpFingerprints.get(notification.name) }
|
|
715
|
+
: {}),
|
|
716
|
+
});
|
|
717
|
+
try {
|
|
718
|
+
await flushSessionResumeStore();
|
|
719
|
+
}
|
|
720
|
+
catch (error) {
|
|
721
|
+
reportResumeStoreFlushFailure(error);
|
|
722
|
+
}
|
|
723
|
+
const detail = notification.reason === 'session_load_failed'
|
|
724
|
+
? '保存済み ACP session を読み込めなかったため'
|
|
725
|
+
: '保存済み ACP thread の履歴を読めなかったため';
|
|
726
|
+
sessionLogger.emit({
|
|
727
|
+
type: 'harness.warning',
|
|
728
|
+
message: `worker.session.recovered name=${notification.name} kind=${notification.kind}: ${detail}新しい session で再開します。`,
|
|
729
|
+
});
|
|
730
|
+
eventQueue.enqueue({
|
|
731
|
+
type: 'worker.session.recovered',
|
|
732
|
+
name: notification.name,
|
|
733
|
+
kind: notification.kind,
|
|
734
|
+
reason: notification.reason,
|
|
735
|
+
});
|
|
736
|
+
},
|
|
630
737
|
onWorkerFailed: (failure) => {
|
|
631
738
|
sessionLogger.emit({ type: 'worker.failed', failure });
|
|
632
739
|
eventQueue.enqueue({ type: 'worker.failed', failure });
|
|
@@ -820,22 +927,8 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
820
927
|
repoRoot: options.repoRoot,
|
|
821
928
|
conductorAgentId: conductorAgent.agentId,
|
|
822
929
|
issueUrl: options.issueUrl,
|
|
823
|
-
location:
|
|
824
|
-
}), statusLine, undefined
|
|
825
|
-
...(activeStoreLocation === 'canonical-slug'
|
|
826
|
-
? [
|
|
827
|
-
sessionStateStorePath({
|
|
828
|
-
repoRoot: options.repoRoot,
|
|
829
|
-
conductorAgentId: conductorAgent.agentId,
|
|
830
|
-
location: 'user-path-hash',
|
|
831
|
-
}),
|
|
832
|
-
]
|
|
833
|
-
: []),
|
|
834
|
-
legacySessionStateStorePath({
|
|
835
|
-
repoRoot: options.repoRoot,
|
|
836
|
-
conductorAgentId: conductorAgent.agentId,
|
|
837
|
-
}),
|
|
838
|
-
]));
|
|
930
|
+
location: 'canonical-slug',
|
|
931
|
+
}), statusLine, undefined));
|
|
839
932
|
sessionStateWriteQueue = write.catch(() => { });
|
|
840
933
|
return write;
|
|
841
934
|
},
|
|
@@ -885,16 +978,19 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
885
978
|
: {}),
|
|
886
979
|
...(conductorBackend === 'pi'
|
|
887
980
|
? {
|
|
981
|
+
issueUrl: options.issueUrl,
|
|
888
982
|
pi: resolveConductorPiResourcePaths({
|
|
889
983
|
repoRoot: options.repoRoot,
|
|
890
984
|
config: ensembleConfig,
|
|
891
985
|
}),
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
986
|
+
...(activeLocatedResumeStore
|
|
987
|
+
? {
|
|
988
|
+
resumeCwds: [
|
|
989
|
+
activeLocatedResumeStore.resumeStore.conductorCwd,
|
|
990
|
+
activeLocatedResumeStore.resumeStore.repoRoot,
|
|
991
|
+
].filter((cwd) => Boolean(cwd)),
|
|
992
|
+
}
|
|
993
|
+
: {}),
|
|
898
994
|
}
|
|
899
995
|
: {}),
|
|
900
996
|
...(Object.keys(mcpServers).length > 0 ? { mcpServers } : {}),
|
|
@@ -925,19 +1021,42 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
925
1021
|
throw error;
|
|
926
1022
|
}
|
|
927
1023
|
startupCleanup.add(async () => {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
}
|
|
931
|
-
else {
|
|
932
|
-
await conductorAgent.close();
|
|
933
|
-
}
|
|
1024
|
+
await closeConductorAgentOnce(conductorAgent, {
|
|
1025
|
+
forResume: Boolean(options.resumeAgentId),
|
|
1026
|
+
});
|
|
934
1027
|
});
|
|
935
1028
|
// Factories may not be abortable while pending. Register the returned agent
|
|
936
1029
|
// before checking shutdown so a late success is still closed by the guard.
|
|
937
1030
|
shutdownSignal.throwIfAborted();
|
|
1031
|
+
if (options.resumeAgentId) {
|
|
1032
|
+
const currentSessionStatePath = sessionStateStorePath({
|
|
1033
|
+
repoRoot: options.repoRoot,
|
|
1034
|
+
conductorAgentId: conductorAgent.agentId,
|
|
1035
|
+
issueUrl: options.issueUrl,
|
|
1036
|
+
location: 'canonical-slug',
|
|
1037
|
+
});
|
|
1038
|
+
try {
|
|
1039
|
+
const currentState = await loadSessionStateStore(currentSessionStatePath);
|
|
1040
|
+
if (!currentState &&
|
|
1041
|
+
activeLocatedResumeStore &&
|
|
1042
|
+
resolvePath(activeLocatedResumeStore.resumeStore.repoRoot) !==
|
|
1043
|
+
resolvePath(options.repoRoot)) {
|
|
1044
|
+
reportResumeNotice('保存時 clone に残る legacy session-state YAML は通常読み取り対象ではありません。以前の statusLine と履歴を復元する必要がある場合は、migration tool で canonical slug へ移してください。');
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
catch (error) {
|
|
1048
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1049
|
+
sessionLogger.emit({
|
|
1050
|
+
type: 'harness.warning',
|
|
1051
|
+
message: `Issue 保存先の session state を読み込めませんでした。 error=${detail}`,
|
|
1052
|
+
});
|
|
1053
|
+
reportResumeNotice(`Issue 保存先の session-state YAML を読み込めませんでした。原因: ${detail}`);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
938
1056
|
const conductorHandle = { conductor: conductorAgent };
|
|
939
|
-
activeResumeStorePath ??=
|
|
1057
|
+
activeResumeStorePath ??= canonicalSessionResumeStorePath({
|
|
940
1058
|
repoRoot: options.repoRoot,
|
|
1059
|
+
issueUrl: options.issueUrl,
|
|
941
1060
|
conductorAgentId: conductorAgent.agentId,
|
|
942
1061
|
});
|
|
943
1062
|
// Keep auth/transport reconnects on the same backend factory as the session.
|
|
@@ -945,26 +1064,49 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
945
1064
|
conductorAgentFactory,
|
|
946
1065
|
conductorOptions,
|
|
947
1066
|
retrySuppressionSignal: shutdownIntentController.signal,
|
|
948
|
-
onAuthReconnectAttempt: ({ agentId }) => {
|
|
1067
|
+
onAuthReconnectAttempt: ({ agentId, source, }) => {
|
|
949
1068
|
sessionLogger.emit({
|
|
950
1069
|
type: 'conductor.auth.reconnect',
|
|
951
1070
|
agentId,
|
|
1071
|
+
status: 'attempt',
|
|
1072
|
+
...(source ? { source } : {}),
|
|
952
1073
|
});
|
|
953
1074
|
},
|
|
954
|
-
|
|
1075
|
+
onAuthReconnectComplete: ({ agentId, success, source, closeFailed, }) => {
|
|
1076
|
+
sessionLogger.emit({
|
|
1077
|
+
type: 'conductor.auth.reconnect',
|
|
1078
|
+
agentId,
|
|
1079
|
+
status: success ? 'succeeded' : 'failed',
|
|
1080
|
+
...(source ? { source } : {}),
|
|
1081
|
+
});
|
|
1082
|
+
if (closeFailed) {
|
|
1083
|
+
sessionLogger.emit({
|
|
1084
|
+
type: 'harness.warning',
|
|
1085
|
+
message: '旧 conductor の終了処理に失敗したため、リソース解放は確認できません。再接続後の状態を確認してください。',
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
},
|
|
1089
|
+
onTransportReconnectAttempt: ({ agentId, source, }) => {
|
|
955
1090
|
sessionLogger.emit({
|
|
956
1091
|
type: 'conductor.transport.reconnect',
|
|
957
1092
|
agentId,
|
|
958
1093
|
status: 'attempt',
|
|
1094
|
+
...(source ? { source } : {}),
|
|
959
1095
|
});
|
|
960
1096
|
},
|
|
961
|
-
onTransportReconnectComplete: ({ agentId, success,
|
|
1097
|
+
onTransportReconnectComplete: ({ agentId, success, source, closeFailed, }) => {
|
|
962
1098
|
sessionLogger.emit({
|
|
963
1099
|
type: 'conductor.transport.reconnect',
|
|
964
1100
|
agentId,
|
|
965
1101
|
status: success ? 'succeeded' : 'failed',
|
|
966
|
-
...(
|
|
1102
|
+
...(source ? { source } : {}),
|
|
967
1103
|
});
|
|
1104
|
+
if (closeFailed) {
|
|
1105
|
+
sessionLogger.emit({
|
|
1106
|
+
type: 'harness.warning',
|
|
1107
|
+
message: '旧 conductor の終了処理に失敗したため、リソース解放は確認できません。再接続後の状態を確認してください。',
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
968
1110
|
},
|
|
969
1111
|
};
|
|
970
1112
|
let sessionResumeStoreWriteQueue = Promise.resolve();
|
|
@@ -992,14 +1134,23 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
992
1134
|
(harnessPhase === 'running' || harnessPhase === 'idle'
|
|
993
1135
|
? 'unknown'
|
|
994
1136
|
: undefined);
|
|
1137
|
+
const cursorBootstrapComplete = cursorBootstrapState
|
|
1138
|
+
? cursorBootstrapCompleteForStore(cursorBootstrapState)
|
|
1139
|
+
: undefined;
|
|
995
1140
|
return {
|
|
996
1141
|
version: SESSION_RESUME_STORE_VERSION,
|
|
997
1142
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
998
1143
|
conductorBackend,
|
|
1144
|
+
...(createdHarnessCliVersion !== undefined
|
|
1145
|
+
? { createdHarnessCliVersion }
|
|
1146
|
+
: {}),
|
|
999
1147
|
conductorCwd,
|
|
1000
1148
|
...(cursorBootstrapRunId
|
|
1001
1149
|
? { cursorBootstrapRunId }
|
|
1002
1150
|
: {}),
|
|
1151
|
+
...(cursorBootstrapComplete !== undefined
|
|
1152
|
+
? { cursorBootstrapComplete }
|
|
1153
|
+
: {}),
|
|
1003
1154
|
lazyWorkers: activeLazyWorkers,
|
|
1004
1155
|
...(harnessSocketPath ? { harnessSocketPath } : {}),
|
|
1005
1156
|
issueUrl: options.issueUrl,
|
|
@@ -1033,7 +1184,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1033
1184
|
repoRoot: options.repoRoot,
|
|
1034
1185
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
1035
1186
|
issueUrl: options.issueUrl,
|
|
1036
|
-
location:
|
|
1187
|
+
location: 'canonical-slug',
|
|
1037
1188
|
}), snapshot);
|
|
1038
1189
|
};
|
|
1039
1190
|
const persistSessionResumeStore = async (snapshot, lifecycle) => {
|
|
@@ -1121,6 +1272,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1121
1272
|
const toolCallHistoryPath = toolCallSnapshotHistoryPath({
|
|
1122
1273
|
repoRoot: options.repoRoot,
|
|
1123
1274
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
1275
|
+
issueUrl: options.issueUrl,
|
|
1124
1276
|
});
|
|
1125
1277
|
let toolCallHistoryFlushTimer;
|
|
1126
1278
|
let toolCallHistoryFlushQueue = Promise.resolve();
|
|
@@ -1293,9 +1445,38 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1293
1445
|
let stopReason = 'completed';
|
|
1294
1446
|
const continueOnConductorError = options.continueOnConductorError ?? false;
|
|
1295
1447
|
const waitForOperatorExit = options.waitForOperatorExit ?? false;
|
|
1448
|
+
const operatorCanInspectRecovery = options.operatorCanInspectRecovery === true;
|
|
1296
1449
|
let operatorRequestedExit = false;
|
|
1297
1450
|
let operatorRequestedClose = false;
|
|
1298
1451
|
let disposeOperatorInput;
|
|
1452
|
+
const resolveCursorBootstrapUnknown = (assumption) => {
|
|
1453
|
+
if (!operatorCanInspectRecovery ||
|
|
1454
|
+
!cursorBootstrapState ||
|
|
1455
|
+
cursorBootstrapState.status !== 'unknown') {
|
|
1456
|
+
return false;
|
|
1457
|
+
}
|
|
1458
|
+
cursorBootstrapState.status = 'saving';
|
|
1459
|
+
cursorBootstrapState.pendingAssumption = assumption;
|
|
1460
|
+
void flushSessionResumeStore()
|
|
1461
|
+
.then(() => {
|
|
1462
|
+
cursorBootstrapState.status =
|
|
1463
|
+
assumption === 'assume-complete' ? 'complete' : 'incomplete';
|
|
1464
|
+
delete cursorBootstrapState.pendingAssumption;
|
|
1465
|
+
sessionLogger.emit({
|
|
1466
|
+
type: 'harness.warning',
|
|
1467
|
+
message: assumption === 'assume-complete'
|
|
1468
|
+
? 'operator が Cursor bootstrap を complete と仮定する判断を SessionResumeStore に保存しました。compiled prompt は追加送信しません。'
|
|
1469
|
+
: 'operator が Cursor bootstrap を incomplete と仮定する判断を SessionResumeStore に保存しました。次の新しい event に compiled prompt を添えて送ります。',
|
|
1470
|
+
});
|
|
1471
|
+
})
|
|
1472
|
+
.catch((error) => {
|
|
1473
|
+
cursorBootstrapState.status = 'unknown';
|
|
1474
|
+
delete cursorBootstrapState.pendingAssumption;
|
|
1475
|
+
reportResumeStoreFlushFailure(error);
|
|
1476
|
+
})
|
|
1477
|
+
.finally(() => dispatchLifecycle.wake());
|
|
1478
|
+
return true;
|
|
1479
|
+
};
|
|
1299
1480
|
const onOperatorMessageQueued = (delivery) => {
|
|
1300
1481
|
scheduleSessionResumeStoreFlush();
|
|
1301
1482
|
if (delivery !== 'interrupt')
|
|
@@ -1347,23 +1528,33 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1347
1528
|
onOperatorMessageQueued(delivery);
|
|
1348
1529
|
return true;
|
|
1349
1530
|
};
|
|
1531
|
+
const requestOperatorShutdown = (mode) => {
|
|
1532
|
+
if (teardownStarted || operatorRequestedExit || operatorRequestedClose) {
|
|
1533
|
+
return false;
|
|
1534
|
+
}
|
|
1535
|
+
if (mode === 'exit') {
|
|
1536
|
+
sessionLogger.emit({ type: 'session.operator_exit' });
|
|
1537
|
+
workerSession.runtime.cancelAllActivePrompts();
|
|
1538
|
+
operatorRequestedExit = true;
|
|
1539
|
+
}
|
|
1540
|
+
else {
|
|
1541
|
+
sessionLogger.emit({ type: 'session.operator_close' });
|
|
1542
|
+
workerSession.runtime.cancelAllActivePrompts();
|
|
1543
|
+
operatorRequestedClose = true;
|
|
1544
|
+
}
|
|
1545
|
+
shutdownIntentController.abort();
|
|
1546
|
+
abortAfterOpenQuestionDrain(operatorTerminationController);
|
|
1547
|
+
return true;
|
|
1548
|
+
};
|
|
1350
1549
|
if (options.bindOperatorInput) {
|
|
1351
1550
|
const bindingDispose = options.bindOperatorInput({
|
|
1352
1551
|
submit: (message, submitOptions) => {
|
|
1353
1552
|
if (isOperatorExitCommand(message)) {
|
|
1354
|
-
|
|
1355
|
-
workerSession.runtime.cancelAllActivePrompts();
|
|
1356
|
-
operatorRequestedExit = true;
|
|
1357
|
-
shutdownIntentController.abort();
|
|
1358
|
-
abortAfterOpenQuestionDrain(operatorTerminationController);
|
|
1553
|
+
requestOperatorShutdown('exit');
|
|
1359
1554
|
return false;
|
|
1360
1555
|
}
|
|
1361
1556
|
if (isOperatorCloseCommand(message)) {
|
|
1362
|
-
|
|
1363
|
-
workerSession.runtime.cancelAllActivePrompts();
|
|
1364
|
-
operatorRequestedClose = true;
|
|
1365
|
-
shutdownIntentController.abort();
|
|
1366
|
-
abortAfterOpenQuestionDrain(operatorTerminationController);
|
|
1557
|
+
requestOperatorShutdown('close');
|
|
1367
1558
|
return false;
|
|
1368
1559
|
}
|
|
1369
1560
|
if (isOperatorReconnectCommand(message)) {
|
|
@@ -1395,6 +1586,21 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1395
1586
|
}]
|
|
1396
1587
|
: []),
|
|
1397
1588
|
}),
|
|
1589
|
+
listRecoverySnapshots: () => recoveryInbox.list(),
|
|
1590
|
+
...(operatorCanInspectRecovery
|
|
1591
|
+
? {
|
|
1592
|
+
getRecoverySnapshot: (recoveryId) => recoveryInbox.get(recoveryId),
|
|
1593
|
+
}
|
|
1594
|
+
: {}),
|
|
1595
|
+
clearRecoverySnapshot: (recoveryId) => recoveryInbox.remove(recoveryId),
|
|
1596
|
+
continueAfterRecovery: () => dispatchLifecycle.confirmRecovery(),
|
|
1597
|
+
recoveryAttentionAttemptId: () => dispatchLifecycle.pendingAttemptId,
|
|
1598
|
+
...(cursorBootstrapState && operatorCanInspectRecovery
|
|
1599
|
+
? {
|
|
1600
|
+
getCursorBootstrapStatus: () => cursorBootstrapState.status,
|
|
1601
|
+
resolveCursorBootstrapUnknown,
|
|
1602
|
+
}
|
|
1603
|
+
: {}),
|
|
1398
1604
|
});
|
|
1399
1605
|
if (typeof bindingDispose === 'function') {
|
|
1400
1606
|
disposeOperatorInput = bindingDispose;
|
|
@@ -1445,29 +1651,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1445
1651
|
repoRoot: options.repoRoot,
|
|
1446
1652
|
conductorAgentId: conductorAgent.agentId,
|
|
1447
1653
|
issueUrl: options.issueUrl,
|
|
1448
|
-
location:
|
|
1654
|
+
location: 'canonical-slug',
|
|
1449
1655
|
});
|
|
1450
|
-
const
|
|
1451
|
-
...(activeStoreLocation === 'canonical-slug'
|
|
1452
|
-
? [
|
|
1453
|
-
sessionStateStorePath({
|
|
1454
|
-
repoRoot: options.repoRoot,
|
|
1455
|
-
conductorAgentId: conductorAgent.agentId,
|
|
1456
|
-
location: 'user-path-hash',
|
|
1457
|
-
}),
|
|
1458
|
-
]
|
|
1459
|
-
: []),
|
|
1460
|
-
legacySessionStateStorePath({
|
|
1461
|
-
repoRoot: options.repoRoot,
|
|
1462
|
-
conductorAgentId: conductorAgent.agentId,
|
|
1463
|
-
}),
|
|
1464
|
-
];
|
|
1465
|
-
let sessionState = await loadSessionStateStore(currentStatePath);
|
|
1466
|
-
for (const fallbackPath of fallbackStatePaths) {
|
|
1467
|
-
if (sessionState)
|
|
1468
|
-
break;
|
|
1469
|
-
sessionState = await loadSessionStateStore(fallbackPath);
|
|
1470
|
-
}
|
|
1656
|
+
const sessionState = await loadSessionStateStore(currentStatePath);
|
|
1471
1657
|
return {
|
|
1472
1658
|
...openQuestions.snapshot(),
|
|
1473
1659
|
...(sessionState ? { sessionState } : {}),
|
|
@@ -1479,6 +1665,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1479
1665
|
}
|
|
1480
1666
|
return sendOperatorMessage({ message: text, delivery });
|
|
1481
1667
|
},
|
|
1668
|
+
requestOperatorShutdown: ({ mode }) => requestOperatorShutdown(mode),
|
|
1482
1669
|
answerOpenQuestion: async ({ questionId, answer }) => {
|
|
1483
1670
|
if (teardownStarted) {
|
|
1484
1671
|
throw new OpenQuestionControlOperationError(-32000, 'The session is shutting down.');
|
|
@@ -1589,6 +1776,10 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1589
1776
|
conductorHandle,
|
|
1590
1777
|
sendReconnect,
|
|
1591
1778
|
eventQueue,
|
|
1779
|
+
recoveryInbox,
|
|
1780
|
+
recoveryBackend: conductorBackend,
|
|
1781
|
+
dispatchLifecycle,
|
|
1782
|
+
operatorCanInspectRecovery,
|
|
1592
1783
|
dispatchHoldState,
|
|
1593
1784
|
onDispatchHoldChanged,
|
|
1594
1785
|
resetOutboundDispatchesThisSend: () => {
|
|
@@ -1635,6 +1826,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1635
1826
|
// permission.pending) must be dispatched without waiting for a new
|
|
1636
1827
|
// session briefing.
|
|
1637
1828
|
skipInitialSend: Boolean(options.resumeAgentId),
|
|
1829
|
+
...(cursorBootstrapState ? { cursorBootstrapState } : {}),
|
|
1638
1830
|
onSendStarted: (info) => {
|
|
1639
1831
|
reportHarnessActivity('conductor', true);
|
|
1640
1832
|
sessionLogger.emit({
|
|
@@ -1652,6 +1844,45 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1652
1844
|
});
|
|
1653
1845
|
},
|
|
1654
1846
|
onSendComplete: recordSendComplete,
|
|
1847
|
+
onRecoveryAttention: ({ attemptId, sourceKey, status, failureClass, confirmationRequired, pendingOperatorMessageCount, snapshot, agentAvailable, }) => {
|
|
1848
|
+
const recoveryAction = operatorCanInspectRecovery
|
|
1849
|
+
? snapshot
|
|
1850
|
+
? `入力を確認するには /recovery list の後に /recovery show ${snapshot.recoveryId} を実行してください。`
|
|
1851
|
+
: 'この send に operator-authored input は含まれていません。'
|
|
1852
|
+
: 'この実行環境では recovery 本文を確認できません。同一 process 内でも取得できず、process 終了時に破棄されます。';
|
|
1853
|
+
const queueNotice = pendingOperatorMessageCount > 0
|
|
1854
|
+
? operatorCanInspectRecovery
|
|
1855
|
+
? `未送信の operator message が ${pendingOperatorMessageCount} 件、既存 queue に残っています。`
|
|
1856
|
+
: `未送信の operator message ${pendingOperatorMessageCount} 件は既存 queue に残っていますが、非 TTY one-shot 終了時に破棄されます。必要なら状態を確認して再実行してください。`
|
|
1857
|
+
: undefined;
|
|
1858
|
+
const confirmationNotice = confirmationRequired
|
|
1859
|
+
? operatorCanInspectRecovery
|
|
1860
|
+
? '状態を確認してから必要な続きを新しい指示で送り、後続 dispatch を再開するには /recovery continue を実行してください。'
|
|
1861
|
+
: '失敗した入力は自動再送せず、後続 dispatch も停止しています。非 TTY では本文を確認できないため、状態を確かめてから安全な再開方法を判断してください。'
|
|
1862
|
+
: '明示的な interrupt 入力が queue に残っているため、その入力を次に処理します。/recovery continue は不要です。';
|
|
1863
|
+
sessionLogger.emit({
|
|
1864
|
+
type: 'harness.warning',
|
|
1865
|
+
message: [
|
|
1866
|
+
`conductor send が未完了です (source=${escapeTerminalControlCharacters(sourceKey)}, attempt=${attemptId}, status=${escapeTerminalControlCharacters(status)}, failure=${failureClass}).`,
|
|
1867
|
+
recoveryAction,
|
|
1868
|
+
queueNotice,
|
|
1869
|
+
agentAvailable
|
|
1870
|
+
? undefined
|
|
1871
|
+
: 'agent は unavailable です。接続を直した後に /reconnect を実行してください。',
|
|
1872
|
+
confirmationNotice,
|
|
1873
|
+
]
|
|
1874
|
+
.filter((part) => part !== undefined)
|
|
1875
|
+
.join(' '),
|
|
1876
|
+
});
|
|
1877
|
+
},
|
|
1878
|
+
onRecoveryCapacityBlocked: () => {
|
|
1879
|
+
sessionLogger.emit({
|
|
1880
|
+
type: 'harness.warning',
|
|
1881
|
+
message: operatorCanInspectRecovery
|
|
1882
|
+
? 'recovery inbox の容量が上限に達しました。入力は queue に残して dispatch を待っています。/recovery clear <id> で空きを作るか、TTL 経過後に続行します。'
|
|
1883
|
+
: 'recovery inbox の容量が上限に達しました。入力を保持したまま dispatch を待っています。この実行環境では本文を確認できません。',
|
|
1884
|
+
});
|
|
1885
|
+
},
|
|
1655
1886
|
onDispatchBatchSettled: ({ events, result, error }) => {
|
|
1656
1887
|
for (const event of events) {
|
|
1657
1888
|
if (event.type !== 'operator.message')
|
|
@@ -1692,6 +1923,16 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1692
1923
|
cursorBootstrapRunId = info.runId;
|
|
1693
1924
|
scheduleSessionResumeStoreFlush();
|
|
1694
1925
|
}
|
|
1926
|
+
const issueDispatchCompleted = info.status === 'finished' ||
|
|
1927
|
+
info.status === 'completed' ||
|
|
1928
|
+
info.status === 'running';
|
|
1929
|
+
if (conductorBackend === 'cursor' &&
|
|
1930
|
+
cursorBootstrapState?.status === 'incomplete' &&
|
|
1931
|
+
issueDispatchCompleted &&
|
|
1932
|
+
(info.dispatchSource === 'initial' || info.historyInbound !== undefined)) {
|
|
1933
|
+
cursorBootstrapState.status = 'complete';
|
|
1934
|
+
scheduleSessionResumeStoreFlush();
|
|
1935
|
+
}
|
|
1695
1936
|
const responseText = info.result?.trim();
|
|
1696
1937
|
if (info.status === 'finished' && responseText) {
|
|
1697
1938
|
const at = Date.now();
|
|
@@ -1703,7 +1944,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1703
1944
|
if (info.dispatchSource !== 'initial') {
|
|
1704
1945
|
conductorMessages.push({
|
|
1705
1946
|
text: responseText,
|
|
1706
|
-
inbound: info.inbound,
|
|
1947
|
+
inbound: info.historyInbound ?? info.inbound,
|
|
1707
1948
|
at,
|
|
1708
1949
|
sendCount: info.sendCount,
|
|
1709
1950
|
...(info.dispatchSource
|
|
@@ -1798,6 +2039,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1798
2039
|
}
|
|
1799
2040
|
}
|
|
1800
2041
|
finally {
|
|
2042
|
+
disposeOperatorInput?.();
|
|
2043
|
+
disposeOperatorInput = undefined;
|
|
2044
|
+
recoveryInbox.dispose();
|
|
1801
2045
|
const lifecycle = operatorRequestedClose
|
|
1802
2046
|
? 'closed'
|
|
1803
2047
|
: operatorRequestedExit
|
|
@@ -1857,7 +2101,6 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1857
2101
|
}
|
|
1858
2102
|
teardownPhases.openQuestionControl = Date.now() - phaseStart;
|
|
1859
2103
|
}
|
|
1860
|
-
disposeOperatorInput?.();
|
|
1861
2104
|
if (dispatchHoldReminderMonitor) {
|
|
1862
2105
|
emitTeardownPhase('dispatchHoldReminderMonitor');
|
|
1863
2106
|
dispatchHoldReminderMonitor.stop();
|
|
@@ -1873,11 +2116,11 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1873
2116
|
// after this point are rejected by the teardown guard above.
|
|
1874
2117
|
workerSession.runtime.cancelAllActivePrompts();
|
|
1875
2118
|
if (operatorRequestedClose) {
|
|
1876
|
-
// A worker's ACP session exists before its first prompt completes,
|
|
1877
|
-
//
|
|
1878
|
-
//
|
|
1879
|
-
//
|
|
1880
|
-
for (const attached of workerSession.runtime.
|
|
2119
|
+
// A worker's ACP session exists before its first prompt completes, so
|
|
2120
|
+
// snapshot resumable attached sessions before force shutdown. Recovery
|
|
2121
|
+
// bootstrap replacements are excluded until initialized; their prior
|
|
2122
|
+
// workerSessions entry remains available for the next resume.
|
|
2123
|
+
for (const attached of workerSession.runtime.listAttachedForResume()) {
|
|
1881
2124
|
workerSessions.set(attached.name, {
|
|
1882
2125
|
acpSessionId: attached.session.sessionId,
|
|
1883
2126
|
acpCwd: attached.session.acpCwd,
|
|
@@ -1936,12 +2179,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1936
2179
|
const runConductorClose = async () => {
|
|
1937
2180
|
emitTeardownPhase('conductor');
|
|
1938
2181
|
const phaseStart = Date.now();
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
}
|
|
1942
|
-
else {
|
|
1943
|
-
await conductorHandle.conductor.close();
|
|
1944
|
-
}
|
|
2182
|
+
await closeConductorAgentOnce(conductorHandle.conductor, {
|
|
2183
|
+
forResume: operatorRequestedClose,
|
|
2184
|
+
});
|
|
1945
2185
|
teardownPhases.conductor = Date.now() - phaseStart;
|
|
1946
2186
|
};
|
|
1947
2187
|
if (forceShutdown) {
|
|
@@ -2078,15 +2318,46 @@ function attachLegacySessionCallbacks(logger, options) {
|
|
|
2078
2318
|
}
|
|
2079
2319
|
});
|
|
2080
2320
|
}
|
|
2081
|
-
function finalizeSessionWorkerSpecs(workers, defaultAcp) {
|
|
2321
|
+
function finalizeSessionWorkerSpecs(workers, repoRoot, issueNumber, defaultAcp, piAgentDir) {
|
|
2322
|
+
const resolvedPiAgentDir = piAgentDir ??
|
|
2323
|
+
resolveConductorPiResourcePaths({
|
|
2324
|
+
repoRoot,
|
|
2325
|
+
config: defaultAcp?.config,
|
|
2326
|
+
env: defaultAcp?.env,
|
|
2327
|
+
}).agentDir;
|
|
2082
2328
|
for (const worker of workers) {
|
|
2083
2329
|
const resolved = resolveWorkerAcpSpawn({
|
|
2084
2330
|
defaultOptions: defaultAcp,
|
|
2085
2331
|
modelTag: worker.modelTag,
|
|
2086
2332
|
});
|
|
2087
|
-
const
|
|
2333
|
+
const sessionSpawn = resolved.piRuntime === 'builtin'
|
|
2334
|
+
? configurePiWorkerRuntime(resolved, {
|
|
2335
|
+
repoRoot,
|
|
2336
|
+
issueNumber,
|
|
2337
|
+
workerName: worker.name,
|
|
2338
|
+
...(resolvedPiAgentDir
|
|
2339
|
+
? { agentDir: resolvedPiAgentDir }
|
|
2340
|
+
: {}),
|
|
2341
|
+
})
|
|
2342
|
+
: resolved;
|
|
2343
|
+
const finalized = finalizeResolvedAcpSpawn(sessionSpawn);
|
|
2088
2344
|
worker.spawn = resolvedAcpSpawnToOptions(finalized, worker.spawn);
|
|
2089
2345
|
worker.acpFingerprint = acpSpawnFingerprint(finalized);
|
|
2090
2346
|
}
|
|
2091
2347
|
}
|
|
2348
|
+
async function pathExists(path) {
|
|
2349
|
+
try {
|
|
2350
|
+
await stat(path);
|
|
2351
|
+
return true;
|
|
2352
|
+
}
|
|
2353
|
+
catch (error) {
|
|
2354
|
+
if (typeof error === 'object' &&
|
|
2355
|
+
error !== null &&
|
|
2356
|
+
'code' in error &&
|
|
2357
|
+
error.code === 'ENOENT') {
|
|
2358
|
+
return false;
|
|
2359
|
+
}
|
|
2360
|
+
throw error;
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2092
2363
|
//# sourceMappingURL=conductor-session.js.map
|