@intentic/sandbox-contract 1.168.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/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/settings.contract.d.ts +8 -8
- package/dist/index.d.ts +33 -55
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -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 +8 -46
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +7 -23
- package/dist/schemas.js.map +1 -1
- package/dist/workspace-state.d.ts.map +1 -1
- package/dist/workspace-state.js +0 -10
- package/dist/workspace-state.js.map +1 -1
- package/package.json +2 -2
- package/src/contracts/prepush.contract.ts +16 -0
- package/src/index.ts +3 -3
- package/src/quick-model.ts +4 -2
- package/src/schemas.test.ts +11 -10
- package/src/schemas.ts +45 -97
- package/src/workspace-state.ts +0 -10
- 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/schemas.ts
CHANGED
|
@@ -781,34 +781,26 @@ export const SandboxSettingsSchema = z.object({
|
|
|
781
781
|
* OFF still records the interruption: the fleet card reads `interrupted` (see AgentStatusSchema) and an
|
|
782
782
|
* automation's row shows an `interrupted` run — nothing is re-run, but nothing is silently lost either. */
|
|
783
783
|
autoResumeOnRestart: z.boolean().default(true),
|
|
784
|
-
/* THE
|
|
785
|
-
* Empty ⇒ no
|
|
786
|
-
* guessed command that fails on a fresh clone would read as the
|
|
784
|
+
/* THE PRE-PUSH CHECK — the command run when the user pushes, before anything leaves the machine.
|
|
785
|
+
* Empty ⇒ no check at all, which is the default: only the owner knows what verifies this workspace, and a
|
|
786
|
+
* guessed command that fails on a fresh clone would read as the check finding a bug on its first run.
|
|
787
787
|
*
|
|
788
788
|
* Configuring it is the opt-in, which is why there is no separate enable flag to disagree with it. The
|
|
789
|
-
* command runs in the workspace root through `sh -c`, exactly as a terminal would run it
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
*
|
|
789
|
+
* command runs in the workspace root through `sh -c`, exactly as a terminal would run it. */
|
|
790
|
+
prepushCommand: z.string().max(500).default(""),
|
|
791
|
+
// Ceiling on one run, after which the child's whole process group is killed and the result is `failed` with
|
|
792
|
+
// `timedOut`. Never a pass: a suite that did not finish has said nothing about the tree, and the one thing
|
|
793
|
+
// this check exists to prevent is a green light nobody earned.
|
|
794
|
+
prepushTimeoutMs: z.number().min(60_000).max(3_600_000).default(900_000),
|
|
795
|
+
/* WHAT THE SUGGESTED FIX SESSION RUNS ON when the check fails — `${provider}:${model}` (quickModelKey), and
|
|
796
|
+
* the reasoning effort beside it. Both empty ⇒ whatever the chat composer would have started with, which is
|
|
797
|
+
* the right default precisely because it is the model the user already chose to work with.
|
|
797
798
|
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
// Never a pass: a suite that did not finish has not said anything about the tree, and the one thing this
|
|
804
|
-
// gate exists to prevent is a green light nobody earned.
|
|
805
|
-
gateTimeoutMs: z.number().min(60_000).max(3_600_000).default(900_000),
|
|
806
|
-
/* Wake a fixer automatically when the gate goes red, instead of only lighting the badge. ON with a
|
|
807
|
-
* configured command, and the difference from the unattended spend a usage limit refuses is
|
|
808
|
-
* that the spend here is the POINT: a red gate whose fix waits for the user to notice has moved the CI
|
|
809
|
-
* round-trip into the workspace without removing it from the user's day. One attempt per verdict, so a
|
|
810
|
-
* command that fails for a reason no agent can fix costs one turn, not a loop (gate/gate.ts). */
|
|
811
|
-
gateAutoFix: z.boolean().default(true),
|
|
799
|
+
* Pinned here rather than resolved cheapest-first like `quickModel`: this is not a one-click helper, it is a
|
|
800
|
+
* turn that has to read a failing suite and repair it, so the choice is the user's and worth stating. The
|
|
801
|
+
* suggestion dialog seeds from these and stays editable — the setting decides where the dialog OPENS. */
|
|
802
|
+
prepushFixModel: z.string().default(""),
|
|
803
|
+
prepushFixEffort: z.string().default(""),
|
|
812
804
|
});
|
|
813
805
|
export type SandboxSettings = z.infer<typeof SandboxSettingsSchema>;
|
|
814
806
|
|
|
@@ -2243,95 +2235,51 @@ export type CiRunParam = z.infer<typeof CiRunParamSchema>;
|
|
|
2243
2235
|
export const CiFixResponseSchema = z.object({ conversationId: z.string() });
|
|
2244
2236
|
export type CiFixResponse = z.infer<typeof CiFixResponseSchema>;
|
|
2245
2237
|
|
|
2246
|
-
/* ---- the
|
|
2238
|
+
/* ---- the pre-push check: the workspace's own answer to "would this push go red" ----
|
|
2247
2239
|
*
|
|
2248
|
-
* WHERE THIS SITS
|
|
2240
|
+
* WHERE THIS SITS. A fleet of 5-20 agents lands work into the main tree, the user reviews and commits it by
|
|
2241
|
+
* parts, pushes, and CI answers minutes later. The check front-runs that answer at the push itself — the last
|
|
2242
|
+
* moment before the work leaves the machine, and the first moment at which what will be pushed is finally
|
|
2243
|
+
* settled.
|
|
2249
2244
|
*
|
|
2250
|
-
*
|
|
2251
|
-
*
|
|
2252
|
-
*
|
|
2245
|
+
* WHY THE PUSH AND NOT THE LAND, which is where this used to run. A post-land verdict is about a tree that
|
|
2246
|
+
* keeps moving: the user commits by parts, another agent lands, an edit arrives — so the verdict spent its life
|
|
2247
|
+
* either stale or being recomputed, and needed a content fingerprint, a staleness rule and a badge to say which.
|
|
2248
|
+
* All of that machinery existed to answer a question the push asks for free, because at the push there is
|
|
2249
|
+
* exactly one artifact and the user is standing in front of it waiting.
|
|
2253
2250
|
*
|
|
2254
|
-
*
|
|
2255
|
-
*
|
|
2256
|
-
*
|
|
2257
|
-
* else's UNEDITED siblings: it invents failures that don't exist and passes changes that break on the
|
|
2258
|
-
* composite, and two agents editing one contract each go green alone and red together. The composite is the
|
|
2259
|
-
* only honest artifact, and it exists in exactly one place — the main working tree.
|
|
2260
|
-
*
|
|
2261
|
-
* NOT at commit. The user commits BY PARTS, and a suite reads the worktree, not the index — so a verdict taken
|
|
2262
|
-
* at a partial commit describes a tree that never gets pushed as such. Commit is where a verdict is DISPLAYED
|
|
2263
|
-
* (ReviewPanel's badge), computed earlier.
|
|
2264
|
-
*
|
|
2265
|
-
* NOT at push. By then HEAD has moved, per-path attribution has expired (agents/origins.ts), and the agents may
|
|
2266
|
-
* be archived with their worktrees reclaimed — so the fix starts cold, in the same position `/ci/fix` is in.
|
|
2267
|
-
* That saves the CI round-trip and none of the context switch.
|
|
2268
|
-
*
|
|
2269
|
-
* So: after the land, before the staging — the one window where the artifact is what CI will see, attribution
|
|
2270
|
-
* is still live, and nobody is waiting on it. */
|
|
2251
|
+
* SO THERE IS NO STORED VERDICT AND NOTHING IS POLLED AT REST. A run exists while it runs, reports to the
|
|
2252
|
+
* dialog that started it, and is gone. Nothing survives a daemon restart because nothing needs to: the next
|
|
2253
|
+
* push asks again. */
|
|
2271
2254
|
|
|
2272
|
-
/*
|
|
2255
|
+
/* Where a run is.
|
|
2273
2256
|
*
|
|
2274
|
-
* idle —
|
|
2275
|
-
* armed — work landed; the quiet period is counting down (see gateQuietMs).
|
|
2257
|
+
* idle — nothing has run in this daemon's life, or the last run was cleared.
|
|
2276
2258
|
* running — the check is live. `output` grows as it streams.
|
|
2277
|
-
* passed — exited 0
|
|
2278
|
-
* failed — exited non-zero, or was killed by
|
|
2279
|
-
* error — the
|
|
2280
|
-
* there is nothing wrong with the code — the
|
|
2259
|
+
* passed — exited 0. The push goes.
|
|
2260
|
+
* failed — exited non-zero, or was killed by prepushTimeoutMs (`timedOut`). The state a fix answers.
|
|
2261
|
+
* error — the check could not run at all: the command was not spawnable. NOT a fix-able failure, because
|
|
2262
|
+
* there is nothing wrong with the code — the command is misconfigured, and saying "tests failed"
|
|
2281
2263
|
* would send an agent hunting a bug that isn't there.
|
|
2282
|
-
* cancelled — the user stopped the run
|
|
2264
|
+
* cancelled — the user stopped the run.
|
|
2283
2265
|
*/
|
|
2284
|
-
export const
|
|
2285
|
-
export type
|
|
2286
|
-
|
|
2287
|
-
// An agent whose landed work the failure implicates. `paths` are its attributed files that the check's own
|
|
2288
|
-
// output NAMED — empty when the output named none of them, which is the honest shape for a failure that could
|
|
2289
|
-
// not be pinpointed (an integration break between two deltas, a suite that prints no paths at all): the agent
|
|
2290
|
-
// is listed because its work is in the tree under test, not because anything accused it.
|
|
2291
|
-
export const GateAgentSchema = z.object({
|
|
2292
|
-
agentId: z.string(),
|
|
2293
|
-
title: z.string().optional(),
|
|
2294
|
-
provider: AgentProviderSchema.optional(),
|
|
2295
|
-
paths: z.array(z.string()),
|
|
2296
|
-
});
|
|
2297
|
-
export type GateAgent = z.infer<typeof GateAgentSchema>;
|
|
2266
|
+
export const PrepushStatusSchema = z.enum(["idle", "running", "passed", "failed", "error", "cancelled"]);
|
|
2267
|
+
export type PrepushStatus = z.infer<typeof PrepushStatusSchema>;
|
|
2298
2268
|
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
//
|
|
2302
|
-
export const GateFixSchema = z.object({
|
|
2303
|
-
startedAt: z.number(),
|
|
2304
|
-
conversationId: z.string(),
|
|
2305
|
-
// `running` while the turn streams; `done` when it ended cleanly, whatever the re-check then said;
|
|
2306
|
-
// `error` when the turn itself failed (a provider outage, no credential), which is worth distinguishing
|
|
2307
|
-
// because it is the one case where re-running the fix could still help.
|
|
2308
|
-
outcome: z.enum(["running", "done", "error"]),
|
|
2309
|
-
detail: z.string().optional(),
|
|
2310
|
-
});
|
|
2311
|
-
export type GateFix = z.infer<typeof GateFixSchema>;
|
|
2312
|
-
|
|
2313
|
-
export const GateVerdictSchema = z.object({
|
|
2314
|
-
status: GateStatusSchema,
|
|
2315
|
-
// The command this verdict ran, echoed rather than read back from settings: a verdict read after the
|
|
2269
|
+
export const PrepushRunSchema = z.object({
|
|
2270
|
+
status: PrepushStatusSchema,
|
|
2271
|
+
// The command this run executed, echoed rather than read back from settings: a result read after the
|
|
2316
2272
|
// setting changed still has to say what produced it.
|
|
2317
2273
|
command: z.string(),
|
|
2318
2274
|
startedAt: z.number().optional(),
|
|
2319
2275
|
finishedAt: z.number().optional(),
|
|
2320
2276
|
exitCode: z.number().optional(),
|
|
2321
2277
|
timedOut: z.boolean().optional(),
|
|
2322
|
-
// The check's own output, tail-capped (
|
|
2278
|
+
// The check's own output, tail-capped (PREPUSH_OUTPUT_BYTES). The TAIL, not the head: a suite's verdict and
|
|
2323
2279
|
// its failure summary are at the end, and a head-capped buffer of a chatty build is all progress lines.
|
|
2324
2280
|
output: z.string(),
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
* green light over a tree that has since moved. This is what keeps a passed verdict from outliving its
|
|
2328
|
-
* subject when the user edits, discards, or commits half of it. */
|
|
2329
|
-
fingerprint: z.string(),
|
|
2330
|
-
stale: z.boolean(),
|
|
2331
|
-
implicated: z.array(GateAgentSchema),
|
|
2332
|
-
fix: GateFixSchema.optional(),
|
|
2333
|
-
});
|
|
2334
|
-
export type GateVerdict = z.infer<typeof GateVerdictSchema>;
|
|
2281
|
+
});
|
|
2282
|
+
export type PrepushRun = z.infer<typeof PrepushRunSchema>;
|
|
2335
2283
|
|
|
2336
2284
|
// ---- drafts: agent-proposed posts awaiting owner approval (.intentic/drafts/<id>.json) ----
|
|
2337
2285
|
// One JSON file per draft. The AGENT creates drafts with its normal file tools — it can't call daemon routes,
|
package/src/workspace-state.ts
CHANGED
|
@@ -89,16 +89,6 @@ export const WORKSPACE_STATE_FILES: readonly WorkspaceStateFile[] = [
|
|
|
89
89
|
},
|
|
90
90
|
|
|
91
91
|
// ---- daemon-owned, nothing derives from watching them ----
|
|
92
|
-
{
|
|
93
|
-
path: ".intentic/gate.json",
|
|
94
|
-
invalidates: [],
|
|
95
|
-
why: "The landing gate's verdict is POLLED on purpose (web's useGate). Its fingerprint pass rewrites this file every couple of seconds while a check runs, and pushing that back would refetch the review set — the daemon's most expensive read — on every poll.",
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
path: ".intentic/gate-index/",
|
|
99
|
-
invalidates: [],
|
|
100
|
-
why: "The gate's per-repo git index. Machine state, rewritten continuously by the fingerprint pass.",
|
|
101
|
-
},
|
|
102
92
|
/* Agent session transcripts, rewritten on every streamed token.
|
|
103
93
|
*
|
|
104
94
|
* The memory notes under it (`projects/<slug>/memory/**`) ARE user-facing and the /memory view polls them
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export declare const gateContract: {
|
|
2
|
-
verdict: import("@orpc/contract").ContractProcedureBuilderWithOutput<import("@orpc/contract").Schema<unknown, unknown>, import("zod").ZodObject<{
|
|
3
|
-
status: import("zod").ZodEnum<{
|
|
4
|
-
armed: "armed";
|
|
5
|
-
cancelled: "cancelled";
|
|
6
|
-
error: "error";
|
|
7
|
-
failed: "failed";
|
|
8
|
-
idle: "idle";
|
|
9
|
-
passed: "passed";
|
|
10
|
-
running: "running";
|
|
11
|
-
}>;
|
|
12
|
-
command: import("zod").ZodString;
|
|
13
|
-
startedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
14
|
-
finishedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
15
|
-
exitCode: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
16
|
-
timedOut: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
17
|
-
output: import("zod").ZodString;
|
|
18
|
-
fingerprint: import("zod").ZodString;
|
|
19
|
-
stale: import("zod").ZodBoolean;
|
|
20
|
-
implicated: import("zod").ZodArray<import("zod").ZodObject<{
|
|
21
|
-
agentId: import("zod").ZodString;
|
|
22
|
-
title: import("zod").ZodOptional<import("zod").ZodString>;
|
|
23
|
-
provider: import("zod").ZodOptional<import("zod").ZodString>;
|
|
24
|
-
paths: import("zod").ZodArray<import("zod").ZodString>;
|
|
25
|
-
}, import("zod/v4/core").$strip>>;
|
|
26
|
-
fix: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
27
|
-
startedAt: import("zod").ZodNumber;
|
|
28
|
-
conversationId: import("zod").ZodString;
|
|
29
|
-
outcome: import("zod").ZodEnum<{
|
|
30
|
-
done: "done";
|
|
31
|
-
error: "error";
|
|
32
|
-
running: "running";
|
|
33
|
-
}>;
|
|
34
|
-
detail: import("zod").ZodOptional<import("zod").ZodString>;
|
|
35
|
-
}, import("zod/v4/core").$strip>>;
|
|
36
|
-
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
37
|
-
run: import("@orpc/contract").ContractProcedureBuilderWithOutput<import("@orpc/contract").Schema<unknown, unknown>, import("zod").ZodObject<{
|
|
38
|
-
ok: import("zod").ZodLiteral<true>;
|
|
39
|
-
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
40
|
-
cancel: import("@orpc/contract").ContractProcedureBuilderWithOutput<import("@orpc/contract").Schema<unknown, unknown>, import("zod").ZodObject<{
|
|
41
|
-
ok: import("zod").ZodLiteral<true>;
|
|
42
|
-
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
43
|
-
fix: import("@orpc/contract").ContractProcedureBuilderWithOutput<import("@orpc/contract").Schema<unknown, unknown>, import("zod").ZodObject<{
|
|
44
|
-
ok: import("zod").ZodLiteral<true>;
|
|
45
|
-
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
46
|
-
};
|
|
47
|
-
//# sourceMappingURL=gate.contract.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gate.contract.d.ts","sourceRoot":"","sources":["../../src/contracts/gate.contract.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,YAAY;IACrB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IACP,GAAG;;;IACH,MAAM;;;IACN,GAAG;;;CACN,CAAC"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { oc } from "@orpc/contract";
|
|
2
|
-
import { GateVerdictSchema, OkSchema } from "../schemas.js";
|
|
3
|
-
export const gateContract = {
|
|
4
|
-
verdict: oc.route({ method: "GET", path: "/gate/verdict" }).output(GateVerdictSchema),
|
|
5
|
-
run: oc.route({ method: "POST", path: "/gate/run" }).output(OkSchema),
|
|
6
|
-
cancel: oc.route({ method: "POST", path: "/gate/cancel" }).output(OkSchema),
|
|
7
|
-
fix: oc.route({ method: "POST", path: "/gate/fix" }).output(OkSchema),
|
|
8
|
-
};
|
|
9
|
-
//# sourceMappingURL=gate.contract.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gate.contract.js","sourceRoot":"","sources":["../../src/contracts/gate.contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAY5D,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;IACrF,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACrE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC3E,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;CACxE,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { oc } from "@orpc/contract";
|
|
2
|
-
import { GateVerdictSchema, OkSchema } from "../schemas.js";
|
|
3
|
-
|
|
4
|
-
// The landing gate — the check command run over the composite of landed work once the fleet goes quiet (see
|
|
5
|
-
// GateVerdictSchema for where this sits and why). Four verbs, all about ONE verdict: the gate answers about the
|
|
6
|
-
// main working tree, of which there is exactly one, so nothing here is addressed by id.
|
|
7
|
-
//
|
|
8
|
-
// `verdict` is the one read, and the panel polls it; it recomputes staleness per call, so a passed verdict stops
|
|
9
|
-
// claiming a green light the moment the tree moves under it. The three writes answer `ok` and nothing else —
|
|
10
|
-
// each starts work that outlives the request, so there is no result to return and the poll is what reports.
|
|
11
|
-
// `run` arms nothing and waits for nothing: it starts the check now, the user's own "I'm about to commit, check
|
|
12
|
-
// this". `fix` opens a seeded workspace conversation for a red verdict; it has the same registry lifecycle as
|
|
13
|
-
// /ci/fix, minus the isolated worktree it must not have.
|
|
14
|
-
export const gateContract = {
|
|
15
|
-
verdict: oc.route({ method: "GET", path: "/gate/verdict" }).output(GateVerdictSchema),
|
|
16
|
-
run: oc.route({ method: "POST", path: "/gate/run" }).output(OkSchema),
|
|
17
|
-
cancel: oc.route({ method: "POST", path: "/gate/cancel" }).output(OkSchema),
|
|
18
|
-
fix: oc.route({ method: "POST", path: "/gate/fix" }).output(OkSchema),
|
|
19
|
-
};
|