@intentic/sandbox-contract 1.226.0 → 1.226.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contracts/activity.contract.d.ts.map +1 -1
- package/dist/contracts/activity.contract.js +17 -2
- package/dist/contracts/activity.contract.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +71 -8
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +1 -0
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +164 -19
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.js +78 -9
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +98 -11
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/chores.contract.d.ts.map +1 -1
- package/dist/contracts/chores.contract.js +26 -3
- package/dist/contracts/chores.contract.js.map +1 -1
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.js +52 -6
- package/dist/contracts/ci.contract.js.map +1 -1
- package/dist/contracts/claude.contract.d.ts.map +1 -1
- package/dist/contracts/claude.contract.js +44 -5
- package/dist/contracts/claude.contract.js.map +1 -1
- package/dist/contracts/drafts.contract.d.ts.map +1 -1
- package/dist/contracts/drafts.contract.js +26 -3
- package/dist/contracts/drafts.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +17 -2
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/exit.contract.d.ts.map +1 -1
- package/dist/contracts/exit.contract.js +62 -7
- package/dist/contracts/exit.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js +124 -15
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +384 -43
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/grok.contract.d.ts.map +1 -1
- package/dist/contracts/grok.contract.js +25 -3
- package/dist/contracts/grok.contract.js.map +1 -1
- package/dist/contracts/history.contract.d.ts.map +1 -1
- package/dist/contracts/history.contract.js +35 -4
- package/dist/contracts/history.contract.js.map +1 -1
- package/dist/contracts/intentic.contract.d.ts.map +1 -1
- package/dist/contracts/intentic.contract.js +25 -3
- package/dist/contracts/intentic.contract.js.map +1 -1
- package/dist/contracts/inventory.contract.d.ts.map +1 -1
- package/dist/contracts/inventory.contract.js +26 -3
- package/dist/contracts/inventory.contract.js.map +1 -1
- package/dist/contracts/logs.contract.d.ts.map +1 -1
- package/dist/contracts/logs.contract.js +17 -2
- package/dist/contracts/logs.contract.js.map +1 -1
- package/dist/contracts/loops.contract.d.ts.map +1 -1
- package/dist/contracts/loops.contract.js +52 -6
- package/dist/contracts/loops.contract.js.map +1 -1
- package/dist/contracts/panels.contract.d.ts.map +1 -1
- package/dist/contracts/panels.contract.js +26 -3
- package/dist/contracts/panels.contract.js.map +1 -1
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.js +71 -8
- package/dist/contracts/personas.contract.js.map +1 -1
- package/dist/contracts/ports.contract.d.ts.map +1 -1
- package/dist/contracts/ports.contract.js +26 -3
- package/dist/contracts/ports.contract.js.map +1 -1
- package/dist/contracts/prepush.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.js +24 -3
- package/dist/contracts/prepush.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.js +9 -1
- package/dist/contracts/providers.contract.js.map +1 -1
- package/dist/contracts/public.contract.d.ts.map +1 -1
- package/dist/contracts/public.contract.js +26 -3
- package/dist/contracts/public.contract.js.map +1 -1
- package/dist/contracts/push.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.js +35 -4
- package/dist/contracts/push.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +43 -5
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.js +15 -2
- package/dist/contracts/sessions.contract.js.map +1 -1
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +43 -5
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/share.contract.d.ts.map +1 -1
- package/dist/contracts/share.contract.js +35 -4
- package/dist/contracts/share.contract.js.map +1 -1
- package/dist/contracts/skills.contract.d.ts.map +1 -1
- package/dist/contracts/skills.contract.js +35 -4
- package/dist/contracts/skills.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +107 -14
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.js +29 -4
- package/dist/contracts/translator.contract.js.map +1 -1
- package/dist/contracts/usage.contract.d.ts.map +1 -1
- package/dist/contracts/usage.contract.js +9 -1
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/contracts/vpn.contract.d.ts.map +1 -1
- package/dist/contracts/vpn.contract.js +32 -4
- package/dist/contracts/vpn.contract.js.map +1 -1
- package/dist/contracts/workflows.contract.d.ts.map +1 -1
- package/dist/contracts/workflows.contract.js +70 -8
- package/dist/contracts/workflows.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +216 -25
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +179 -88
- 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 +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/schemas.d.ts +1 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +2856 -1276
- package/dist/schemas.js.map +1 -1
- package/package.json +4 -4
- package/src/contracts/activity.contract.ts +18 -2
- package/src/contracts/agent.contract.ts +78 -8
- package/src/contracts/agents.contract.ts +180 -19
- package/src/contracts/automations.contract.ts +80 -9
- package/src/contracts/capabilities.contract.ts +106 -11
- package/src/contracts/chores.contract.ts +29 -3
- package/src/contracts/ci.contract.ts +55 -6
- package/src/contracts/claude.contract.ts +47 -5
- package/src/contracts/drafts.contract.ts +26 -3
- package/src/contracts/endpoints.contract.ts +19 -2
- package/src/contracts/exit.contract.ts +69 -7
- package/src/contracts/extensions.contract.ts +134 -15
- package/src/contracts/git.contract.ts +421 -43
- package/src/contracts/grok.contract.ts +26 -3
- package/src/contracts/history.contract.ts +37 -4
- package/src/contracts/intentic.contract.ts +28 -3
- package/src/contracts/inventory.contract.ts +27 -3
- package/src/contracts/logs.contract.ts +18 -2
- package/src/contracts/loops.contract.ts +58 -6
- package/src/contracts/panels.contract.ts +26 -3
- package/src/contracts/personas.contract.ts +77 -8
- package/src/contracts/ports.contract.ts +27 -3
- package/src/contracts/prepush.contract.ts +26 -3
- package/src/contracts/providers.contract.ts +10 -1
- package/src/contracts/public.contract.ts +29 -3
- package/src/contracts/push.contract.ts +37 -4
- package/src/contracts/secrets.contract.ts +46 -5
- package/src/contracts/sessions.contract.ts +16 -2
- package/src/contracts/settings.contract.ts +46 -5
- package/src/contracts/share.contract.ts +37 -4
- package/src/contracts/skills.contract.ts +39 -4
- package/src/contracts/system.contract.ts +119 -14
- package/src/contracts/translator.contract.ts +32 -4
- package/src/contracts/usage.contract.ts +10 -1
- package/src/contracts/vpn.contract.ts +35 -4
- package/src/contracts/workflows.contract.ts +77 -8
- package/src/contracts/workspace.contract.ts +231 -25
- package/src/events.ts +207 -88
- package/src/history-state.ts +6 -0
- package/src/schemas.ts +3506 -1260
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentic/sandbox-contract",
|
|
3
|
-
"version": "1.226.
|
|
3
|
+
"version": "1.226.1",
|
|
4
4
|
"description": "oRPC wire contract for the intentic sandbox daemon, shared by the daemon and its browser client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"@orpc/contract": "1.14.13",
|
|
90
90
|
"tslib": "2.8.1",
|
|
91
91
|
"zod": "4.4.3",
|
|
92
|
-
"@intentic/constants": "1.226.
|
|
93
|
-
"@intentic/
|
|
94
|
-
"@intentic/
|
|
92
|
+
"@intentic/constants": "1.226.1",
|
|
93
|
+
"@intentic/extension-manifest": "1.226.1",
|
|
94
|
+
"@intentic/registry": "1.226.1"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
97
|
"@types/node": "24.13.2",
|
|
@@ -4,6 +4,22 @@ import { ActivityListSchema, ActivityQuerySchema, ActivityStatusSchema } from ".
|
|
|
4
4
|
// The activity audit feed (provider-agnostic; Discord is the first source). Read-only by design,
|
|
5
5
|
// events are appended daemon-side only, so the log stays a trustworthy record of what the agent did.
|
|
6
6
|
export const activityContract = {
|
|
7
|
-
list: oc
|
|
8
|
-
|
|
7
|
+
list: oc
|
|
8
|
+
.route({
|
|
9
|
+
method: "GET",
|
|
10
|
+
path: "/activity",
|
|
11
|
+
summary: "What the agent has done out in the world",
|
|
12
|
+
description:
|
|
13
|
+
"The audit trail of actions taken on outside services. Read-only on purpose: entries are written by the sandbox alone, which is what makes it a record worth trusting.",
|
|
14
|
+
})
|
|
15
|
+
.input(ActivityQuerySchema)
|
|
16
|
+
.output(ActivityListSchema),
|
|
17
|
+
status: oc
|
|
18
|
+
.route({
|
|
19
|
+
method: "GET",
|
|
20
|
+
path: "/activity/status",
|
|
21
|
+
summary: "Whether the audit trail is being kept",
|
|
22
|
+
description: "Which sources are feeding the record and whether each is working.",
|
|
23
|
+
})
|
|
24
|
+
.output(ActivityStatusSchema),
|
|
9
25
|
};
|
|
@@ -19,20 +19,90 @@ import {
|
|
|
19
19
|
// turn waiting on any interactive card (plan approval, clarifying questions, a per-tool permission prompt);
|
|
20
20
|
// steer injects a user message into the running turn; stop hard-cancels it daemon-side.
|
|
21
21
|
export const agentContract = {
|
|
22
|
-
run: oc
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
run: oc
|
|
23
|
+
.route({
|
|
24
|
+
method: "POST",
|
|
25
|
+
path: "/agent",
|
|
26
|
+
summary: "Say something to an agent",
|
|
27
|
+
description:
|
|
28
|
+
"Starts a turn and answers immediately with its id; the work runs inside the sandbox whether or not anybody stays connected. Watch it by attaching. Naming a conversation that does not exist yet opens it.",
|
|
29
|
+
})
|
|
30
|
+
.input(AgentTurnSchema)
|
|
31
|
+
.output(StartedTurnSchema),
|
|
32
|
+
attach: oc
|
|
33
|
+
.route({
|
|
34
|
+
method: "POST",
|
|
35
|
+
path: "/agent/attach",
|
|
36
|
+
summary: "Watch a turn happen",
|
|
37
|
+
description:
|
|
38
|
+
"Streams everything the agent does: its words, the tools it reaches for, and the answers it gets. Give it the point you have already seen and it replays from there before going live, so a reload loses nothing. The window that started the turn holds no special claim, and any number of watchers on any number of devices see the same thing.",
|
|
39
|
+
})
|
|
40
|
+
.input(AttachTurnSchema)
|
|
41
|
+
.output(eventIterator(AttachFrameSchema)),
|
|
42
|
+
reply: oc
|
|
43
|
+
.route({
|
|
44
|
+
method: "POST",
|
|
45
|
+
path: "/agent/reply",
|
|
46
|
+
summary: "Answer a question the agent asked",
|
|
47
|
+
description:
|
|
48
|
+
"Un-parks a turn that is waiting on you: approving a plan, choosing between options, or permitting a tool. The turn picks up where it stopped.",
|
|
49
|
+
})
|
|
50
|
+
.input(AgentReplySchema)
|
|
51
|
+
.output(OkSchema),
|
|
52
|
+
steer: oc
|
|
53
|
+
.route({
|
|
54
|
+
method: "POST",
|
|
55
|
+
path: "/agent/steer",
|
|
56
|
+
summary: "Interrupt a running turn",
|
|
57
|
+
description:
|
|
58
|
+
"Slips a message into a turn already under way, without stopping it. This is how you redirect an agent mid-thought rather than waiting for it to finish being wrong.",
|
|
59
|
+
})
|
|
60
|
+
.input(SteerSchema)
|
|
61
|
+
.output(OkSchema),
|
|
62
|
+
stop: oc
|
|
63
|
+
.route({
|
|
64
|
+
method: "POST",
|
|
65
|
+
path: "/agent/stop",
|
|
66
|
+
summary: "Stop a turn now",
|
|
67
|
+
description: "Cancels the running turn inside the sandbox. Whatever it had already written to disk stays written.",
|
|
68
|
+
})
|
|
69
|
+
.input(StopTurnSchema)
|
|
70
|
+
.output(OkSchema),
|
|
27
71
|
// Go back to a message: restore the workspace to that turn's checkpoint, drop the messages after it, and
|
|
28
72
|
// forget the provider session. CONFLICT while a turn is running, a restore cannot overwrite files an
|
|
29
73
|
// agent is editing. NOT_FOUND when that message has no checkpoint to go back to.
|
|
30
|
-
rewind: oc
|
|
74
|
+
rewind: oc
|
|
75
|
+
.route({
|
|
76
|
+
method: "POST",
|
|
77
|
+
path: "/agent/rewind",
|
|
78
|
+
summary: "Go back to an earlier message",
|
|
79
|
+
description:
|
|
80
|
+
"Puts the files back as they stood at that point, drops every message after it, and forgets what the model remembered, so the next thing you say starts from there cleanly. Refused while a turn is running, because a restore cannot overwrite files an agent is editing, and refused for a message with no saved state to return to.",
|
|
81
|
+
})
|
|
82
|
+
.input(RewindTurnSchema)
|
|
83
|
+
.output(RewindResultSchema),
|
|
31
84
|
// The provider's slash commands as last published by one of its turns, so a conversation's `/` popover is
|
|
32
85
|
// populated before it has run one. The live `commands` frame stays authoritative for a running turn.
|
|
33
|
-
commands: oc
|
|
86
|
+
commands: oc
|
|
87
|
+
.route({
|
|
88
|
+
method: "GET",
|
|
89
|
+
path: "/agent/commands",
|
|
90
|
+
summary: "Shortcut commands the agent knows",
|
|
91
|
+
description:
|
|
92
|
+
"The commands a provider published the last time one of its turns ran, so a composer can offer them before this conversation has run anything. A running turn's own list wins over this one.",
|
|
93
|
+
})
|
|
94
|
+
.input(AgentCommandsQuerySchema)
|
|
95
|
+
.output(AgentCommandsSchema),
|
|
34
96
|
// The last refusal per provider, as reported by whichever turn was refused (ProviderRefusalSchema). Read
|
|
35
97
|
// alongside the account listings by the surfaces that draw plan limits: the snapshot on an account row says
|
|
36
98
|
// how full its pools were when last polled, and this says whether one of them has since said no.
|
|
37
|
-
refusals: oc
|
|
99
|
+
refusals: oc
|
|
100
|
+
.route({
|
|
101
|
+
method: "GET",
|
|
102
|
+
path: "/agent/refusals",
|
|
103
|
+
summary: "The last time each provider said no",
|
|
104
|
+
description:
|
|
105
|
+
"What each model provider most recently refused and why. Read this alongside an account's usage: the usage says how full it was when last checked, this says whether it has since started turning work away.",
|
|
106
|
+
})
|
|
107
|
+
.output(ProviderRefusalsSchema),
|
|
38
108
|
};
|
|
@@ -47,27 +47,96 @@ import {
|
|
|
47
47
|
// own agent, so there should be none) and answers with what it actually deleted: a teardown that fails on one
|
|
48
48
|
// agent's repo leaves that one behind rather than taking the batch down with it.
|
|
49
49
|
export const agentsContract = {
|
|
50
|
-
list: oc
|
|
51
|
-
|
|
50
|
+
list: oc
|
|
51
|
+
.route({
|
|
52
|
+
method: "GET",
|
|
53
|
+
path: "/agents",
|
|
54
|
+
summary: "Every live conversation",
|
|
55
|
+
description:
|
|
56
|
+
"The fleet as the board draws it: each conversation with its title, what it is doing, when it last moved and whether anybody has read it since. Archived conversations are not in here.",
|
|
57
|
+
})
|
|
58
|
+
.output(AgentsListSchema),
|
|
59
|
+
archived: oc
|
|
60
|
+
.route({
|
|
61
|
+
method: "GET",
|
|
62
|
+
path: "/agents/archived",
|
|
63
|
+
summary: "Conversations put away",
|
|
64
|
+
description:
|
|
65
|
+
"The same shape as the live fleet, for the conversations somebody has decided are finished. Their work is kept, and any one of them can be brought back.",
|
|
66
|
+
})
|
|
67
|
+
.output(AgentsListSchema),
|
|
52
68
|
// The board's filter. Answers over BOTH halves of the fleet, the live roster and the archive, because
|
|
53
69
|
// the board hides by design (the Finished lane windows to a handful, archived agents are off the roster
|
|
54
70
|
// entirely), and a filter that reports "no matches" while the agent sits one click away is a lie. The
|
|
55
71
|
// never-carded conversations that are neither are `sessions.list`'s query, which matches by the same rule.
|
|
56
|
-
search: oc
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
search: oc
|
|
73
|
+
.route({
|
|
74
|
+
method: "GET",
|
|
75
|
+
path: "/agents/search",
|
|
76
|
+
summary: "Find a conversation",
|
|
77
|
+
description:
|
|
78
|
+
"Searches the live fleet and the archive together. Both halves on purpose: the board hides finished work by design, and a filter that says it found nothing while the answer sits one click away is simply wrong.",
|
|
79
|
+
})
|
|
80
|
+
.input(AgentSearchQuerySchema)
|
|
81
|
+
.output(AgentSearchResultSchema),
|
|
82
|
+
get: oc
|
|
83
|
+
.route({
|
|
84
|
+
method: "GET",
|
|
85
|
+
path: "/agents/{id}",
|
|
86
|
+
summary: "One conversation's card",
|
|
87
|
+
description: "Everything the board shows for a single conversation: its title, state, working branch, unread marker and timestamps.",
|
|
88
|
+
})
|
|
89
|
+
.input(AgentIdSchema)
|
|
90
|
+
.output(AgentSummarySchema),
|
|
91
|
+
transcript: oc
|
|
92
|
+
.route({
|
|
93
|
+
method: "GET",
|
|
94
|
+
path: "/agents/{id}/transcript",
|
|
95
|
+
summary: "The full conversation record",
|
|
96
|
+
description:
|
|
97
|
+
"Every message in one conversation, in order, including the tool calls and their results. This is the record the chat replays and the next turn is seeded from.",
|
|
98
|
+
})
|
|
99
|
+
.input(AgentIdSchema)
|
|
100
|
+
.output(AgentTranscriptSchema),
|
|
59
101
|
/* SPEAK AS THE AGENT, append the user's words to the conversation's record as an assistant row, with no
|
|
60
102
|
* turn behind them and no reply. The row is marked `placed` for human readers (RestoredMessageSchema); the
|
|
61
103
|
* provider session is FORGOTTEN in the same breath, rewind-style, so the next real turn opens a fresh
|
|
62
104
|
* runtime session seeded from the record, where the placed line reads as the agent's own words, because
|
|
63
105
|
* the handoff renders every assistant row identically. A running turn is CONFLICT: the illusion can only be
|
|
64
106
|
* established between turns, and a concurrent turn would resume the very session this exists to retire. */
|
|
65
|
-
place: oc
|
|
66
|
-
|
|
107
|
+
place: oc
|
|
108
|
+
.route({
|
|
109
|
+
method: "POST",
|
|
110
|
+
path: "/agents/{id}/place",
|
|
111
|
+
summary: "Put words in the agent's mouth",
|
|
112
|
+
description:
|
|
113
|
+
"Writes a line into the record as though the agent had said it, with no turn behind it and no reply. Human readers see it marked as placed. The next real turn starts fresh from the record, where the line reads as the agent's own. Refused while a turn is running.",
|
|
114
|
+
})
|
|
115
|
+
.input(AgentPlaceSchema)
|
|
116
|
+
.output(OkSchema),
|
|
117
|
+
rename: oc
|
|
118
|
+
.route({
|
|
119
|
+
method: "POST",
|
|
120
|
+
path: "/agents/{id}/rename",
|
|
121
|
+
summary: "Retitle a conversation",
|
|
122
|
+
description:
|
|
123
|
+
"Sets the title a person chose, replacing the one that was generated. Allowed while the conversation is working, and it does not count as activity.",
|
|
124
|
+
})
|
|
125
|
+
.input(AgentRenameSchema)
|
|
126
|
+
.output(AgentSummarySchema),
|
|
67
127
|
// This agent's own land-at-completion posture, an override of the sandbox-wide `autoLand` setting; null
|
|
68
128
|
// clears it back to "inherit". Legal mid-turn on purpose: the setting is read at turn COMPLETION, so
|
|
69
129
|
// flipping it while the agent works is exactly "hold THIS turn's work for review", the press that matters.
|
|
70
|
-
autoLand: oc
|
|
130
|
+
autoLand: oc
|
|
131
|
+
.route({
|
|
132
|
+
method: "POST",
|
|
133
|
+
path: "/agents/{id}/auto-land",
|
|
134
|
+
summary: "Whether this conversation merges its work automatically",
|
|
135
|
+
description:
|
|
136
|
+
"Overrides the sandbox-wide setting for one conversation; clear it to go back to following the default. Deliberately allowed mid-turn, because the setting is read when the turn finishes, so flipping it while the agent works means exactly hold this piece of work for review.",
|
|
137
|
+
})
|
|
138
|
+
.input(AgentAutoLandSchema)
|
|
139
|
+
.output(AgentSummarySchema),
|
|
71
140
|
/* THIS conversation's answer to a provider outage, an override of the sandbox-wide `resumeAfterOutage`
|
|
72
141
|
* setting; null clears it back to "inherit". The chat's offer at the moment a turn dies writes this and
|
|
73
142
|
* never the global: the press happens inside one conversation and means "finish this piece of work", so
|
|
@@ -76,20 +145,112 @@ export const agentsContract = {
|
|
|
76
145
|
* Legal mid-turn, and unlike autoLand it is legal for a WORKSPACE conversation too, an outage kills a
|
|
77
146
|
* main-tree chat exactly as readily as an isolated one, and there is no branch involved either way. */
|
|
78
147
|
resumeAfterOutage: oc
|
|
79
|
-
.route({
|
|
148
|
+
.route({
|
|
149
|
+
method: "POST",
|
|
150
|
+
path: "/agents/{id}/resume-after-outage",
|
|
151
|
+
summary: "Whether this conversation retries after a provider outage",
|
|
152
|
+
description:
|
|
153
|
+
"Overrides the sandbox-wide setting for one conversation; clear it to follow the default again. This is what the offer shown when a turn dies writes, because the press happens inside one conversation and honestly means finish this piece of work.",
|
|
154
|
+
})
|
|
80
155
|
.input(AgentResumeAfterOutageSchema)
|
|
81
156
|
.output(AgentSummarySchema),
|
|
82
|
-
seen: oc
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
157
|
+
seen: oc
|
|
158
|
+
.route({
|
|
159
|
+
method: "POST",
|
|
160
|
+
path: "/agents/{id}/seen",
|
|
161
|
+
summary: "Mark a conversation read",
|
|
162
|
+
description:
|
|
163
|
+
"Stamps the read marker behind the unread badge on one card. Allowed while the conversation is working, and reading never counts as activity.",
|
|
164
|
+
})
|
|
165
|
+
.input(AgentIdSchema)
|
|
166
|
+
.output(AgentSummarySchema),
|
|
167
|
+
seenAll: oc
|
|
168
|
+
.route({
|
|
169
|
+
method: "POST",
|
|
170
|
+
path: "/agents/seen",
|
|
171
|
+
summary: "Mark every conversation read",
|
|
172
|
+
description: "Clears the unread badge across the whole fleet at once, and hands the refreshed list back.",
|
|
173
|
+
})
|
|
174
|
+
.output(AgentsListSchema),
|
|
175
|
+
diff: oc
|
|
176
|
+
.route({
|
|
177
|
+
method: "GET",
|
|
178
|
+
path: "/agents/{id}/diff",
|
|
179
|
+
summary: "Everything a conversation has changed",
|
|
180
|
+
description:
|
|
181
|
+
"One flat set of changed files per repo, measured against where each repo stood when the conversation started, with every file flagged as already merged or not. Not the staged-and-unstaged shape a working copy has, because nobody ever checks this branch out to stage into it.",
|
|
182
|
+
})
|
|
183
|
+
.input(AgentIdSchema)
|
|
184
|
+
.output(AgentChangesSchema),
|
|
185
|
+
fileDiff: oc
|
|
186
|
+
.route({
|
|
187
|
+
method: "GET",
|
|
188
|
+
path: "/agents/{id}/{repo}/file-diff",
|
|
189
|
+
summary: "One file's before and after in a conversation's work",
|
|
190
|
+
description: "Both sides of a single file: what it held when the conversation started and what it holds on its branch now.",
|
|
191
|
+
})
|
|
192
|
+
.input(AgentFileDiffQuerySchema)
|
|
193
|
+
.output(FileDiffSchema),
|
|
194
|
+
land: oc
|
|
195
|
+
.route({
|
|
196
|
+
method: "POST",
|
|
197
|
+
path: "/agents/{id}/land",
|
|
198
|
+
summary: "Merge a conversation's work into the workspace",
|
|
199
|
+
description:
|
|
200
|
+
"Brings the conversation's branches into the main tree, one repo at a time. A conflict is reported rather than raised and nothing is lost when it fails. Refused while a turn is running, and refused for a conversation that works directly in the shared tree, which has nothing to merge.",
|
|
201
|
+
})
|
|
202
|
+
.input(AgentLandSchema)
|
|
203
|
+
.output(LandResultSchema),
|
|
87
204
|
// A collaborator's ask for the land they may not perform themselves (role floors put `land`/`discard` at
|
|
88
205
|
// maintainer). Stamps AgentSummarySchema.landRequested with the caller's identity and re-frames the fleet,
|
|
89
206
|
// so every maintainer's board carries the request; the land or discard that answers it clears the stamp.
|
|
90
|
-
requestLand: oc
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
207
|
+
requestLand: oc
|
|
208
|
+
.route({
|
|
209
|
+
method: "POST",
|
|
210
|
+
path: "/agents/{id}/request-land",
|
|
211
|
+
summary: "Ask a maintainer to merge this work",
|
|
212
|
+
description:
|
|
213
|
+
"For a collaborator who is not allowed to merge: marks the conversation as waiting for review, with who asked. The request shows on every maintainer's board and clears when somebody merges or discards it.",
|
|
214
|
+
})
|
|
215
|
+
.input(AgentIdSchema)
|
|
216
|
+
.output(AgentSummarySchema),
|
|
217
|
+
discard: oc
|
|
218
|
+
.route({
|
|
219
|
+
method: "POST",
|
|
220
|
+
path: "/agents/{id}/discard",
|
|
221
|
+
summary: "Throw a conversation's work away",
|
|
222
|
+
description:
|
|
223
|
+
"Deletes the conversation's working copies, its branches and its entry. Nothing is kept. Refused while a turn is running, and refused for a conversation working in the shared tree.",
|
|
224
|
+
})
|
|
225
|
+
.input(AgentIdSchema)
|
|
226
|
+
.output(OkSchema),
|
|
227
|
+
archive: oc
|
|
228
|
+
.route({
|
|
229
|
+
method: "POST",
|
|
230
|
+
path: "/agents/archive",
|
|
231
|
+
summary: "Put conversations away",
|
|
232
|
+
description:
|
|
233
|
+
"The gentle counterpart to discarding. Commits whatever the conversation still has in progress onto its own branch, releases its working copy, and keeps the entry and the record. It leaves the live fleet and joins the archive. Refused for a conversation that is running.",
|
|
234
|
+
})
|
|
235
|
+
.input(AgentArchiveSchema)
|
|
236
|
+
.output(AgentsMovedSchema),
|
|
237
|
+
unarchive: oc
|
|
238
|
+
.route({
|
|
239
|
+
method: "POST",
|
|
240
|
+
path: "/agents/unarchive",
|
|
241
|
+
summary: "Bring conversations back",
|
|
242
|
+
description:
|
|
243
|
+
"Returns archived conversations to the live fleet. The next turn picks up a fresh working copy from the branch that was kept.",
|
|
244
|
+
})
|
|
245
|
+
.input(AgentIdsSchema)
|
|
246
|
+
.output(AgentsMovedSchema),
|
|
247
|
+
purge: oc
|
|
248
|
+
.route({
|
|
249
|
+
method: "POST",
|
|
250
|
+
path: "/agents/purge",
|
|
251
|
+
summary: "Empty the archive for good",
|
|
252
|
+
description:
|
|
253
|
+
"Discards every conversation already in the archive: working copies, branches and entries. The whole archive rather than a chosen few, because the archive is the pile somebody has already decided is over. A teardown that fails on one conversation leaves that one behind instead of taking the rest down with it.",
|
|
254
|
+
})
|
|
255
|
+
.output(AgentsRemovedSchema),
|
|
95
256
|
};
|
|
@@ -17,15 +17,54 @@ import {
|
|
|
17
17
|
// The `pending*` routes are the owner's approval queue: a `requireApproval` automation holds each fire here
|
|
18
18
|
// instead of waking; `approve` runs the held wake, `reject` drops it.
|
|
19
19
|
export const automationsContract = {
|
|
20
|
-
list: oc
|
|
20
|
+
list: oc
|
|
21
|
+
.route({
|
|
22
|
+
method: "GET",
|
|
23
|
+
path: "/automations",
|
|
24
|
+
summary: "Things that wake an agent on their own",
|
|
25
|
+
description: "Every automation with its recent runs and when it fires next.",
|
|
26
|
+
})
|
|
27
|
+
.output(AutomationsListSchema),
|
|
21
28
|
/* WHAT CAN WAKE AN AGENT HERE, and what to start from, the daemon's own sources and templates merged with
|
|
22
29
|
* every installed extension's. The composer's entire vocabulary, so that adding a trigger to an area is a
|
|
23
30
|
* change to that area and to nothing else. `upsert` below validates against the same merge, which is what
|
|
24
31
|
* keeps the surface and the daemon from disagreeing about what is allowed. */
|
|
25
|
-
catalog: oc
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
catalog: oc
|
|
33
|
+
.route({
|
|
34
|
+
method: "GET",
|
|
35
|
+
path: "/automations/catalog",
|
|
36
|
+
summary: "What can trigger an automation here",
|
|
37
|
+
description:
|
|
38
|
+
"Every trigger this sandbox understands and every template worth starting from, the daemon's own merged with each installed extension's. Writing an automation is checked against this same list, so a screen and the daemon can never disagree about what is allowed.",
|
|
39
|
+
})
|
|
40
|
+
.output(AutomationCatalogSchema),
|
|
41
|
+
upsert: oc
|
|
42
|
+
.route({
|
|
43
|
+
method: "POST",
|
|
44
|
+
path: "/automations",
|
|
45
|
+
summary: "Create or edit an automation",
|
|
46
|
+
description: "Writes an automation by id. Nothing needs provisioning: the scheduler picks it up on its next sweep.",
|
|
47
|
+
})
|
|
48
|
+
.input(AutomationSchema)
|
|
49
|
+
.output(OkSchema),
|
|
50
|
+
setEnabled: oc
|
|
51
|
+
.route({
|
|
52
|
+
method: "POST",
|
|
53
|
+
path: "/automations/{id}/enabled",
|
|
54
|
+
summary: "Turn an automation on or off",
|
|
55
|
+
description: "Flips only the switch, so a row in a list can be toggled without rebuilding the whole record.",
|
|
56
|
+
})
|
|
57
|
+
.input(AutomationEnabledInputSchema)
|
|
58
|
+
.output(OkSchema),
|
|
59
|
+
remove: oc
|
|
60
|
+
.route({
|
|
61
|
+
method: "DELETE",
|
|
62
|
+
path: "/automations/{id}",
|
|
63
|
+
summary: "Delete an automation",
|
|
64
|
+
description: "Removes it, so nothing fires from it again.",
|
|
65
|
+
})
|
|
66
|
+
.input(AutomationIdParamSchema)
|
|
67
|
+
.output(OkSchema),
|
|
29
68
|
/* Fire one automation NOW, by hand, the answer to "I wrote a 3 a.m. cron and I have no way to try it".
|
|
30
69
|
* It runs the SAME path the real trigger runs: a schedule stays a headless main-tree wake, because a
|
|
31
70
|
* test-fire that proves an isolated worktree works proves nothing about the fire it is standing in for. The
|
|
@@ -45,8 +84,40 @@ export const automationsContract = {
|
|
|
45
84
|
*
|
|
46
85
|
* Acks immediately with the turn detached, like /fire and `approve`: the guard alone may take a minute, and
|
|
47
86
|
* the run history (with the session that makes it openable) is where the outcome lands. */
|
|
48
|
-
run: oc
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
run: oc
|
|
88
|
+
.route({
|
|
89
|
+
method: "POST",
|
|
90
|
+
path: "/automations/{id}/run",
|
|
91
|
+
summary: "Fire an automation by hand",
|
|
92
|
+
description:
|
|
93
|
+
"The answer to writing something that runs at three in the morning and having no way to try it. It takes exactly the path the real trigger takes, including the check that decides whether there was anything to do, since skipped by the guard is the most useful thing this can tell you. A switched-off automation fires too, because trying it before switching it on is the main reason to press this. Not available for the trigger that listens for incoming messages, where a hand-fire would produce an agent asked to handle events and handed none; send the bot a message instead. Answers straight away and runs detached.",
|
|
94
|
+
})
|
|
95
|
+
.input(AutomationIdParamSchema)
|
|
96
|
+
.output(OkSchema),
|
|
97
|
+
pendingList: oc
|
|
98
|
+
.route({
|
|
99
|
+
method: "GET",
|
|
100
|
+
path: "/automations/pending",
|
|
101
|
+
summary: "Automations waiting for a yes",
|
|
102
|
+
description: "The queue an automation set to ask first lands in each time it would have fired.",
|
|
103
|
+
})
|
|
104
|
+
.output(AutomationApprovalsListSchema),
|
|
105
|
+
approve: oc
|
|
106
|
+
.route({
|
|
107
|
+
method: "POST",
|
|
108
|
+
path: "/automations/pending/{id}/approve",
|
|
109
|
+
summary: "Let a held automation run",
|
|
110
|
+
description: "Releases one waiting automation and runs the wake it was holding. Answers straight away and runs detached.",
|
|
111
|
+
})
|
|
112
|
+
.input(AutomationApprovalIdParamSchema)
|
|
113
|
+
.output(OkSchema),
|
|
114
|
+
reject: oc
|
|
115
|
+
.route({
|
|
116
|
+
method: "POST",
|
|
117
|
+
path: "/automations/pending/{id}/reject",
|
|
118
|
+
summary: "Drop a held automation",
|
|
119
|
+
description: "Throws one waiting fire away. The automation stays on, and the next trigger queues as usual.",
|
|
120
|
+
})
|
|
121
|
+
.input(AutomationApprovalIdParamSchema)
|
|
122
|
+
.output(OkSchema),
|
|
52
123
|
};
|
|
@@ -29,32 +29,127 @@ import {
|
|
|
29
29
|
* anything runs, the only way to change one setting on a tunnel without re-typing its key. A marker with
|
|
30
30
|
* nothing behind it is refused rather than written. */
|
|
31
31
|
export const capabilitiesContract = {
|
|
32
|
-
list: oc
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
list: oc
|
|
33
|
+
.route({
|
|
34
|
+
method: "GET",
|
|
35
|
+
path: "/capabilities",
|
|
36
|
+
summary: "Everything this sandbox is connected to",
|
|
37
|
+
description:
|
|
38
|
+
"Each connection with its live state, the settings that are safe to show, and the names of the credentials it holds. The values of those credentials are never in the answer, on any route but one.",
|
|
39
|
+
})
|
|
40
|
+
.output(CapabilitiesListSchema),
|
|
41
|
+
add: oc
|
|
42
|
+
.route({
|
|
43
|
+
method: "POST",
|
|
44
|
+
path: "/capabilities",
|
|
45
|
+
summary: "Connect something, or change a connection",
|
|
46
|
+
description:
|
|
47
|
+
"Writes a connection and streams the work of applying it, because some kinds provision real infrastructure and take a while. Sending an id that already exists edits that connection: this is the edit as well as the create. Since a caller is never shown stored credentials, it marks the ones it is leaving alone and the daemon fills them in, which is the only way to change one setting without retyping a key.",
|
|
48
|
+
})
|
|
49
|
+
.input(CapabilitySchema)
|
|
50
|
+
.output(eventIterator(IntenticLineSchema)),
|
|
51
|
+
remove: oc
|
|
52
|
+
.route({
|
|
53
|
+
method: "DELETE",
|
|
54
|
+
path: "/capabilities/{id}",
|
|
55
|
+
summary: "Disconnect something",
|
|
56
|
+
description:
|
|
57
|
+
"Tears a connection down. The kinds that own real infrastructure refuse, because deleting those would be losing data rather than losing a connection.",
|
|
58
|
+
})
|
|
59
|
+
.input(CapabilityIdParamSchema)
|
|
60
|
+
.output(OkSchema),
|
|
35
61
|
/* Give a connection a different name, carrying what the old one keyed: a browser profile with its logins,
|
|
36
62
|
* a connected machine's enrollment, an extension's checkout. The name is the agent's handle for the thing,
|
|
37
63
|
* so this is a migration, add + remove would lose exactly the state that makes the connection worth
|
|
38
64
|
* keeping. A kind whose name is part of what it IS (the scaffolders, the one-per-sandbox cards) refuses. */
|
|
39
|
-
rename: oc
|
|
65
|
+
rename: oc
|
|
66
|
+
.route({
|
|
67
|
+
method: "POST",
|
|
68
|
+
path: "/capabilities/{id}/rename",
|
|
69
|
+
summary: "Rename a connection",
|
|
70
|
+
description:
|
|
71
|
+
"Carries everything the old name keyed across with it: a browser profile and its logins, an enrolled machine, an extension's copy of its source. Removing and re-adding would lose exactly the state that made the connection worth keeping. Kinds whose name is part of what they are refuse.",
|
|
72
|
+
})
|
|
73
|
+
.input(CapabilityRenameSchema)
|
|
74
|
+
.output(OkSchema),
|
|
40
75
|
// Replace just the secret in a capability's config (the /secrets page's edit) and re-run its apply.
|
|
41
|
-
setSecret: oc
|
|
42
|
-
|
|
76
|
+
setSecret: oc
|
|
77
|
+
.route({
|
|
78
|
+
method: "POST",
|
|
79
|
+
path: "/capabilities/{id}/secret",
|
|
80
|
+
summary: "Replace a stored credential",
|
|
81
|
+
description: "Swaps one connection's key or token for a new one and re-applies it, without touching any of its other settings.",
|
|
82
|
+
})
|
|
83
|
+
.input(CapabilitySecretInputSchema)
|
|
84
|
+
.output(OkSchema),
|
|
85
|
+
status: oc
|
|
86
|
+
.route({
|
|
87
|
+
method: "GET",
|
|
88
|
+
path: "/capabilities/{id}/status",
|
|
89
|
+
summary: "Re-check one connection",
|
|
90
|
+
description: "Probes a single connection right now, for a screen that wants to refresh one row rather than the whole list.",
|
|
91
|
+
})
|
|
92
|
+
.input(CapabilityIdParamSchema)
|
|
93
|
+
.output(CapabilityStatusSchema),
|
|
43
94
|
/* One capability's stored config, secrets included, how an extension BACKEND dials the service behind a
|
|
44
95
|
* connected capability (ext-deployments reads its Komodo's key pair through this). Never a browser's: the
|
|
45
96
|
* handler refuses any caller with a member identity, so only the daemon's header grants reach it, and an
|
|
46
97
|
* extension's grant reaches it only when its manifest declares the route in `permissions.daemon`, which
|
|
47
98
|
* is the install dialog saying, in one line, "this extension can read connected credentials". */
|
|
48
|
-
connection: oc
|
|
49
|
-
|
|
99
|
+
connection: oc
|
|
100
|
+
.route({
|
|
101
|
+
method: "GET",
|
|
102
|
+
path: "/capabilities/{id}/connection",
|
|
103
|
+
summary: "A connection's settings, credentials included",
|
|
104
|
+
description:
|
|
105
|
+
"The one call that hands back stored secrets, so an extension's own backend can dial the service behind a connection. Never answered for a signed-in person: only a machine credential reaches it, and an extension's only if its manifest asked for this route out loud at install time.",
|
|
106
|
+
})
|
|
107
|
+
.input(CapabilityIdParamSchema)
|
|
108
|
+
.output(CapabilityConnectionSchema),
|
|
109
|
+
marketplace: oc
|
|
110
|
+
.route({
|
|
111
|
+
method: "POST",
|
|
112
|
+
path: "/capabilities/marketplace",
|
|
113
|
+
summary: "Read a plugin marketplace",
|
|
114
|
+
description: "Resolves a plugin marketplace source into the list of connections you could install from it.",
|
|
115
|
+
})
|
|
116
|
+
.input(MarketplaceRequestSchema)
|
|
117
|
+
.output(MarketplaceSchema),
|
|
50
118
|
// "Not needed": stop offering this card until the workspace evidence behind it changes. Nothing is torn
|
|
51
119
|
// down and nothing is remembered about the card itself, only the evidence it was declined against.
|
|
52
|
-
dismiss: oc
|
|
120
|
+
dismiss: oc
|
|
121
|
+
.route({
|
|
122
|
+
method: "DELETE",
|
|
123
|
+
path: "/capabilities/recommendations/{card}",
|
|
124
|
+
summary: "Stop suggesting this connection",
|
|
125
|
+
description:
|
|
126
|
+
"Not needed, for now. Nothing is torn down. The suggestion comes back if what prompted it in the workspace changes, because what is remembered is the evidence, not the refusal.",
|
|
127
|
+
})
|
|
128
|
+
.input(CapabilityCardParamSchema)
|
|
129
|
+
.output(OkSchema),
|
|
53
130
|
// Start an agent-kind capability's interactive login (its declared loginCommand) in a visible terminal
|
|
54
131
|
// session the user types into, device-code sign-in flows. Returns the session the panel attaches to.
|
|
55
|
-
login: oc
|
|
132
|
+
login: oc
|
|
133
|
+
.route({
|
|
134
|
+
method: "POST",
|
|
135
|
+
path: "/capabilities/{id}/login",
|
|
136
|
+
summary: "Sign in to a connection by hand",
|
|
137
|
+
description:
|
|
138
|
+
"Opens the connection's own sign-in in a terminal a person can type into, for the flows that need a code pasted or a device confirmed. The answer names the terminal to attach to.",
|
|
139
|
+
})
|
|
140
|
+
.input(CapabilityIdParamSchema)
|
|
141
|
+
.output(CapabilityLoginSchema),
|
|
56
142
|
// Mint one TOTP code from the capability's stored seed (a field its card marks `totp`). The one capability
|
|
57
143
|
// read the agent token is admitted to (see auth/grants): a code expires within its period and never reveals
|
|
58
144
|
// the seed, so the in-sandbox `otp` command can answer a 2FA prompt without the agent holding the factor.
|
|
59
|
-
otp: oc
|
|
145
|
+
otp: oc
|
|
146
|
+
.route({
|
|
147
|
+
method: "GET",
|
|
148
|
+
path: "/capabilities/{id}/otp",
|
|
149
|
+
summary: "Mint a one-time code",
|
|
150
|
+
description:
|
|
151
|
+
"Generates a single two-factor code from a stored seed. The one credential-adjacent read an agent is allowed, and it is safe because a code expires in seconds and never reveals the seed, so an agent can answer a prompt without ever holding the factor.",
|
|
152
|
+
})
|
|
153
|
+
.input(CapabilityIdParamSchema)
|
|
154
|
+
.output(CapabilityOtpSchema),
|
|
60
155
|
};
|