@intentic/sandbox-contract 1.155.1 → 1.157.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.
Files changed (52) hide show
  1. package/dist/agent-catalog.d.ts +4 -1
  2. package/dist/agent-catalog.d.ts.map +1 -1
  3. package/dist/agent-catalog.js +8 -5
  4. package/dist/agent-catalog.js.map +1 -1
  5. package/dist/contracts/agent.contract.d.ts +24 -0
  6. package/dist/contracts/agent.contract.d.ts.map +1 -1
  7. package/dist/contracts/agents.contract.d.ts +265 -0
  8. package/dist/contracts/agents.contract.d.ts.map +1 -1
  9. package/dist/contracts/agents.contract.js +6 -1
  10. package/dist/contracts/agents.contract.js.map +1 -1
  11. package/dist/contracts/automations.contract.d.ts +16 -0
  12. package/dist/contracts/automations.contract.d.ts.map +1 -1
  13. package/dist/contracts/claude.contract.d.ts +12 -16
  14. package/dist/contracts/claude.contract.d.ts.map +1 -1
  15. package/dist/contracts/grok.contract.d.ts +6 -8
  16. package/dist/contracts/grok.contract.d.ts.map +1 -1
  17. package/dist/contracts/kimi.contract.d.ts +12 -16
  18. package/dist/contracts/kimi.contract.d.ts.map +1 -1
  19. package/dist/contracts/sessions.contract.d.ts +37 -0
  20. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  21. package/dist/contracts/sessions.contract.js +2 -1
  22. package/dist/contracts/sessions.contract.js.map +1 -1
  23. package/dist/contracts/settings.contract.d.ts +2 -0
  24. package/dist/contracts/settings.contract.d.ts.map +1 -1
  25. package/dist/contracts/system.contract.d.ts +4 -0
  26. package/dist/contracts/system.contract.d.ts.map +1 -1
  27. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  28. package/dist/contracts/vpn.contract.js +4 -1
  29. package/dist/contracts/vpn.contract.js.map +1 -1
  30. package/dist/contracts/workspace.contract.d.ts +23 -0
  31. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  32. package/dist/contracts/workspace.contract.js +3 -1
  33. package/dist/contracts/workspace.contract.js.map +1 -1
  34. package/dist/events.d.ts +156 -0
  35. package/dist/events.d.ts.map +1 -1
  36. package/dist/events.js +19 -1
  37. package/dist/events.js.map +1 -1
  38. package/dist/index.d.ts +401 -40
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/schemas.d.ts +187 -33
  41. package/dist/schemas.d.ts.map +1 -1
  42. package/dist/schemas.js +38 -2
  43. package/dist/schemas.js.map +1 -1
  44. package/package.json +2 -2
  45. package/src/agent-catalog.ts +31 -8
  46. package/src/contracts/agents.contract.ts +16 -0
  47. package/src/contracts/sessions.contract.ts +6 -4
  48. package/src/contracts/vpn.contract.ts +4 -1
  49. package/src/contracts/workspace.contract.ts +9 -0
  50. package/src/events.ts +49 -3
  51. package/src/schemas.test.ts +4 -1
  52. package/src/schemas.ts +124 -10
package/src/schemas.ts CHANGED
@@ -181,6 +181,11 @@ export const AgentSummarySchema = z.object({
181
181
  // Present while a turn runs: its start, ms since epoch.
182
182
  startedAt: z.number().optional(),
183
183
  updatedAt: z.number(),
184
+ // When the agent was last OPENED, ms since epoch — the unread badge's reference point (`updatedAt >
185
+ // seenAt` ⇒ the agent has done something you haven't looked at). Absent ⇒ never opened. Daemon-side on
186
+ // purpose: read state is a fact about the WORK, not about one browser profile, so clearing site data or
187
+ // picking up the phone must not resurrect every badge.
188
+ seenAt: z.number().optional(),
184
189
  attention: AgentAttentionSchema,
185
190
  // Completed turns and lifetime tool calls — the card's msgs/tools counters.
186
191
  turns: z.number().optional(),
@@ -188,10 +193,26 @@ export const AgentSummarySchema = z.object({
188
193
  // The agent's cumulative output (base → branch tip across every repo), refreshed on each land —
189
194
  // the card's "12 files · +412 −96" readout. Independent of what has landed.
190
195
  diff: z.object({ files: z.number(), insertions: z.number(), deletions: z.number() }).optional(),
196
+ // When the agent was ARCHIVED (ms epoch) — off the board, but nothing lost: its checkout was retired
197
+ // (worktree removed) while the agent/<id> branch, the transcript, and every counter stayed. Absent ⇒ live
198
+ // on the board. Archived agents are excluded from the roster the fleet renders; `agents.archived` lists
199
+ // them, `agents.unarchive` brings one back, and the next turn re-attaches its worktree from the branch.
200
+ archivedAt: z.number().optional(),
191
201
  });
192
202
  export type AgentSummary = z.infer<typeof AgentSummarySchema>;
193
203
  export const AgentsListSchema = z.object({ agents: z.array(AgentSummarySchema) });
194
204
  export const AgentIdSchema = z.object({ id: z.string().min(1) });
205
+ // archive's input: the agents to take off the board. Absent `ids` ⇒ every finished agent that is archivable
206
+ // right now (the lane header's "Clear"); unarchive always names its ids (a restore, or a bulk archive's undo).
207
+ export const AgentArchiveSchema = z.object({ ids: z.array(z.string().min(1)).max(500).optional() });
208
+ export const AgentIdsSchema = z.object({ ids: z.array(z.string().min(1)).min(1).max(500) });
209
+ // What actually MOVED, and deliberately NOT the roster afterwards. Two archives in flight at once each finish
210
+ // holding a full-roster snapshot from a different instant, so a client that swapped one in wholesale would let
211
+ // the slower response resurrect what the faster one just filed away — a delta composes where a snapshot races.
212
+ // Whole summaries rather than ids because the receiving side has to SHOW them (the archive list, and the agent
213
+ // detail page addressed by id); the ids "Undo" needs come off them for free.
214
+ export const AgentsMovedSchema = z.object({ moved: z.array(AgentSummarySchema) });
215
+ export type AgentsMoved = z.infer<typeof AgentsMovedSchema>;
195
216
  // rename's input: the user-chosen display title (bounded like sanitizeTitle's cap).
196
217
  export const AgentRenameSchema = z.object({ id: z.string().min(1), title: z.string().trim().min(1).max(80) });
197
218
  export const AgentFileDiffQuerySchema = z.object({ id: z.string().min(1), repo: z.string().min(1), path: z.string().min(1) });
@@ -262,10 +283,11 @@ export const SteerSchema = z.object({ conversationId: z.string().min(1), text: z
262
283
  export const StopTurnSchema = z.object({ conversationId: z.string().min(1) });
263
284
 
264
285
  // ---- claude subscription usage ----
265
- // Which usage window is active for a Claude account, how much of it is spent, and when it resets. Two readers,
266
- // so it lives here rather than beside the stream frames: the SDK's rate_limit_event rides it out on the agent
267
- // stream (see the `rate_limit_info` frame in events.ts), and the daemon persists the latest snapshot per
268
- // account so `/claude/accounts` can answer "how much is left on each" without spending a turn to find out.
286
+ // The GATE signal: whether the provider is letting turns through right now, and when it is refusing — which
287
+ // window is binding and when it lifts. This is the SDK's rate_limit_event, mapped one-to-one, and it is only
288
+ // ever about the CURRENT moment. It is deliberately NOT the thing the headroom displays read: the event names a
289
+ // single window (whichever the CLI considered binding), which is how "weekly 1%" ended up standing in for an
290
+ // account that was really at 98% on another weekly pool.
269
291
  export const RateLimitInfoSchema = z.object({
270
292
  status: z.enum(["allowed", "allowed_warning", "rejected"]),
271
293
  resetsAt: z.number().optional(), // epoch seconds
@@ -274,11 +296,32 @@ export const RateLimitInfoSchema = z.object({
274
296
  });
275
297
  export type RateLimitInfo = z.infer<typeof RateLimitInfoSchema>;
276
298
 
277
- // The persisted view: a snapshot plus when it was taken. Within one window utilization only climbs, so a
278
- // snapshot stays a valid FLOOR until `resetsAt` passes after that the window has rolled over and the store
279
- // drops it rather than reporting a stale number. `measuredAt` is epoch MS (matching connectedAt), while
280
- // `resetsAt` stays epoch SECONDS (matching the SDK frame) they are deliberately different units.
281
- export const AccountUsageSchema = RateLimitInfoSchema.extend({ measuredAt: z.number() });
299
+ // One plan-limit pool. `kind` is the provider's own key ('five_hour' | 'seven_day' | 'seven_day_opus' |
300
+ // 'seven_day_sonnet' | 'model:Fable' | …) rather than an enum we'd have to keep in step with the provider: an
301
+ // unrecognised pool is shown under its raw key, which is far better than being silently folded into a
302
+ // neighbour. `label` is the provider's OWN display name where it supplies one (the per-model buckets do) — it
303
+ // wins over anything we'd infer, because the model names in a plan's limits are the provider's to rename.
304
+ // `resetsAt` is epoch SECONDS (matching the SDK's frame).
305
+ export const UsageWindowSchema = z.object({
306
+ kind: z.string(),
307
+ label: z.string().optional(),
308
+ utilization: z.number(), // 0-100
309
+ resetsAt: z.number().optional(),
310
+ });
311
+ export type UsageWindow = z.infer<typeof UsageWindowSchema>;
312
+
313
+ // An account's headroom: EVERY window the provider reports, read together, plus when the reading was taken.
314
+ // All of them, not the binding one, because "which pool is binding" changes between turns and a reader
315
+ // comparing accounts needs the same pools on every row. Sourced from the CLI's own usage endpoint at turn end
316
+ // (see claudeUsageWindows) — a control request, so it costs no tokens.
317
+ //
318
+ // Within one window utilization only climbs, so an un-reset window stays a valid FLOOR however old it is; past
319
+ // its `resetsAt` it describes a pool that no longer exists and the store drops it. `measuredAt` is epoch MS
320
+ // (matching connectedAt) — deliberately a different unit from the windows' seconds.
321
+ export const AccountUsageSchema = z.object({
322
+ windows: z.array(UsageWindowSchema),
323
+ measuredAt: z.number(),
324
+ });
282
325
  export type AccountUsage = z.infer<typeof AccountUsageSchema>;
283
326
 
284
327
  // ---- provider oauth ----
@@ -376,7 +419,6 @@ export const ModelsSchema = z.object({ models: z.array(ModelSchema), default: z.
376
419
  export const SessionIdParamSchema = z.object({ id: z.string() });
377
420
  export const SessionSummarySchema = z.object({ id: z.string(), title: z.string(), updatedAt: z.number() });
378
421
  export const SessionsListSchema = z.object({ sessions: z.array(SessionSummarySchema) });
379
- export const SessionTranscriptSchema = z.object({ messages: z.array(SessionTranscriptMessageSchema) });
380
422
 
381
423
  // ---- settings: per-sandbox agent settings (.intentic/settings.json) ----
382
424
  // Small user-owned config the /settings routes edit and streamAgent reads — all opt-in booleans the owner
@@ -422,6 +464,11 @@ export const SandboxSettingsSchema = z.object({
422
464
  outputCleaners: z.string().default("off"),
423
465
  outputHoldout: z.number().min(0).max(1).default(0),
424
466
  filterBackend: z.enum(["native", "rtk"]).default("native"),
467
+ // How long a finished agent stays on the board before it is archived automatically (days; 0 ⇒ never).
468
+ // Unlike every other flag here this one defaults ON, because the lane it governs is the board's only
469
+ // terminal state: without a sweep the Finished lane grows for the life of the sandbox, and each card it
470
+ // holds is a live worktree checkout, not just a row.
471
+ agentRetentionDays: z.number().min(0).max(365).default(3),
425
472
  });
426
473
  export type SandboxSettings = z.infer<typeof SandboxSettingsSchema>;
427
474
 
@@ -806,6 +853,30 @@ export const WorkspaceSearchResultSchema = z.object({
806
853
  });
807
854
  export type WorkspaceSearchResult = z.infer<typeof WorkspaceSearchResultSchema>;
808
855
 
856
+ // ---- workspace setup (dependency readiness) ----
857
+
858
+ // One project under /work and whether its dependencies are actually installed. A drop omits node_modules/.venv
859
+ // on purpose, so a freshly imported project is present-but-unusable until this says "ready" — the import UI,
860
+ // the agent's post-edit type-check, and the agent's turn context all gate on it.
861
+ // `dir` is root-relative ("" = the workspace root itself); `manager` is the real binary (pnpm/npm/uv/…);
862
+ // `evidence` is the file that decided it ("pnpm-lock.yaml"), so the UI can show WHY, not just what.
863
+ // state: ready | installing | needs-setup | unsupported (manager absent from this sandbox — `manager` names it).
864
+ export const ProjectSetupSchema = z.object({
865
+ dir: z.string(),
866
+ ecosystem: z.enum(["node", "python"]),
867
+ manager: z.string(),
868
+ command: z.string(),
869
+ evidence: z.string(),
870
+ state: z.enum(["ready", "installing", "needs-setup", "unsupported"]),
871
+ });
872
+ export type ProjectSetup = z.infer<typeof ProjectSetupSchema>;
873
+ export const WorkspaceSetupSchema = z.object({ projects: z.array(ProjectSetupSchema) });
874
+ export type WorkspaceSetup = z.infer<typeof WorkspaceSetupSchema>;
875
+ // Install these projects' dependencies. Dirs already ready, already installing, or whose manager is missing are
876
+ // skipped server-side, so a stale client list can't spawn redundant installs — `started` is what actually ran.
877
+ export const WorkspaceInstallSchema = z.object({ dirs: z.array(z.string()).min(1) });
878
+ export const WorkspaceInstallResultSchema = z.object({ started: z.array(z.string()) });
879
+
809
880
  // ---- workspace repos ----
810
881
 
811
882
  // Every discovered repo's id (root-relative dir under /work), sorted — roles included.
@@ -1379,6 +1450,42 @@ export type ExtensionProcessStatus = z.infer<typeof ExtensionProcessStatusSchema
1379
1450
  // /webchat/<id>/message and the agent's reply streams back over SSE. Its address is the public automation id, so
1380
1451
  // allowedOrigins (the widget's embed sites) + a per-conversation rate limit are its abuse boundary — no secret
1381
1452
  // token can live in a browser.
1453
+ // `workspace` fires from the sandbox's OWN codebase instead of the outside world — see WorkspaceEventKindSchema.
1454
+
1455
+ // What the daemon emits as the fleet works, and what a `workspace` trigger names. These are the events a code
1456
+ // CHORE runs on (continuous review, post-land checks): the daemon is both producer and consumer, so unlike
1457
+ // `event` there is no token and no route — nothing outside the sandbox can reach them.
1458
+ //
1459
+ // The two OVERLAP on the common path: a clean turn auto-lands, firing both. A chore should name exactly one.
1460
+ // `turn.settled` fires once per isolated turn whatever its outcome, so it also covers the errored and
1461
+ // conflicted turns most worth a second pair of eyes, and it fires while the user is still looking at the diff —
1462
+ // before they decide to land. `agent.landed` fires only when work actually reached the main tree, including an
1463
+ // explicit Land from the review panel long after the turn ended.
1464
+ export const WorkspaceEventKindSchema = z.enum(["turn.settled", "agent.landed"]);
1465
+ export type WorkspaceEventKind = z.infer<typeof WorkspaceEventKindSchema>;
1466
+
1467
+ // The payload a workspace-triggered wake carries: one JSON object, in $AUTOMATION_PAYLOAD for the guard and
1468
+ // appended to the prompt for the turn.
1469
+ //
1470
+ // `repos` names the change to look at as an OPEN span — `git -C <dir> diff <from>`, with no upper bound. Each
1471
+ // `from` is where that repo stood before the turn (its last landed tip, or the base it branched from); the
1472
+ // other end is deliberately the working tree rather than a sha, because a turn that ERRORED left its work
1473
+ // uncommitted in the worktree and a commit-to-commit span would report it as nothing at all. `dir` is that
1474
+ // repo's dir inside the agent's own checkout, so a chore reads the agent's work without touching /work.
1475
+ //
1476
+ // No diffstat rides along on purpose: the registry's counts are refreshed at land, so an errored or conflicted
1477
+ // turn would carry stale numbers, and a guard that wants a size threshold gets the true one from
1478
+ // `git -C <dir> diff --numstat <from>` for the price of one spawn.
1479
+ export const WorkspaceEventSchema = z.object({
1480
+ event: WorkspaceEventKindSchema,
1481
+ agentId: z.string(),
1482
+ title: z.string().optional(),
1483
+ branch: z.string(),
1484
+ outcome: z.enum(["landed", "conflict", "idle", "error"]),
1485
+ repos: z.array(z.object({ repo: z.string(), from: z.string(), dir: z.string() })),
1486
+ });
1487
+ export type WorkspaceEvent = z.infer<typeof WorkspaceEventSchema>;
1488
+
1382
1489
  export const TriggerSchema = z.discriminatedUnion("kind", [
1383
1490
  z.object({ kind: z.literal("schedule"), cron: z.string().min(1) }),
1384
1491
  z.object({ kind: z.literal("event"), token: z.string().min(1).optional() }),
@@ -1391,6 +1498,8 @@ export const TriggerSchema = z.discriminatedUnion("kind", [
1391
1498
  // webchat only: the website origins allowed to POST to the widget endpoint. Absent/empty ⇒ none admitted.
1392
1499
  allowedOrigins: z.array(z.string()).optional(),
1393
1500
  }),
1501
+ // `repo` narrows to events whose span touches one workspace repo ("root" or a repo id); absent ⇒ any.
1502
+ z.object({ kind: z.literal("workspace"), event: WorkspaceEventKindSchema, repo: z.string().min(1).optional() }),
1394
1503
  ]);
1395
1504
  export type Trigger = z.infer<typeof TriggerSchema>;
1396
1505
 
@@ -1408,6 +1517,11 @@ export const AutomationSchema = z.object({
1408
1517
  model: z.string().optional(),
1409
1518
  // When true, a fire doesn't wake the agent — it's held in the approvals queue until the owner approves.
1410
1519
  requireApproval: z.boolean().optional(),
1520
+ // A code CHORE: maintenance of THIS codebase rather than a reaction to the outside world. Purely a
1521
+ // classification — the daemon fires a chore exactly like any other automation — but it cannot be derived
1522
+ // from the trigger, which is why it is stored: a nightly `pnpm audit` sweep and a nightly Stripe poll are
1523
+ // both `schedule`, and belong on different shelves. Absent ⇒ an ordinary automation.
1524
+ chore: z.boolean().optional(),
1411
1525
  enabled: z.boolean(),
1412
1526
  });
1413
1527
  export type Automation = z.infer<typeof AutomationSchema>;