@agents-ensemble/core 0.21.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 +2 -3
- package/dist/conductor/conductor-auth.d.ts.map +1 -1
- package/dist/conductor/conductor-auth.js +5 -2
- 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 +6 -0
- package/dist/conductor/conductor-history.d.ts.map +1 -1
- package/dist/conductor/conductor-history.js +11 -6
- 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 +27 -5
- package/dist/conductor/conductor-send-reconnect.d.ts.map +1 -1
- package/dist/conductor/conductor-send-reconnect.js +88 -39
- package/dist/conductor/conductor-send-reconnect.js.map +1 -1
- package/dist/conductor/conductor-session-driver.d.ts +32 -7
- package/dist/conductor/conductor-session-driver.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.js +474 -233
- package/dist/conductor/conductor-session-driver.js.map +1 -1
- package/dist/conductor/conductor-session.d.ts +2 -0
- package/dist/conductor/conductor-session.d.ts.map +1 -1
- package/dist/conductor/conductor-session.js +404 -156
- 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 +15 -6
- package/dist/conductor/index.d.ts.map +1 -1
- package/dist/conductor/index.js +8 -4
- package/dist/conductor/index.js.map +1 -1
- package/dist/conductor/operator-command.d.ts +1 -1
- package/dist/conductor/operator-command.js +1 -1
- package/dist/conductor/operator-command.js.map +1 -1
- package/dist/conductor/operator-input-binding.d.ts +12 -0
- package/dist/conductor/operator-input-binding.d.ts.map +1 -1
- package/dist/conductor/pi-auth-recovery-snapshot-store.d.ts +4 -1
- package/dist/conductor/pi-auth-recovery-snapshot-store.d.ts.map +1 -1
- package/dist/conductor/pi-auth-recovery-snapshot-store.js +4 -1
- package/dist/conductor/pi-auth-recovery-snapshot-store.js.map +1 -1
- 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 +272 -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/session-event.d.ts +15 -2
- 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 +1 -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 +25 -4
- 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 +31 -2
- package/dist/conductor/session/select-dispatch-batch.js.map +1 -1
- package/dist/conductor/session/session-event-queue.d.ts +5 -0
- package/dist/conductor/session/session-event-queue.d.ts.map +1 -1
- package/dist/conductor/session/session-event-queue.js +41 -4
- 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 +4 -2
- 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 +17 -4
- package/dist/operator-runtime.d.ts.map +1 -1
- package/dist/operator-runtime.js +12 -3
- 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 +4 -3
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +2 -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 +77 -10
- package/dist/session/session-resume-store.d.ts.map +1 -1
- package/dist/session/session-resume-store.js +346 -83
- package/dist/session/session-resume-store.js.map +1 -1
- package/dist/session/session-snapshot-paths.d.ts +7 -1
- package/dist/session/session-snapshot-paths.d.ts.map +1 -1
- package/dist/session/session-snapshot-paths.js +29 -26
- package/dist/session/session-snapshot-paths.js.map +1 -1
- 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 +13 -1
- package/dist/session/worker-session-history.d.ts.map +1 -1
- package/dist/session/worker-session-history.js +171 -50
- package/dist/session/worker-session-history.js.map +1 -1
- 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,26 +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';
|
|
53
|
-
import {
|
|
60
|
+
import { ConductorDispatchLifecycle } from './conductor-dispatch-lifecycle.js';
|
|
61
|
+
import { ConductorRecoveryInbox } from './conductor-recovery-inbox.js';
|
|
54
62
|
import { enqueueOperatorMessage as enqueueOperatorMessageEvent, submitOperatorInput, } from './submit-operator-input.js';
|
|
55
63
|
import { createGitHubMonitor, } from '../github/github-monitor.js';
|
|
56
64
|
import { resolveConductorBackendSetting, resolveConductorPiResourcePaths, resolveGitHubMonitorEnabled, } from '../config/resolve-settings.js';
|
|
@@ -64,7 +72,6 @@ import { createRegisterGitHubWatchTool } from '../github/register-github-watch-t
|
|
|
64
72
|
import { createUnregisterGitHubWatchTool } from '../github/unregister-github-watch-tool.js';
|
|
65
73
|
import { compileConductorSystemPrompt } from '../prompt/compile-system-prompt.js';
|
|
66
74
|
import { loadUserInstructions } from '../prompt/load-user-instructions.js';
|
|
67
|
-
import { resolveEnsemblePaths } from '../ensemble-paths.js';
|
|
68
75
|
const OPEN_QUESTION_CONTROL_DRAIN_TIMEOUT_MS = 5_000;
|
|
69
76
|
const RECORDED_ANSWER_UNKNOWN_DISPATCH = {
|
|
70
77
|
outcome: 'unknown',
|
|
@@ -169,7 +176,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
169
176
|
});
|
|
170
177
|
});
|
|
171
178
|
attachLegacySessionCallbacks(sessionLogger, options);
|
|
172
|
-
const expiredHistory = await pruneExpiredToolCallSnapshotHistoryFiles(options.repoRoot);
|
|
179
|
+
const expiredHistory = await pruneExpiredToolCallSnapshotHistoryFiles({ repoRoot: options.repoRoot, issueUrl: options.issueUrl });
|
|
173
180
|
if (expiredHistory.failedCount > 0) {
|
|
174
181
|
sessionLogger.emit({
|
|
175
182
|
type: 'harness.warning',
|
|
@@ -186,8 +193,16 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
186
193
|
let lastConductorMessage = null;
|
|
187
194
|
const conductorMessages = [];
|
|
188
195
|
const eventQueue = new SessionEventQueue();
|
|
189
|
-
const
|
|
190
|
-
|
|
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());
|
|
191
206
|
const openQuestionDispatchReceipts = new WeakMap();
|
|
192
207
|
const pendingOpenQuestionDispatchReceipts = new Set();
|
|
193
208
|
const dispatchHoldState = createDispatchHoldState();
|
|
@@ -210,12 +225,13 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
210
225
|
let githubMonitorCursor;
|
|
211
226
|
let githubMonitor;
|
|
212
227
|
let activeResumeStorePath;
|
|
228
|
+
let activeLocatedResumeStore;
|
|
213
229
|
let createdHarnessCliVersion = options.cliPackageVersion;
|
|
214
|
-
let activeStoreLocation = 'user-path-hash';
|
|
215
230
|
let drainStartupResumeStoreWrites = async () => { };
|
|
216
231
|
const pendingGitHubRecoveries = [];
|
|
217
232
|
const conductorCwd = options.conductorCwd ?? process.cwd();
|
|
218
233
|
let cursorBootstrapRunId;
|
|
234
|
+
const cursorBootstrapState = conductorBackend === 'cursor' ? { status: 'incomplete' } : undefined;
|
|
219
235
|
const mcpServers = await resolveMcpServers(options.repoRoot, options.mcpConfigOptions);
|
|
220
236
|
const mcpConfigDigest = computeMcpConfigDigest(mcpServers);
|
|
221
237
|
const mcpConfigConfigured = Object.keys(mcpServers).length > 0;
|
|
@@ -225,12 +241,13 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
225
241
|
const locatedResumeStore = await requireLocatedSessionResumeStoreForResume({
|
|
226
242
|
repoRoot: options.repoRoot,
|
|
227
243
|
conductorAgentId: options.resumeAgentId,
|
|
244
|
+
issueUrl: options.issueUrl,
|
|
228
245
|
});
|
|
229
246
|
const loadedResumeStore = locatedResumeStore.resumeStore;
|
|
247
|
+
activeLocatedResumeStore = locatedResumeStore;
|
|
230
248
|
// A resume keeps its origin version; a legacy store stays without one.
|
|
231
249
|
createdHarnessCliVersion = loadedResumeStore.createdHarnessCliVersion;
|
|
232
250
|
activeResumeStorePath = locatedResumeStore.path;
|
|
233
|
-
activeStoreLocation = locatedResumeStore.location;
|
|
234
251
|
const savedConfigDigestScheme = loadedResumeStore.ensembleConfigDigestScheme;
|
|
235
252
|
const effectiveConfigDigestScheme = savedConfigDigestScheme ?? 'full';
|
|
236
253
|
const currentEnsembleConfigDigest = effectiveConfigDigestScheme === 'resume-feasibility'
|
|
@@ -239,17 +256,39 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
239
256
|
assertSessionResumeStoreMatches(loadedResumeStore, {
|
|
240
257
|
conductorAgentId: options.resumeAgentId,
|
|
241
258
|
issueUrl: options.issueUrl,
|
|
242
|
-
repoRoot: options.repoRoot,
|
|
243
|
-
conductorBackend,
|
|
244
|
-
mcpConfigDigest,
|
|
245
|
-
mcpConfigConfigured,
|
|
246
|
-
ensembleConfigDigest: currentEnsembleConfigDigest,
|
|
247
259
|
});
|
|
248
|
-
if (loadedResumeStore.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
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 を使います。');
|
|
253
292
|
}
|
|
254
293
|
const hasComparableLegacyFullDigest = effectiveConfigDigestScheme === 'full' &&
|
|
255
294
|
loadedResumeStore.ensembleConfigDigest !== undefined;
|
|
@@ -276,6 +315,35 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
276
315
|
// acquired resource is released successfully; otherwise keep this record
|
|
277
316
|
// marked unknown/running so it does not claim a possibly active session is
|
|
278
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
|
+
}
|
|
279
347
|
const resumeStore = {
|
|
280
348
|
...loadedResumeStore,
|
|
281
349
|
lifecycle: 'unknown',
|
|
@@ -284,7 +352,6 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
284
352
|
harnessSocketPath: undefined,
|
|
285
353
|
updatedAt: Date.now(),
|
|
286
354
|
};
|
|
287
|
-
cursorBootstrapRunId = loadedResumeStore.cursorBootstrapRunId;
|
|
288
355
|
harnessPhase = 'running';
|
|
289
356
|
harnessModifiedAt = resumeStore.modifiedAt;
|
|
290
357
|
let resumeStoreActivationCommitted = false;
|
|
@@ -306,6 +373,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
306
373
|
const history = await loadToolCallSnapshotHistory({
|
|
307
374
|
repoRoot: options.repoRoot,
|
|
308
375
|
conductorAgentId: options.resumeAgentId,
|
|
376
|
+
issueUrl: options.issueUrl,
|
|
309
377
|
});
|
|
310
378
|
resumeToolCallSnapshots = history.entries;
|
|
311
379
|
toolCallHistoryNeedsRewrite = history.needsRewrite;
|
|
@@ -315,47 +383,8 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
315
383
|
message: `${history.warning}; the session will continue without affected history`,
|
|
316
384
|
});
|
|
317
385
|
}
|
|
318
|
-
const openQuestionsPath =
|
|
319
|
-
repoRoot: options.repoRoot,
|
|
320
|
-
conductorAgentId: options.resumeAgentId,
|
|
321
|
-
issueUrl: options.issueUrl,
|
|
322
|
-
location: activeStoreLocation,
|
|
323
|
-
});
|
|
386
|
+
const openQuestionsPath = sessionSnapshotPaths(options.repoRoot, locatedResumeStore, 'open-questions')[0];
|
|
324
387
|
let openQuestionsSnapshot = await loadOpenQuestionsStore(openQuestionsPath);
|
|
325
|
-
if (!openQuestionsSnapshot) {
|
|
326
|
-
const fallbackPaths = [
|
|
327
|
-
...(activeStoreLocation === 'canonical-slug'
|
|
328
|
-
? [
|
|
329
|
-
openQuestionsStorePath({
|
|
330
|
-
repoRoot: options.repoRoot,
|
|
331
|
-
conductorAgentId: options.resumeAgentId,
|
|
332
|
-
location: 'user-path-hash',
|
|
333
|
-
}),
|
|
334
|
-
]
|
|
335
|
-
: []),
|
|
336
|
-
legacyOpenQuestionsStorePath({
|
|
337
|
-
repoRoot: options.repoRoot,
|
|
338
|
-
conductorAgentId: options.resumeAgentId,
|
|
339
|
-
}),
|
|
340
|
-
];
|
|
341
|
-
for (const fallbackPath of fallbackPaths) {
|
|
342
|
-
openQuestionsSnapshot = await loadOpenQuestionsStore(fallbackPath);
|
|
343
|
-
if (openQuestionsSnapshot)
|
|
344
|
-
break;
|
|
345
|
-
}
|
|
346
|
-
if (openQuestionsSnapshot) {
|
|
347
|
-
try {
|
|
348
|
-
await saveOpenQuestionsStore(openQuestionsPath, openQuestionsSnapshot);
|
|
349
|
-
}
|
|
350
|
-
catch (error) {
|
|
351
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
352
|
-
sessionLogger.emit({
|
|
353
|
-
type: 'harness.warning',
|
|
354
|
-
message: `旧保存先の open question を user 保存先へ移行できませんでした。今回のセッションでは旧 YAML を読み込みます。 error=${detail}`,
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
388
|
if (openQuestionsSnapshot) {
|
|
360
389
|
openQuestions.restore(openQuestionsSnapshot);
|
|
361
390
|
}
|
|
@@ -376,9 +405,6 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
376
405
|
});
|
|
377
406
|
}
|
|
378
407
|
}
|
|
379
|
-
activeProfile = resumeStore.profile;
|
|
380
|
-
// ResumeStores written before this setting always started every worker eagerly.
|
|
381
|
-
activeLazyWorkers = resumeStore.lazyWorkers ?? false;
|
|
382
408
|
githubMonitorCursor = resumeStore.githubMonitor;
|
|
383
409
|
for (const [name, worker] of Object.entries(resumeStore.workers)) {
|
|
384
410
|
workerSessions.set(name, {
|
|
@@ -505,23 +531,70 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
505
531
|
});
|
|
506
532
|
},
|
|
507
533
|
};
|
|
534
|
+
const piAgentDir = resolveConductorPiResourcePaths({
|
|
535
|
+
repoRoot: options.repoRoot,
|
|
536
|
+
config: ensembleConfig,
|
|
537
|
+
}).agentDir;
|
|
508
538
|
const workers = profileWorkersToSessionSpecs(activeProfile, {
|
|
509
539
|
defaultAcp: options.defaultAcp,
|
|
510
540
|
spawnBase,
|
|
541
|
+
repoRoot: options.repoRoot,
|
|
542
|
+
issueNumber: issue.number,
|
|
543
|
+
...(piAgentDir ? { piAgentDir } : {}),
|
|
544
|
+
onWarning: (message) => sessionLogger.emit({ type: 'harness.warning', message }),
|
|
511
545
|
});
|
|
512
546
|
if (workers.length > 0) {
|
|
513
547
|
validateWorkerAcpPrerequisites(workers.map((worker) => resolveWorkerAcpSpawn({
|
|
514
548
|
defaultOptions: options.defaultAcp,
|
|
515
549
|
modelTag: worker.modelTag,
|
|
516
550
|
})));
|
|
517
|
-
finalizeSessionWorkerSpecs(workers, options.defaultAcp);
|
|
551
|
+
finalizeSessionWorkerSpecs(workers, options.repoRoot, issue.number, options.defaultAcp, piAgentDir);
|
|
518
552
|
}
|
|
519
553
|
const workerAcpFingerprints = new Map(workers.map((worker) => [worker.name, worker.acpFingerprint]));
|
|
520
554
|
let teardownStarted = false;
|
|
521
555
|
const workerWorktree = options.workerWorktree ??
|
|
522
556
|
(workers.length > 0
|
|
523
|
-
? 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
|
+
})
|
|
524
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
|
+
}
|
|
525
598
|
if (workerWorktree) {
|
|
526
599
|
sessionLogger.emit({
|
|
527
600
|
type: 'harness.worktree',
|
|
@@ -633,6 +706,34 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
633
706
|
eventQueue.enqueue({ type: 'worker.completed', result });
|
|
634
707
|
scheduleSessionResumeStoreFlush();
|
|
635
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
|
+
},
|
|
636
737
|
onWorkerFailed: (failure) => {
|
|
637
738
|
sessionLogger.emit({ type: 'worker.failed', failure });
|
|
638
739
|
eventQueue.enqueue({ type: 'worker.failed', failure });
|
|
@@ -826,22 +927,8 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
826
927
|
repoRoot: options.repoRoot,
|
|
827
928
|
conductorAgentId: conductorAgent.agentId,
|
|
828
929
|
issueUrl: options.issueUrl,
|
|
829
|
-
location:
|
|
830
|
-
}), statusLine, undefined
|
|
831
|
-
...(activeStoreLocation === 'canonical-slug'
|
|
832
|
-
? [
|
|
833
|
-
sessionStateStorePath({
|
|
834
|
-
repoRoot: options.repoRoot,
|
|
835
|
-
conductorAgentId: conductorAgent.agentId,
|
|
836
|
-
location: 'user-path-hash',
|
|
837
|
-
}),
|
|
838
|
-
]
|
|
839
|
-
: []),
|
|
840
|
-
legacySessionStateStorePath({
|
|
841
|
-
repoRoot: options.repoRoot,
|
|
842
|
-
conductorAgentId: conductorAgent.agentId,
|
|
843
|
-
}),
|
|
844
|
-
]));
|
|
930
|
+
location: 'canonical-slug',
|
|
931
|
+
}), statusLine, undefined));
|
|
845
932
|
sessionStateWriteQueue = write.catch(() => { });
|
|
846
933
|
return write;
|
|
847
934
|
},
|
|
@@ -891,16 +978,19 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
891
978
|
: {}),
|
|
892
979
|
...(conductorBackend === 'pi'
|
|
893
980
|
? {
|
|
981
|
+
issueUrl: options.issueUrl,
|
|
894
982
|
pi: resolveConductorPiResourcePaths({
|
|
895
983
|
repoRoot: options.repoRoot,
|
|
896
984
|
config: ensembleConfig,
|
|
897
985
|
}),
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
986
|
+
...(activeLocatedResumeStore
|
|
987
|
+
? {
|
|
988
|
+
resumeCwds: [
|
|
989
|
+
activeLocatedResumeStore.resumeStore.conductorCwd,
|
|
990
|
+
activeLocatedResumeStore.resumeStore.repoRoot,
|
|
991
|
+
].filter((cwd) => Boolean(cwd)),
|
|
992
|
+
}
|
|
993
|
+
: {}),
|
|
904
994
|
}
|
|
905
995
|
: {}),
|
|
906
996
|
...(Object.keys(mcpServers).length > 0 ? { mcpServers } : {}),
|
|
@@ -931,19 +1021,42 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
931
1021
|
throw error;
|
|
932
1022
|
}
|
|
933
1023
|
startupCleanup.add(async () => {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
}
|
|
937
|
-
else {
|
|
938
|
-
await conductorAgent.close();
|
|
939
|
-
}
|
|
1024
|
+
await closeConductorAgentOnce(conductorAgent, {
|
|
1025
|
+
forResume: Boolean(options.resumeAgentId),
|
|
1026
|
+
});
|
|
940
1027
|
});
|
|
941
1028
|
// Factories may not be abortable while pending. Register the returned agent
|
|
942
1029
|
// before checking shutdown so a late success is still closed by the guard.
|
|
943
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
|
+
}
|
|
944
1056
|
const conductorHandle = { conductor: conductorAgent };
|
|
945
|
-
activeResumeStorePath ??=
|
|
1057
|
+
activeResumeStorePath ??= canonicalSessionResumeStorePath({
|
|
946
1058
|
repoRoot: options.repoRoot,
|
|
1059
|
+
issueUrl: options.issueUrl,
|
|
947
1060
|
conductorAgentId: conductorAgent.agentId,
|
|
948
1061
|
});
|
|
949
1062
|
// Keep auth/transport reconnects on the same backend factory as the session.
|
|
@@ -951,26 +1064,49 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
951
1064
|
conductorAgentFactory,
|
|
952
1065
|
conductorOptions,
|
|
953
1066
|
retrySuppressionSignal: shutdownIntentController.signal,
|
|
954
|
-
onAuthReconnectAttempt: ({ agentId }) => {
|
|
1067
|
+
onAuthReconnectAttempt: ({ agentId, source, }) => {
|
|
1068
|
+
sessionLogger.emit({
|
|
1069
|
+
type: 'conductor.auth.reconnect',
|
|
1070
|
+
agentId,
|
|
1071
|
+
status: 'attempt',
|
|
1072
|
+
...(source ? { source } : {}),
|
|
1073
|
+
});
|
|
1074
|
+
},
|
|
1075
|
+
onAuthReconnectComplete: ({ agentId, success, source, closeFailed, }) => {
|
|
955
1076
|
sessionLogger.emit({
|
|
956
1077
|
type: 'conductor.auth.reconnect',
|
|
957
1078
|
agentId,
|
|
1079
|
+
status: success ? 'succeeded' : 'failed',
|
|
1080
|
+
...(source ? { source } : {}),
|
|
958
1081
|
});
|
|
1082
|
+
if (closeFailed) {
|
|
1083
|
+
sessionLogger.emit({
|
|
1084
|
+
type: 'harness.warning',
|
|
1085
|
+
message: '旧 conductor の終了処理に失敗したため、リソース解放は確認できません。再接続後の状態を確認してください。',
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
959
1088
|
},
|
|
960
|
-
onTransportReconnectAttempt: ({ agentId }) => {
|
|
1089
|
+
onTransportReconnectAttempt: ({ agentId, source, }) => {
|
|
961
1090
|
sessionLogger.emit({
|
|
962
1091
|
type: 'conductor.transport.reconnect',
|
|
963
1092
|
agentId,
|
|
964
1093
|
status: 'attempt',
|
|
1094
|
+
...(source ? { source } : {}),
|
|
965
1095
|
});
|
|
966
1096
|
},
|
|
967
|
-
onTransportReconnectComplete: ({ agentId, success,
|
|
1097
|
+
onTransportReconnectComplete: ({ agentId, success, source, closeFailed, }) => {
|
|
968
1098
|
sessionLogger.emit({
|
|
969
1099
|
type: 'conductor.transport.reconnect',
|
|
970
1100
|
agentId,
|
|
971
1101
|
status: success ? 'succeeded' : 'failed',
|
|
972
|
-
...(
|
|
1102
|
+
...(source ? { source } : {}),
|
|
973
1103
|
});
|
|
1104
|
+
if (closeFailed) {
|
|
1105
|
+
sessionLogger.emit({
|
|
1106
|
+
type: 'harness.warning',
|
|
1107
|
+
message: '旧 conductor の終了処理に失敗したため、リソース解放は確認できません。再接続後の状態を確認してください。',
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
974
1110
|
},
|
|
975
1111
|
};
|
|
976
1112
|
let sessionResumeStoreWriteQueue = Promise.resolve();
|
|
@@ -998,6 +1134,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
998
1134
|
(harnessPhase === 'running' || harnessPhase === 'idle'
|
|
999
1135
|
? 'unknown'
|
|
1000
1136
|
: undefined);
|
|
1137
|
+
const cursorBootstrapComplete = cursorBootstrapState
|
|
1138
|
+
? cursorBootstrapCompleteForStore(cursorBootstrapState)
|
|
1139
|
+
: undefined;
|
|
1001
1140
|
return {
|
|
1002
1141
|
version: SESSION_RESUME_STORE_VERSION,
|
|
1003
1142
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
@@ -1009,6 +1148,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1009
1148
|
...(cursorBootstrapRunId
|
|
1010
1149
|
? { cursorBootstrapRunId }
|
|
1011
1150
|
: {}),
|
|
1151
|
+
...(cursorBootstrapComplete !== undefined
|
|
1152
|
+
? { cursorBootstrapComplete }
|
|
1153
|
+
: {}),
|
|
1012
1154
|
lazyWorkers: activeLazyWorkers,
|
|
1013
1155
|
...(harnessSocketPath ? { harnessSocketPath } : {}),
|
|
1014
1156
|
issueUrl: options.issueUrl,
|
|
@@ -1042,7 +1184,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1042
1184
|
repoRoot: options.repoRoot,
|
|
1043
1185
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
1044
1186
|
issueUrl: options.issueUrl,
|
|
1045
|
-
location:
|
|
1187
|
+
location: 'canonical-slug',
|
|
1046
1188
|
}), snapshot);
|
|
1047
1189
|
};
|
|
1048
1190
|
const persistSessionResumeStore = async (snapshot, lifecycle) => {
|
|
@@ -1130,6 +1272,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1130
1272
|
const toolCallHistoryPath = toolCallSnapshotHistoryPath({
|
|
1131
1273
|
repoRoot: options.repoRoot,
|
|
1132
1274
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
1275
|
+
issueUrl: options.issueUrl,
|
|
1133
1276
|
});
|
|
1134
1277
|
let toolCallHistoryFlushTimer;
|
|
1135
1278
|
let toolCallHistoryFlushQueue = Promise.resolve();
|
|
@@ -1302,9 +1445,38 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1302
1445
|
let stopReason = 'completed';
|
|
1303
1446
|
const continueOnConductorError = options.continueOnConductorError ?? false;
|
|
1304
1447
|
const waitForOperatorExit = options.waitForOperatorExit ?? false;
|
|
1448
|
+
const operatorCanInspectRecovery = options.operatorCanInspectRecovery === true;
|
|
1305
1449
|
let operatorRequestedExit = false;
|
|
1306
1450
|
let operatorRequestedClose = false;
|
|
1307
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
|
+
};
|
|
1308
1480
|
const onOperatorMessageQueued = (delivery) => {
|
|
1309
1481
|
scheduleSessionResumeStoreFlush();
|
|
1310
1482
|
if (delivery !== 'interrupt')
|
|
@@ -1356,23 +1528,33 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1356
1528
|
onOperatorMessageQueued(delivery);
|
|
1357
1529
|
return true;
|
|
1358
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
|
+
};
|
|
1359
1549
|
if (options.bindOperatorInput) {
|
|
1360
1550
|
const bindingDispose = options.bindOperatorInput({
|
|
1361
1551
|
submit: (message, submitOptions) => {
|
|
1362
1552
|
if (isOperatorExitCommand(message)) {
|
|
1363
|
-
|
|
1364
|
-
workerSession.runtime.cancelAllActivePrompts();
|
|
1365
|
-
operatorRequestedExit = true;
|
|
1366
|
-
shutdownIntentController.abort();
|
|
1367
|
-
abortAfterOpenQuestionDrain(operatorTerminationController);
|
|
1553
|
+
requestOperatorShutdown('exit');
|
|
1368
1554
|
return false;
|
|
1369
1555
|
}
|
|
1370
1556
|
if (isOperatorCloseCommand(message)) {
|
|
1371
|
-
|
|
1372
|
-
workerSession.runtime.cancelAllActivePrompts();
|
|
1373
|
-
operatorRequestedClose = true;
|
|
1374
|
-
shutdownIntentController.abort();
|
|
1375
|
-
abortAfterOpenQuestionDrain(operatorTerminationController);
|
|
1557
|
+
requestOperatorShutdown('close');
|
|
1376
1558
|
return false;
|
|
1377
1559
|
}
|
|
1378
1560
|
if (isOperatorReconnectCommand(message)) {
|
|
@@ -1404,9 +1586,21 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1404
1586
|
}]
|
|
1405
1587
|
: []),
|
|
1406
1588
|
}),
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
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
|
+
: {}),
|
|
1410
1604
|
});
|
|
1411
1605
|
if (typeof bindingDispose === 'function') {
|
|
1412
1606
|
disposeOperatorInput = bindingDispose;
|
|
@@ -1457,29 +1651,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1457
1651
|
repoRoot: options.repoRoot,
|
|
1458
1652
|
conductorAgentId: conductorAgent.agentId,
|
|
1459
1653
|
issueUrl: options.issueUrl,
|
|
1460
|
-
location:
|
|
1654
|
+
location: 'canonical-slug',
|
|
1461
1655
|
});
|
|
1462
|
-
const
|
|
1463
|
-
...(activeStoreLocation === 'canonical-slug'
|
|
1464
|
-
? [
|
|
1465
|
-
sessionStateStorePath({
|
|
1466
|
-
repoRoot: options.repoRoot,
|
|
1467
|
-
conductorAgentId: conductorAgent.agentId,
|
|
1468
|
-
location: 'user-path-hash',
|
|
1469
|
-
}),
|
|
1470
|
-
]
|
|
1471
|
-
: []),
|
|
1472
|
-
legacySessionStateStorePath({
|
|
1473
|
-
repoRoot: options.repoRoot,
|
|
1474
|
-
conductorAgentId: conductorAgent.agentId,
|
|
1475
|
-
}),
|
|
1476
|
-
];
|
|
1477
|
-
let sessionState = await loadSessionStateStore(currentStatePath);
|
|
1478
|
-
for (const fallbackPath of fallbackStatePaths) {
|
|
1479
|
-
if (sessionState)
|
|
1480
|
-
break;
|
|
1481
|
-
sessionState = await loadSessionStateStore(fallbackPath);
|
|
1482
|
-
}
|
|
1656
|
+
const sessionState = await loadSessionStateStore(currentStatePath);
|
|
1483
1657
|
return {
|
|
1484
1658
|
...openQuestions.snapshot(),
|
|
1485
1659
|
...(sessionState ? { sessionState } : {}),
|
|
@@ -1491,6 +1665,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1491
1665
|
}
|
|
1492
1666
|
return sendOperatorMessage({ message: text, delivery });
|
|
1493
1667
|
},
|
|
1668
|
+
requestOperatorShutdown: ({ mode }) => requestOperatorShutdown(mode),
|
|
1494
1669
|
answerOpenQuestion: async ({ questionId, answer }) => {
|
|
1495
1670
|
if (teardownStarted) {
|
|
1496
1671
|
throw new OpenQuestionControlOperationError(-32000, 'The session is shutting down.');
|
|
@@ -1601,7 +1776,10 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1601
1776
|
conductorHandle,
|
|
1602
1777
|
sendReconnect,
|
|
1603
1778
|
eventQueue,
|
|
1604
|
-
|
|
1779
|
+
recoveryInbox,
|
|
1780
|
+
recoveryBackend: conductorBackend,
|
|
1781
|
+
dispatchLifecycle,
|
|
1782
|
+
operatorCanInspectRecovery,
|
|
1605
1783
|
dispatchHoldState,
|
|
1606
1784
|
onDispatchHoldChanged,
|
|
1607
1785
|
resetOutboundDispatchesThisSend: () => {
|
|
@@ -1648,6 +1826,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1648
1826
|
// permission.pending) must be dispatched without waiting for a new
|
|
1649
1827
|
// session briefing.
|
|
1650
1828
|
skipInitialSend: Boolean(options.resumeAgentId),
|
|
1829
|
+
...(cursorBootstrapState ? { cursorBootstrapState } : {}),
|
|
1651
1830
|
onSendStarted: (info) => {
|
|
1652
1831
|
reportHarnessActivity('conductor', true);
|
|
1653
1832
|
sessionLogger.emit({
|
|
@@ -1665,12 +1844,43 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1665
1844
|
});
|
|
1666
1845
|
},
|
|
1667
1846
|
onSendComplete: recordSendComplete,
|
|
1668
|
-
|
|
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 は不要です。';
|
|
1669
1863
|
sessionLogger.emit({
|
|
1670
1864
|
type: 'harness.warning',
|
|
1671
|
-
message:
|
|
1672
|
-
|
|
1673
|
-
|
|
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 を待っています。この実行環境では本文を確認できません。',
|
|
1674
1884
|
});
|
|
1675
1885
|
},
|
|
1676
1886
|
onDispatchBatchSettled: ({ events, result, error }) => {
|
|
@@ -1713,6 +1923,16 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1713
1923
|
cursorBootstrapRunId = info.runId;
|
|
1714
1924
|
scheduleSessionResumeStoreFlush();
|
|
1715
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
|
+
}
|
|
1716
1936
|
const responseText = info.result?.trim();
|
|
1717
1937
|
if (info.status === 'finished' && responseText) {
|
|
1718
1938
|
const at = Date.now();
|
|
@@ -1724,7 +1944,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1724
1944
|
if (info.dispatchSource !== 'initial') {
|
|
1725
1945
|
conductorMessages.push({
|
|
1726
1946
|
text: responseText,
|
|
1727
|
-
inbound: info.inbound,
|
|
1947
|
+
inbound: info.historyInbound ?? info.inbound,
|
|
1728
1948
|
at,
|
|
1729
1949
|
sendCount: info.sendCount,
|
|
1730
1950
|
...(info.dispatchSource
|
|
@@ -1821,7 +2041,7 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1821
2041
|
finally {
|
|
1822
2042
|
disposeOperatorInput?.();
|
|
1823
2043
|
disposeOperatorInput = undefined;
|
|
1824
|
-
|
|
2044
|
+
recoveryInbox.dispose();
|
|
1825
2045
|
const lifecycle = operatorRequestedClose
|
|
1826
2046
|
? 'closed'
|
|
1827
2047
|
: operatorRequestedExit
|
|
@@ -1896,11 +2116,11 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1896
2116
|
// after this point are rejected by the teardown guard above.
|
|
1897
2117
|
workerSession.runtime.cancelAllActivePrompts();
|
|
1898
2118
|
if (operatorRequestedClose) {
|
|
1899
|
-
// A worker's ACP session exists before its first prompt completes,
|
|
1900
|
-
//
|
|
1901
|
-
//
|
|
1902
|
-
//
|
|
1903
|
-
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()) {
|
|
1904
2124
|
workerSessions.set(attached.name, {
|
|
1905
2125
|
acpSessionId: attached.session.sessionId,
|
|
1906
2126
|
acpCwd: attached.session.acpCwd,
|
|
@@ -1959,12 +2179,9 @@ async function runConductorSessionWithStartupGuard(options, startupCleanup) {
|
|
|
1959
2179
|
const runConductorClose = async () => {
|
|
1960
2180
|
emitTeardownPhase('conductor');
|
|
1961
2181
|
const phaseStart = Date.now();
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
}
|
|
1965
|
-
else {
|
|
1966
|
-
await conductorHandle.conductor.close();
|
|
1967
|
-
}
|
|
2182
|
+
await closeConductorAgentOnce(conductorHandle.conductor, {
|
|
2183
|
+
forResume: operatorRequestedClose,
|
|
2184
|
+
});
|
|
1968
2185
|
teardownPhases.conductor = Date.now() - phaseStart;
|
|
1969
2186
|
};
|
|
1970
2187
|
if (forceShutdown) {
|
|
@@ -2101,15 +2318,46 @@ function attachLegacySessionCallbacks(logger, options) {
|
|
|
2101
2318
|
}
|
|
2102
2319
|
});
|
|
2103
2320
|
}
|
|
2104
|
-
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;
|
|
2105
2328
|
for (const worker of workers) {
|
|
2106
2329
|
const resolved = resolveWorkerAcpSpawn({
|
|
2107
2330
|
defaultOptions: defaultAcp,
|
|
2108
2331
|
modelTag: worker.modelTag,
|
|
2109
2332
|
});
|
|
2110
|
-
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);
|
|
2111
2344
|
worker.spawn = resolvedAcpSpawnToOptions(finalized, worker.spawn);
|
|
2112
2345
|
worker.acpFingerprint = acpSpawnFingerprint(finalized);
|
|
2113
2346
|
}
|
|
2114
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
|
+
}
|
|
2115
2363
|
//# sourceMappingURL=conductor-session.js.map
|