@intentic/sandbox-contract 1.167.0 → 1.169.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/dist/agent-catalog.d.ts +20 -2
- package/dist/agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog.js +80 -4
- package/dist/agent-catalog.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts +36 -8
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +1 -2
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +37 -39
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +4 -0
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.d.ts +25 -0
- package/dist/contracts/prepush.contract.d.ts.map +1 -0
- package/dist/contracts/prepush.contract.js +8 -0
- package/dist/contracts/prepush.contract.js.map +1 -0
- package/dist/contracts/sessions.contract.d.ts +1 -39
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +8 -10
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +56 -0
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +7 -2
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/translator.contract.d.ts +36 -0
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/events.d.ts +88 -159
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +37 -4
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +218 -157
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/quick-model.d.ts +1 -0
- package/dist/quick-model.d.ts.map +1 -1
- package/dist/quick-model.js +1 -1
- package/dist/quick-model.js.map +1 -1
- package/dist/schemas.d.ts +176 -69
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +48 -40
- package/dist/schemas.js.map +1 -1
- package/dist/title.d.ts.map +1 -1
- package/dist/title.js.map +1 -1
- package/dist/workspace-state.d.ts +9 -0
- package/dist/workspace-state.d.ts.map +1 -0
- package/dist/workspace-state.js +61 -0
- package/dist/workspace-state.js.map +1 -0
- package/package.json +2 -2
- package/src/agent-catalog.test.ts +118 -0
- package/src/agent-catalog.ts +179 -15
- package/src/contracts/agent.contract.ts +1 -14
- package/src/contracts/prepush.contract.ts +16 -0
- package/src/contracts/system.contract.ts +15 -1
- package/src/events.test.ts +32 -0
- package/src/events.ts +105 -27
- package/src/index.ts +4 -3
- package/src/quick-model.ts +4 -2
- package/src/schemas.test.ts +13 -18
- package/src/schemas.ts +179 -152
- package/src/title.ts +6 -2
- package/src/workspace-state.test.ts +129 -0
- package/src/workspace-state.ts +150 -0
- package/dist/contracts/gate.contract.d.ts +0 -47
- package/dist/contracts/gate.contract.d.ts.map +0 -1
- package/dist/contracts/gate.contract.js +0 -9
- package/dist/contracts/gate.contract.js.map +0 -1
- package/src/contracts/gate.contract.ts +0 -19
package/src/events.ts
CHANGED
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
LandConflictSchema,
|
|
7
7
|
PermissionModeSchema,
|
|
8
8
|
RateLimitInfoSchema,
|
|
9
|
+
SubagentKindSchema,
|
|
10
|
+
SubagentStatusSchema,
|
|
9
11
|
UsageWindowSchema,
|
|
10
12
|
} from "./schemas.js";
|
|
11
13
|
|
|
@@ -125,19 +127,36 @@ export type ToolCallContent = z.infer<typeof ToolCallContentSchema>;
|
|
|
125
127
|
// tool_use/tool_result blocks, so a restored card carries everything the live `tool_call` frame did except
|
|
126
128
|
// the streaming-only correlation fields.
|
|
127
129
|
//
|
|
128
|
-
// One restored tool card.
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
// One restored tool card. A subagent's own calls and its thinking nest under the Agent card that spawned them,
|
|
131
|
+
// the same two fields (and the same recursion) the live ChatTool carries — so a reopened chat redraws the
|
|
132
|
+
// delegation it was showing instead of a leaf card with the whole child collapsed into its result text.
|
|
133
|
+
// z.lazy because the shape refers to itself: a subagent that delegates nests one level deeper.
|
|
134
|
+
export const RestoredToolCallSchema: z.ZodType<RestoredToolCall> = z.lazy(() =>
|
|
135
|
+
z.object({
|
|
136
|
+
id: z.string(),
|
|
137
|
+
name: z.string(),
|
|
138
|
+
category: ToolKindSchema,
|
|
139
|
+
status: ToolCallStatusSchema,
|
|
140
|
+
target: z.string().optional(),
|
|
141
|
+
locations: z.array(ToolCallLocationSchema).optional(),
|
|
142
|
+
content: z.array(ToolCallContentSchema).optional(),
|
|
143
|
+
children: z.array(RestoredToolCallSchema).optional(),
|
|
144
|
+
thinking: z.string().optional(),
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
// Mutable, unlike most of this file: both builders settle a card IN PLACE when its result arrives turns later
|
|
148
|
+
// (restoredTurn's `cards` map, readWorkspaceSession's `awaiting`), which is what saves them a second pass.
|
|
149
|
+
export interface RestoredToolCall {
|
|
150
|
+
id: string;
|
|
151
|
+
name: string;
|
|
152
|
+
category: ToolKind;
|
|
153
|
+
status: ToolCallStatus;
|
|
154
|
+
target?: string | undefined;
|
|
155
|
+
locations?: ToolCallLocation[] | undefined;
|
|
156
|
+
content?: ToolCallContent[] | undefined;
|
|
157
|
+
children?: RestoredToolCall[] | undefined;
|
|
158
|
+
thinking?: string | undefined;
|
|
159
|
+
}
|
|
141
160
|
|
|
142
161
|
// One restored bubble. Each stored assistant message becomes its own, which is what reproduces the live
|
|
143
162
|
// interleaving — prose, the tool cards that prose introduced, then the next block of prose — rather than
|
|
@@ -162,7 +181,8 @@ export const AgentTranscriptSchema = SessionTranscriptSchema.extend({ sessionId:
|
|
|
162
181
|
// without a UI mapping is dropped. `plan`/`question`/`permission` pause the turn until the user answers on the
|
|
163
182
|
// `POST /agent/reply` side channel, and `resolved` releases the one it names; `mode` reports the live
|
|
164
183
|
// permission posture as the agent changes it.
|
|
165
|
-
// `parentToolUseId` tags frames produced inside a subagent (Task tool)
|
|
184
|
+
// `parentToolUseId` tags frames produced inside a subagent (Task tool); `subagent`/`subagent_update` report the
|
|
185
|
+
// subagent itself, keyed by the same tool_use id those tagged frames carry.
|
|
166
186
|
export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
167
187
|
z.object({ kind: z.literal("session"), sessionId: z.string() }),
|
|
168
188
|
/* First frame of an isolated turn: the conversation's worktree identity — its branch (agent/<id>) and the
|
|
@@ -229,6 +249,40 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
229
249
|
// `browser-<id>` session, and the client surfaces it in the same panel as the terminals. One per turn, for
|
|
230
250
|
// the same reason: one browser serves every browser call the turn makes.
|
|
231
251
|
z.object({ kind: z.literal("browser"), session: z.string() }),
|
|
252
|
+
/* THE AGENT STARTED ANOTHER AGENT — an Agent/Task subagent, or a Codex/Grok CLI it drove from its own Bash
|
|
253
|
+
* (see SubagentSessionSchema). One `subagent` frame per child, then `subagent_update` as it works: the same
|
|
254
|
+
* call/update pair `tool_call`/`tool_call_update` uses, and for the same reason — the fields that move
|
|
255
|
+
* (status, spend, what it is doing) arrive many times and must REPLACE, while the fields that identify it are
|
|
256
|
+
* said once.
|
|
257
|
+
*
|
|
258
|
+
* `id` is the SPAWNING TOOL CALL's id — the same id the client already nests the child's inner frames under
|
|
259
|
+
* (`parentToolUseId`), so both frames land on the card that spawned the child by the lookup that is already
|
|
260
|
+
* there (mapToolAnywhere). No second correlation, and nothing to get wrong.
|
|
261
|
+
*
|
|
262
|
+
* These exist because the SDK's task messages were dropped. A BACKGROUNDED child (the Agent tool's default)
|
|
263
|
+
* emits its tool_use and then nothing until its result lands, which for a long child is minutes of a spinner
|
|
264
|
+
* that cannot say whether anything is happening. */
|
|
265
|
+
z.object({
|
|
266
|
+
kind: z.literal("subagent"),
|
|
267
|
+
id: z.string(),
|
|
268
|
+
subagentKind: SubagentKindSchema,
|
|
269
|
+
agentType: z.string().optional(),
|
|
270
|
+
description: z.string().optional(),
|
|
271
|
+
model: z.string().optional(),
|
|
272
|
+
background: z.boolean().optional(),
|
|
273
|
+
// A delegation's tmux session — the one live view a subagent doesn't have (SubagentSessionSchema).
|
|
274
|
+
terminal: z.string().optional(),
|
|
275
|
+
}),
|
|
276
|
+
z.object({
|
|
277
|
+
kind: z.literal("subagent_update"),
|
|
278
|
+
id: z.string(),
|
|
279
|
+
status: SubagentStatusSchema.optional(),
|
|
280
|
+
tokens: z.number().optional(),
|
|
281
|
+
toolUses: z.number().optional(),
|
|
282
|
+
lastTool: z.string().optional(),
|
|
283
|
+
summary: z.string().optional(),
|
|
284
|
+
error: z.string().optional(),
|
|
285
|
+
}),
|
|
232
286
|
z.object({ kind: z.literal("todos"), items: z.array(TodoItemSchema) }),
|
|
233
287
|
// The provider's own slash commands (ACP available_commands_update), replaced whole each time — the
|
|
234
288
|
// composer's `/` popover lists them; invoking one is plain `/name …` prompt text (the ACP convention).
|
|
@@ -322,9 +376,11 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
322
376
|
"claude-reauth",
|
|
323
377
|
// The API refused this turn's token MID-FLIGHT — nearly always one superseded by a rotation,
|
|
324
378
|
// which Anthropic retires the moment its successor is minted. Distinct from claude-reauth: the
|
|
325
|
-
// account is fine and the daemon re-mints on the spot, so this
|
|
326
|
-
// that
|
|
327
|
-
//
|
|
379
|
+
// account is fine and the daemon re-mints on the spot, so this is usually a notice about a turn
|
|
380
|
+
// that is coming back rather than a request for the user to do anything. `autoResume` says
|
|
381
|
+
// which of the two: "scheduled" means the re-mint-and-re-run is armed, and its absence means
|
|
382
|
+
// nothing is coming (the turn was already a resume, or it ran on a credential with nothing to
|
|
383
|
+
// re-mint from) — that is the case where reconnecting really is the fix.
|
|
328
384
|
"claude-token-refused",
|
|
329
385
|
// The model provider itself failed transiently — 500/502/503, a 529 at capacity, a dropped
|
|
330
386
|
// socket — and the harness's own in-turn retries did not outlast it. Nothing about the workspace
|
|
@@ -346,12 +402,12 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
346
402
|
// rate_limit_event or the account's persisted usage windows). Absent when the reset instant is unknown
|
|
347
403
|
// (nothing to schedule against).
|
|
348
404
|
resetsAt: z.number().optional(),
|
|
349
|
-
// Where the daemon's resume of THIS turn stands
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
// the
|
|
353
|
-
//
|
|
354
|
-
//
|
|
405
|
+
// Where the daemon's resume of THIS turn stands, for the two codes that have one (provider-outage,
|
|
406
|
+
// claude-token-refused). "scheduled" = the resume is armed and this turn comes back by itself;
|
|
407
|
+
// "available" = the daemon remembered the failed turn and turning resumeAfterOutage on arms that same
|
|
408
|
+
// resume, which is what the chat's offer banner hangs off — outage only, since a renewal is never gated
|
|
409
|
+
// on a setting. Absent means there is nothing automatic to resume: a spent usage limit never has one,
|
|
410
|
+
// and a refused credential has none once re-minting it has already been tried and failed.
|
|
355
411
|
autoResume: z.enum(["scheduled", "available"]).optional(),
|
|
356
412
|
/* provider-outage only: the shape of the wait. `retryAt` (epoch seconds) is when the next attempt is
|
|
357
413
|
* due — not a fixed cadence, because an outage has no reset instant to aim at and hammering a provider
|
|
@@ -362,10 +418,6 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
362
418
|
* on-by-default retry that gives no account of how long it will keep going is the kind users switch off
|
|
363
419
|
* defensively; one that says "attempt 2 of 6" is one they leave on. */
|
|
364
420
|
outage: z.object({ retryAt: z.number(), attempt: z.number(), maxAttempts: z.number() }).optional(),
|
|
365
|
-
// rate_limit only: the account whose allowance is spent, as the DAEMON resolved it (the client's own
|
|
366
|
-
// selection can be empty, which means "the provider's first"). It is what lets the chat offer the
|
|
367
|
-
// provider's OTHER accounts as a resume-now instead of a wait — see /agent/resume-limit.
|
|
368
|
-
account: z.string().optional(),
|
|
369
421
|
}),
|
|
370
422
|
z.object({ kind: z.literal("done") }),
|
|
371
423
|
]);
|
|
@@ -384,6 +436,32 @@ export const AttachFrameSchema = z.discriminatedUnion("kind", [
|
|
|
384
436
|
]);
|
|
385
437
|
export type AttachFrame = z.infer<typeof AttachFrameSchema>;
|
|
386
438
|
|
|
439
|
+
/* WHAT A RESUMED TURN'S PROMPT SAYS IT IS. The daemon re-runs a turn something underneath it killed (turn-resume.ts)
|
|
440
|
+
* by sending the original prompt again behind one of these sentences, so the model knows what interrupted it.
|
|
441
|
+
*
|
|
442
|
+
* They live on the wire rather than in the daemon because the CLIENT has to recognise them too: an attach head
|
|
443
|
+
* carries the run's prompt verbatim, and a window joining a resumed run would otherwise render the note as a
|
|
444
|
+
* message the USER wrote — the same words the user already said one run up, with a machine's preamble on them.
|
|
445
|
+
* Recognising the prefix is what lets that window reuse the bubble that is already there instead. */
|
|
446
|
+
export const RESUME_NOTES = {
|
|
447
|
+
auth: "The Claude credential that interrupted this conversation has been renewed, and this turn resumed automatically.",
|
|
448
|
+
outage: "The model provider was briefly unavailable and interrupted this conversation; this turn resumed automatically.",
|
|
449
|
+
restart: "The sandbox restarted while this turn was running, which stopped it, and this turn resumed automatically once it came back.",
|
|
450
|
+
} as const;
|
|
451
|
+
|
|
452
|
+
// The prompt a resume actually sends: the note, then why the words below are being repeated, then them.
|
|
453
|
+
export const withResumeNote = (prompt: string, note: string): string =>
|
|
454
|
+
Object.values(RESUME_NOTES).some((known) => prompt.startsWith(known))
|
|
455
|
+
? prompt
|
|
456
|
+
: `${note} The interrupted request is repeated below — where part of it was already completed in this session, continue from that point instead of starting over.\n\n${prompt}`;
|
|
457
|
+
|
|
458
|
+
// The user's own words inside a resumed prompt — the note and its explanation stripped back off. Returns the
|
|
459
|
+
// prompt unchanged when it is not a resume, so a caller can hand every attach head through it.
|
|
460
|
+
export const withoutResumeNote = (prompt: string): string => {
|
|
461
|
+
const note = Object.values(RESUME_NOTES).find((known) => prompt.startsWith(known));
|
|
462
|
+
return note === undefined ? prompt : prompt.slice(prompt.indexOf("\n\n") + 2);
|
|
463
|
+
};
|
|
464
|
+
|
|
387
465
|
// One parsed line from `intentic … --output ndjson` (engine events, provider `log`, the terminal `result`).
|
|
388
466
|
// Open-ended by design — the sandbox consumes the wire shape, not @intentic/engine's types — so a string
|
|
389
467
|
// `kind` plus arbitrary extra fields pass through. The apply-events tail (intentic.contract `applyEvents`) rides
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,6 @@ import { claudeContract } from "./contracts/claude.contract.js";
|
|
|
10
10
|
import { codexContract } from "./contracts/codex.contract.js";
|
|
11
11
|
import { draftsContract } from "./contracts/drafts.contract.js";
|
|
12
12
|
import { extensionsContract } from "./contracts/extensions.contract.js";
|
|
13
|
-
import { gateContract } from "./contracts/gate.contract.js";
|
|
14
13
|
import { geminiContract } from "./contracts/gemini.contract.js";
|
|
15
14
|
import { gitContract } from "./contracts/git.contract.js";
|
|
16
15
|
import { grokContract } from "./contracts/grok.contract.js";
|
|
@@ -22,6 +21,7 @@ import { logsContract } from "./contracts/logs.contract.js";
|
|
|
22
21
|
import { memoryContract } from "./contracts/memory.contract.js";
|
|
23
22
|
import { panelsContract } from "./contracts/panels.contract.js";
|
|
24
23
|
import { portsContract } from "./contracts/ports.contract.js";
|
|
24
|
+
import { prepushContract } from "./contracts/prepush.contract.js";
|
|
25
25
|
import { pushContract } from "./contracts/push.contract.js";
|
|
26
26
|
import { secretsContract } from "./contracts/secrets.contract.js";
|
|
27
27
|
import { sessionsContract } from "./contracts/sessions.contract.js";
|
|
@@ -42,7 +42,6 @@ export { claudeContract } from "./contracts/claude.contract.js";
|
|
|
42
42
|
export { codexContract } from "./contracts/codex.contract.js";
|
|
43
43
|
export { draftsContract } from "./contracts/drafts.contract.js";
|
|
44
44
|
export { extensionsContract } from "./contracts/extensions.contract.js";
|
|
45
|
-
export { gateContract } from "./contracts/gate.contract.js";
|
|
46
45
|
export { geminiContract } from "./contracts/gemini.contract.js";
|
|
47
46
|
export { gitContract } from "./contracts/git.contract.js";
|
|
48
47
|
export { grokContract } from "./contracts/grok.contract.js";
|
|
@@ -54,6 +53,7 @@ export { logsContract } from "./contracts/logs.contract.js";
|
|
|
54
53
|
export { memoryContract } from "./contracts/memory.contract.js";
|
|
55
54
|
export { panelsContract } from "./contracts/panels.contract.js";
|
|
56
55
|
export { portsContract } from "./contracts/ports.contract.js";
|
|
56
|
+
export { prepushContract } from "./contracts/prepush.contract.js";
|
|
57
57
|
export { pushContract } from "./contracts/push.contract.js";
|
|
58
58
|
export { secretsContract } from "./contracts/secrets.contract.js";
|
|
59
59
|
export { sessionsContract } from "./contracts/sessions.contract.js";
|
|
@@ -67,6 +67,7 @@ export * from "./effects.js";
|
|
|
67
67
|
export * from "./events.js";
|
|
68
68
|
export * from "./sse.js";
|
|
69
69
|
export * from "./routes.js";
|
|
70
|
+
export * from "./workspace-state.js";
|
|
70
71
|
export * from "./agent-catalog.js";
|
|
71
72
|
export * from "./hostnames.js";
|
|
72
73
|
export * from "./model-order.js";
|
|
@@ -94,7 +95,6 @@ export const sandboxContract = {
|
|
|
94
95
|
settings: settingsContract,
|
|
95
96
|
intentic: intenticContract,
|
|
96
97
|
gemini: geminiContract,
|
|
97
|
-
gate: gateContract,
|
|
98
98
|
git: gitContract,
|
|
99
99
|
grok: grokContract,
|
|
100
100
|
kimi: kimiContract,
|
|
@@ -105,6 +105,7 @@ export const sandboxContract = {
|
|
|
105
105
|
memory: memoryContract,
|
|
106
106
|
panels: panelsContract,
|
|
107
107
|
ports: portsContract,
|
|
108
|
+
prepush: prepushContract,
|
|
108
109
|
push: pushContract,
|
|
109
110
|
secrets: secretsContract,
|
|
110
111
|
system: systemContract,
|
package/src/quick-model.ts
CHANGED
|
@@ -37,8 +37,10 @@ export interface QuickModelChoice {
|
|
|
37
37
|
// for its entries (PickerEntry.key). Empty ⇒ Auto.
|
|
38
38
|
export const quickModelKey = (choice: QuickModelChoice): string => `${choice.provider}:${choice.model}`;
|
|
39
39
|
|
|
40
|
-
// Split on the FIRST colon only: a provider id never contains one and a model id might.
|
|
41
|
-
|
|
40
|
+
// Split on the FIRST colon only: a provider id never contains one and a model id might. Exported because the
|
|
41
|
+
// key shape is shared: `prepushFixModel` pins the suggested fix session's model the same way, and the dialog
|
|
42
|
+
// that seeds from it has to read one back.
|
|
43
|
+
export const parsePinned = (pinned: string): QuickModelChoice | undefined => {
|
|
42
44
|
const separator = pinned.indexOf(`:`);
|
|
43
45
|
if (separator <= 0 || separator === pinned.length - 1) {
|
|
44
46
|
return undefined;
|
package/src/schemas.test.ts
CHANGED
|
@@ -29,13 +29,12 @@ test("a payload from a build that predates a toggle parses, with the new toggle
|
|
|
29
29
|
quickModel: "",
|
|
30
30
|
agentRetentionDays: 3,
|
|
31
31
|
autoLand: true,
|
|
32
|
-
autoResumeOnLimit: false,
|
|
33
32
|
resumeAfterOutage: true,
|
|
34
33
|
autoResumeOnRestart: true,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
prepushCommand: "",
|
|
35
|
+
prepushTimeoutMs: 900_000,
|
|
36
|
+
prepushFixModel: "",
|
|
37
|
+
prepushFixEffort: "",
|
|
39
38
|
});
|
|
40
39
|
});
|
|
41
40
|
|
|
@@ -68,19 +67,19 @@ test("an empty object is the full default settings object", () => {
|
|
|
68
67
|
// On because it is the historical behaviour — defaulting off would silently hold every existing
|
|
69
68
|
// sandbox's finished work on branches nobody is watching.
|
|
70
69
|
autoLand: true,
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
// committed, and the turns it saves are the unattended ones nobody is watching to restart by hand.
|
|
70
|
+
// On, where a spent usage limit re-runs nothing: an outage resume spends nothing the dead turn hadn't
|
|
71
|
+
// already committed, and the turns it saves are the unattended ones nobody is watching to restart by hand.
|
|
74
72
|
resumeAfterOutage: true,
|
|
75
73
|
// On: a daemon restart is usually intentic's own doing (an image update, an approved environment
|
|
76
74
|
// change), not the user's decision, so the turn it interrupted resumes rather than staying stuck.
|
|
77
75
|
autoResumeOnRestart: true,
|
|
78
|
-
// Empty disables the
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
|
|
76
|
+
// Empty disables the pre-push check until the owner supplies this workspace's verification command.
|
|
77
|
+
prepushCommand: "",
|
|
78
|
+
prepushTimeoutMs: 900_000,
|
|
79
|
+
// Empty ⇒ the suggested fix session opens on whatever the chat composer would have started with, which
|
|
80
|
+
// is the model the user already chose to work with.
|
|
81
|
+
prepushFixModel: "",
|
|
82
|
+
prepushFixEffort: "",
|
|
84
83
|
});
|
|
85
84
|
});
|
|
86
85
|
|
|
@@ -90,7 +89,3 @@ test("a key of the wrong type is still a parse failure — tolerance is for abse
|
|
|
90
89
|
// The prompt cap is a real bound, not advice: the text IS the system prompt, and every turn pays for it.
|
|
91
90
|
expect(SandboxSettingsSchema.safeParse({ systemPrompt: "x".repeat(20001) }).success).toBe(false);
|
|
92
91
|
});
|
|
93
|
-
|
|
94
|
-
test("usage-limit auto-resume stays off while the feature is disabled, including for an older saved true value", () => {
|
|
95
|
-
expect(SandboxSettingsSchema.parse({ autoResumeOnLimit: true }).autoResumeOnLimit).toBe(false);
|
|
96
|
-
});
|