start-command 0.42.0 → 0.44.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/.changeset/README.md +1 -1
- package/CHANGELOG.md +26 -0
- package/README.md +2 -0
- package/package.json +6 -6
- package/src/lib/args-parser-queries.js +64 -3
- package/src/lib/docker-inspect-batch.js +3 -0
- package/src/lib/execution-attach.js +10 -1
- package/src/lib/execution-cleanup.js +8 -0
- package/src/lib/execution-control.js +14 -3
- package/src/lib/execution-pause.js +701 -0
- package/src/lib/execution-recovery.js +6 -0
- package/src/lib/execution-resume-all.js +14 -0
- package/src/lib/execution-resume.js +16 -1
- package/src/lib/execution-store.js +5 -1
- package/src/lib/formal-ai-client.js +8 -5
- package/src/lib/formal-ai-files.js +474 -61
- package/src/lib/formal-ai.js +170 -7
- package/src/lib/log-sanitizer.js +5 -0
- package/src/lib/query-commands.js +33 -1
- package/src/lib/session-probe.js +27 -1
- package/src/lib/status-formatter.js +13 -3
- package/src/lib/status-probe.js +19 -5
- package/src/lib/usage.js +8 -1
- package/test/args-parser-attach-resume.js +1 -1
- package/test/args-parser-control.js +3 -3
- package/test/args-parser.js +1 -1
- package/test/fixtures/formal-ai/receipts-258.json +27 -9
- package/test/fixtures/formal-ai/receipts-261.json +589 -0
- package/test/fixtures/formal-ai/replay.cjs +4 -1
- package/test/fixtures/pause-golden.cjs +142 -0
- package/test/regression-243.js +4 -1
- package/test/regression-258-files.js +27 -5
- package/test/regression-258.js +22 -9
- package/test/regression-261.js +856 -0
- package/test/regression-263.js +867 -0
- package/test/shared-golden.js +28 -3
|
@@ -34,6 +34,7 @@ const ResumeAllAction = {
|
|
|
34
34
|
RUNNING: 'running',
|
|
35
35
|
RECONCILED: 'reconciled',
|
|
36
36
|
UNKNOWN: 'unknown',
|
|
37
|
+
PAUSED: 'paused',
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
function formatResumeAllAsLinksNotation(summary) {
|
|
@@ -137,6 +138,19 @@ function resumeAllExecutions(store, deps = {}) {
|
|
|
137
138
|
continue;
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
if (probe.state === SessionState.PAUSED) {
|
|
142
|
+
// Neither restarted nor re-watched while frozen (issue #263).
|
|
143
|
+
executions.push(
|
|
144
|
+
describeRecord(
|
|
145
|
+
record,
|
|
146
|
+
probe,
|
|
147
|
+
ResumeAllAction.PAUSED,
|
|
148
|
+
`Skipped paused container: ${sessionName}. Use \`$ --unpause ${record.uuid}\` to continue it.`
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
140
154
|
if (probe.alive && probe.backend === 'docker') {
|
|
141
155
|
startWatcher(
|
|
142
156
|
sessionName,
|
|
@@ -43,7 +43,11 @@ const {
|
|
|
43
43
|
rollbackLaunch,
|
|
44
44
|
failLaunchedPersistence,
|
|
45
45
|
} = require('./launch-persistence');
|
|
46
|
-
const {
|
|
46
|
+
const {
|
|
47
|
+
SessionState,
|
|
48
|
+
pausedSessionError,
|
|
49
|
+
probeSession,
|
|
50
|
+
} = require('./session-probe');
|
|
47
51
|
const { getDockerNetworks } = require('./docker-network-lifecycle');
|
|
48
52
|
const {
|
|
49
53
|
writeCommandHandoff,
|
|
@@ -217,6 +221,10 @@ function buildResumePlan(
|
|
|
217
221
|
return { error: 'Only detached isolated executions can be resumed.' };
|
|
218
222
|
}
|
|
219
223
|
|
|
224
|
+
if (probe.state === SessionState.PAUSED) {
|
|
225
|
+
return pausedSessionError('resume', record.uuid, sessionName);
|
|
226
|
+
}
|
|
227
|
+
|
|
220
228
|
if (probe.alive) {
|
|
221
229
|
return {
|
|
222
230
|
error:
|
|
@@ -481,6 +489,13 @@ async function resumeExecution(store, identifier, deps = {}) {
|
|
|
481
489
|
const runner = deps.runner || runCommand;
|
|
482
490
|
const probeFn = deps.probe || ((r) => probeSession(r, runner));
|
|
483
491
|
const probe = probeFn(record);
|
|
492
|
+
if (probe.state === SessionState.PAUSED) {
|
|
493
|
+
// Refused before any snapshot or resource change (issue #263).
|
|
494
|
+
return {
|
|
495
|
+
success: false,
|
|
496
|
+
...pausedSessionError('resume', record.uuid, probe.sessionName),
|
|
497
|
+
};
|
|
498
|
+
}
|
|
484
499
|
const opts = record.options || {};
|
|
485
500
|
let resources;
|
|
486
501
|
try {
|
|
@@ -663,7 +663,11 @@ class ExecutionStore {
|
|
|
663
663
|
const staleRecords = [];
|
|
664
664
|
|
|
665
665
|
for (const record of executingRecords) {
|
|
666
|
-
if (
|
|
666
|
+
if (
|
|
667
|
+
require('./launch-owner').hasActiveLaunch(record) ||
|
|
668
|
+
require('./execution-pause').isConfirmedPaused(record)
|
|
669
|
+
) {
|
|
670
|
+
// A paused container is alive, just frozen (issue #263).
|
|
667
671
|
continue;
|
|
668
672
|
}
|
|
669
673
|
let isStale = false;
|
|
@@ -15,6 +15,7 @@ const { API_PREFIX } = require('./formal-ai-runtime');
|
|
|
15
15
|
const {
|
|
16
16
|
FILE_TOOLS,
|
|
17
17
|
describeFileCall,
|
|
18
|
+
echoedByTool,
|
|
18
19
|
normalizeFileArgs,
|
|
19
20
|
} = require('./formal-ai-files');
|
|
20
21
|
|
|
@@ -144,7 +145,12 @@ const GAP_SCHEMAS = Object.freeze({
|
|
|
144
145
|
'EditToolUnavailable',
|
|
145
146
|
'ReadToolUnavailable',
|
|
146
147
|
],
|
|
147
|
-
|
|
148
|
+
// SourcePreimageUnavailable: Formal AI could not bind the complete Read
|
|
149
|
+
// before its edit to the change (issue #261).
|
|
150
|
+
'workspace-change-verification-gap/v1': [
|
|
151
|
+
'VerificationRunToolUnavailable',
|
|
152
|
+
'SourcePreimageUnavailable',
|
|
153
|
+
],
|
|
148
154
|
});
|
|
149
155
|
const CAPABILITIES = new Set([
|
|
150
156
|
'read',
|
|
@@ -196,10 +202,7 @@ function recognizeCapabilityGap(content, messages = []) {
|
|
|
196
202
|
) {
|
|
197
203
|
return null;
|
|
198
204
|
}
|
|
199
|
-
|
|
200
|
-
(m) => m && m.role === 'tool' && String(m.content || '').includes(text)
|
|
201
|
-
);
|
|
202
|
-
if (echoed) {
|
|
205
|
+
if (echoedByTool(text, messages)) {
|
|
203
206
|
return null;
|
|
204
207
|
}
|
|
205
208
|
return {
|