@intentic/sandbox-contract 1.240.0 → 1.242.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 +12 -0
- package/dist/plan-pools.d.ts.map +1 -0
- package/dist/plan-pools.js +30 -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 +31 -5
- package/dist/schemas/computers.d.ts.map +1 -1
- package/dist/schemas/computers.js +7 -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 +82 -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 +52 -11
- 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
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// approvals: things the agent prepared and may not do until the owner says yes (.intentic/config/approvals/<id>.json)
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { entryId } from "./internal.js";
|
|
4
|
+
|
|
5
|
+
/* ONE QUEUE FOR EVERYTHING THAT WAITS ON A YES, and the test for what belongs in it: the agent prepared an exact
|
|
6
|
+
* thing, the owner's click releases it, a machine then carries out precisely that thing, and the outcome is
|
|
7
|
+
* written back. A post is the first such thing and was the whole of this file (it was `drafts`); a hotel
|
|
8
|
+
* booking, a payment, a message sent under the owner's name are the same shape with a different payload, and
|
|
9
|
+
* each of them arriving as its own inbox is how a product grows five tiles that all say "approve".
|
|
10
|
+
*
|
|
11
|
+
* So the record is an ENVELOPE plus a KIND. The envelope is what every approval shares and what the queue, the
|
|
12
|
+
* badge and the daemon act on: who it acts as, when it is due, where it stands, what happened. The kind is what
|
|
13
|
+
* the row draws and the daemon dispatches on, a discriminated union so a new kind is one variant here, one
|
|
14
|
+
* body component in the extension and one executor in the daemon, and nothing else moves.
|
|
15
|
+
*
|
|
16
|
+
* What does NOT belong here, and why the line is drawn where it is: an inbox of FACTS (the issues queue, where
|
|
17
|
+
* a crash arrived and the owner's verbs are resolve / ignore / investigate) has no prepared thing to release,
|
|
18
|
+
* and a hold a RUNNING turn is blocked on (a permission card, a spend offer) lives in the conversation, because
|
|
19
|
+
* a queue is the wrong latency for a click somebody is spinning on.
|
|
20
|
+
*
|
|
21
|
+
* One JSON file per approval. The AGENT creates them with its normal file tools, it can't call daemon routes,
|
|
22
|
+
* the same split as the environment proposal, while the daemon edits/deletes them on the owner's behalf, so
|
|
23
|
+
* the two writers never share a file. The id IS the filename (entryId charset ⇒ path-safe); the body never
|
|
24
|
+
* carries it. */
|
|
25
|
+
|
|
26
|
+
export const ApprovalKindSchema = z.enum(["post", "action"]);
|
|
27
|
+
export type ApprovalKind = z.infer<typeof ApprovalKindSchema>;
|
|
28
|
+
|
|
29
|
+
/* proposed (agent) → approved (owner) → running (executor, set BEFORE acting so a dead turn can't do it twice)
|
|
30
|
+
* → done | failed. Reject = delete the file; retry = re-approve a failed one. The names are deliberately not a
|
|
31
|
+
* post's ("posting", "posted"): they are read by every kind, and a booking is not "posted". */
|
|
32
|
+
export const ApprovalStatusSchema = z.enum(["proposed", "approved", "running", "done", "failed"]);
|
|
33
|
+
export type ApprovalStatus = z.infer<typeof ApprovalStatusSchema>;
|
|
34
|
+
|
|
35
|
+
/* THE ENVELOPE, spread into every variant below (zod's discriminated union wants flat objects, not an extended
|
|
36
|
+
* base), which is also why a variant's own fields sit beside these rather than under a `payload` key: the file
|
|
37
|
+
* an agent writes stays one level deep, and "which fields are mine" is answered by the variant's schema. */
|
|
38
|
+
const envelope = {
|
|
39
|
+
/* WHOSE NAME THIS ACTS UNDER, a PersonaSchema id, handed to the executing turn as AgentTurnSchema.actsAs.
|
|
40
|
+
* Required in practice for every post outside DIRECT_PUBLISH_PLATFORMS, and the reason is the whole shape
|
|
41
|
+
* of turnPersona: acting through a browser needs a logged-in account, and an UNATTENDED turn that names no
|
|
42
|
+
* persona is denied every account there is. Without this field the executor could only wake such a turn,
|
|
43
|
+
* one structurally unable to reach the login the post needs, which read from inside the turn as "this
|
|
44
|
+
* account is not connected" and cost two approved posts before anyone traced it back here.
|
|
45
|
+
*
|
|
46
|
+
* A PERSONA RATHER THAN AN ACCOUNT ID, because that is the vocabulary the rest of the system already speaks:
|
|
47
|
+
* `actsAs` is the only pin turnPersona honours, and a card carries the workspace scope the turn also needs to
|
|
48
|
+
* write this file's own status back. Naming the account directly would invent a second way to say the same
|
|
49
|
+
* thing, and the two would disagree the first time a card's accounts changed.
|
|
50
|
+
*
|
|
51
|
+
* The daemon never guesses it. One site can be connected several times over, five Reddit logins here, and
|
|
52
|
+
* picking for the owner means picking wrong in public, with no undo. A post that needs a turn and names
|
|
53
|
+
* nobody is failed with that sentence instead of sent. An ACTION that names nobody runs with no accounts,
|
|
54
|
+
* which is a legitimate choice for work that needs none. */
|
|
55
|
+
actsAs: entryId
|
|
56
|
+
.optional()
|
|
57
|
+
.describe(
|
|
58
|
+
"Whose name it acts under. Needed for anything that requires being logged in, because an unwatched turn naming nobody is allowed no account at all. Never guessed: one site can be connected five times over, and picking for you means picking wrong in public with no undo.",
|
|
59
|
+
),
|
|
60
|
+
// Suggested time (epoch ms, the at/nextRun convention). Optional, the agent may propose without a date and
|
|
61
|
+
// the owner sets one at approval; an approved item with no date is dated one hold ahead by the daemon.
|
|
62
|
+
scheduledAt: z
|
|
63
|
+
.number()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe(
|
|
66
|
+
"When it should happen, in milliseconds. An agent may propose without one and you set it when approving; an approved item with no time goes after a short countdown you can still stop.",
|
|
67
|
+
),
|
|
68
|
+
// Agent-written files only need the kind's own fields; status defaults, the rest are optional, so a
|
|
69
|
+
// well-formed proposal never lands in `invalid` just for omitting bookkeeping fields.
|
|
70
|
+
status: ApprovalStatusSchema.default("proposed").describe(
|
|
71
|
+
"Where it is: proposed by the agent, approved by you, being carried out, done, or failed. Rejecting is deleting it; retrying is approving a failed one again.",
|
|
72
|
+
),
|
|
73
|
+
createdAt: z.number().optional().describe("When it was written, in milliseconds."),
|
|
74
|
+
// When execution STARTED, stamped with status "running". The executor needs it to tell a run that is under
|
|
75
|
+
// way from one whose turn died mid-flight, and those two are indistinguishable from the due time: a post
|
|
76
|
+
// scheduled for last week is not a post that has been sending since last week.
|
|
77
|
+
startedAt: z
|
|
78
|
+
.number()
|
|
79
|
+
.optional()
|
|
80
|
+
.describe(
|
|
81
|
+
"When it started being carried out, in milliseconds. Needed to tell a run that is under way from one whose turn died mid-flight, which the scheduled time cannot.",
|
|
82
|
+
),
|
|
83
|
+
finishedAt: z.number().optional().describe("When it was done, in milliseconds."),
|
|
84
|
+
// What came back, when something did: a post's own address, a booking's confirmation. The one thing a done
|
|
85
|
+
// row can offer that reading the proposal cannot: the result itself, to go and look at. A URL is drawn as
|
|
86
|
+
// a link; anything else as the sentence it is.
|
|
87
|
+
result: z
|
|
88
|
+
.string()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe(
|
|
91
|
+
"What came back, when something did: the post's own address, a confirmation number. The one thing a finished item can offer that reading it cannot.",
|
|
92
|
+
),
|
|
93
|
+
// Why it failed; set with status "failed". Written for the owner to read in the queue, so it is a sentence
|
|
94
|
+
// rather than a code.
|
|
95
|
+
error: z.string().optional().describe("Why it failed, written as a sentence for a person to read rather than as a code."),
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/* A POST, the first kind: words that go out in public under the owner's name and cannot be recalled. */
|
|
99
|
+
export const PostApprovalSchema = z.object({
|
|
100
|
+
kind: z.literal("post").describe("A post to publish somewhere."),
|
|
101
|
+
// Which skill posts it: "x" | "reddit" | "youtube" | "discord" | …, a bare string so new platforms need
|
|
102
|
+
// no contract change; an unknown platform simply fails at posting time.
|
|
103
|
+
platform: z
|
|
104
|
+
.string()
|
|
105
|
+
.min(1)
|
|
106
|
+
.describe("Where it should go. A plain name, so a new site needs no change here; an unknown one simply fails when it tries to post."),
|
|
107
|
+
content: z.string().min(1).describe("The post itself."),
|
|
108
|
+
// Reddit posts / YouTube uploads need one.
|
|
109
|
+
title: z.string().optional().describe("A title, where the site wants one."),
|
|
110
|
+
/* Where on the platform: subreddit / Discord channel id / community. OR the URL of the thing this post
|
|
111
|
+
* replies to. A URL target means the post is a reply, and on reddit the difference between a thread's
|
|
112
|
+
* address and one comment's permalink is the difference between talking to the room and answering the
|
|
113
|
+
* person: the publisher opens exactly this and replies where it lands. */
|
|
114
|
+
target: z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe(
|
|
118
|
+
"Where on the site: a community, a channel. Or the address of the thing this replies to, in which case it is a reply, and on some sites the difference between a thread's address and one comment's is the difference between talking to the room and answering the person.",
|
|
119
|
+
),
|
|
120
|
+
// Workspace-relative attachment paths, e.g. ".intentic/config/approvals/media/chart.png".
|
|
121
|
+
media: z.array(z.string()).optional().describe("Anything to attach, as workspace paths."),
|
|
122
|
+
...envelope,
|
|
123
|
+
});
|
|
124
|
+
export type PostApproval = z.infer<typeof PostApprovalSchema>;
|
|
125
|
+
|
|
126
|
+
/* AN ACTION, the general kind: anything else the agent is about to do that it should not do unasked. A
|
|
127
|
+
* booking, a purchase, a message to a person, a deletion that cannot be undone. The agent writes what it will
|
|
128
|
+
* do in words the owner reads (`summary`, `details`), and what it will tell ITSELF to do once released
|
|
129
|
+
* (`instructions`), because the turn that carries it out is a fresh one, hours later, with none of the
|
|
130
|
+
* conversation that led here. Executed by an agent turn, always: there is no typed door for "whatever it is". */
|
|
131
|
+
export const ActionApprovalSchema = z.object({
|
|
132
|
+
kind: z.literal("action").describe("Something the agent will do once you say so."),
|
|
133
|
+
summary: z.string().min(1).max(200).describe("What will happen, in one line: the row's headline and the confirm dialog's item."),
|
|
134
|
+
// Markdown. The specifics a yes is being asked for: the hotel and the dates, the amount and the account,
|
|
135
|
+
// the exact message and its recipient. Everything the owner has to see to be able to say no.
|
|
136
|
+
details: z.string().optional().describe("The specifics, as Markdown: everything you would want to see before saying yes."),
|
|
137
|
+
// What the executing turn is told. Written by the agent for its later self, so it names files, ids and
|
|
138
|
+
// steps rather than saying "do what we discussed".
|
|
139
|
+
instructions: z
|
|
140
|
+
.string()
|
|
141
|
+
.min(1)
|
|
142
|
+
.describe(
|
|
143
|
+
"What to do once approved, written for the fresh turn that will do it: names, ids and steps, since it has none of this conversation.",
|
|
144
|
+
),
|
|
145
|
+
...envelope,
|
|
146
|
+
});
|
|
147
|
+
export type ActionApproval = z.infer<typeof ActionApprovalSchema>;
|
|
148
|
+
|
|
149
|
+
// The on-disk file body, whichever kind it is.
|
|
150
|
+
export const ApprovalSchema = z.discriminatedUnion("kind", [PostApprovalSchema, ActionApprovalSchema]);
|
|
151
|
+
export type Approval = z.infer<typeof ApprovalSchema>;
|
|
152
|
+
|
|
153
|
+
// The list row / upsert input: the file body plus its filename id.
|
|
154
|
+
const withId = { id: entryId.describe("The approval's id.") };
|
|
155
|
+
export const PostApprovalSummarySchema = PostApprovalSchema.extend(withId);
|
|
156
|
+
export type PostApprovalSummary = z.infer<typeof PostApprovalSummarySchema>;
|
|
157
|
+
export const ActionApprovalSummarySchema = ActionApprovalSchema.extend(withId);
|
|
158
|
+
export type ActionApprovalSummary = z.infer<typeof ActionApprovalSummarySchema>;
|
|
159
|
+
export const ApprovalSummarySchema = z.discriminatedUnion("kind", [PostApprovalSummarySchema, ActionApprovalSummarySchema]);
|
|
160
|
+
export type ApprovalSummary = z.infer<typeof ApprovalSummarySchema>;
|
|
161
|
+
|
|
162
|
+
// `invalid` = filenames that failed to parse. Agent-written files are a trust boundary, without this a typo'd
|
|
163
|
+
// approval (or one of a kind this daemon does not know) would silently never run.
|
|
164
|
+
export const ApprovalsListSchema = z.object({
|
|
165
|
+
approvals: z.array(ApprovalSummarySchema).describe("The queue."),
|
|
166
|
+
invalid: z
|
|
167
|
+
.array(z.string())
|
|
168
|
+
.describe(
|
|
169
|
+
"Files that could not be read at all, or name a kind this daemon does not know. Listed rather than skipped, because an agent writes these files directly and a malformed one would otherwise never run and never say why.",
|
|
170
|
+
),
|
|
171
|
+
});
|
|
172
|
+
export type ApprovalsList = z.infer<typeof ApprovalsListSchema>;
|
|
173
|
+
// entryId, not a bare string: the id becomes a filename under .intentic/config/approvals/.
|
|
174
|
+
export const ApprovalIdParamSchema = z.object({ id: entryId.describe("Which approval.") });
|
package/src/schemas/ci.ts
CHANGED
|
@@ -124,22 +124,8 @@ export const CiRunsResponseSchema = z.object({
|
|
|
124
124
|
repos: z.array(CiRepoSchema).describe("Which workspace repositories are wired to a forge, and how each one's notifications are set up."),
|
|
125
125
|
// Newest first, across all mapped repos.
|
|
126
126
|
runs: z.array(PipelineRunSchema).describe("Runs across all of them, newest first."),
|
|
127
|
-
// When the owner last opened the pipelines view. Rides the runs response so the rail can decide what is
|
|
128
|
-
// NEW without a second call, a breakage older than this has already been seen and must not badge again.
|
|
129
|
-
// Absent ⇒ never opened, so everything counts as unseen.
|
|
130
|
-
seenAt: z
|
|
131
|
-
.number()
|
|
132
|
-
.optional()
|
|
133
|
-
.describe(
|
|
134
|
-
"When this was last looked at, in milliseconds, so a badge can tell new breakages from ones already read without a second call. Absent means never, so everything counts as new.",
|
|
135
|
-
),
|
|
136
127
|
});
|
|
137
128
|
export type CiRunsResponse = z.infer<typeof CiRunsResponseSchema>;
|
|
138
|
-
// Stamping the view as read hands back the timestamp it wrote, so the client updates without a refetch.
|
|
139
|
-
export const CiSeenResponseSchema = z.object({
|
|
140
|
-
seenAt: z.number().describe("The timestamp that was written, handed back so a caller can update without asking again."),
|
|
141
|
-
});
|
|
142
|
-
export type CiSeenResponse = z.infer<typeof CiSeenResponseSchema>;
|
|
143
129
|
// rerun/cancel/fix address a run by repo + vendor id; the daemon re-resolves repo → project + token per call,
|
|
144
130
|
// so a stale card can't act on a project the workspace no longer maps to.
|
|
145
131
|
export const CiRunParamSchema = z.object({
|
|
@@ -181,21 +167,28 @@ export type CiFixResponse = z.infer<typeof CiFixResponseSchema>;
|
|
|
181
167
|
* dialog that started it, and is gone. Nothing survives a daemon restart because nothing needs to: the next
|
|
182
168
|
* push asks again. */
|
|
183
169
|
|
|
184
|
-
/*
|
|
170
|
+
/* A COMMAND RUN ON A CLICK, in a visible terminal, with a verdict and a quotable tail: the ONE shape for
|
|
171
|
+
* everything the daemon runs because the owner pressed a button and then has to be told how it went. The
|
|
172
|
+
* pre-push check is one (above); the push itself is another (PushRunSchema, schemas/git.ts), because a push
|
|
173
|
+
* runs the repository's own pre-push hook, which is a suite in disguise. One shape rather than one per
|
|
174
|
+
* moment, so a field the browser learns to read for the check (the terminal to open, the tail to quote, the
|
|
175
|
+
* kill to distinguish from the timeout) is read for the push by the same code, and cannot drift.
|
|
176
|
+
*
|
|
177
|
+
* Where a run is.
|
|
185
178
|
*
|
|
186
179
|
* idle , nothing has run in this daemon's life, or the last run was cleared.
|
|
187
|
-
* running , the
|
|
188
|
-
* passed , exited 0. The push goes.
|
|
189
|
-
* failed , exited non-zero, or was killed by
|
|
190
|
-
* error , the
|
|
191
|
-
*
|
|
192
|
-
*
|
|
180
|
+
* running , the command is live. Its output is the terminal's (`session`), not this object's.
|
|
181
|
+
* passed , exited 0. The push goes (or went).
|
|
182
|
+
* failed , exited non-zero, or was killed by its ceiling (`timedOut`). The state a fix answers.
|
|
183
|
+
* error , the command could not run at all: it was not spawnable. NOT a fix-able failure, because there
|
|
184
|
+
* is nothing wrong with the code, the command is misconfigured, and saying "tests failed" would
|
|
185
|
+
* send an agent hunting a bug that isn't there.
|
|
193
186
|
* cancelled, the user stopped the run.
|
|
194
187
|
*/
|
|
195
|
-
export const
|
|
196
|
-
export type
|
|
197
|
-
export const
|
|
198
|
-
status:
|
|
188
|
+
export const CommandRunStatusSchema = z.enum(["idle", "running", "passed", "failed", "error", "cancelled"]);
|
|
189
|
+
export type CommandRunStatus = z.infer<typeof CommandRunStatusSchema>;
|
|
190
|
+
export const CommandRunSchema = z.object({
|
|
191
|
+
status: CommandRunStatusSchema.describe(
|
|
199
192
|
"Where the run is. Failed and error are deliberately different: failed means the code is wrong, error means the command could not be run at all, and calling the second one a test failure would send an agent hunting a bug that is not there.",
|
|
200
193
|
),
|
|
201
194
|
// The command this run executed, echoed rather than read back from settings: a result read after the
|
|
@@ -232,4 +225,4 @@ export const PrepushRunSchema = z.object({
|
|
|
232
225
|
"The end of what it printed, as plain text with the colour codes and redrawn progress lines resolved away. The end rather than the beginning, because a suite's verdict is at the end. Empty while it runs, and for one that was killed.",
|
|
233
226
|
),
|
|
234
227
|
});
|
|
235
|
-
export type
|
|
228
|
+
export type CommandRun = z.infer<typeof CommandRunSchema>;
|
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
|
});
|
|
@@ -294,13 +306,39 @@ export type ComputerGap = z.infer<typeof ComputerGapSchema>;
|
|
|
294
306
|
* enrolled ssh key's comment vs. the capability id the user typed, so the two are reconciled on the `hostname`
|
|
295
307
|
* their reports agree on, and left as separate rows when there is nothing to reconcile them by. Guessing that two
|
|
296
308
|
* differently-named machines are the same one would merge two people's laptops on a shared sandbox. */
|
|
309
|
+
/* THE DESKTOP-SYNC ENROLLMENT BEHIND A ROW, which used to be a boolean and could not be.
|
|
310
|
+
*
|
|
311
|
+
* `syncEnrolled: true` answered "is this machine paired" and nothing a reader standing in front of the row
|
|
312
|
+
* actually asks next: WHICH half of desktop sync it holds (files and ports, or ports alone), whether it has
|
|
313
|
+
* ever used the enrollment, and how to name it when they want it gone. Those three lived on /system/sync
|
|
314
|
+
* instead, as one machine's worth of `syncingFrom` plus a list of `mirroredBy` names, which is the sandbox-level
|
|
315
|
+
* shape this view exists to stop being: one card claiming a sandbox has A desktop sync, over a list of the
|
|
316
|
+
* several computers that actually do.
|
|
317
|
+
*
|
|
318
|
+
* `machine` is the enrollment's own name for the box (the ssh key's comment). It is what the reports are filed
|
|
319
|
+
* under, and it is the id the revoke route takes — the same string, so a row can revoke exactly the enrollment
|
|
320
|
+
* it is drawn from. Two machines that present the same comment share one enrollment identity throughout the
|
|
321
|
+
* daemon (reports included); that is a pre-existing property of naming machines by their key comment, and this
|
|
322
|
+
* field inherits it rather than inventing a second identity that would disagree with the first. */
|
|
323
|
+
export const ComputerSyncSchema = z.object({
|
|
324
|
+
machine: z.string(),
|
|
325
|
+
/* Which half. "sync" is files AND ports and is SINGLE-HOLDER for the sandbox; "mirror" is ports only and any
|
|
326
|
+
* number of machines may hold one. The row says which, because "your laptop is paired" is read as the first
|
|
327
|
+
* by somebody who has the second, and then their files are not where they expect them. */
|
|
328
|
+
mode: z.enum(["sync", "mirror"]),
|
|
329
|
+
// When this machine last USED its enrollment (its watcher's own polls stamp it). Absent on one that never
|
|
330
|
+
// has, which is exactly what a setup that did not finish leaves behind, and must not read as healthy.
|
|
331
|
+
seenAt: z.number().optional(),
|
|
332
|
+
});
|
|
333
|
+
export type ComputerSync = z.infer<typeof ComputerSyncSchema>;
|
|
297
334
|
export const ComputerSchema = z.object({
|
|
298
335
|
// Stable row key: the reported hostname when either door produced one, else the name that door knows it by.
|
|
299
336
|
key: z.string(),
|
|
300
337
|
// What to call it on screen, the user's own name for the machine wherever one exists.
|
|
301
338
|
label: z.string(),
|
|
302
|
-
//
|
|
303
|
-
|
|
339
|
+
// The desktop-sync enrollment this machine holds with this sandbox, absent when it has none (a computer
|
|
340
|
+
// reached only through its `host` capability).
|
|
341
|
+
sync: ComputerSyncSchema.optional(),
|
|
304
342
|
// The host capability's id, when this machine is also a connected computer. Absent otherwise.
|
|
305
343
|
hostId: z.string().optional(),
|
|
306
344
|
// Host-capability liveness. Absent when there is no host capability, which is NOT the same as offline.
|
|
@@ -327,9 +365,16 @@ export const ComputerSchema = z.object({
|
|
|
327
365
|
});
|
|
328
366
|
export type Computer = z.infer<typeof ComputerSchema>;
|
|
329
367
|
export const ComputersListSchema = z.object({ computers: z.array(ComputerSchema) });
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
368
|
+
/* GET /system/sync: what desktop sync is doing for this sandbox, WITHOUT naming any one machine as the answer.
|
|
369
|
+
*
|
|
370
|
+
* It used to carry `syncingFrom` + `syncSeenAt` + `mirroredBy`, which is the enrollment list flattened into one
|
|
371
|
+
* holder and a list of everybody else — the shape a card that believed a sandbox has A desktop sync needed, and
|
|
372
|
+
* the reason that card kept restating facts the Computers list beside it already had per machine. Every one of
|
|
373
|
+
* those now rides on the machine's own row (ComputerSync), where a reader can act on it.
|
|
374
|
+
*
|
|
375
|
+
* What is left is what is genuinely about the SANDBOX rather than about any computer: whether sync is possible
|
|
376
|
+
* here at all, whether anything at all is enrolled, and the raw reports, which is the cheap ambient read the
|
|
377
|
+
* rail's badge lives on (it must never fan out to somebody's laptop just to decide whether to draw a chip). */
|
|
333
378
|
export const SyncStatusSchema = z.object({
|
|
334
379
|
enrolled: z.boolean(),
|
|
335
380
|
/* Whether this sandbox can do desktop sync at all. It used to be the SSH hostname the laptop would dial, and
|
|
@@ -338,10 +383,6 @@ export const SyncStatusSchema = z.object({
|
|
|
338
383
|
* surface now, so a sandbox that can answer this read can also sync. Kept as a field rather than assumed,
|
|
339
384
|
* because the card branches on it and a daemon too old to say is one that should not be offered sync. */
|
|
340
385
|
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
386
|
machines: z.array(MachineReportSchema).optional(),
|
|
346
387
|
});
|
|
347
388
|
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
|