@intentic/sandbox-contract 1.307.0 → 1.308.2
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 +12 -0
- package/dist/contracts/accounts.contract.d.ts +6 -6
- package/dist/contracts/accounts.contract.js +7 -7
- package/dist/contracts/accounts.contract.js.map +1 -1
- package/dist/contracts/activity.contract.d.ts +2 -2
- package/dist/contracts/activity.contract.js +3 -3
- package/dist/contracts/activity.contract.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts +10 -10
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +21 -11
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +41 -27
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +44 -28
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/approvals.contract.d.ts +3 -3
- package/dist/contracts/approvals.contract.js +4 -4
- package/dist/contracts/approvals.contract.js.map +1 -1
- package/dist/contracts/areas.contract.d.ts +3 -3
- package/dist/contracts/areas.contract.d.ts.map +1 -1
- package/dist/contracts/areas.contract.js +5 -4
- package/dist/contracts/areas.contract.js.map +1 -1
- package/dist/contracts/automations.contract.d.ts +11 -11
- package/dist/contracts/automations.contract.js +12 -12
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +13 -13
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +18 -14
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/chores.contract.d.ts +3 -3
- package/dist/contracts/chores.contract.js +4 -4
- package/dist/contracts/chores.contract.js.map +1 -1
- package/dist/contracts/ci.contract.d.ts +5 -5
- package/dist/contracts/ci.contract.js +6 -6
- package/dist/contracts/ci.contract.js.map +1 -1
- package/dist/contracts/diff.contract.d.ts +1 -1
- package/dist/contracts/diff.contract.js +2 -2
- package/dist/contracts/diff.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +4 -4
- package/dist/contracts/endpoints.contract.js +5 -5
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/exit.contract.d.ts +7 -7
- package/dist/contracts/exit.contract.d.ts.map +1 -1
- package/dist/contracts/exit.contract.js +9 -8
- package/dist/contracts/exit.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +17 -17
- package/dist/contracts/extensions.contract.js +18 -18
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/git.contract.d.ts +47 -45
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +46 -46
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/history.contract.d.ts +4 -4
- package/dist/contracts/history.contract.js +5 -5
- package/dist/contracts/history.contract.js.map +1 -1
- package/dist/contracts/intentic.contract.d.ts +3 -3
- package/dist/contracts/intentic.contract.d.ts.map +1 -1
- package/dist/contracts/intentic.contract.js +5 -4
- package/dist/contracts/intentic.contract.js.map +1 -1
- package/dist/contracts/inventory.contract.d.ts +3 -3
- package/dist/contracts/inventory.contract.js +4 -4
- package/dist/contracts/inventory.contract.js.map +1 -1
- package/dist/contracts/issues.contract.d.ts +5 -5
- package/dist/contracts/issues.contract.js +6 -6
- package/dist/contracts/issues.contract.js.map +1 -1
- package/dist/contracts/logs.contract.d.ts +3 -3
- package/dist/contracts/logs.contract.d.ts.map +1 -1
- package/dist/contracts/logs.contract.js +6 -4
- package/dist/contracts/logs.contract.js.map +1 -1
- package/dist/contracts/loops.contract.d.ts +6 -6
- package/dist/contracts/loops.contract.js +7 -7
- package/dist/contracts/loops.contract.js.map +1 -1
- package/dist/contracts/netdisk.contract.d.ts +3 -3
- package/dist/contracts/netdisk.contract.d.ts.map +1 -1
- package/dist/contracts/netdisk.contract.js +5 -4
- package/dist/contracts/netdisk.contract.js.map +1 -1
- package/dist/contracts/panels.contract.d.ts +3 -3
- package/dist/contracts/panels.contract.js +4 -4
- package/dist/contracts/panels.contract.js.map +1 -1
- package/dist/contracts/personas.contract.d.ts +8 -8
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.js +10 -9
- package/dist/contracts/personas.contract.js.map +1 -1
- package/dist/contracts/ports.contract.d.ts +3 -3
- package/dist/contracts/ports.contract.d.ts.map +1 -1
- package/dist/contracts/ports.contract.js +5 -4
- package/dist/contracts/ports.contract.js.map +1 -1
- package/dist/contracts/prepush.contract.d.ts +3 -3
- package/dist/contracts/prepush.contract.js +4 -4
- package/dist/contracts/prepush.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts +2 -2
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.js +5 -3
- package/dist/contracts/providers.contract.js.map +1 -1
- package/dist/contracts/public.contract.d.ts +3 -3
- package/dist/contracts/public.contract.js +4 -4
- package/dist/contracts/public.contract.js.map +1 -1
- package/dist/contracts/push.contract.d.ts +4 -4
- package/dist/contracts/push.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.js +9 -5
- package/dist/contracts/push.contract.js.map +1 -1
- package/dist/contracts/safety.contract.d.ts +3 -3
- package/dist/contracts/safety.contract.js +4 -4
- package/dist/contracts/safety.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts +9 -9
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +13 -10
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +2 -2
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.js +5 -3
- package/dist/contracts/sessions.contract.js.map +1 -1
- package/dist/contracts/settings.contract.d.ts +11 -9
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +11 -10
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/share.contract.d.ts +4 -4
- package/dist/contracts/share.contract.js +5 -5
- package/dist/contracts/share.contract.js.map +1 -1
- package/dist/contracts/skills.contract.d.ts +5 -5
- package/dist/contracts/skills.contract.js +6 -6
- package/dist/contracts/skills.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +22 -19
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +27 -20
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/translator.contract.d.ts +5 -5
- package/dist/contracts/translator.contract.js +6 -6
- package/dist/contracts/translator.contract.js.map +1 -1
- package/dist/contracts/usage.contract.d.ts +4 -4
- package/dist/contracts/usage.contract.js +5 -5
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/contracts/vpn.contract.d.ts +4 -4
- package/dist/contracts/vpn.contract.d.ts.map +1 -1
- package/dist/contracts/vpn.contract.js +6 -5
- package/dist/contracts/vpn.contract.js.map +1 -1
- package/dist/contracts/workflows.contract.d.ts +9 -9
- package/dist/contracts/workflows.contract.js +10 -10
- package/dist/contracts/workflows.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +30 -30
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +46 -31
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/land-breakage.d.ts +4 -0
- package/dist/events/land-breakage.d.ts.map +1 -0
- package/dist/events/land-breakage.js +4 -0
- package/dist/events/land-breakage.js.map +1 -0
- package/dist/events/system-events.d.ts +2 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/index.d.ts +9379 -9350
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol/procedure-types.d.ts +10 -0
- package/dist/protocol/procedure-types.d.ts.map +1 -0
- package/dist/protocol/procedure-types.js +2 -0
- package/dist/protocol/procedure-types.js.map +1 -0
- package/dist/protocol/raw-routes.d.ts +417 -0
- package/dist/protocol/raw-routes.d.ts.map +1 -0
- package/dist/protocol/raw-routes.js +140 -0
- package/dist/protocol/raw-routes.js.map +1 -0
- package/dist/protocol/route-meta.d.ts +18 -0
- package/dist/protocol/route-meta.d.ts.map +1 -0
- package/dist/protocol/route-meta.js +3 -0
- package/dist/protocol/route-meta.js.map +1 -0
- package/dist/protocol/routes.d.ts +3 -0
- package/dist/protocol/routes.d.ts.map +1 -1
- package/dist/protocol/routes.js +47 -14
- package/dist/protocol/routes.js.map +1 -1
- package/dist/schemas/agent.d.ts +33 -0
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +22 -3
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +4 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +4 -0
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/automations.d.ts +1 -0
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +2 -2
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/git/git.d.ts +3 -0
- package/dist/schemas/git/git.d.ts.map +1 -1
- package/dist/schemas/hosts.d.ts +1 -0
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +1 -0
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/settings.d.ts +1 -0
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +4 -0
- package/dist/schemas/settings.js.map +1 -1
- package/dist/state/definition.d.ts +4 -0
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/history-state.d.ts.map +1 -1
- package/dist/state/history-state.js +2 -12
- package/dist/state/history-state.js.map +1 -1
- package/dist/state/landed-commit.d.ts +4 -0
- package/dist/state/landed-commit.d.ts.map +1 -0
- package/dist/state/landed-commit.js +12 -0
- package/dist/state/landed-commit.js.map +1 -0
- package/package.json +5 -5
- package/src/contracts/accounts.contract.ts +7 -7
- package/src/contracts/activity.contract.ts +3 -3
- package/src/contracts/agent.contract.ts +25 -11
- package/src/contracts/agents.contract.ts +48 -30
- package/src/contracts/approvals.contract.ts +4 -4
- package/src/contracts/areas.contract.ts +5 -4
- package/src/contracts/automations.contract.ts +12 -12
- package/src/contracts/capabilities.contract.ts +23 -14
- package/src/contracts/chores.contract.ts +4 -4
- package/src/contracts/ci.contract.ts +6 -6
- package/src/contracts/diff.contract.ts +2 -2
- package/src/contracts/endpoints.contract.ts +5 -5
- package/src/contracts/exit.contract.ts +11 -8
- package/src/contracts/extensions.contract.ts +18 -18
- package/src/contracts/git.contract.ts +46 -46
- package/src/contracts/history.contract.ts +5 -5
- package/src/contracts/intentic.contract.ts +5 -4
- package/src/contracts/inventory.contract.ts +4 -4
- package/src/contracts/issues.contract.ts +6 -6
- package/src/contracts/logs.contract.ts +8 -4
- package/src/contracts/loops.contract.ts +7 -7
- package/src/contracts/netdisk.contract.ts +7 -4
- package/src/contracts/panels.contract.ts +4 -4
- package/src/contracts/personas.contract.ts +10 -9
- package/src/contracts/ports.contract.ts +6 -4
- package/src/contracts/prepush.contract.ts +4 -4
- package/src/contracts/providers.contract.ts +5 -3
- package/src/contracts/public.contract.ts +4 -4
- package/src/contracts/push.contract.ts +12 -5
- package/src/contracts/safety.contract.ts +4 -4
- package/src/contracts/secrets.contract.ts +16 -10
- package/src/contracts/sessions.contract.ts +6 -3
- package/src/contracts/settings.contract.ts +11 -10
- package/src/contracts/share.contract.ts +5 -5
- package/src/contracts/skills.contract.ts +6 -6
- package/src/contracts/system.contract.ts +32 -20
- package/src/contracts/translator.contract.ts +6 -6
- package/src/contracts/usage.contract.ts +5 -5
- package/src/contracts/vpn.contract.ts +8 -5
- package/src/contracts/workflows.contract.ts +10 -10
- package/src/contracts/workspace.contract.ts +49 -31
- package/src/events/land-breakage.ts +11 -0
- package/src/index.ts +23 -1
- package/src/models/capability-ledger.test.ts +1 -1
- package/src/protocol/procedure-types.ts +24 -0
- package/src/protocol/raw-routes.ts +191 -0
- package/src/protocol/route-meta.ts +39 -0
- package/src/protocol/routes.test.ts +65 -2
- package/src/protocol/routes.ts +88 -27
- package/src/schemas/agent.test.ts +66 -0
- package/src/schemas/agent.ts +184 -154
- package/src/schemas/agents.ts +6 -0
- package/src/schemas/devices.ts +2 -2
- package/src/schemas/hosts.ts +4 -0
- package/src/schemas/settings.ts +9 -0
- package/src/state/history-state.ts +14 -29
- package/src/state/landed-commit.test.ts +18 -0
- package/src/state/landed-commit.ts +17 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { procedure } from "../protocol/route-meta.js";
|
|
2
2
|
import { WorkspaceHealthQuerySchema, WorkspaceHealthSchema } from "../schemas/codebase-health.js";
|
|
3
3
|
import { WorkspaceModulesSchema } from "../schemas/git/git.js";
|
|
4
4
|
import { OkSchema } from "../schemas/shared.js";
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
// External MCP tools live in the capabilities manifest (mcp kind), not here.
|
|
45
45
|
export const workspaceContract = {
|
|
46
46
|
// `agent` picks whose workspace copy to read (WorkspaceScopeSchema); omitted means the shared /work tree.
|
|
47
|
-
tree:
|
|
47
|
+
tree: procedure
|
|
48
48
|
.route({
|
|
49
49
|
method: "GET",
|
|
50
50
|
path: "/workspace/tree",
|
|
@@ -52,10 +52,11 @@ export const workspaceContract = {
|
|
|
52
52
|
description:
|
|
53
53
|
"Every folder and file under the workspace root, as one walk. Name a conversation to read its own private copy of the tree instead of the shared one. Folders the daemon skips, such as installed packages, come back without their contents; ask for those separately.",
|
|
54
54
|
})
|
|
55
|
+
.meta({ guest: true })
|
|
55
56
|
.input(WorkspaceScopeSchema)
|
|
56
57
|
.output(WorkspaceTreeSchema),
|
|
57
58
|
// Lazy-loads a folder's children the tree walk skipped (node_modules, .git…) to bound its entry budget.
|
|
58
|
-
children:
|
|
59
|
+
children: procedure
|
|
59
60
|
.route({
|
|
60
61
|
method: "GET",
|
|
61
62
|
path: "/workspace/children",
|
|
@@ -63,10 +64,11 @@ export const workspaceContract = {
|
|
|
63
64
|
description:
|
|
64
65
|
"The entries inside a folder as one flat list. Direct children are the default, which is how the explorer opens a folder the full tree walk left closed; callers that need a small subtree can ask for up to five levels without a request per directory.",
|
|
65
66
|
})
|
|
67
|
+
.meta({ guest: true })
|
|
66
68
|
.input(WorkspaceChildrenQuerySchema)
|
|
67
69
|
.output(WorkspaceChildrenSchema),
|
|
68
70
|
// One window of a file's text plus its size, never the whole file: an unbounded read can stall the daemon.
|
|
69
|
-
file:
|
|
71
|
+
file: procedure
|
|
70
72
|
.route({
|
|
71
73
|
method: "GET",
|
|
72
74
|
path: "/workspace/file",
|
|
@@ -74,10 +76,11 @@ export const workspaceContract = {
|
|
|
74
76
|
description:
|
|
75
77
|
"A window of one file's text, plus how large the whole file is. Never the entire file: an unbounded read is how a single enormous log stalls the daemon for everyone, so ask for the slice you mean to show and page through if you need more.",
|
|
76
78
|
})
|
|
79
|
+
.meta({ guest: true })
|
|
77
80
|
.input(WorkspaceFileReadQuerySchema)
|
|
78
81
|
.output(WorkspaceFileSchema),
|
|
79
82
|
// The markdown shadow fileq keeps of a binary file; the read is a plain file read, no derivation triggered.
|
|
80
|
-
derived:
|
|
83
|
+
derived: procedure
|
|
81
84
|
.route({
|
|
82
85
|
method: "GET",
|
|
83
86
|
path: "/workspace/derived",
|
|
@@ -85,10 +88,11 @@ export const workspaceContract = {
|
|
|
85
88
|
description:
|
|
86
89
|
"What a document, picture, recording or archive says, as text, from the shadow the sandbox keeps beside it. This is the same rendering an agent reads instead of the bytes, so it is also the way to check what one is working from. Nothing is derived here: a file with no shadow yet answers that it has none, and whether it could have one.",
|
|
87
90
|
})
|
|
91
|
+
.meta({ guest: true })
|
|
88
92
|
.input(WorkspaceDerivedQuerySchema)
|
|
89
93
|
.output(WorkspaceDerivedSchema),
|
|
90
94
|
// The lazy path, on demand: same convergence the background sweep runs, for one file someone is looking at.
|
|
91
|
-
derive:
|
|
95
|
+
derive: procedure
|
|
92
96
|
.route({
|
|
93
97
|
method: "POST",
|
|
94
98
|
path: "/workspace/derive",
|
|
@@ -96,10 +100,12 @@ export const workspaceContract = {
|
|
|
96
100
|
description:
|
|
97
101
|
"Renders one file to text and answers with the result, for when its shadow is missing or you want it rebuilt. The same work the background pass does when that setting is on, so this is how a reader gets the text without turning it on for the whole workspace. Costs a parse of exactly one file; a format nothing can read says so rather than failing.",
|
|
98
102
|
})
|
|
103
|
+
// Rendering one file as text is reading it: a regenerable cache entry, one parse of a readable file.
|
|
104
|
+
.meta({ floor: "viewer", guest: true })
|
|
99
105
|
.input(WorkspaceDerivedQuerySchema)
|
|
100
106
|
.output(WorkspaceDerivedSchema),
|
|
101
107
|
// Where the background pass stands, with no file in hand: what the setting's own row reports about itself.
|
|
102
|
-
derivedStatus:
|
|
108
|
+
derivedStatus: procedure
|
|
103
109
|
.route({
|
|
104
110
|
method: "GET",
|
|
105
111
|
path: "/workspace/derived-status",
|
|
@@ -107,9 +113,10 @@ export const workspaceContract = {
|
|
|
107
113
|
description:
|
|
108
114
|
"Whether documents, pictures, recordings and archives are being rendered to text in the background, how many are waiting, which are being read right now, and how many shadows the last whole-tree pass counted. Ask this to tell a file nothing can read from a file whose turn has not come.",
|
|
109
115
|
})
|
|
116
|
+
.meta({ guest: true })
|
|
110
117
|
.output(SidecarStatusSchema),
|
|
111
118
|
// Mints the ticket GET /workspace/media (a plain Hono byte-range route, no oRPC shape) requires to stream.
|
|
112
|
-
mediaTicket:
|
|
119
|
+
mediaTicket: procedure
|
|
113
120
|
.route({
|
|
114
121
|
method: "POST",
|
|
115
122
|
path: "/workspace/media-ticket",
|
|
@@ -117,10 +124,12 @@ export const workspaceContract = {
|
|
|
117
124
|
description:
|
|
118
125
|
"Mints the short-lived ticket a video or audio element hands to the streaming route, which serves byte ranges and so cannot carry an ordinary header. Minting it here means a caller can tell whether this sandbox streams media at all, rather than discovering it mid-playback.",
|
|
119
126
|
})
|
|
127
|
+
// Opening a media file is a read, and the ticket is strictly narrower than the bearer.
|
|
128
|
+
.meta({ floor: "viewer", guest: true })
|
|
120
129
|
.input(WorkspaceMediaTicketQuerySchema)
|
|
121
130
|
.output(WorkspaceMediaTicketSchema),
|
|
122
131
|
// Matches a prose-written path, often just a suffix, against the tree rather than trusting it as root-relative.
|
|
123
|
-
resolve:
|
|
132
|
+
resolve: procedure
|
|
124
133
|
.route({
|
|
125
134
|
method: "GET",
|
|
126
135
|
path: "/workspace/resolve",
|
|
@@ -128,10 +137,11 @@ export const workspaceContract = {
|
|
|
128
137
|
description:
|
|
129
138
|
"Matches a path somebody wrote in prose against the real tree and says which file it means. A path mentioned in a message is often only the tail of the real one, so this is the lookup behind every clickable file reference rather than a plain existence check.",
|
|
130
139
|
})
|
|
140
|
+
.meta({ guest: true })
|
|
131
141
|
.input(WorkspaceResolveQuerySchema)
|
|
132
142
|
.output(WorkspaceResolveSchema),
|
|
133
143
|
// `mode` narrows the search to one kind; default fuses text, structure, meaning and history in one pass.
|
|
134
|
-
search:
|
|
144
|
+
search: procedure
|
|
135
145
|
.route({
|
|
136
146
|
method: "GET",
|
|
137
147
|
path: "/workspace/search",
|
|
@@ -139,10 +149,11 @@ export const workspaceContract = {
|
|
|
139
149
|
description:
|
|
140
150
|
"Ranked results across the whole workspace, grouped, each carrying why it matched and how fresh it is. Left alone it blends plain text, structure, meaning and history in one pass; narrow it to a single kind of search when you already know which you want. Long result sets resume from the cursor it hands back.",
|
|
141
151
|
})
|
|
152
|
+
.meta({ guest: true, control: "editor" })
|
|
142
153
|
.input(WorkspaceSearchQuerySchema)
|
|
143
154
|
.output(WorkspaceSearchResultSchema),
|
|
144
155
|
// Per-file churn × complexity, index totals, top modules; scoped to a repo, not the whole /work drop.
|
|
145
|
-
health:
|
|
156
|
+
health: procedure
|
|
146
157
|
.route({
|
|
147
158
|
method: "GET",
|
|
148
159
|
path: "/workspace/health",
|
|
@@ -153,7 +164,7 @@ export const workspaceContract = {
|
|
|
153
164
|
.input(WorkspaceHealthQuerySchema)
|
|
154
165
|
.output(WorkspaceHealthSchema),
|
|
155
166
|
// Deterministic, no-LLM classification into coarse buckets; read-only, applied only via the move route.
|
|
156
|
-
classify:
|
|
167
|
+
classify: procedure
|
|
157
168
|
.route({
|
|
158
169
|
method: "GET",
|
|
159
170
|
path: "/workspace/classify",
|
|
@@ -163,16 +174,18 @@ export const workspaceContract = {
|
|
|
163
174
|
})
|
|
164
175
|
.output(WorkspaceClassificationSchema),
|
|
165
176
|
// Delete sends `{path}` in the body, not the query: oRPC's OpenAPI codec reads non-GET input from the body.
|
|
166
|
-
mkdir:
|
|
177
|
+
mkdir: procedure
|
|
167
178
|
.route({
|
|
168
179
|
method: "POST",
|
|
169
180
|
path: "/workspace/dir",
|
|
170
181
|
summary: "Create a folder",
|
|
171
182
|
description: "Makes a folder, and any missing folders above it.",
|
|
172
183
|
})
|
|
184
|
+
// Editing the shared tree is the writer grant; each file route resolves its path inside the caller's fence.
|
|
185
|
+
.meta({ floor: "writer" })
|
|
173
186
|
.input(WorkspaceDirSchema)
|
|
174
187
|
.output(OkSchema),
|
|
175
|
-
delete:
|
|
188
|
+
delete: procedure
|
|
176
189
|
.route({
|
|
177
190
|
method: "DELETE",
|
|
178
191
|
path: "/workspace/entry",
|
|
@@ -180,27 +193,30 @@ export const workspaceContract = {
|
|
|
180
193
|
description:
|
|
181
194
|
"Removes one entry and everything under it. The path travels in the body rather than the address, the same as every other write in this group.",
|
|
182
195
|
})
|
|
196
|
+
.meta({ floor: "writer" })
|
|
183
197
|
.input(WorkspaceFileQuerySchema)
|
|
184
198
|
.output(OkSchema),
|
|
185
|
-
move:
|
|
199
|
+
move: procedure
|
|
186
200
|
.route({
|
|
187
201
|
method: "POST",
|
|
188
202
|
path: "/workspace/move",
|
|
189
203
|
summary: "Move or rename something",
|
|
190
204
|
description: "Moves one entry to a new path, which is also how you rename it.",
|
|
191
205
|
})
|
|
206
|
+
.meta({ floor: "writer" })
|
|
192
207
|
.input(WorkspaceMoveSchema)
|
|
193
208
|
.output(OkSchema),
|
|
194
|
-
copy:
|
|
209
|
+
copy: procedure
|
|
195
210
|
.route({
|
|
196
211
|
method: "POST",
|
|
197
212
|
path: "/workspace/copy",
|
|
198
213
|
summary: "Copy a file or folder",
|
|
199
214
|
description: "Duplicates one entry at a new path, recursively for a folder.",
|
|
200
215
|
})
|
|
216
|
+
.meta({ floor: "writer" })
|
|
201
217
|
.input(WorkspaceMoveSchema)
|
|
202
218
|
.output(OkSchema),
|
|
203
|
-
extract:
|
|
219
|
+
extract: procedure
|
|
204
220
|
.route({
|
|
205
221
|
method: "POST",
|
|
206
222
|
path: "/workspace/extract",
|
|
@@ -208,10 +224,11 @@ export const workspaceContract = {
|
|
|
208
224
|
description:
|
|
209
225
|
"Unpacks a zip or tar already in the workspace into a new folder beside it, named after the archive. An archive that is one folder of its own name lands as that folder rather than as it twice, and a .gz, .bz2, .xz or .zst holding a single file lands as that file. Nothing is ever written over: the answer says where it landed. Formats with no tool here, such as .7z and .rar, are refused.",
|
|
210
226
|
})
|
|
227
|
+
.meta({ floor: "writer" })
|
|
211
228
|
.input(WorkspaceFileQuerySchema)
|
|
212
229
|
.output(WorkspaceExtractSchema),
|
|
213
230
|
// An imported project lacks node_modules/.venv; until this says ready, its type checks and tests can mislead.
|
|
214
|
-
setup:
|
|
231
|
+
setup: procedure
|
|
215
232
|
.route({
|
|
216
233
|
method: "GET",
|
|
217
234
|
path: "/workspace/setup",
|
|
@@ -220,7 +237,7 @@ export const workspaceContract = {
|
|
|
220
237
|
"Per project, whether its dependencies are actually present. A project that arrives by import comes without them, so files landing is not the same as the project working: until this says a project is ready, its type checks and tests can only mislead you.",
|
|
221
238
|
})
|
|
222
239
|
.output(WorkspaceSetupSchema),
|
|
223
|
-
install:
|
|
240
|
+
install: procedure
|
|
224
241
|
.route({
|
|
225
242
|
method: "POST",
|
|
226
243
|
path: "/workspace/setup/install",
|
|
@@ -230,15 +247,16 @@ export const workspaceContract = {
|
|
|
230
247
|
})
|
|
231
248
|
.input(WorkspaceInstallSchema)
|
|
232
249
|
.output(WorkspaceInstallResultSchema),
|
|
233
|
-
repos:
|
|
250
|
+
repos: procedure
|
|
234
251
|
.route({
|
|
235
252
|
method: "GET",
|
|
236
253
|
path: "/workspace/repos",
|
|
237
254
|
summary: "Repos in the workspace",
|
|
238
255
|
description: "Every git repo the daemon found in the workspace, with where each one sits and what it is called.",
|
|
239
256
|
})
|
|
257
|
+
.meta({ guest: true })
|
|
240
258
|
.output(ReposListSchema),
|
|
241
|
-
addRepo:
|
|
259
|
+
addRepo: procedure
|
|
242
260
|
.route({
|
|
243
261
|
method: "POST",
|
|
244
262
|
path: "/workspace/repos",
|
|
@@ -247,7 +265,7 @@ export const workspaceContract = {
|
|
|
247
265
|
})
|
|
248
266
|
.input(CloneRepoSchema)
|
|
249
267
|
.output(CloneResultSchema),
|
|
250
|
-
createRepo:
|
|
268
|
+
createRepo: procedure
|
|
251
269
|
.route({
|
|
252
270
|
method: "POST",
|
|
253
271
|
path: "/workspace/repos/new",
|
|
@@ -258,7 +276,7 @@ export const workspaceContract = {
|
|
|
258
276
|
.input(CreateRepoSchema)
|
|
259
277
|
.output(CloneResultSchema),
|
|
260
278
|
// Mutates the tree (fetch + fast-forward), which is why this is POST rather than GET.
|
|
261
|
-
sync:
|
|
279
|
+
sync: procedure
|
|
262
280
|
.route({
|
|
263
281
|
method: "POST",
|
|
264
282
|
path: "/workspace/sync",
|
|
@@ -268,7 +286,7 @@ export const workspaceContract = {
|
|
|
268
286
|
})
|
|
269
287
|
.output(WorkspaceSyncSchema),
|
|
270
288
|
// The source repo's templates.json app types; drives the apps extension's Add-app picker.
|
|
271
|
-
templates:
|
|
289
|
+
templates: procedure
|
|
272
290
|
.route({
|
|
273
291
|
method: "GET",
|
|
274
292
|
path: "/workspace/templates",
|
|
@@ -277,7 +295,7 @@ export const workspaceContract = {
|
|
|
277
295
|
})
|
|
278
296
|
.output(TemplatesListSchema),
|
|
279
297
|
// Runs as a one-shot tmux job named `panel-<repo>--add_apps`, executing `intentic scaffold add-app`.
|
|
280
|
-
addApps:
|
|
298
|
+
addApps: procedure
|
|
281
299
|
.route({
|
|
282
300
|
method: "POST",
|
|
283
301
|
path: "/workspace/repos/{repo}/apps",
|
|
@@ -287,7 +305,7 @@ export const workspaceContract = {
|
|
|
287
305
|
})
|
|
288
306
|
.input(AddAppsSchema)
|
|
289
307
|
.output(OkSchema),
|
|
290
|
-
appsList:
|
|
308
|
+
appsList: procedure
|
|
291
309
|
.route({
|
|
292
310
|
method: "GET",
|
|
293
311
|
path: "/workspace/repos/{repo}/apps",
|
|
@@ -297,7 +315,7 @@ export const workspaceContract = {
|
|
|
297
315
|
.input(RepoAppsParamSchema)
|
|
298
316
|
.output(AppsListSchema),
|
|
299
317
|
// The monorepo's package dependency graph, from pnpm-workspace.yaml globs and each package.json's deps.
|
|
300
|
-
packageGraph:
|
|
318
|
+
packageGraph: procedure
|
|
301
319
|
.route({
|
|
302
320
|
method: "GET",
|
|
303
321
|
path: "/workspace/repos/{repo}/graph",
|
|
@@ -307,7 +325,7 @@ export const workspaceContract = {
|
|
|
307
325
|
.input(RepoAppsParamSchema)
|
|
308
326
|
.output(WorkspaceGraphSchema),
|
|
309
327
|
// Every repo's package dirs in one call, since a review spans repos and per-repo would fan out per open.
|
|
310
|
-
modules:
|
|
328
|
+
modules: procedure
|
|
311
329
|
.route({
|
|
312
330
|
method: "GET",
|
|
313
331
|
path: "/workspace/modules",
|
|
@@ -316,7 +334,7 @@ export const workspaceContract = {
|
|
|
316
334
|
"The named packages in the whole workspace, which is what a review list groups changed files under when a reader wants packages rather than paths. Whole-workspace in one answer, because a review spans repos and asking per repo would be a fan-out on every open.",
|
|
317
335
|
})
|
|
318
336
|
.output(WorkspaceModulesSchema),
|
|
319
|
-
startApp:
|
|
337
|
+
startApp: procedure
|
|
320
338
|
.route({
|
|
321
339
|
method: "POST",
|
|
322
340
|
path: "/workspace/repos/{repo}/apps/{app}/start",
|
|
@@ -325,7 +343,7 @@ export const workspaceContract = {
|
|
|
325
343
|
})
|
|
326
344
|
.input(AppParamSchema)
|
|
327
345
|
.output(OkSchema),
|
|
328
|
-
stopApp:
|
|
346
|
+
stopApp: procedure
|
|
329
347
|
.route({
|
|
330
348
|
method: "POST",
|
|
331
349
|
path: "/workspace/repos/{repo}/apps/{app}/stop",
|
|
@@ -335,7 +353,7 @@ export const workspaceContract = {
|
|
|
335
353
|
.input(AppParamSchema)
|
|
336
354
|
.output(OkSchema),
|
|
337
355
|
// Runs tests for the named dirs in a one-shot tmux panel; mirrors addApps: an ack, terminal as result surface.
|
|
338
|
-
runTests:
|
|
356
|
+
runTests: procedure
|
|
339
357
|
.route({
|
|
340
358
|
method: "POST",
|
|
341
359
|
path: "/workspace/repos/{repo}/tests",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// The follow-up the daemon sends a conversation whose land turned the main tree's own check red, recognised by its opening.
|
|
2
|
+
|
|
3
|
+
// Anchored on by the chat, so it must stay unique and stable across releases.
|
|
4
|
+
export const LAND_BREAKAGE_OPENING =
|
|
5
|
+
"What this conversation landed turned the main tree's own check red after it arrived. Each failure below appeared with that land and was not failing before it. Fix them on this branch and check the fix as you would any change; it lands like any other turn.";
|
|
6
|
+
|
|
7
|
+
// The prompt a breakage actually sends: its opening, then the failures, each already worded for the model.
|
|
8
|
+
export const landBreakagePrompt = (parts: readonly string[]): string => [LAND_BREAKAGE_OPENING, ...parts].join("\n\n");
|
|
9
|
+
|
|
10
|
+
// Whether a stored prompt is one.
|
|
11
|
+
export const isLandBreakage = (prompt: string): boolean => prompt.startsWith(LAND_BREAKAGE_OPENING);
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { getEventIteratorSchemaDetails, isContractProcedure } from "@orpc/contract";
|
|
2
|
+
import type { z } from "zod";
|
|
3
|
+
import { RAW_ROUTE_LIST } from "./protocol/raw-routes.js";
|
|
1
4
|
import type { ContractRoute } from "./protocol/routes.js";
|
|
2
|
-
import { contractRoutes, requestPathFor, routeForProcedure, routeNameForRequest, routeShapes } from "./protocol/routes.js";
|
|
5
|
+
import { contractRoutes, requestPathFor, routeForProcedure, routeNameForRequest, routeShapes, servedRoute } from "./protocol/routes.js";
|
|
3
6
|
import { accountsContract } from "./contracts/accounts.contract.js";
|
|
4
7
|
import { activityContract } from "./contracts/activity.contract.js";
|
|
5
8
|
import { agentContract } from "./contracts/agent.contract.js";
|
|
@@ -108,6 +111,7 @@ export * from "./events/requests.js";
|
|
|
108
111
|
export * from "./events/resume.js";
|
|
109
112
|
export * from "./events/system-events.js";
|
|
110
113
|
export * from "./events/transcript.js";
|
|
114
|
+
export * from "./events/land-breakage.js";
|
|
111
115
|
export * from "./events/verify-nudge.js";
|
|
112
116
|
export * from "./events/watch-wake.js";
|
|
113
117
|
export * from "./policy/request-status.js";
|
|
@@ -115,6 +119,9 @@ export * from "./policy/turned-away.js";
|
|
|
115
119
|
export * from "./text/mentions.js";
|
|
116
120
|
export * from "./protocol/sse.js";
|
|
117
121
|
export * from "./protocol/routes.js";
|
|
122
|
+
export type { ControlReach, RouteMeta } from "./protocol/route-meta.js";
|
|
123
|
+
export { RAW_ROUTE_LIST, RAW_ROUTES, type RawRouteKey, rawRoutePath } from "./protocol/raw-routes.js";
|
|
124
|
+
export type { SandboxCallInput, SandboxGroup, SandboxHandlerInput, SandboxHandlerOutput, SandboxProcedure } from "./protocol/procedure-types.js";
|
|
118
125
|
export * from "./policy/control-scopes.js";
|
|
119
126
|
// The container's directory layout, re-exported since extensions can't import @intentic/constants directly.
|
|
120
127
|
export { HISTORY_ROOT, HOST_STATE_ROOT, STATE_DIR, WORKSPACE_ROOT } from "@intentic/constants";
|
|
@@ -123,6 +130,7 @@ export * from "./state/runtime-state.js";
|
|
|
123
130
|
export * from "./state/state-portability.js";
|
|
124
131
|
export * from "./state/history-state.js";
|
|
125
132
|
export * from "./state/fix-stance.js";
|
|
133
|
+
export * from "./state/landed-commit.js";
|
|
126
134
|
export * from "./state/fix-attempt-plan.js";
|
|
127
135
|
// Provider vocabulary bottom-up: agent-runtimes, provider-specs, agent-catalog; three modules since the dependency
|
|
128
136
|
// points one way.
|
|
@@ -288,9 +296,23 @@ export const SANDBOX_ROUTE_SHAPES: Readonly<Record<string, string>> = routeShape
|
|
|
288
296
|
export const sandboxRouteName = (method: string, pathWithQuery: string): string | undefined =>
|
|
289
297
|
routeNameForRequest(SANDBOX_ROUTES, method, pathWithQuery);
|
|
290
298
|
|
|
299
|
+
// The route of either kind that serves a request to the daemon, bound to this build's tables; its meta is the policy the
|
|
300
|
+
// daemon holds the request to, and undefined means nothing serves it.
|
|
301
|
+
export const sandboxRouteFor = (method: string, pathWithQuery: string): ContractRoute | undefined =>
|
|
302
|
+
servedRoute(RAW_ROUTE_LIST, SANDBOX_ROUTES, method, pathWithQuery);
|
|
303
|
+
|
|
291
304
|
// The method and path a typed call is about to send, bound to this build's route table. Undefined for an undeclared
|
|
292
305
|
// procedure; the host gate then refuses it rather than assuming it's harmless.
|
|
293
306
|
export const sandboxRequestFor = (procedure: readonly string[], input: unknown): { method: string; path: string } | undefined => {
|
|
294
307
|
const route = routeForProcedure(SANDBOX_ROUTES, procedure);
|
|
295
308
|
return route === undefined ? undefined : { method: route.method, path: requestPathFor(route, input) };
|
|
296
309
|
};
|
|
310
|
+
|
|
311
|
+
// The schema a procedure's answer is parsed by, bound to this build's contract; undefined for a streamed answer, which
|
|
312
|
+
// passes as it arrives, since a frame kind this build does not know must not end the stream.
|
|
313
|
+
export const sandboxAnswerSchema = (procedure: readonly string[]): z.ZodType | undefined => {
|
|
314
|
+
const [group = "", name = ""] = procedure;
|
|
315
|
+
const declared = (sandboxContract as Readonly<Record<string, Readonly<Record<string, unknown>>>>)[group]?.[name];
|
|
316
|
+
const schema = isContractProcedure(declared) ? declared["~orpc"].outputSchema : undefined;
|
|
317
|
+
return schema === undefined || getEventIteratorSchemaDetails(schema) !== undefined ? undefined : (schema as z.ZodType);
|
|
318
|
+
};
|
|
@@ -8,7 +8,7 @@ import type { AgentCapabilities } from "./agent-runtimes.js";
|
|
|
8
8
|
type Backing = "enforced" | "descriptive";
|
|
9
9
|
|
|
10
10
|
const LEDGER: Record<keyof AgentCapabilities, Backing> = {
|
|
11
|
-
//
|
|
11
|
+
// runtime-table.ts maps this runtime to its serving adapter; also keys per-runtime health probes.
|
|
12
12
|
runtime: "enforced",
|
|
13
13
|
// conversation.ts's `steerable`: the composer offers mid-turn injection only where there is a queue.
|
|
14
14
|
steering: "enforced",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AnySchema, ContractProcedure, ErrorMap, InferSchemaInput, InferSchemaOutput, Meta } from "@orpc/contract";
|
|
2
|
+
import type { sandboxContract } from "../index.js";
|
|
3
|
+
|
|
4
|
+
// Every procedure's wire types by group and name, from both ends: what a caller sends, and what a handler is given and
|
|
5
|
+
// may answer. The two ends differ wherever a schema coerces or defaults, so a stand-in daemon types itself by the
|
|
6
|
+
// handler's end and a caller by its own.
|
|
7
|
+
|
|
8
|
+
type Contract = typeof sandboxContract;
|
|
9
|
+
|
|
10
|
+
export type SandboxGroup = keyof Contract;
|
|
11
|
+
export type SandboxProcedure<G extends SandboxGroup> = keyof Contract[G] & string;
|
|
12
|
+
|
|
13
|
+
// What a caller hands the typed client, before the client spreads it over the path, the query and the body.
|
|
14
|
+
export type SandboxCallInput<G extends SandboxGroup, P extends SandboxProcedure<G>> =
|
|
15
|
+
Contract[G][P] extends ContractProcedure<infer I extends AnySchema, AnySchema, ErrorMap, Meta> ? InferSchemaInput<I> : never;
|
|
16
|
+
|
|
17
|
+
// What a handler is given: the request's input as the input schema parsed it, a query's "true" already a boolean.
|
|
18
|
+
export type SandboxHandlerInput<G extends SandboxGroup, P extends SandboxProcedure<G>> =
|
|
19
|
+
Contract[G][P] extends ContractProcedure<infer I extends AnySchema, AnySchema, ErrorMap, Meta> ? InferSchemaOutput<I> : never;
|
|
20
|
+
|
|
21
|
+
// What a handler may answer: anything the output schema parses, so a defaulted field may be left out. A streamed
|
|
22
|
+
// procedure's is an async iterator of frames in the same sense.
|
|
23
|
+
export type SandboxHandlerOutput<G extends SandboxGroup, P extends SandboxProcedure<G>> =
|
|
24
|
+
Contract[G][P] extends ContractProcedure<AnySchema, infer O extends AnySchema, ErrorMap, Meta> ? InferSchemaInput<O> : never;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { RouteMeta } from "./route-meta.js";
|
|
2
|
+
import type { ContractRoute } from "./routes.js";
|
|
3
|
+
import { runnerTranslatorPath } from "./runner-protocol.js";
|
|
4
|
+
|
|
5
|
+
// Every route the daemon serves outside oRPC (streamed bytes, WebSocket upgrades, doors checking their own credential),
|
|
6
|
+
// keyed `METHOD /path` in the order the daemon registers them: among overlapping ones the first registered answers.
|
|
7
|
+
// `{param}` is one path segment, a trailing `/*` any further ones, `ALL` every method; the daemon serves no other.
|
|
8
|
+
export const RAW_ROUTES = {
|
|
9
|
+
// The "is a daemon there" probe every flow uses; it names the sandbox and says whether it is still converging.
|
|
10
|
+
"GET /health": { auth: "door", beforeBoot: true },
|
|
11
|
+
"GET /diff/raw": {},
|
|
12
|
+
// Arming the dictation model is a read any tier makes; dictating is writing a message, the collaborator's grant.
|
|
13
|
+
"GET /speech/status": { guest: true },
|
|
14
|
+
"POST /speech/transcribe": { floor: "collaborator", guest: true },
|
|
15
|
+
// The bytes behind the workspace reads; each applies the caller's fence itself.
|
|
16
|
+
"GET /workspace/raw": { guest: true },
|
|
17
|
+
// No door, unlike media: the page fetches a thumbnail itself, so the request carries the header.
|
|
18
|
+
"GET /workspace/thumb": { guest: true },
|
|
19
|
+
// Fetched by a <video>/<audio> tag, which sends no header: its scoped ticket is checked in the handler.
|
|
20
|
+
"GET /workspace/media": { auth: "door", guest: true },
|
|
21
|
+
// An attachment is part of the message it rides with; any other target edits the shared tree.
|
|
22
|
+
"POST /workspace/upload": { floor: "writer", attachmentFloor: "collaborator" },
|
|
23
|
+
"POST /workspace/upload-diff": {},
|
|
24
|
+
"POST /workspace/upload-archive": {},
|
|
25
|
+
// Minting is cheap: each WebSocket upgrade floors its own redemption.
|
|
26
|
+
"POST /system/ws-ticket": { beforeBoot: true, floor: "collaborator", control: "never" },
|
|
27
|
+
// A WebSocket upgrade carries no Authorization header; the terminal and both browser wires check a query ticket.
|
|
28
|
+
"GET /system/terminal": { auth: "door", beforeBoot: true, control: "never" },
|
|
29
|
+
// Desktop sync's byte pipe, guarded again by sshd's own key check against the same enrollment.
|
|
30
|
+
"GET /system/sync/ssh": { sync: "pipe", control: "never" },
|
|
31
|
+
"GET /system/browser-profile": { auth: "door", beforeBoot: true, control: "never" },
|
|
32
|
+
"GET /system/browser-view": { auth: "door", beforeBoot: true, control: "never" },
|
|
33
|
+
// Deploy-target enrollment, gated by the connect token.
|
|
34
|
+
"POST /enroll": { auth: "door", control: "never" },
|
|
35
|
+
// An event automation's webhook, gated by the automation's own token.
|
|
36
|
+
"POST /automations/{id}/fire": { auth: "door" },
|
|
37
|
+
// The release gate a pipeline runner waits on, gated by the workflow's minted gate token.
|
|
38
|
+
"POST /workflows/{id}/gate": { auth: "door" },
|
|
39
|
+
// The Visitor chat, embedded on the owner's sites: gated by its origin allowlist, rate limit and bot check.
|
|
40
|
+
"GET /webchat/widget.js": { auth: "door", embedded: true },
|
|
41
|
+
"GET /webchat/{id}/config": { auth: "door", embedded: true },
|
|
42
|
+
"GET /webchat/{id}/challenge": { auth: "door", embedded: true },
|
|
43
|
+
"POST /webchat/{id}/message": { auth: "door", embedded: true },
|
|
44
|
+
"GET /webchat/{id}/messages": { auth: "door", embedded: true },
|
|
45
|
+
// Which sites loaded the widget is the owner's diagnostic, not the visitor's.
|
|
46
|
+
"GET /webchat/{id}/installs": {},
|
|
47
|
+
// The bug intake, the other anonymous door: gated by origin allowlist or ingest key, rate window and daily ceiling.
|
|
48
|
+
"GET /intake/sdk.js": { auth: "door", embedded: true },
|
|
49
|
+
"GET /intake/{id}/config": { auth: "door", embedded: true },
|
|
50
|
+
"GET /intake/{id}/challenge": { auth: "door", embedded: true },
|
|
51
|
+
"POST /intake/{id}/report": { auth: "door", embedded: true },
|
|
52
|
+
// The roster is ownership's to change; giving up one's own grant is every tier's.
|
|
53
|
+
"GET /members": { control: "never" },
|
|
54
|
+
"POST /members": { control: "never" },
|
|
55
|
+
"DELETE /members": { control: "never" },
|
|
56
|
+
"DELETE /members/self": { floor: "viewer", guest: true, control: "never" },
|
|
57
|
+
"GET /environment": {},
|
|
58
|
+
"GET /environment/contents": {},
|
|
59
|
+
"POST /environment/approve": {},
|
|
60
|
+
"POST /environment/reject": {},
|
|
61
|
+
"POST /environment/runtime-install": {},
|
|
62
|
+
"GET /engines": {},
|
|
63
|
+
"POST /engines/channel": {},
|
|
64
|
+
"POST /engines/update": {},
|
|
65
|
+
"POST /engines/revert": {},
|
|
66
|
+
"GET /bundles": { control: "never" },
|
|
67
|
+
"POST /bundles": { control: "never" },
|
|
68
|
+
"DELETE /bundles": { control: "never" },
|
|
69
|
+
"POST /bundles/ticket": { control: "never" },
|
|
70
|
+
// Navigated to by the browser, so no header: its ticket is checked in the handler.
|
|
71
|
+
"GET /bundles/download": { auth: "door", control: "never" },
|
|
72
|
+
"GET /definition": {},
|
|
73
|
+
"POST /definition/diff": {},
|
|
74
|
+
"GET /definition/workspace": {},
|
|
75
|
+
"POST /definition/workspace/publish": {},
|
|
76
|
+
"POST /arrivals/plan": {},
|
|
77
|
+
"GET /arrivals/hosts": {},
|
|
78
|
+
"POST /arrivals/scan": {},
|
|
79
|
+
"POST /arrivals/apply": {},
|
|
80
|
+
"DELETE /arrivals": {},
|
|
81
|
+
"GET /extensions/{id}/bundle": {},
|
|
82
|
+
// An extension backend's own namespace, proxied verbatim.
|
|
83
|
+
"ALL /x/*": {},
|
|
84
|
+
// The `capabilities` CLI: discovery by name, and the ask that parks on an owner-decided card.
|
|
85
|
+
"GET /capabilities/connectable": { floor: "maintainer", agent: true, control: "never" },
|
|
86
|
+
"POST /capabilities/ask": { floor: "maintainer", agent: true, control: "never" },
|
|
87
|
+
// The `sandboxes` CLI; every create parks on a card in the owner's chat first.
|
|
88
|
+
"GET /sandboxes": { agent: true },
|
|
89
|
+
"POST /sandboxes": { agent: true },
|
|
90
|
+
// The `wallet` CLI; spend is bounded by the owner's policy and the key never enters the container.
|
|
91
|
+
"GET /wallet/status": { agent: true, control: "never" },
|
|
92
|
+
"POST /wallet/fetch": { agent: true, control: "never" },
|
|
93
|
+
"GET /wallet/history": { agent: true, control: "never" },
|
|
94
|
+
// The `agents` CLI's children: start, follow up, answer (never a consent card), list.
|
|
95
|
+
"POST /children/spawn": { agent: true, control: "never" },
|
|
96
|
+
"GET /children/providers": { agent: true, control: "never" },
|
|
97
|
+
"POST /children/wait": { agent: true, control: "never" },
|
|
98
|
+
"POST /children/send": { agent: true, control: "never" },
|
|
99
|
+
"POST /children/answer": { agent: true, control: "never" },
|
|
100
|
+
"GET /children": { agent: true, control: "never" },
|
|
101
|
+
// The fleet reads, and the one write: words in front of another conversation, which a person can do by typing.
|
|
102
|
+
"GET /fleet": { agent: true },
|
|
103
|
+
"POST /fleet/message": { agent: true },
|
|
104
|
+
"GET /fleet/{handle}": { agent: true },
|
|
105
|
+
// An extension gateway's realtime-listener control, reached with the panel token.
|
|
106
|
+
"GET /listeners/{provider}/state": {},
|
|
107
|
+
"POST /listeners/{provider}/dispatch": {},
|
|
108
|
+
"POST /listeners/{provider}/failure": {},
|
|
109
|
+
"POST /listeners/{provider}/status": {},
|
|
110
|
+
// The CI webhook receiver, gated by the per-sandbox webhook secret.
|
|
111
|
+
"POST /ci/webhook/{host}": { auth: "door" },
|
|
112
|
+
// Below maintainer a pairing is capped to port-mirror, so a collaborator may mint a preview tunnel.
|
|
113
|
+
"POST /system/sync/pair": { floor: "collaborator", control: "never" },
|
|
114
|
+
// The peer doors: a device, browser or runner redeems its pairing at `enroll` and dials `connect` with the token.
|
|
115
|
+
"POST /system/hosts/pair": { control: "never" },
|
|
116
|
+
"POST /system/hosts/enroll": { auth: "door", control: "never" },
|
|
117
|
+
"GET /system/hosts": { control: "never" },
|
|
118
|
+
"DELETE /system/hosts/{id}": { control: "never" },
|
|
119
|
+
// A peer's socket reconnects on its own backoff, so it answers before boot.
|
|
120
|
+
"GET /system/hosts/connect": { auth: "door", beforeBoot: true, control: "never" },
|
|
121
|
+
// The MCP bridge onto a peer, carrying the per-boot bridge token its handler checks.
|
|
122
|
+
"POST /mcp/hosts/{id}": { auth: "door" },
|
|
123
|
+
"GET /mcp/hosts/{id}": { auth: "door" },
|
|
124
|
+
"DELETE /mcp/hosts/{id}": { auth: "door" },
|
|
125
|
+
"POST /system/webext/pair": { control: "never" },
|
|
126
|
+
"POST /system/webext/enroll": { auth: "door", control: "never" },
|
|
127
|
+
"GET /system/webext": { control: "never" },
|
|
128
|
+
"DELETE /system/webext/{id}": { control: "never" },
|
|
129
|
+
"GET /system/webext/connect": { auth: "door", beforeBoot: true, control: "never" },
|
|
130
|
+
"POST /mcp/webext/{id}": { auth: "door" },
|
|
131
|
+
"GET /mcp/webext/{id}": { auth: "door" },
|
|
132
|
+
"DELETE /mcp/webext/{id}": { auth: "door" },
|
|
133
|
+
"POST /system/runners/pair": { control: "never" },
|
|
134
|
+
"POST /system/runners/enroll": { auth: "door", control: "never" },
|
|
135
|
+
"GET /system/runners": { control: "never" },
|
|
136
|
+
"DELETE /system/runners/{id}": { control: "never" },
|
|
137
|
+
"GET /system/runners/connect": { auth: "door", beforeBoot: true, control: "never" },
|
|
138
|
+
// A turn's own browser router, carrying the per-boot browser bridge token.
|
|
139
|
+
"POST /system/browser/prepare": { auth: "door", control: "never" },
|
|
140
|
+
// A connected browser's credential doors, on its durable token: a sign-in moves in (`session`) or out (`lend`).
|
|
141
|
+
"POST /system/webext/session": { auth: "door", control: "never" },
|
|
142
|
+
"POST /system/webext/lend": { auth: "door", control: "never" },
|
|
143
|
+
"POST /system/runners/{id}/definition/sync": { control: "never" },
|
|
144
|
+
// A runner's git door and credential doors, each on the runner's own bearer.
|
|
145
|
+
"GET /system/runners/git/{repo}/info/refs": { auth: "door", control: "never" },
|
|
146
|
+
"POST /system/runners/git/{repo}/git-upload-pack": { auth: "door", control: "never" },
|
|
147
|
+
"POST /system/runners/git/{repo}/git-receive-pack": { auth: "door", control: "never" },
|
|
148
|
+
"POST /system/runners/credentials": { auth: "door", control: "never" },
|
|
149
|
+
"POST /system/runners/credentials/refresh": { auth: "door", control: "never" },
|
|
150
|
+
[`ALL ${runnerTranslatorPath}/*` as const]: { auth: "door", control: "never" },
|
|
151
|
+
"POST /system/control/tokens": { control: "never" },
|
|
152
|
+
"GET /system/control/tokens": { control: "never" },
|
|
153
|
+
"DELETE /system/control/tokens/{id}": { control: "never" },
|
|
154
|
+
// One's own passkeys are identity, like staying signed in; the policy and recovery codes are ownership's.
|
|
155
|
+
"GET /system/passkeys": { guest: true, control: "never" },
|
|
156
|
+
"POST /system/passkeys/register/options": { floor: "viewer", guest: true, enrolment: true, control: "never" },
|
|
157
|
+
"POST /system/passkeys/register": { floor: "viewer", guest: true, enrolment: true, control: "never" },
|
|
158
|
+
// The assertion has no bearer yet, since it is how one is minted.
|
|
159
|
+
"POST /system/passkeys/assert/options": { auth: "door", beforeBoot: true, control: "never" },
|
|
160
|
+
"POST /system/passkeys/assert": { auth: "door", beforeBoot: true, control: "never" },
|
|
161
|
+
"POST /system/passkeys/policy": { control: "never" },
|
|
162
|
+
"POST /system/passkeys/recovery": { control: "never" },
|
|
163
|
+
// One's own passkey; the handler holds another member's to the owner.
|
|
164
|
+
"DELETE /system/passkeys/{id}": { floor: "viewer", guest: true, control: "never" },
|
|
165
|
+
// Checks its own bearer, since the require-passkey policy would otherwise hold out the owner it exists for.
|
|
166
|
+
"POST /system/session/recover": { auth: "door", beforeBoot: true, control: "never" },
|
|
167
|
+
"POST /system/sessions/revoke": { control: "never" },
|
|
168
|
+
// Stays repeatable after a partial attempt; the handler does its own owner check.
|
|
169
|
+
"POST /system/access/disable": { auth: "door", control: "never" },
|
|
170
|
+
// The desktop-sync agent: redeems a one-time pairing, and later revokes with its own token.
|
|
171
|
+
"POST /system/authorized-key": { auth: "door", control: "never" },
|
|
172
|
+
"GET /system/sync": { control: "never" },
|
|
173
|
+
// The sync agent's own machine report, the daemon's only view of SYNC_DIR.
|
|
174
|
+
"POST /system/sync/report": { sync: "poll", control: "never" },
|
|
175
|
+
"DELETE /system/authorized-key": { auth: "door", control: "never" },
|
|
176
|
+
// The owner revoking one machine is no door: it goes through the session middleware.
|
|
177
|
+
"DELETE /system/authorized-key/{machine}": { control: "never" },
|
|
178
|
+
} as const satisfies Readonly<Record<`${"GET" | "POST" | "PUT" | "DELETE" | "ALL"} /${string}`, RouteMeta>>;
|
|
179
|
+
|
|
180
|
+
export type RawRouteKey = keyof typeof RAW_ROUTES;
|
|
181
|
+
|
|
182
|
+
// A raw route's path, for a caller that builds a URL to it rather than registering it.
|
|
183
|
+
export const rawRoutePath = (key: RawRouteKey): string => key.slice(key.indexOf(" ") + 1);
|
|
184
|
+
|
|
185
|
+
// The table as routes of their own, each named by its key, in registration order.
|
|
186
|
+
export const RAW_ROUTE_LIST: readonly (ContractRoute & { readonly name: RawRouteKey })[] = (Object.keys(RAW_ROUTES) as RawRouteKey[]).map((name) => ({
|
|
187
|
+
name,
|
|
188
|
+
method: name.slice(0, name.indexOf(" ")),
|
|
189
|
+
path: rawRoutePath(name),
|
|
190
|
+
meta: RAW_ROUTES[name],
|
|
191
|
+
}));
|