@intentic/sandbox-contract 1.240.0 → 1.243.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/README.md +52 -16
- package/dist/agent-catalog.d.ts +5 -28
- package/dist/agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog.js +21 -157
- package/dist/agent-catalog.js.map +1 -1
- package/dist/agent-run-model.d.ts +3 -2
- package/dist/agent-run-model.d.ts.map +1 -1
- package/dist/agent-run-model.js +9 -6
- package/dist/agent-run-model.js.map +1 -1
- package/dist/agent-runtimes.d.ts +27 -0
- package/dist/agent-runtimes.d.ts.map +1 -0
- package/dist/agent-runtimes.js +113 -0
- package/dist/agent-runtimes.js.map +1 -0
- package/dist/approvals-execution.d.ts +11 -0
- package/dist/approvals-execution.d.ts.map +1 -0
- package/dist/approvals-execution.js +44 -0
- package/dist/approvals-execution.js.map +1 -0
- package/dist/arrival.d.ts +151 -0
- package/dist/arrival.d.ts.map +1 -0
- package/dist/arrival.js +56 -0
- package/dist/arrival.js.map +1 -0
- package/dist/card-status.d.ts +5 -0
- package/dist/card-status.d.ts.map +1 -0
- package/dist/card-status.js +74 -0
- package/dist/card-status.js.map +1 -0
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js +1 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/command-classes.d.ts +0 -1
- package/dist/command-classes.d.ts.map +1 -1
- package/dist/command-classes.js +9 -2
- package/dist/command-classes.js.map +1 -1
- package/dist/command-run.d.ts +10 -0
- package/dist/command-run.d.ts.map +1 -0
- package/dist/command-run.js +46 -0
- package/dist/command-run.js.map +1 -0
- package/dist/contracts/agent.contract.d.ts +991 -771
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.d.ts +345 -337
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +20 -2
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/approvals.contract.d.ts +99 -0
- package/dist/contracts/approvals.contract.d.ts.map +1 -0
- package/dist/contracts/approvals.contract.js +32 -0
- package/dist/contracts/approvals.contract.js.map +1 -0
- package/dist/contracts/ci.contract.d.ts +1 -4
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.js +1 -9
- package/dist/contracts/ci.contract.js.map +1 -1
- package/dist/contracts/claude.contract.d.ts +9 -0
- package/dist/contracts/claude.contract.d.ts.map +1 -1
- package/dist/contracts/cursor.contract.d.ts +6 -0
- package/dist/contracts/cursor.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.d.ts +63 -1
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +22 -4
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/grok.contract.d.ts +3 -0
- package/dist/contracts/grok.contract.d.ts.map +1 -1
- package/dist/contracts/keys.contract.d.ts +81 -0
- package/dist/contracts/keys.contract.d.ts.map +1 -0
- package/dist/contracts/keys.contract.js +51 -0
- package/dist/contracts/keys.contract.js.map +1 -0
- package/dist/contracts/panels.contract.d.ts +7 -0
- package/dist/contracts/panels.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.js +2 -2
- package/dist/contracts/providers.contract.d.ts +2 -0
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.d.ts +84 -86
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/safety.contract.d.ts +35 -0
- package/dist/contracts/safety.contract.d.ts.map +1 -0
- package/dist/contracts/safety.contract.js +32 -0
- package/dist/contracts/safety.contract.js.map +1 -0
- package/dist/contracts/sessions.contract.d.ts +73 -337
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +30 -32
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +139 -337
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.d.ts +31 -3
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/usage.contract.d.ts +29 -20
- package/dist/contracts/usage.contract.d.ts.map +1 -1
- package/dist/contracts/usage.contract.js +13 -0
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +8 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/conversation-ids.d.ts +2 -0
- package/dist/conversation-ids.d.ts.map +1 -1
- package/dist/conversation-ids.js +8 -0
- package/dist/conversation-ids.js.map +1 -1
- package/dist/credential-material.d.ts +1 -0
- package/dist/credential-material.d.ts.map +1 -1
- package/dist/credential-material.js +24 -2
- package/dist/credential-material.js.map +1 -1
- package/dist/definition.d.ts +51 -93
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +6 -28
- package/dist/definition.js.map +1 -1
- package/dist/events.d.ts +1831 -2285
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +155 -55
- package/dist/events.js.map +1 -1
- package/dist/history-state.d.ts.map +1 -1
- package/dist/history-state.js +1 -0
- package/dist/history-state.js.map +1 -1
- package/dist/index.d.ts +1959 -1903
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/ingress-protocol.d.ts +13 -1
- package/dist/ingress-protocol.d.ts.map +1 -1
- package/dist/ingress-protocol.js +19 -0
- package/dist/ingress-protocol.js.map +1 -1
- package/dist/mentions.d.ts +3 -0
- package/dist/mentions.d.ts.map +1 -0
- package/dist/mentions.js +13 -0
- package/dist/mentions.js.map +1 -0
- package/dist/needs-action.d.ts +7 -0
- package/dist/needs-action.d.ts.map +1 -0
- package/dist/needs-action.js +3 -0
- package/dist/needs-action.js.map +1 -0
- package/dist/overlay-lint.d.ts +7 -0
- package/dist/overlay-lint.d.ts.map +1 -0
- package/dist/overlay-lint.js +68 -0
- package/dist/overlay-lint.js.map +1 -0
- package/dist/owner-ticket.d.ts +18 -0
- package/dist/owner-ticket.d.ts.map +1 -0
- package/dist/owner-ticket.js +51 -0
- package/dist/owner-ticket.js.map +1 -0
- package/dist/plan-pools.d.ts +13 -0
- package/dist/plan-pools.d.ts.map +1 -0
- package/dist/plan-pools.js +31 -0
- package/dist/plan-pools.js.map +1 -0
- package/dist/provider-specs.d.ts +228 -0
- package/dist/provider-specs.d.ts.map +1 -0
- package/dist/provider-specs.js +124 -0
- package/dist/provider-specs.js.map +1 -0
- package/dist/quick-model.d.ts.map +1 -1
- package/dist/quick-model.js +2 -1
- package/dist/quick-model.js.map +1 -1
- package/dist/runner-protocol.js +2 -2
- package/dist/runner-protocol.js.map +1 -1
- package/dist/runtime-state.d.ts +2 -2
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +1 -1
- package/dist/runtime-state.js.map +1 -1
- package/dist/safety-policy.d.ts +49 -0
- package/dist/safety-policy.d.ts.map +1 -0
- package/dist/safety-policy.js +52 -0
- package/dist/safety-policy.js.map +1 -0
- package/dist/schemas/agent.d.ts +21 -3
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +18 -8
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +19 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +15 -0
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/approvals.d.ts +241 -0
- package/dist/schemas/approvals.d.ts.map +1 -0
- package/dist/schemas/approvals.js +63 -0
- package/dist/schemas/approvals.js.map +1 -0
- package/dist/schemas/automations.d.ts +5 -0
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/ci.d.ts +5 -9
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/ci.js +3 -10
- package/dist/schemas/ci.js.map +1 -1
- package/dist/schemas/computers.d.ts +40 -5
- package/dist/schemas/computers.d.ts.map +1 -1
- package/dist/schemas/computers.js +16 -5
- package/dist/schemas/computers.js.map +1 -1
- package/dist/schemas/environment.d.ts +11 -131
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js +5 -42
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/git-history.d.ts +4 -0
- package/dist/schemas/git-history.d.ts.map +1 -1
- package/dist/schemas/git.d.ts +179 -0
- package/dist/schemas/git.d.ts.map +1 -1
- package/dist/schemas/git.js +39 -1
- package/dist/schemas/git.js.map +1 -1
- package/dist/schemas/panels.d.ts +21 -0
- package/dist/schemas/panels.d.ts.map +1 -1
- package/dist/schemas/panels.js +5 -0
- package/dist/schemas/panels.js.map +1 -1
- package/dist/schemas/plan-limits.d.ts +50 -3
- package/dist/schemas/plan-limits.d.ts.map +1 -1
- package/dist/schemas/plan-limits.js +11 -6
- package/dist/schemas/plan-limits.js.map +1 -1
- package/dist/schemas/provider-oauth.d.ts +6 -0
- package/dist/schemas/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/provider-subscriptions.d.ts +2 -1
- package/dist/schemas/provider-subscriptions.d.ts.map +1 -1
- package/dist/schemas/provider-subscriptions.js +2 -1
- package/dist/schemas/provider-subscriptions.js.map +1 -1
- package/dist/schemas/settings.d.ts +29 -16
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +13 -20
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/system.d.ts +3 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +5 -1
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/workspace-repos.d.ts +14 -0
- package/dist/schemas/workspace-repos.d.ts.map +1 -1
- package/dist/schemas/workspace-repos.js +5 -0
- package/dist/schemas/workspace-repos.js.map +1 -1
- package/dist/schemas/workspace-tree.d.ts +1 -0
- package/dist/schemas/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace-tree.js +3 -0
- package/dist/schemas/workspace-tree.js.map +1 -1
- package/dist/transcript-fold.d.ts +31 -0
- package/dist/transcript-fold.d.ts.map +1 -0
- package/dist/transcript-fold.js +457 -0
- package/dist/transcript-fold.js.map +1 -0
- package/dist/workspace-state.d.ts +20 -3
- package/dist/workspace-state.d.ts.map +1 -1
- package/dist/workspace-state.js +22 -2
- package/dist/workspace-state.js.map +1 -1
- package/package.json +27 -5
- package/src/agent-catalog.test.ts +1 -1
- package/src/agent-catalog.ts +76 -555
- package/src/agent-run-model.test.ts +31 -15
- package/src/agent-run-model.ts +26 -12
- package/src/agent-runtimes.ts +419 -0
- package/src/approvals-execution.ts +96 -0
- package/src/arrival.ts +160 -0
- package/src/capability-ledger.test.ts +6 -4
- package/src/card-status.ts +93 -0
- package/src/chores/chores.ts +6 -3
- package/src/command-classes.test.ts +25 -0
- package/src/command-classes.ts +47 -5
- package/src/command-run.ts +78 -0
- package/src/contract-lock.test.ts +1 -1
- package/src/contract-lock.ts +2 -2
- package/src/contracts/agents.contract.ts +35 -2
- package/src/contracts/approvals.contract.ts +37 -0
- package/src/contracts/ci.contract.ts +0 -13
- package/src/contracts/git.contract.ts +28 -3
- package/src/contracts/keys.contract.ts +79 -0
- package/src/contracts/prepush.contract.ts +3 -3
- package/src/contracts/safety.contract.ts +48 -0
- package/src/contracts/usage.contract.ts +22 -0
- package/src/conversation-ids.test.ts +31 -1
- package/src/conversation-ids.ts +37 -3
- package/src/credential-material.test.ts +69 -1
- package/src/credential-material.ts +86 -5
- package/src/definition.ts +25 -53
- package/src/events.ts +374 -173
- package/src/history-state.ts +6 -0
- package/src/index.ts +24 -5
- package/src/ingress-protocol.ts +52 -1
- package/src/mentions.test.ts +22 -0
- package/src/mentions.ts +25 -0
- package/src/needs-action.ts +14 -0
- package/src/overlay-lint.test.ts +89 -0
- package/src/overlay-lint.ts +116 -0
- package/src/owner-ticket.test.ts +54 -0
- package/src/owner-ticket.ts +102 -0
- package/src/plan-pools.test.ts +71 -0
- package/src/plan-pools.ts +92 -0
- package/src/provider-specs.test.ts +130 -0
- package/src/provider-specs.ts +352 -0
- package/src/quick-model.ts +9 -5
- package/src/runner-protocol.ts +2 -2
- package/src/runtime-state.ts +6 -6
- package/src/safety-policy.ts +165 -0
- package/src/schemas/agent.ts +62 -17
- package/src/schemas/agents.ts +71 -0
- package/src/schemas/approvals.ts +174 -0
- package/src/schemas/ci.ts +19 -26
- package/src/schemas/computers.ts +91 -15
- package/src/schemas/environment.ts +21 -100
- package/src/schemas/git.ts +121 -6
- package/src/schemas/issues.ts +1 -1
- package/src/schemas/panels.ts +20 -0
- package/src/schemas/plan-limits.ts +58 -11
- package/src/schemas/provider-subscriptions.ts +7 -2
- package/src/schemas/settings.ts +67 -93
- package/src/schemas/system.ts +12 -1
- package/src/schemas/workspace-repos.ts +9 -0
- package/src/schemas/workspace-tree.ts +11 -0
- package/src/transcript-fold.test.ts +493 -0
- package/src/transcript-fold.ts +655 -0
- package/src/workspace-state.test.ts +77 -29
- package/src/workspace-state.ts +99 -31
- package/dist/contracts/drafts.contract.d.ts +0 -57
- package/dist/contracts/drafts.contract.d.ts.map +0 -1
- package/dist/contracts/drafts.contract.js +0 -32
- package/dist/contracts/drafts.contract.js.map +0 -1
- package/dist/definition-action.d.ts +0 -7
- package/dist/definition-action.d.ts.map +0 -1
- package/dist/definition-action.js +0 -3
- package/dist/definition-action.js.map +0 -1
- package/dist/publish-drafts.d.ts +0 -7
- package/dist/publish-drafts.d.ts.map +0 -1
- package/dist/publish-drafts.js +0 -20
- package/dist/publish-drafts.js.map +0 -1
- package/dist/schemas/drafts.d.ts +0 -84
- package/dist/schemas/drafts.d.ts.map +0 -1
- package/dist/schemas/drafts.js +0 -44
- package/dist/schemas/drafts.js.map +0 -1
- package/src/contracts/drafts.contract.ts +0 -35
- package/src/definition-action.ts +0 -8
- package/src/publish-drafts.ts +0 -59
- package/src/schemas/drafts.ts +0 -108
package/src/schemas/computers.ts
CHANGED
|
@@ -133,7 +133,19 @@ export type MachineFlowLine = z.infer<typeof MachineFlowLineSchema>;
|
|
|
133
133
|
*
|
|
134
134
|
* The machine still enforces its own switches. "Run commands" being off comes back as its own refusal, in its
|
|
135
135
|
* own words, naming the control to flip — exactly as it does for the sandbox ops. */
|
|
136
|
-
|
|
136
|
+
/* THE SET, and why the file-sync half of it is here beside the mirroring half.
|
|
137
|
+
*
|
|
138
|
+
* Both are the same gesture to the person clicking: something this computer is doing for this sandbox, turned
|
|
139
|
+
* off or on from the row that describes it. They were split for a while by nothing but which one had been built
|
|
140
|
+
* — mirroring had a button and pausing a file sync had a paragraph telling you to go and find a terminal — and
|
|
141
|
+
* that is exactly the gap this door exists to close.
|
|
142
|
+
*
|
|
143
|
+
* `sync-unpair` is the one that DESTROYS something, and it is deliberately the machine's `sync uninstall
|
|
144
|
+
* --sandbox`, not this side's idea of unpairing: the agent terminates both Mutagen sessions, drops the local
|
|
145
|
+
* pairing and self-revokes its enrollment on the way out, so the machine cleans up after itself rather than
|
|
146
|
+
* leaving a sandbox to guess what it managed to do. Revoking from the SANDBOX side (an unreachable machine, a
|
|
147
|
+
* laptop that is never coming back) is a different act and a different route, see the enrollment revoke. */
|
|
148
|
+
export const MachineCommandSchema = z.enum(["mirror-off", "mirror-on", "sync-pause", "sync-resume", "sync-unpair"]);
|
|
137
149
|
export type MachineCommand = z.infer<typeof MachineCommandSchema>;
|
|
138
150
|
/* Which paired sandbox the command acts on: the machine's own id for it, as it appears in that machine's report,
|
|
139
151
|
* so nothing here has to re-derive the sanitizing the agent applied. Absent means every sandbox that machine
|
|
@@ -195,7 +207,7 @@ export const MachinePairingSchema = z.object({
|
|
|
195
207
|
/* The SECOND session's word, the one-way mirror carrying the sandbox's state dir down (sync's backupSpec).
|
|
196
208
|
* Reported separately rather than folded into the status above, because the two fail independently and mean
|
|
197
209
|
* different things: the first going quiet stops the owner's edits moving, the second going quiet stops their
|
|
198
|
-
* personas, skills, automations,
|
|
210
|
+
* personas, skills, automations, approvals and transcripts from surviving the sandbox. A backup that is not
|
|
199
211
|
* running is only dangerous while nobody knows, so it gets its own word on the line. */
|
|
200
212
|
backupStatus: z.string().optional(),
|
|
201
213
|
});
|
|
@@ -232,6 +244,12 @@ export type MachinePort = z.infer<typeof MachinePortSchema>;
|
|
|
232
244
|
export const MachineWatcherSchema = z.object({
|
|
233
245
|
running: z.boolean(),
|
|
234
246
|
pid: z.number().int().optional(),
|
|
247
|
+
/* WHICH BUILD IS ACTUALLY SERVING, stamped into the pidfile by the loop that claimed it, which is the only
|
|
248
|
+
* place the fact exists: replacing the binary does not touch the running process, so a machine can hold a
|
|
249
|
+
* current agent and go on serving a months-old one indefinitely. `agents.sync` is the file, this is the
|
|
250
|
+
* process, and the two differing is a restart somebody is owed (see watcherBuildSkew). Absent when no loop
|
|
251
|
+
* is running, and when the one running predates the stamp. */
|
|
252
|
+
build: z.string().optional(),
|
|
235
253
|
/* When the watcher last FINISHED a pass, the field that makes `running` mean something. The agent holds its
|
|
236
254
|
* SSH transport listeners on its own event loop, so a failure that escapes the loop leaves a process that is
|
|
237
255
|
* alive and a loop that is gone: pid present, unit "active", mirroring and the git bridge stopped. Absent
|
|
@@ -256,10 +274,18 @@ export const MachineReportSchema = z.object({
|
|
|
256
274
|
* the same box, so it is what dedupes them into a single row. */
|
|
257
275
|
hostname: z.string(),
|
|
258
276
|
os: z.string(),
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
277
|
+
/* Which agents this machine has, and at what version, so one on an old build is visible rather than
|
|
278
|
+
* mysteriously lacking a field. Same argument as HostSummary.version.
|
|
279
|
+
*
|
|
280
|
+
* `sync` is the agent INSTALLED here — the file on disk — and `watcher.build` beside it is the loop running
|
|
281
|
+
* from that file. It used to be neither: whichever process happened to build the report stamped its own
|
|
282
|
+
* version here, so the same machine answered its running build to a sandbox its loop posted to and its
|
|
283
|
+
* installed build to one that ran `status --json` over a host capability. One field, two meanings, and the
|
|
284
|
+
* gap between them — a machine updated but never restarted — invisible in both.
|
|
285
|
+
*
|
|
286
|
+
* `host` is what the live socket announced (so: what is running), filled by the daemon at merge time from
|
|
287
|
+
* the hello frame it already holds, never by the sync agent, which would have to go reading another agent's
|
|
288
|
+
* config to guess at it. */
|
|
263
289
|
agents: z.object({ sync: z.string().optional(), host: z.string().optional() }),
|
|
264
290
|
// Filled by the READER, never the agent (see above). Empty is the resting state: no Docker on the machine,
|
|
265
291
|
// or nothing has looked. Neither is an error, and neither means "no sandboxes exist".
|
|
@@ -272,6 +298,27 @@ export const MachineReportSchema = z.object({
|
|
|
272
298
|
capturedAt: z.number(),
|
|
273
299
|
});
|
|
274
300
|
export type MachineReport = z.infer<typeof MachineReportSchema>;
|
|
301
|
+
|
|
302
|
+
/* THE AGENT THIS MACHINE INSTALLED AND THE ONE IT IS RUNNING, when they are not the same build — the whole of
|
|
303
|
+
* "you updated the agent and nothing changed", as a value.
|
|
304
|
+
*
|
|
305
|
+
* It is one comparison, and it lives HERE for the same reason watcherStalled does: the terminal (`intentic-machine
|
|
306
|
+
* status`) and the browser (the Computers row) both answer this question, and a machine that is behind in one and
|
|
307
|
+
* fine in the other is worse than either answer alone. The remedy is the same in both: restart the loop.
|
|
308
|
+
*
|
|
309
|
+
* Silent whenever either half is unknown, which covers a loop that is stopped (nothing is serving, and the row
|
|
310
|
+
* already says so in louder words), an agent too old to stamp its build, and a machine with no installed agent to
|
|
311
|
+
* compare against — none of which is a skew, and each of which would otherwise nag about a difference nobody can
|
|
312
|
+
* act on. */
|
|
313
|
+
export const watcherBuildSkew = (report: MachineReport): { readonly running: string; readonly installed: string } | undefined => {
|
|
314
|
+
const running = report.watcher.build;
|
|
315
|
+
const installed = report.agents.sync;
|
|
316
|
+
if (!report.watcher.running || running === undefined || installed === undefined || running === installed) {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
return { running, installed };
|
|
320
|
+
};
|
|
321
|
+
|
|
275
322
|
// Why a computer that is plainly THERE has no report to show. Each is a different errand for the reader, which is
|
|
276
323
|
// the whole reason they are not collapsed into one "unavailable".
|
|
277
324
|
export const ComputerGapSchema = z.enum([
|
|
@@ -294,13 +341,39 @@ export type ComputerGap = z.infer<typeof ComputerGapSchema>;
|
|
|
294
341
|
* enrolled ssh key's comment vs. the capability id the user typed, so the two are reconciled on the `hostname`
|
|
295
342
|
* their reports agree on, and left as separate rows when there is nothing to reconcile them by. Guessing that two
|
|
296
343
|
* differently-named machines are the same one would merge two people's laptops on a shared sandbox. */
|
|
344
|
+
/* THE DESKTOP-SYNC ENROLLMENT BEHIND A ROW, which used to be a boolean and could not be.
|
|
345
|
+
*
|
|
346
|
+
* `syncEnrolled: true` answered "is this machine paired" and nothing a reader standing in front of the row
|
|
347
|
+
* actually asks next: WHICH half of desktop sync it holds (files and ports, or ports alone), whether it has
|
|
348
|
+
* ever used the enrollment, and how to name it when they want it gone. Those three lived on /system/sync
|
|
349
|
+
* instead, as one machine's worth of `syncingFrom` plus a list of `mirroredBy` names, which is the sandbox-level
|
|
350
|
+
* shape this view exists to stop being: one card claiming a sandbox has A desktop sync, over a list of the
|
|
351
|
+
* several computers that actually do.
|
|
352
|
+
*
|
|
353
|
+
* `machine` is the enrollment's own name for the box (the ssh key's comment). It is what the reports are filed
|
|
354
|
+
* under, and it is the id the revoke route takes — the same string, so a row can revoke exactly the enrollment
|
|
355
|
+
* it is drawn from. Two machines that present the same comment share one enrollment identity throughout the
|
|
356
|
+
* daemon (reports included); that is a pre-existing property of naming machines by their key comment, and this
|
|
357
|
+
* field inherits it rather than inventing a second identity that would disagree with the first. */
|
|
358
|
+
export const ComputerSyncSchema = z.object({
|
|
359
|
+
machine: z.string(),
|
|
360
|
+
/* Which half. "sync" is files AND ports and is SINGLE-HOLDER for the sandbox; "mirror" is ports only and any
|
|
361
|
+
* number of machines may hold one. The row says which, because "your laptop is paired" is read as the first
|
|
362
|
+
* by somebody who has the second, and then their files are not where they expect them. */
|
|
363
|
+
mode: z.enum(["sync", "mirror"]),
|
|
364
|
+
// When this machine last USED its enrollment (its watcher's own polls stamp it). Absent on one that never
|
|
365
|
+
// has, which is exactly what a setup that did not finish leaves behind, and must not read as healthy.
|
|
366
|
+
seenAt: z.number().optional(),
|
|
367
|
+
});
|
|
368
|
+
export type ComputerSync = z.infer<typeof ComputerSyncSchema>;
|
|
297
369
|
export const ComputerSchema = z.object({
|
|
298
370
|
// Stable row key: the reported hostname when either door produced one, else the name that door knows it by.
|
|
299
371
|
key: z.string(),
|
|
300
372
|
// What to call it on screen, the user's own name for the machine wherever one exists.
|
|
301
373
|
label: z.string(),
|
|
302
|
-
//
|
|
303
|
-
|
|
374
|
+
// The desktop-sync enrollment this machine holds with this sandbox, absent when it has none (a computer
|
|
375
|
+
// reached only through its `host` capability).
|
|
376
|
+
sync: ComputerSyncSchema.optional(),
|
|
304
377
|
// The host capability's id, when this machine is also a connected computer. Absent otherwise.
|
|
305
378
|
hostId: z.string().optional(),
|
|
306
379
|
// Host-capability liveness. Absent when there is no host capability, which is NOT the same as offline.
|
|
@@ -327,9 +400,16 @@ export const ComputerSchema = z.object({
|
|
|
327
400
|
});
|
|
328
401
|
export type Computer = z.infer<typeof ComputerSchema>;
|
|
329
402
|
export const ComputersListSchema = z.object({ computers: z.array(ComputerSchema) });
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
403
|
+
/* GET /system/sync: what desktop sync is doing for this sandbox, WITHOUT naming any one machine as the answer.
|
|
404
|
+
*
|
|
405
|
+
* It used to carry `syncingFrom` + `syncSeenAt` + `mirroredBy`, which is the enrollment list flattened into one
|
|
406
|
+
* holder and a list of everybody else — the shape a card that believed a sandbox has A desktop sync needed, and
|
|
407
|
+
* the reason that card kept restating facts the Computers list beside it already had per machine. Every one of
|
|
408
|
+
* those now rides on the machine's own row (ComputerSync), where a reader can act on it.
|
|
409
|
+
*
|
|
410
|
+
* What is left is what is genuinely about the SANDBOX rather than about any computer: whether sync is possible
|
|
411
|
+
* here at all, whether anything at all is enrolled, and the raw reports, which is the cheap ambient read the
|
|
412
|
+
* rail's badge lives on (it must never fan out to somebody's laptop just to decide whether to draw a chip). */
|
|
333
413
|
export const SyncStatusSchema = z.object({
|
|
334
414
|
enrolled: z.boolean(),
|
|
335
415
|
/* Whether this sandbox can do desktop sync at all. It used to be the SSH hostname the laptop would dial, and
|
|
@@ -338,10 +418,6 @@ export const SyncStatusSchema = z.object({
|
|
|
338
418
|
* surface now, so a sandbox that can answer this read can also sync. Kept as a field rather than assumed,
|
|
339
419
|
* because the card branches on it and a daemon too old to say is one that should not be offered sync. */
|
|
340
420
|
available: z.boolean().optional(),
|
|
341
|
-
// The single machine holding file sync, and when its heartbeat last landed.
|
|
342
|
-
syncingFrom: z.string().optional(),
|
|
343
|
-
syncSeenAt: z.number().optional(),
|
|
344
|
-
mirroredBy: z.array(z.string()).optional(),
|
|
345
421
|
machines: z.array(MachineReportSchema).optional(),
|
|
346
422
|
});
|
|
347
423
|
export type SyncStatus = z.infer<typeof SyncStatusSchema>;
|
|
@@ -70,8 +70,22 @@ export const EnvironmentRecurringSchema = z.object({
|
|
|
70
70
|
live: z.boolean(),
|
|
71
71
|
drafted: z.boolean().optional(),
|
|
72
72
|
declined: z.boolean().optional(),
|
|
73
|
+
/* The Dockerfile step that would bake this tool, when its ecosystem has one that follows from the name
|
|
74
|
+
* alone (auto-drafts.ts `stepFor`). Sent rather than re-derived in the browser because it is the SAME string
|
|
75
|
+
* the owner would approve, and because its presence is the honest answer to "can this be fixed by pressing a
|
|
76
|
+
* button?": absent means the fix is a judgement call (which pip package, replaying which installer) and the
|
|
77
|
+
* card offers an agent instead. */
|
|
78
|
+
step: z.string().optional(),
|
|
73
79
|
});
|
|
74
80
|
export type EnvironmentRecurring = z.infer<typeof EnvironmentRecurringSchema>;
|
|
81
|
+
/* The owner's answer to ONE line of that list. `adopt` writes the tool's overlay draft now, without waiting for
|
|
82
|
+
* the sweep to re-earn it; `dismiss` tombstones it so nothing proposes it again; `restore` undoes a dismissal.
|
|
83
|
+
* One route rather than three because it is one decision surface about one ledger entry. */
|
|
84
|
+
export const EnvironmentRuntimeDecisionSchema = z.object({
|
|
85
|
+
tool: z.string().min(1),
|
|
86
|
+
decision: z.enum(["adopt", "dismiss", "restore"]),
|
|
87
|
+
});
|
|
88
|
+
export type EnvironmentRuntimeDecision = z.infer<typeof EnvironmentRuntimeDecisionSchema>;
|
|
75
89
|
export const EnvironmentSchema = z.object({
|
|
76
90
|
proposal: environmentFileSchema.optional(),
|
|
77
91
|
// The owner-approved agent-written custom section (.intentic/config/environment.custom.Dockerfile).
|
|
@@ -142,116 +156,23 @@ export const EnvironmentItemSchema = z.object({
|
|
|
142
156
|
export type EnvironmentItem = z.infer<typeof EnvironmentItemSchema>;
|
|
143
157
|
export const EnvironmentContentsSchema = z.object({ items: z.array(EnvironmentItemSchema) });
|
|
144
158
|
export type EnvironmentContents = z.infer<typeof EnvironmentContentsSchema>;
|
|
145
|
-
/* ---- portability: exporting a sandbox's environment
|
|
159
|
+
/* ---- portability: exporting a sandbox's environment ----
|
|
146
160
|
*
|
|
147
161
|
* A sandbox is four stores, not one: `/work` (the workspace and the daemon's manifests), `/history` (every
|
|
148
162
|
* repo's real git dir, the fleet registry, the ledgers), the CONTAINER (the built overlay image plus the env
|
|
149
163
|
* the run contract replays) and the AI-provider credential root. A bundle carries the first two, declared entry
|
|
150
164
|
* by entry in WORKSPACE_STATE_FILES / HISTORY_STATE_FILES. It cannot carry the other two, and the honest
|
|
151
|
-
* consequence is that
|
|
165
|
+
* consequence is that taking one in ends in a REPORT rather than a claim of equivalence, the container has no
|
|
152
166
|
* docker socket, so only the host can rebuild the image the overlay describes.
|
|
153
167
|
*
|
|
154
168
|
* The bundle's manifest (BundleManifestSchema) lives in definition.ts beside the sandbox DEFINITION it embeds:
|
|
155
169
|
* a bundle is definition + state, and keeping the two schemas together is what keeps the two export doors from
|
|
156
|
-
* drifting into different answers about what an environment is.
|
|
157
|
-
|
|
158
|
-
// What a restore actually did. `needsAction` is the part that matters: the environment rebuild command, the
|
|
159
|
-
// credentials to re-enter, the logins to redo, each one a thing the target cannot do for itself.
|
|
160
|
-
export const ImportReportSchema = z.object({
|
|
161
|
-
restored: z.object({ workspaceFiles: z.number(), historyFiles: z.number(), repos: z.array(z.string()), bytes: z.number() }),
|
|
162
|
-
// Entries the bundle carried that this daemon refused to write (an identity file, an escaping path), empty
|
|
163
|
-
// for any bundle a matching exporter produced, and a tamper signal when it is not.
|
|
164
|
-
refused: z.array(z.string()),
|
|
165
|
-
needsAction: z.array(z.object({ subject: z.string(), detail: z.string() })),
|
|
166
|
-
});
|
|
167
|
-
export type ImportReport = z.infer<typeof ImportReportSchema>;
|
|
168
|
-
/* ---- migrations: importing a FOREIGN assistant's setup (Hermes, OpenClaw) ----
|
|
169
|
-
*
|
|
170
|
-
* A different crossing than a bundle restore, and deliberately a different surface: a bundle is our own format,
|
|
171
|
-
* re-derived entry by entry against the state manifests, while a migration reads a directory some OTHER
|
|
172
|
-
* program laid out (`~/.hermes`) and TRANSLATES it into native things, skills, automations, capabilities,
|
|
173
|
-
* merged memory. Nothing foreign is executed or copied verbatim into daemon state; every item lands through the
|
|
174
|
-
* same write paths the settings/skills/automations/capabilities surfaces use, which is what keeps an imported
|
|
175
|
-
* setup editable and deletable in the ordinary UI the day after (docs/assistant-import-design.md).
|
|
170
|
+
* drifting into different answers about what an environment is.
|
|
176
171
|
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
|
|
181
|
-
export const MigrationSourceSchema = z.enum(["hermes", "openclaw"]);
|
|
182
|
-
export type MigrationSource = z.infer<typeof MigrationSourceSchema>;
|
|
183
|
-
// What an item becomes here, not what it was there, the apply loop dispatches on this, and the checklist
|
|
184
|
-
// groups by it so the owner reads "3 skills, 2 automations" rather than a foreign directory listing.
|
|
185
|
-
export const MigrationTargetSchema = z.enum(["memory", "skill", "automation", "capability", "secret", "file"]);
|
|
186
|
-
export type MigrationTarget = z.infer<typeof MigrationTargetSchema>;
|
|
187
|
-
export const MigrationItemSchema = z.object({
|
|
188
|
-
// Deterministic (derived from the source artifact, e.g. `skill:weather`), so the ids the owner ticked name
|
|
189
|
-
// the same items when the plan is re-derived at apply.
|
|
190
|
-
id: z.string(),
|
|
191
|
-
target: MigrationTargetSchema,
|
|
192
|
-
// The checklist line, plain words: "Skill, weather", "Nightly digest (9:00 every day)".
|
|
193
|
-
label: z.string(),
|
|
194
|
-
detail: z.string().optional(),
|
|
195
|
-
/* The default tick. False marks the items the owner should read before taking, a server URL that points at
|
|
196
|
-
* localhost on the OLD machine, an .env key that looks like tuning rather than a credential. They still
|
|
197
|
-
* import fine when ticked; the flag is the adapter's judgment, not a gate. */
|
|
198
|
-
recommended: z.boolean(),
|
|
199
|
-
// Names of the secrets this item would store (never values, values stay in the held archive until apply,
|
|
200
|
-
// and only move when the apply says includeSecrets). Empty for items that carry none.
|
|
201
|
-
secrets: z.array(z.string()),
|
|
202
|
-
});
|
|
203
|
-
export type MigrationItem = z.infer<typeof MigrationItemSchema>;
|
|
204
|
-
export const MigrationNeedsActionSchema = z.object({ subject: z.string(), detail: z.string() });
|
|
205
|
-
export const MigrationPlanSchema = z.object({
|
|
206
|
-
source: MigrationSourceSchema,
|
|
207
|
-
// Names the held upload for the apply call. Minted per plan; a new upload replaces the held one.
|
|
208
|
-
token: z.string(),
|
|
209
|
-
items: z.array(MigrationItemSchema),
|
|
210
|
-
// What the adapter saw and will not move, sessions, logs, pairing state, listed rather than silent.
|
|
211
|
-
refused: z.array(z.string()),
|
|
212
|
-
// What is already known not to move mechanically (channels to reconnect, a model to pick), the same
|
|
213
|
-
// honesty ImportReportSchema carries, surfaced at PREVIEW time so the owner ticks with open eyes.
|
|
214
|
-
needsAction: z.array(MigrationNeedsActionSchema),
|
|
215
|
-
});
|
|
216
|
-
export type MigrationPlan = z.infer<typeof MigrationPlanSchema>;
|
|
217
|
-
/* One of the owner's own computers, as an import SOURCE, the answer to "where is my setup" that needs no
|
|
218
|
-
* packing at all. Read on the card's first render for every enrolled machine, so the offer appears before the
|
|
219
|
-
* owner has read a single instruction.
|
|
220
|
-
*
|
|
221
|
-
* `found` absent means "connected, and nothing to import here", which is a real answer worth rendering
|
|
222
|
-
* quietly, not an error: the machine may simply be a different one from the machine the assistant runs on. */
|
|
223
|
-
export const MigrationHostSchema = z.object({
|
|
224
|
-
id: z.string(),
|
|
225
|
-
online: z.boolean(),
|
|
226
|
-
found: MigrationSourceSchema.optional(),
|
|
227
|
-
// Why this machine cannot be read right now, when it cannot, offline, or its own refusal, in its words.
|
|
228
|
-
detail: z.string().optional(),
|
|
229
|
-
});
|
|
230
|
-
export const MigrationHostsSchema = z.object({ hosts: z.array(MigrationHostSchema) });
|
|
231
|
-
export type MigrationHost = z.infer<typeof MigrationHostSchema>;
|
|
232
|
-
// Read the setup off a connected computer instead of an upload. Answers with a plan, exactly as the upload
|
|
233
|
-
// route does, everything after this point is identical whichever door the setup came through.
|
|
234
|
-
export const MigrationScanSchema = z.object({ host: z.string().min(1) });
|
|
235
|
-
export const MigrationApplySchema = z.object({
|
|
236
|
-
token: z.string(),
|
|
237
|
-
// The ticked item ids. Ids the re-derived plan does not contain are ignored rather than erroring, the
|
|
238
|
-
// archive is the truth, and a stale checklist must not block the items that still exist.
|
|
239
|
-
items: z.array(z.string()),
|
|
240
|
-
// The owner's explicit consent to move credential VALUES (mirrors the bundle export's `?secrets=`, and the
|
|
241
|
-
// `--include-secrets` these tools' own migrate commands require). Off: secret items are skipped and
|
|
242
|
-
// capability configs land without their keys.
|
|
243
|
-
includeSecrets: z.boolean(),
|
|
244
|
-
});
|
|
245
|
-
export type MigrationApply = z.infer<typeof MigrationApplySchema>;
|
|
246
|
-
export const MigrationReportSchema = z.object({
|
|
247
|
-
applied: z.array(z.object({ id: z.string(), target: MigrationTargetSchema, label: z.string() })),
|
|
248
|
-
// Items that were ticked and did not land, each with the reason, a full disk, an env store that needs
|
|
249
|
-
// DevOps active. Distinct from `refused`, which is the class of things never attempted.
|
|
250
|
-
failed: z.array(z.object({ id: z.string(), label: z.string(), error: z.string() })),
|
|
251
|
-
refused: z.array(z.string()),
|
|
252
|
-
needsAction: z.array(MigrationNeedsActionSchema),
|
|
253
|
-
});
|
|
254
|
-
export type MigrationReport = z.infer<typeof MigrationReportSchema>;
|
|
172
|
+
* ONLY THE OUTBOUND HALF IS HERE. Taking a bundle IN is not a surface of its own any more: it is one of the
|
|
173
|
+
* four sources the arrival pipeline reads (arrival.ts), beside a definition and the two foreign assistants,
|
|
174
|
+
* because all four answer the same question and used to answer it three different ways. */
|
|
175
|
+
|
|
255
176
|
/* One export sitting in the daemon's export directory, the ARTIFACT a bundle is, rather than the request that
|
|
256
177
|
* produced it. Packing takes minutes over a real workspace, so tying it to a response made it a property of one
|
|
257
178
|
* browser tab: a refresh abandoned the work and left nothing to come back to. It is a file now, and every field
|
package/src/schemas/git.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { AgentProviderSchema } from "./agent.js";
|
|
3
3
|
import { LandConflictSchema, LandedMessageSchema } from "./agents.js";
|
|
4
|
+
import { CommandRunSchema } from "./ci.js";
|
|
4
5
|
import { RefNameSchema } from "./internal.js";
|
|
5
6
|
import { RepoParamSchema } from "./shared.js";
|
|
6
7
|
// What a commit records, three shapes, each a real git spelling. The last two are for the case where nothing
|
|
@@ -48,6 +49,34 @@ export const PushSchema = RepoParamSchema.extend({
|
|
|
48
49
|
.optional()
|
|
49
50
|
.describe("Which branch to push. Leave it out for the checked-out one. A branch with no upstream yet gets one set on this push."),
|
|
50
51
|
});
|
|
52
|
+
/* WHO SAID NO to a push, read off git's final words (git/git.ts pushRefusal), because the three answers ask
|
|
53
|
+
* three different things of the owner and only one of them is an agent's to fix:
|
|
54
|
+
* hook , this repository's own pre-push hook refused it: the code is known to be wrong, the hook's
|
|
55
|
+
* output says how, and a fix is worth proposing.
|
|
56
|
+
* remote , the server rejected the refs: a non-fast-forward, a protected branch. Pull first, or push
|
|
57
|
+
* somewhere else; nothing about the code has been judged.
|
|
58
|
+
* transport , it never got there: credentials, a host that does not answer, a remote that is not a
|
|
59
|
+
* repository. The same again, and a retry is the only sensible button. */
|
|
60
|
+
export const PushRefusalSchema = z.enum(["hook", "remote", "transport"]);
|
|
61
|
+
export type PushRefusal = z.infer<typeof PushRefusalSchema>;
|
|
62
|
+
/* THE PUSH AS A RUN: the pre-push check's shape (CommandRunSchema) with the three things a push adds. A push is
|
|
63
|
+
* a command that runs this repository's pre-push hook, which for a workspace with a real gate is the whole
|
|
64
|
+
* suite, minutes of output; it is a terminal to watch and a verdict to poll for exactly as the check is, and
|
|
65
|
+
* NOT a request held open for its duration (the browser's header deadline is seconds, and a push that ran a
|
|
66
|
+
* suite inside its own request reported "failed" over a push that had gone). One shape for both halves of
|
|
67
|
+
* the push flow is what lets the browser render a refused push with the card, the terminal link and the
|
|
68
|
+
* proposed fix it already has for a red check. */
|
|
69
|
+
export const PushRunSchema = CommandRunSchema.extend({
|
|
70
|
+
repo: z.string().describe("The repository this run is about, the same id the routes take."),
|
|
71
|
+
reason: z
|
|
72
|
+
.string()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("Why not, in git's own words: the last verdict line, for a row that has room for one line. The whole tail is `output`."),
|
|
75
|
+
refusedBy: PushRefusalSchema.optional().describe(
|
|
76
|
+
"Who refused a failed push: this repository's pre-push hook (the code is wrong, a fix is worth proposing), the remote (pull first), or the transport (credentials, network: retry). Absent while it runs and for a push that went.",
|
|
77
|
+
),
|
|
78
|
+
});
|
|
79
|
+
export type PushRun = z.infer<typeof PushRunSchema>;
|
|
51
80
|
export const GitFileQuerySchema = RepoParamSchema.extend({ path: z.string().min(1).describe("The file to read, relative to the repository root.") });
|
|
52
81
|
export const GitFileWriteSchema = RepoParamSchema.extend({
|
|
53
82
|
path: z.string().min(1).describe("Where to write, relative to the repository root. Missing folders are created."),
|
|
@@ -107,6 +136,22 @@ export const GitChangeSchema = z.object({
|
|
|
107
136
|
.optional()
|
|
108
137
|
.describe("Lines added. Absent for a binary file, and for an untracked one, which has nothing to compare against."),
|
|
109
138
|
deletions: z.number().optional().describe("Lines removed. Absent for the same reasons additions is."),
|
|
139
|
+
/* THE SAME CHANGE WITH THE COMMENTS TAKEN OUT, computed here rather than by whoever renders the row, and
|
|
140
|
+
* that is the whole point of it being on the wire. A review's diffs open on code alone, so the numbers beside
|
|
141
|
+
* them are the code's; working those out needs both whole sides of the file and a TextMate walk over each,
|
|
142
|
+
* which the app used to do per file, as the files were read — so a row arrived showing git's count and
|
|
143
|
+
* changed to this one the moment anything read it, which moved the row under the reader when the list was
|
|
144
|
+
* sorted by size. Shipped with the list, the number a reader sees first is the number it stays.
|
|
145
|
+
*
|
|
146
|
+
* Absent, not zero, when there is nothing to say: a binary file, one side too large to read, a path whose
|
|
147
|
+
* grammar this build does not ship, or a list too long to count whole (see git/code-counts.ts). The caller
|
|
148
|
+
* then shows git's own counts, which for such a file are the only honest reading anyway. */
|
|
149
|
+
code: z
|
|
150
|
+
.object({ additions: z.number(), deletions: z.number() })
|
|
151
|
+
.optional()
|
|
152
|
+
.describe(
|
|
153
|
+
"The same +/− with every comment stripped from both sides, which is what a review shows beside a diff that opens on code alone. Absent when the file cannot be read that way (binary, too large, or a language this build ships no grammar for): git's own counts above are then the reading.",
|
|
154
|
+
),
|
|
110
155
|
});
|
|
111
156
|
export type GitChange = z.infer<typeof GitChangeSchema>;
|
|
112
157
|
// Where a repo's checked-out branch stands against its remote. Every field is optional-or-zero because every
|
|
@@ -375,16 +420,25 @@ export const RepoModulesSchema = z.object({
|
|
|
375
420
|
export type RepoModules = z.infer<typeof RepoModulesSchema>;
|
|
376
421
|
export const WorkspaceModulesSchema = z.object({ repos: z.array(RepoModulesSchema).describe("Every repository with the packages inside it.") });
|
|
377
422
|
export type WorkspaceModules = z.infer<typeof WorkspaceModulesSchema>;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
423
|
+
/* One file an agent touched AND STILL DIFFERS FROM MAIN ON, plus whether the main working tree is already
|
|
424
|
+
* holding it. The list is what the conversation wrote measured against the main line as it stands right now,
|
|
425
|
+
* which takes three states to say and each one decides a different next move for the reader:
|
|
426
|
+
*
|
|
427
|
+
* · main's history has this content: the user accepted it, it is their commit, and it is no longer a
|
|
428
|
+
* difference against main. There is no row (see `absorbed` on the response).
|
|
429
|
+
* · the main working tree has it, uncommitted: the steady state seconds after a land, waiting in the Changes
|
|
430
|
+
* panel. A row, `landed: true`.
|
|
431
|
+
* · neither: never landed, or landed and then discarded. A row, `landed: false`, and this is exactly what
|
|
432
|
+
* "Land now" would apply.
|
|
433
|
+
*
|
|
434
|
+
* Landed work keeps its row on purpose: a clean turn auto-lands within milliseconds, so a list scoped to the
|
|
435
|
+
* outstanding remainder would show an empty panel for work nobody had looked at yet. What retires a row is the
|
|
436
|
+
* user committing it, which is the one act that says they are done reviewing it. */
|
|
383
437
|
export const AgentChangeSchema = GitChangeSchema.extend({
|
|
384
438
|
landed: z
|
|
385
439
|
.boolean()
|
|
386
440
|
.describe(
|
|
387
|
-
"Whether
|
|
441
|
+
"Whether your workspace already holds this content. Read from the tree at request time, not from what a land recorded: discard a landed file in the Changes panel and this goes back to false, which is what puts it back under Land now.",
|
|
388
442
|
),
|
|
389
443
|
});
|
|
390
444
|
export type AgentChange = z.infer<typeof AgentChangeSchema>;
|
|
@@ -420,6 +474,16 @@ export type AgentRepoChanges = z.infer<typeof AgentRepoChangesSchema>;
|
|
|
420
474
|
* than the last attempt. */
|
|
421
475
|
export const AgentChangesSchema = z.object({
|
|
422
476
|
repos: z.array(AgentRepoChangesSchema).describe("One entry per repository the conversation touched."),
|
|
477
|
+
/* HOW MUCH OF THE WORK IS NO LONGER A DIFFERENCE, so an empty list can say WHICH kind of empty it is. An
|
|
478
|
+
* agent that has written nothing and an agent whose every file the user committed both answer with no rows,
|
|
479
|
+
* and they are opposite facts: one is "ask it for something", the other is "it is all in your history". A
|
|
480
|
+
* count rather than the rows themselves, because that is the whole of what the surface needs to pick a
|
|
481
|
+
* sentence, and carrying the rows would put the list back where it started. */
|
|
482
|
+
absorbed: z
|
|
483
|
+
.number()
|
|
484
|
+
.describe(
|
|
485
|
+
"How many of this conversation's files your own history already carries, and which are therefore not listed as differences any more.",
|
|
486
|
+
),
|
|
423
487
|
conflicts: z
|
|
424
488
|
.array(LandConflictSchema)
|
|
425
489
|
.optional()
|
|
@@ -428,3 +492,54 @@ export const AgentChangesSchema = z.object({
|
|
|
428
492
|
),
|
|
429
493
|
});
|
|
430
494
|
export type AgentChanges = z.infer<typeof AgentChangesSchema>;
|
|
495
|
+
|
|
496
|
+
/* WHERE THE WORK WENT once it stopped being a difference, the other half of the sentence `absorbed` above can
|
|
497
|
+
* only start. The review is what still differs from main, so a reader who committed an agent's every file
|
|
498
|
+
* arrives at an empty panel; the count lets it say WHICH kind of empty, and this says where to go and shows
|
|
499
|
+
* the work, which is what the reader actually came for.
|
|
500
|
+
*
|
|
501
|
+
* Deliberately its OWN read rather than more fields on the review. The review is on the panel's hot path and
|
|
502
|
+
* this is a `git log` per repo that only matters once history has taken something, so it is asked for exactly
|
|
503
|
+
* when there is an answer to have. That also keeps the review's shape honest: its rows are differences against
|
|
504
|
+
* main, and these are not.
|
|
505
|
+
*
|
|
506
|
+
* A COMMIT CARRIES the work, it did not necessarily author it: a path is attributed to the newest commit that
|
|
507
|
+
* left the agent's content there, which is where a reader should be sent to read it now. See the daemon's
|
|
508
|
+
* agents/landed-history.ts for the span this is measured over and for why an unattributable path is counted
|
|
509
|
+
* rather than assigned to a plausible commit. */
|
|
510
|
+
export const AgentHistoryCommitSchema = z.object({
|
|
511
|
+
sha: z.string().describe("The commit."),
|
|
512
|
+
short: z.string().describe("Its abbreviated hash, which is what a reader recognises it by."),
|
|
513
|
+
subject: z.string().describe("Its first line."),
|
|
514
|
+
author: z.string().describe("Who committed it."),
|
|
515
|
+
at: z.number().describe("When it was authored, in milliseconds."),
|
|
516
|
+
changes: z
|
|
517
|
+
.array(GitChangeSchema)
|
|
518
|
+
.describe(
|
|
519
|
+
"The conversation's files that this commit is the newest carrier of, as the conversation changed them. Every file appears under exactly one commit, so these counts add up to the work rather than over-counting a file that history touched twice.",
|
|
520
|
+
),
|
|
521
|
+
});
|
|
522
|
+
export type AgentHistoryCommit = z.infer<typeof AgentHistoryCommitSchema>;
|
|
523
|
+
export const AgentRepoHistorySchema = z.object({
|
|
524
|
+
repo: z.string().describe("Which repository."),
|
|
525
|
+
commits: z.array(AgentHistoryCommitSchema).describe("The commits carrying this conversation's work there, newest first."),
|
|
526
|
+
/* Carried for the same reason the review's rows carry it, and read from the same tree at the same instant:
|
|
527
|
+
* a package the conversation created lives only in its own copy, so the shared tree cannot name it, and
|
|
528
|
+
* without this every file of a brand-new package groups under no package at all. */
|
|
529
|
+
modules: z.array(WorkspaceModuleSchema).describe("The packages of the tree these files came from, so a review can group them by package."),
|
|
530
|
+
});
|
|
531
|
+
export type AgentRepoHistory = z.infer<typeof AgentRepoHistorySchema>;
|
|
532
|
+
export const AgentHistorySchema = z.object({
|
|
533
|
+
repos: z.array(AgentRepoHistorySchema).describe("One entry per repository holding committed work of this conversation."),
|
|
534
|
+
/* FILES HISTORY HOLDS THAT NO COMMIT HERE ACCOUNTS FOR, reported rather than hidden. Content reaches the
|
|
535
|
+
* main line by roads that do not pass through a commit since the land: a cherry-pick from elsewhere,
|
|
536
|
+
* another conversation landing the same lines, the user typing them by hand before this one landed. Those
|
|
537
|
+
* files are absorbed and unattributable at once, and a surface that quietly dropped them would be claiming
|
|
538
|
+
* the commits it names are the whole story. */
|
|
539
|
+
unaccounted: z
|
|
540
|
+
.number()
|
|
541
|
+
.describe(
|
|
542
|
+
"How many of the conversation's absorbed files none of these commits carries. Above zero means its content reached your main line by some other road, so the commits listed are not the whole story.",
|
|
543
|
+
),
|
|
544
|
+
});
|
|
545
|
+
export type AgentHistory = z.infer<typeof AgentHistorySchema>;
|
package/src/schemas/issues.ts
CHANGED
|
@@ -150,7 +150,7 @@ export type Issue = z.infer<typeof IssueSchema>;
|
|
|
150
150
|
export const IssueSummarySchema = IssueSchema.extend({ id: entryId.describe("The issue's id, which is its fingerprint.") });
|
|
151
151
|
export type IssueSummary = z.infer<typeof IssueSummarySchema>;
|
|
152
152
|
|
|
153
|
-
// `invalid` is the same trust-boundary confession the
|
|
153
|
+
// `invalid` is the same trust-boundary confession the approvals list makes, for the opposite reason: nothing but
|
|
154
154
|
// the daemon writes these, so a file in here that will not parse is a BUG in this daemon or a half-written
|
|
155
155
|
// volume, and either is worth seeing rather than silently skipping.
|
|
156
156
|
export const IssuesListSchema = z.object({
|
package/src/schemas/panels.ts
CHANGED
|
@@ -5,12 +5,32 @@ import { z } from "zod";
|
|
|
5
5
|
// preview-<panelKey>-<sandboxId>.<zone> to it) PLUS content facts, evidence the web app's extensions run their
|
|
6
6
|
// detect() over, computed daemon-side in one pass so the browser never scans /work file-by-file.
|
|
7
7
|
|
|
8
|
+
/* WHERE A START THE SANDBOX IS RUNNING HAS GOT TO, between the click and the first byte served. The process
|
|
9
|
+
* manager watches the pane's foreground command every couple of seconds (processes/managed-processes.ts), and
|
|
10
|
+
* these four words are what that sampling can honestly say: the shell is still coming up; the install that
|
|
11
|
+
* runs first when node_modules is missing is still going; the dev command is running but nothing listens yet;
|
|
12
|
+
* or the command has already exited back to a prompt, which is the one a person needs told at once, because
|
|
13
|
+
* the "Preparing the preview…" it would otherwise sit behind never ends. Absent once the preview proxy has
|
|
14
|
+
* something to serve, and absent for anything the sandbox is not starting. */
|
|
15
|
+
export const PanelLaunchSchema = z.enum(["launching", "installing", "starting", "exited"]);
|
|
16
|
+
export type PanelLaunch = z.infer<typeof PanelLaunchSchema>;
|
|
17
|
+
|
|
8
18
|
export const PanelSummarySchema = z.object({
|
|
9
19
|
// The repo id: its root-relative dir under /work (slashes become `--` in the preview subdomain label).
|
|
10
20
|
repo: z.string().describe("Which repository."),
|
|
11
21
|
// Whether the repo ships a runnable dev server (a package.json `dev` script at operator/ or the root).
|
|
12
22
|
hasPanel: z.boolean().describe("Whether it has anything runnable at all."),
|
|
13
23
|
running: z.boolean().describe("Whether the sandbox has it running."),
|
|
24
|
+
/* Whether its dependencies are on disk, a node_modules at the directory Start runs in. What decides what a
|
|
25
|
+
* Start COSTS: seconds when true, an install first when false, and the Start screen's copy says which
|
|
26
|
+
* instead of promising "a few minutes" over a tree that is already installed (the starter site's is: the
|
|
27
|
+
* image bakes it). True for a repo with nothing runnable, which has nothing to install for. */
|
|
28
|
+
installed: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.describe("Whether its dependencies are installed, which is what decides whether a start takes seconds or an install first."),
|
|
31
|
+
launch: PanelLaunchSchema.optional().describe(
|
|
32
|
+
"Where a start the sandbox is running has got to: its shell coming up, installing, its dev command running with nothing listening yet, or exited back to a prompt. Absent when nothing is starting and once it serves.",
|
|
33
|
+
),
|
|
14
34
|
// Whether anything this repo owns is answering, see `servers`. Not the same question as `running`: a panel
|
|
15
35
|
// whose install is still going is running and not yet healthy, and a dev server someone started in their own
|
|
16
36
|
// terminal is healthy without the daemon running it.
|