@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.
Files changed (165) hide show
  1. package/dist/contracts/activity.contract.d.ts.map +1 -1
  2. package/dist/contracts/activity.contract.js +17 -2
  3. package/dist/contracts/activity.contract.js.map +1 -1
  4. package/dist/contracts/agent.contract.d.ts.map +1 -1
  5. package/dist/contracts/agent.contract.js +71 -8
  6. package/dist/contracts/agent.contract.js.map +1 -1
  7. package/dist/contracts/agents.contract.d.ts +1 -0
  8. package/dist/contracts/agents.contract.d.ts.map +1 -1
  9. package/dist/contracts/agents.contract.js +164 -19
  10. package/dist/contracts/agents.contract.js.map +1 -1
  11. package/dist/contracts/automations.contract.d.ts.map +1 -1
  12. package/dist/contracts/automations.contract.js +78 -9
  13. package/dist/contracts/automations.contract.js.map +1 -1
  14. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  15. package/dist/contracts/capabilities.contract.js +98 -11
  16. package/dist/contracts/capabilities.contract.js.map +1 -1
  17. package/dist/contracts/chores.contract.d.ts.map +1 -1
  18. package/dist/contracts/chores.contract.js +26 -3
  19. package/dist/contracts/chores.contract.js.map +1 -1
  20. package/dist/contracts/ci.contract.d.ts.map +1 -1
  21. package/dist/contracts/ci.contract.js +52 -6
  22. package/dist/contracts/ci.contract.js.map +1 -1
  23. package/dist/contracts/claude.contract.d.ts.map +1 -1
  24. package/dist/contracts/claude.contract.js +44 -5
  25. package/dist/contracts/claude.contract.js.map +1 -1
  26. package/dist/contracts/drafts.contract.d.ts.map +1 -1
  27. package/dist/contracts/drafts.contract.js +26 -3
  28. package/dist/contracts/drafts.contract.js.map +1 -1
  29. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  30. package/dist/contracts/endpoints.contract.js +17 -2
  31. package/dist/contracts/endpoints.contract.js.map +1 -1
  32. package/dist/contracts/exit.contract.d.ts.map +1 -1
  33. package/dist/contracts/exit.contract.js +62 -7
  34. package/dist/contracts/exit.contract.js.map +1 -1
  35. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  36. package/dist/contracts/extensions.contract.js +124 -15
  37. package/dist/contracts/extensions.contract.js.map +1 -1
  38. package/dist/contracts/git.contract.d.ts.map +1 -1
  39. package/dist/contracts/git.contract.js +384 -43
  40. package/dist/contracts/git.contract.js.map +1 -1
  41. package/dist/contracts/grok.contract.d.ts.map +1 -1
  42. package/dist/contracts/grok.contract.js +25 -3
  43. package/dist/contracts/grok.contract.js.map +1 -1
  44. package/dist/contracts/history.contract.d.ts.map +1 -1
  45. package/dist/contracts/history.contract.js +35 -4
  46. package/dist/contracts/history.contract.js.map +1 -1
  47. package/dist/contracts/intentic.contract.d.ts.map +1 -1
  48. package/dist/contracts/intentic.contract.js +25 -3
  49. package/dist/contracts/intentic.contract.js.map +1 -1
  50. package/dist/contracts/inventory.contract.d.ts.map +1 -1
  51. package/dist/contracts/inventory.contract.js +26 -3
  52. package/dist/contracts/inventory.contract.js.map +1 -1
  53. package/dist/contracts/logs.contract.d.ts.map +1 -1
  54. package/dist/contracts/logs.contract.js +17 -2
  55. package/dist/contracts/logs.contract.js.map +1 -1
  56. package/dist/contracts/loops.contract.d.ts.map +1 -1
  57. package/dist/contracts/loops.contract.js +52 -6
  58. package/dist/contracts/loops.contract.js.map +1 -1
  59. package/dist/contracts/panels.contract.d.ts.map +1 -1
  60. package/dist/contracts/panels.contract.js +26 -3
  61. package/dist/contracts/panels.contract.js.map +1 -1
  62. package/dist/contracts/personas.contract.d.ts.map +1 -1
  63. package/dist/contracts/personas.contract.js +71 -8
  64. package/dist/contracts/personas.contract.js.map +1 -1
  65. package/dist/contracts/ports.contract.d.ts.map +1 -1
  66. package/dist/contracts/ports.contract.js +26 -3
  67. package/dist/contracts/ports.contract.js.map +1 -1
  68. package/dist/contracts/prepush.contract.d.ts.map +1 -1
  69. package/dist/contracts/prepush.contract.js +24 -3
  70. package/dist/contracts/prepush.contract.js.map +1 -1
  71. package/dist/contracts/providers.contract.d.ts.map +1 -1
  72. package/dist/contracts/providers.contract.js +9 -1
  73. package/dist/contracts/providers.contract.js.map +1 -1
  74. package/dist/contracts/public.contract.d.ts.map +1 -1
  75. package/dist/contracts/public.contract.js +26 -3
  76. package/dist/contracts/public.contract.js.map +1 -1
  77. package/dist/contracts/push.contract.d.ts.map +1 -1
  78. package/dist/contracts/push.contract.js +35 -4
  79. package/dist/contracts/push.contract.js.map +1 -1
  80. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  81. package/dist/contracts/secrets.contract.js +43 -5
  82. package/dist/contracts/secrets.contract.js.map +1 -1
  83. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  84. package/dist/contracts/sessions.contract.js +15 -2
  85. package/dist/contracts/sessions.contract.js.map +1 -1
  86. package/dist/contracts/settings.contract.d.ts.map +1 -1
  87. package/dist/contracts/settings.contract.js +43 -5
  88. package/dist/contracts/settings.contract.js.map +1 -1
  89. package/dist/contracts/share.contract.d.ts.map +1 -1
  90. package/dist/contracts/share.contract.js +35 -4
  91. package/dist/contracts/share.contract.js.map +1 -1
  92. package/dist/contracts/skills.contract.d.ts.map +1 -1
  93. package/dist/contracts/skills.contract.js +35 -4
  94. package/dist/contracts/skills.contract.js.map +1 -1
  95. package/dist/contracts/system.contract.d.ts.map +1 -1
  96. package/dist/contracts/system.contract.js +107 -14
  97. package/dist/contracts/system.contract.js.map +1 -1
  98. package/dist/contracts/translator.contract.d.ts.map +1 -1
  99. package/dist/contracts/translator.contract.js +29 -4
  100. package/dist/contracts/translator.contract.js.map +1 -1
  101. package/dist/contracts/usage.contract.d.ts.map +1 -1
  102. package/dist/contracts/usage.contract.js +9 -1
  103. package/dist/contracts/usage.contract.js.map +1 -1
  104. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  105. package/dist/contracts/vpn.contract.js +32 -4
  106. package/dist/contracts/vpn.contract.js.map +1 -1
  107. package/dist/contracts/workflows.contract.d.ts.map +1 -1
  108. package/dist/contracts/workflows.contract.js +70 -8
  109. package/dist/contracts/workflows.contract.js.map +1 -1
  110. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  111. package/dist/contracts/workspace.contract.js +216 -25
  112. package/dist/contracts/workspace.contract.js.map +1 -1
  113. package/dist/events.d.ts.map +1 -1
  114. package/dist/events.js +179 -88
  115. package/dist/events.js.map +1 -1
  116. package/dist/history-state.d.ts.map +1 -1
  117. package/dist/history-state.js +1 -0
  118. package/dist/history-state.js.map +1 -1
  119. package/dist/index.d.ts +1 -0
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/schemas.d.ts +1 -0
  122. package/dist/schemas.d.ts.map +1 -1
  123. package/dist/schemas.js +2856 -1276
  124. package/dist/schemas.js.map +1 -1
  125. package/package.json +4 -4
  126. package/src/contracts/activity.contract.ts +18 -2
  127. package/src/contracts/agent.contract.ts +78 -8
  128. package/src/contracts/agents.contract.ts +180 -19
  129. package/src/contracts/automations.contract.ts +80 -9
  130. package/src/contracts/capabilities.contract.ts +106 -11
  131. package/src/contracts/chores.contract.ts +29 -3
  132. package/src/contracts/ci.contract.ts +55 -6
  133. package/src/contracts/claude.contract.ts +47 -5
  134. package/src/contracts/drafts.contract.ts +26 -3
  135. package/src/contracts/endpoints.contract.ts +19 -2
  136. package/src/contracts/exit.contract.ts +69 -7
  137. package/src/contracts/extensions.contract.ts +134 -15
  138. package/src/contracts/git.contract.ts +421 -43
  139. package/src/contracts/grok.contract.ts +26 -3
  140. package/src/contracts/history.contract.ts +37 -4
  141. package/src/contracts/intentic.contract.ts +28 -3
  142. package/src/contracts/inventory.contract.ts +27 -3
  143. package/src/contracts/logs.contract.ts +18 -2
  144. package/src/contracts/loops.contract.ts +58 -6
  145. package/src/contracts/panels.contract.ts +26 -3
  146. package/src/contracts/personas.contract.ts +77 -8
  147. package/src/contracts/ports.contract.ts +27 -3
  148. package/src/contracts/prepush.contract.ts +26 -3
  149. package/src/contracts/providers.contract.ts +10 -1
  150. package/src/contracts/public.contract.ts +29 -3
  151. package/src/contracts/push.contract.ts +37 -4
  152. package/src/contracts/secrets.contract.ts +46 -5
  153. package/src/contracts/sessions.contract.ts +16 -2
  154. package/src/contracts/settings.contract.ts +46 -5
  155. package/src/contracts/share.contract.ts +37 -4
  156. package/src/contracts/skills.contract.ts +39 -4
  157. package/src/contracts/system.contract.ts +119 -14
  158. package/src/contracts/translator.contract.ts +32 -4
  159. package/src/contracts/usage.contract.ts +10 -1
  160. package/src/contracts/vpn.contract.ts +35 -4
  161. package/src/contracts/workflows.contract.ts +77 -8
  162. package/src/contracts/workspace.contract.ts +231 -25
  163. package/src/events.ts +207 -88
  164. package/src/history-state.ts +6 -0
  165. package/src/schemas.ts +3506 -1260
@@ -13,11 +13,37 @@ import { ChoreLedgerWriteSchema, ChoreProbeRequestSchema, ChoresReportSchema, Ok
13
13
  export const choresContract = {
14
14
  // Every repo's standing evidence in one read: cached probe results (with their age and state), the cheap
15
15
  // resident signals, the ledger, and the daemon's node version. The rail badge polls this; so does the panel.
16
- list: oc.route({ method: "GET", path: "/chores" }).output(ChoresReportSchema),
16
+ list: oc
17
+ .route({
18
+ method: "GET",
19
+ path: "/chores",
20
+ summary: "What maintenance the repos are asking for",
21
+ description:
22
+ "Every repo's standing evidence in one read: what the last measurement found and how old it is, the cheap signals that are always current, and what has already been decided about each.",
23
+ })
24
+ .output(ChoresReportSchema),
17
25
  // Re-run one repo's probe now, ignoring its TTL, the panel's per-probe refresh. An ack: the runner works in
18
26
  // the background and the result arrives on the next `list`, because a jscpd sweep outlives any sane request.
19
- probe: oc.route({ method: "POST", path: "/chores/probe" }).input(ChoreProbeRequestSchema).output(OkSchema),
27
+ probe: oc
28
+ .route({
29
+ method: "POST",
30
+ path: "/chores/probe",
31
+ summary: "Measure one repo again now",
32
+ description:
33
+ "Re-runs a single check without waiting for it to go stale. Answers immediately: the work happens in the background and the result turns up in the next read, because some of these sweeps outlive any sane request.",
34
+ })
35
+ .input(ChoreProbeRequestSchema)
36
+ .output(OkSchema),
20
37
  // Record what a chore turn concluded, or snooze one. Upsert by repo+chore: a chore has one current verdict,
21
38
  // and a growing history of "we looked at this and it was fine" is not something any reader wants paged.
22
- record: oc.route({ method: "POST", path: "/chores/ledger" }).input(ChoreLedgerWriteSchema).output(OkSchema),
39
+ record: oc
40
+ .route({
41
+ method: "POST",
42
+ path: "/chores/ledger",
43
+ summary: "Record a verdict, or snooze one",
44
+ description:
45
+ "Writes what somebody concluded about one repo's chore, replacing the previous verdict. A chore has one current answer, not a growing pile of times it was fine.",
46
+ })
47
+ .input(ChoreLedgerWriteSchema)
48
+ .output(OkSchema),
23
49
  };
@@ -15,13 +15,62 @@ import {
15
15
  // (/ci/webhook/:host) is a plain Hono route, vendors can't do Google ID tokens, so it lives outside this
16
16
  // contract, like /automations/{id}/fire.
17
17
  export const ciContract = {
18
- runs: oc.route({ method: "GET", path: "/ci/runs" }).output(CiRunsResponseSchema),
19
- rerun: oc.route({ method: "POST", path: "/ci/runs/rerun" }).input(CiRunParamSchema).output(OkSchema),
20
- cancel: oc.route({ method: "POST", path: "/ci/runs/cancel" }).input(CiRunParamSchema).output(OkSchema),
21
- jobs: oc.route({ method: "POST", path: "/ci/runs/jobs" }).input(CiRunParamSchema).output(CiJobsResponseSchema),
22
- fix: oc.route({ method: "POST", path: "/ci/fix" }).input(CiFixParamSchema).output(CiFixResponseSchema),
18
+ runs: oc
19
+ .route({
20
+ method: "GET",
21
+ path: "/ci/runs",
22
+ summary: "Pipeline runs across the repos",
23
+ description:
24
+ "What the forges are reporting for every workspace repo that has a remote, served from a cache and filled in on demand. Repos whose notifications are not wired up say so.",
25
+ })
26
+ .output(CiRunsResponseSchema),
27
+ rerun: oc
28
+ .route({
29
+ method: "POST",
30
+ path: "/ci/runs/rerun",
31
+ summary: "Run a pipeline again",
32
+ description: "Asks the forge to re-run one pipeline. The daemon only passes the request along.",
33
+ })
34
+ .input(CiRunParamSchema)
35
+ .output(OkSchema),
36
+ cancel: oc
37
+ .route({
38
+ method: "POST",
39
+ path: "/ci/runs/cancel",
40
+ summary: "Cancel a pipeline run",
41
+ description: "Asks the forge to stop a run in progress.",
42
+ })
43
+ .input(CiRunParamSchema)
44
+ .output(OkSchema),
45
+ jobs: oc
46
+ .route({
47
+ method: "POST",
48
+ path: "/ci/runs/jobs",
49
+ summary: "The steps inside one pipeline run",
50
+ description: "Each job in a run with its outcome, which is where you look to find out what actually broke.",
51
+ })
52
+ .input(CiRunParamSchema)
53
+ .output(CiJobsResponseSchema),
54
+ fix: oc
55
+ .route({
56
+ method: "POST",
57
+ path: "/ci/fix",
58
+ summary: "Put an agent on a broken pipeline",
59
+ description:
60
+ "Opens a fresh isolated conversation already holding the failure: which job, which repo, what it said. The answer names the conversation so you can open it.",
61
+ })
62
+ .input(CiFixParamSchema)
63
+ .output(CiFixResponseSchema),
23
64
  // "I have looked at the pipelines", what silences the rail badge for breakages already read. No input:
24
65
  // the surface is read as a whole, and the daemon stamps its own clock so a skewed browser can't mark
25
66
  // future failures as already seen.
26
- seen: oc.route({ method: "POST", path: "/ci/seen" }).output(CiSeenResponseSchema),
67
+ seen: oc
68
+ .route({
69
+ method: "POST",
70
+ path: "/ci/seen",
71
+ summary: "Mark the pipelines as read",
72
+ description:
73
+ "Silences the badge for breakages already looked at. Takes nothing, because the view is read as a whole, and the daemon stamps its own clock so a browser with the wrong time cannot mark future failures as already seen.",
74
+ })
75
+ .output(CiSeenResponseSchema),
27
76
  };
@@ -19,11 +19,53 @@ import {
19
19
  // shared /providers/{provider}/models route (providers.contract.ts). What is left is what is genuinely Claude's
20
20
  //, an account handshake no other provider has.
21
21
  export const claudeContract = {
22
- start: oc.route({ method: "POST", path: "/claude/oauth/start" }).output(AuthorizeChallengeSchema),
23
- exchange: oc.route({ method: "POST", path: "/claude/oauth/exchange" }).input(OauthExchangeSchema).output(OauthAccountSchema),
22
+ start: oc
23
+ .route({
24
+ method: "POST",
25
+ path: "/claude/oauth/start",
26
+ summary: "Begin connecting a Claude account",
27
+ description:
28
+ "Hands back the address to send somebody to, and the proof this sandbox will need to finish the exchange. The sandbox holds the credential afterwards, not the browser.",
29
+ })
30
+ .output(AuthorizeChallengeSchema),
31
+ exchange: oc
32
+ .route({
33
+ method: "POST",
34
+ path: "/claude/oauth/exchange",
35
+ summary: "Finish connecting a Claude account",
36
+ description:
37
+ "Trades the code from the sign-in for stored tokens and answers with the account it just connected. A sandbox can hold several Claude accounts side by side.",
38
+ })
39
+ .input(OauthExchangeSchema)
40
+ .output(OauthAccountSchema),
24
41
  // Each account carries its plan-limit reading. `force` re-measures before answering, see
25
42
  // AccountListQuerySchema, and USAGE_WAIT_MS in claude.routes.ts for what an ordinary read waits.
26
- accounts: oc.route({ method: "GET", path: "/claude/accounts" }).input(AccountListQuerySchema).output(OauthAccountListSchema),
27
- rename: oc.route({ method: "POST", path: "/claude/account/rename" }).input(AccountRenameSchema).output(OauthAccountSchema),
28
- disconnect: oc.route({ method: "POST", path: "/claude/account/disconnect" }).input(AccountIdSchema).output(OkSchema),
43
+ accounts: oc
44
+ .route({
45
+ method: "GET",
46
+ path: "/claude/accounts",
47
+ summary: "Connected Claude accounts",
48
+ description:
49
+ "Each connected account with how full its plan limits were when last measured. Ask for a fresh measurement and it takes one before answering, which is slower.",
50
+ })
51
+ .input(AccountListQuerySchema)
52
+ .output(OauthAccountListSchema),
53
+ rename: oc
54
+ .route({
55
+ method: "POST",
56
+ path: "/claude/account/rename",
57
+ summary: "Rename a Claude account",
58
+ description: "Changes the label one account shows under, so several are tellable apart.",
59
+ })
60
+ .input(AccountRenameSchema)
61
+ .output(OauthAccountSchema),
62
+ disconnect: oc
63
+ .route({
64
+ method: "POST",
65
+ path: "/claude/account/disconnect",
66
+ summary: "Disconnect a Claude account",
67
+ description: "Clears the stored tokens for one account. The others stay connected.",
68
+ })
69
+ .input(AccountIdSchema)
70
+ .output(OkSchema),
29
71
  };
@@ -5,7 +5,30 @@ import { DraftIdParamSchema, DraftsListSchema, DraftSummarySchema, OkSchema } fr
5
5
  // directly, these routes are the OWNER's side: `list` is the approval inbox, `upsert` covers approve / edit /
6
6
  // retry (all a plain re-post with a field changed, like the automations enabled toggle), `remove` is reject.
7
7
  export const draftsContract = {
8
- list: oc.route({ method: "GET", path: "/drafts" }).output(DraftsListSchema),
9
- upsert: oc.route({ method: "POST", path: "/drafts" }).input(DraftSummarySchema).output(OkSchema),
10
- remove: oc.route({ method: "DELETE", path: "/drafts/{id}" }).input(DraftIdParamSchema).output(OkSchema),
8
+ list: oc
9
+ .route({
10
+ method: "GET",
11
+ path: "/drafts",
12
+ summary: "Posts waiting for your approval",
13
+ description: "The queue of things an agent has written and would like to publish. Nothing here has gone anywhere yet.",
14
+ })
15
+ .output(DraftsListSchema),
16
+ upsert: oc
17
+ .route({
18
+ method: "POST",
19
+ path: "/drafts",
20
+ summary: "Approve, edit or retry a draft",
21
+ description: "All three are the same act with a different field changed, so they share one call. Send the draft back as you want it.",
22
+ })
23
+ .input(DraftSummarySchema)
24
+ .output(OkSchema),
25
+ remove: oc
26
+ .route({
27
+ method: "DELETE",
28
+ path: "/drafts/{id}",
29
+ summary: "Reject a draft",
30
+ description: "Throws one away unposted.",
31
+ })
32
+ .input(DraftIdParamSchema)
33
+ .output(OkSchema),
11
34
  };
@@ -44,6 +44,23 @@ export const TrialStatusSchema = z.object({
44
44
  export type TrialStatusResponse = z.infer<typeof TrialStatusSchema>;
45
45
 
46
46
  export const endpointsContract = {
47
- models: oc.route({ method: "GET", path: "/endpoints/{id}/models" }).input(CapabilityIdParamSchema).output(ModelsSchema),
48
- trial: oc.route({ method: "GET", path: "/endpoints/trial/status" }).output(TrialStatusSchema),
47
+ models: oc
48
+ .route({
49
+ method: "GET",
50
+ path: "/endpoints/{id}/models",
51
+ summary: "Models a connected server offers",
52
+ description:
53
+ "Asks one configured model server what it serves. There is no built-in list and no fallback: what a server offers is knowable only by asking it, so an empty answer is the honest report that we could not.",
54
+ })
55
+ .input(CapabilityIdParamSchema)
56
+ .output(ModelsSchema),
57
+ trial: oc
58
+ .route({
59
+ method: "GET",
60
+ path: "/endpoints/trial/status",
61
+ summary: "What is left of the free trial",
62
+ description:
63
+ "The allowance, what has been used, when it resets, and which model actually answered the last message. Not being available is the ordinary answer rather than a failure: most sandboxes run against a platform that offers no trial at all.",
64
+ })
65
+ .output(TrialStatusSchema),
49
66
  };
@@ -18,25 +18,87 @@ export const exitContract = {
18
18
  // Every configured exit with its live state, where it was asked to come out and where it actually does.
19
19
  // Drives the Status card, the browser account picker and `geo list` (the CLI is `geo`: `exit` is a shell
20
20
  // builtin, so a binary of that name is unreachable from a command line).
21
- list: oc.route({ method: "GET", path: "/exit" }).output(ExitListSchema),
21
+ list: oc
22
+ .route({
23
+ method: "GET",
24
+ path: "/exit",
25
+ summary: "Ways to come out somewhere else",
26
+ description:
27
+ "Every configured exit with its live state, the country it was asked to appear in, and the country it actually appears in. Those last two disagreeing is the whole reason this reports both.",
28
+ })
29
+ .output(ExitListSchema),
22
30
  // What this exit can reach, ranked by how much capacity is actually there. Live from the provider when it
23
31
  // answers (Tor's directory, VPN Gate's CSV, the pasted confs), from the baked fallback when it does not,
24
32
  // and `live` says which. This is what auto-fills the country picker instead of a user hunting hostnames.
25
- countries: oc.route({ method: "GET", path: "/exit/{id}/countries" }).input(ExitIdParamSchema).output(ExitCountriesSchema),
33
+ countries: oc
34
+ .route({
35
+ method: "GET",
36
+ path: "/exit/{id}/countries",
37
+ summary: "Countries one exit can reach",
38
+ description:
39
+ "Where this exit can put you, ranked by how much capacity is really there. Asked of the provider when it answers and taken from a built-in list when it does not, and the answer says which of those you got.",
40
+ })
41
+ .input(ExitIdParamSchema)
42
+ .output(ExitCountriesSchema),
26
43
  // Bring the exit up at its stored country. Streams, because a first start pulls a catalog, brings up a
27
44
  // tunnel and then verifies the address, which is tens of seconds on the free providers and can fail at
28
45
  // each step with something the user has to read. Idempotent: starting an up exit reports it and stops.
29
- start: oc.route({ method: "POST", path: "/exit/{id}/start" }).input(ExitIdParamSchema).output(eventIterator(IntenticLineSchema)),
46
+ start: oc
47
+ .route({
48
+ method: "POST",
49
+ path: "/exit/{id}/start",
50
+ summary: "Bring an exit up",
51
+ description:
52
+ "Starts the exit in the country it was configured for. Streamed, because a first start fetches a catalogue, raises a tunnel and then checks the address, which takes tens of seconds on the free providers and can fail at each step with something worth reading. Starting one that is already up simply says so.",
53
+ })
54
+ .input(ExitIdParamSchema)
55
+ .output(eventIterator(IntenticLineSchema)),
30
56
  // Move to another country, starting the exit first if it was down. Streams for the same reason as start,
31
57
  // and THROWS when the observed country does not end up matching: a switch that silently left traffic where
32
58
  // it was is the one failure mode this whole feature exists to make impossible.
33
- use: oc.route({ method: "POST", path: "/exit/{id}/use" }).input(ExitUseInputSchema).output(eventIterator(IntenticLineSchema)),
59
+ use: oc
60
+ .route({
61
+ method: "POST",
62
+ path: "/exit/{id}/use",
63
+ summary: "Move to another country",
64
+ description:
65
+ "Switches the exit's country, starting it first if it was down. It ends by checking where the world actually sees you and fails if that does not match what you asked for. A switch that quietly left your traffic where it was is the exact failure this whole feature exists to rule out.",
66
+ })
67
+ .input(ExitUseInputSchema)
68
+ .output(eventIterator(IntenticLineSchema)),
34
69
  // A different address in the SAME country. Cheap on tor (a control-port signal), a re-dial to another
35
70
  // server on the rest. Fails when the address does not actually change, which on a small pool it can't.
36
- rotate: oc.route({ method: "POST", path: "/exit/{id}/rotate" }).input(ExitIdParamSchema).output(eventIterator(IntenticLineSchema)),
71
+ rotate: oc
72
+ .route({
73
+ method: "POST",
74
+ path: "/exit/{id}/rotate",
75
+ summary: "Take a different address, same country",
76
+ description:
77
+ "Swaps to another address in the country you are already in. Fails if the address does not actually change, which on a small pool it sometimes cannot.",
78
+ })
79
+ .input(ExitIdParamSchema)
80
+ .output(eventIterator(IntenticLineSchema)),
37
81
  // What the world sees through this exit right now. Cheap, unstreamed, and the honest answer to "am I
38
82
  // actually in Germany", which is the question every other route here is judged against.
39
- check: oc.route({ method: "POST", path: "/exit/{id}/check" }).input(ExitIdParamSchema).output(ExitObservationSchema),
83
+ check: oc
84
+ .route({
85
+ method: "POST",
86
+ path: "/exit/{id}/check",
87
+ summary: "Where the world sees you right now",
88
+ description:
89
+ "Looks up the address and country as seen through this exit. Cheap, and the honest answer to whether you are really where you meant to be, which is what every other call here is judged against.",
90
+ })
91
+ .input(ExitIdParamSchema)
92
+ .output(ExitObservationSchema),
40
93
  // Take it down. Tolerates an already-down exit: "make it not be up" is the contract, not "it was up".
41
- stop: oc.route({ method: "POST", path: "/exit/{id}/stop" }).input(ExitIdParamSchema).output(OkSchema),
94
+ stop: oc
95
+ .route({
96
+ method: "POST",
97
+ path: "/exit/{id}/stop",
98
+ summary: "Take an exit down",
99
+ description:
100
+ "Shuts the exit off. One that was already down is fine: the promise is that it is not up afterwards, not that it was up before.",
101
+ })
102
+ .input(ExitIdParamSchema)
103
+ .output(OkSchema),
42
104
  };
@@ -24,25 +24,86 @@ import {
24
24
  // `settings`/`setSettings` carry the extension's own contributes.settings values; keys the manifest never
25
25
  // declared are refused, the same honesty rule the host applies to runtime view/command registrations.
26
26
  export const extensionsContract = {
27
- list: oc.route({ method: "GET", path: "/extensions" }).output(ExtensionsListSchema),
27
+ list: oc
28
+ .route({
29
+ method: "GET",
30
+ path: "/extensions",
31
+ summary: "Installed extensions",
32
+ description:
33
+ "Every extension installed here, resolved to the manifest the owner approved, which is what the app boots its extension host from. The code itself is served separately, because raw script bytes are not a JSON answer.",
34
+ })
35
+ .output(ExtensionsListSchema),
28
36
  // Author a new extension in place: writes a running one into .intentic/config/workspace-extensions/<name>/. The only
29
37
  // creating route here, and it exists because that directory is otherwise reachable exclusively through an
30
38
  // agent's file tools, which is a fine way to CHANGE an extension and a poor way to meet the idea of one.
31
- create: oc.route({ method: "POST", path: "/extensions/workspace" }).input(WorkspaceExtensionCreateSchema).output(WorkspaceExtensionCreatedSchema),
32
- settings: oc.route({ method: "GET", path: "/extensions/{id}/settings" }).input(CapabilityIdParamSchema).output(ExtensionSettingsSchema),
33
- setSettings: oc.route({ method: "POST", path: "/extensions/{id}/settings" }).input(ExtensionSettingsInputSchema).output(OkSchema),
39
+ create: oc
40
+ .route({
41
+ method: "POST",
42
+ path: "/extensions/workspace",
43
+ summary: "Write a new extension in place",
44
+ description:
45
+ "Scaffolds a working extension into this workspace and installs it. The only call here that creates one, and it exists because that folder is otherwise reachable only through an agent's file tools, which is a fine way to change an extension and a poor way to meet the idea of one.",
46
+ })
47
+ .input(WorkspaceExtensionCreateSchema)
48
+ .output(WorkspaceExtensionCreatedSchema),
49
+ settings: oc
50
+ .route({
51
+ method: "GET",
52
+ path: "/extensions/{id}/settings",
53
+ summary: "An extension's settings",
54
+ description: "The current values for the settings this extension declared it has.",
55
+ })
56
+ .input(CapabilityIdParamSchema)
57
+ .output(ExtensionSettingsSchema),
58
+ setSettings: oc
59
+ .route({
60
+ method: "POST",
61
+ path: "/extensions/{id}/settings",
62
+ summary: "Change an extension's settings",
63
+ description:
64
+ "Writes new values. A key the extension never declared is refused rather than quietly stored, the same honesty rule that governs everything else an extension claims.",
65
+ })
66
+ .input(ExtensionSettingsInputSchema)
67
+ .output(OkSchema),
34
68
  // The owner's on/off switch. Disabling stops the extension's declared processes here and now; its agent
35
69
  // plugin dir and PATH entry are rebuilt per turn, and an `environment` fragment only at the next image
36
70
  // rebuild, the Extensions tab states which of those an extension actually has.
37
- setEnabled: oc.route({ method: "POST", path: "/extensions/{id}/enabled" }).input(ExtensionEnabledInputSchema).output(OkSchema),
71
+ setEnabled: oc
72
+ .route({
73
+ method: "POST",
74
+ path: "/extensions/{id}/enabled",
75
+ summary: "Turn an extension on or off",
76
+ description:
77
+ "The owner's switch. Turning one off stops its background processes at once. What it contributes to an agent's tools is rebuilt at the start of the next turn, and anything it adds to the sandbox image only at the next rebuild.",
78
+ })
79
+ .input(ExtensionEnabledInputSchema)
80
+ .output(OkSchema),
38
81
  // The host reporting which declared routes it just let through. Written by the browser because that is where
39
82
  // the permission gate runs (apiImpl.ts), the daemon sees an extension's traffic as ordinary authenticated
40
83
  // requests and cannot tell which extension, or which declared entry, any of it belongs to.
41
- recordUsage: oc.route({ method: "POST", path: "/extensions/{id}/usage" }).input(ExtensionUsageInputSchema).output(OkSchema),
84
+ recordUsage: oc
85
+ .route({
86
+ method: "POST",
87
+ path: "/extensions/{id}/usage",
88
+ summary: "Record what an extension just used",
89
+ description:
90
+ "Written by the app rather than measured by the daemon, because the permission gate runs in the browser: from the sandbox's side an extension's traffic is indistinguishable from anyone else's. This is how the record of which powers an extension actually exercises gets kept.",
91
+ })
92
+ .input(ExtensionUsageInputSchema)
93
+ .output(OkSchema),
42
94
  /* Whether this extension is fit for somebody else to run, the checks answerable from its files alone. Read
43
95
  * on demand rather than carried on the list: it reads the bundle off disk per extension, and it is looked at
44
96
  * when an author is about to publish, not every time the tab renders. */
45
- readiness: oc.route({ method: "GET", path: "/extensions/{id}/readiness" }).input(CapabilityIdParamSchema).output(ExtensionReadinessSchema),
97
+ readiness: oc
98
+ .route({
99
+ method: "GET",
100
+ path: "/extensions/{id}/readiness",
101
+ summary: "Whether an extension is fit to share",
102
+ description:
103
+ "The checks that can be answered from an extension's own files, for an author about to publish. Read on demand rather than carried on the list, because it reads the code off disk each time.",
104
+ })
105
+ .input(CapabilityIdParamSchema)
106
+ .output(ExtensionReadinessSchema),
46
107
  /* The update lifecycle for a GIT-INSTALLED extension. The list carries what the periodic registry check
47
108
  * found (update/advisory/health per row); these are the verbs around it. `checkUpdates` runs the comparison
48
109
  * now (the tab's "check now"). `updatePreview` stages the offered sha and answers with the version story +
@@ -51,25 +112,83 @@ export const extensionsContract = {
51
112
  * checkout one back), restart, health-watch, on the EXISTING capability config, so a private-source token
52
113
  * survives what a bare re-add would lose. `revert` swaps the kept-previous checkout back. Update and revert
53
114
  * change the code that runs, so like install they are owner-only. */
54
- checkUpdates: oc.route({ method: "POST", path: "/extensions/updates/check" }).output(ExtensionUpdatesCheckedSchema),
115
+ checkUpdates: oc
116
+ .route({
117
+ method: "POST",
118
+ path: "/extensions/updates/check",
119
+ summary: "Look for extension updates now",
120
+ description:
121
+ "Compares every installed extension against its source and reports what is newer, what carries an advisory and what looks unhealthy. This also happens on a schedule; call it to check on demand.",
122
+ })
123
+ .output(ExtensionUpdatesCheckedSchema),
55
124
  updatePreview: oc
56
- .route({ method: "POST", path: "/extensions/{id}/update/preview" })
125
+ .route({
126
+ method: "POST",
127
+ path: "/extensions/{id}/update/preview",
128
+ summary: "What an update would change",
129
+ description:
130
+ "The read before the click: which versions are involved and exactly which powers the new code asks for that the running one does not. Costs one throwaway copy of the source, the same as browsing a registry entry.",
131
+ })
57
132
  .input(ExtensionUpdateActionSchema)
58
133
  .output(ExtensionUpdatePreviewSchema),
59
134
  applyUpdate: oc
60
- .route({ method: "POST", path: "/extensions/{id}/update" })
135
+ .route({
136
+ method: "POST",
137
+ path: "/extensions/{id}/update",
138
+ summary: "Update an extension",
139
+ description:
140
+ "The whole swap as one transaction: fetch, check, quiet the running one, replace it while keeping the outgoing copy one step back, restart and watch it come up. The existing configuration is kept, so a token for a private source survives what removing and re-adding would lose. Owner only, because it changes what code runs.",
141
+ })
61
142
  .input(ExtensionUpdateActionSchema)
62
143
  .output(ExtensionUpdateAppliedSchema),
63
- revert: oc.route({ method: "POST", path: "/extensions/{id}/revert" }).input(CapabilityIdParamSchema).output(ExtensionUpdateAppliedSchema),
144
+ revert: oc
145
+ .route({
146
+ method: "POST",
147
+ path: "/extensions/{id}/revert",
148
+ summary: "Go back to the previous version",
149
+ description: "Swaps the copy kept from before the last update back into place. Owner only, for the same reason updating is.",
150
+ })
151
+ .input(CapabilityIdParamSchema)
152
+ .output(ExtensionUpdateAppliedSchema),
64
153
  // The owner's standing answer per extension (notify / agent / auto, and the advisory opt-out), see
65
154
  // ExtensionUpdatePolicySchema for what each rung means.
66
- setUpdatePolicy: oc.route({ method: "POST", path: "/extensions/{id}/update-policy" }).input(ExtensionUpdatePolicyInputSchema).output(OkSchema),
155
+ setUpdatePolicy: oc
156
+ .route({
157
+ method: "POST",
158
+ path: "/extensions/{id}/update-policy",
159
+ summary: "How an extension should handle its own updates",
160
+ description:
161
+ "The owner's standing answer for one extension: tell me, have an agent look at it, or just do it. Security advisories can be opted out of separately.",
162
+ })
163
+ .input(ExtensionUpdatePolicyInputSchema)
164
+ .output(OkSchema),
67
165
  // Declared background processes (contributes.processes): tmux-managed through the panel machinery
68
166
  // (session `panel-ext-<id>-<name>`, PORT-assigned, optional tunneled preview route).
69
167
  processStatus: oc
70
- .route({ method: "GET", path: "/extensions/{id}/processes/{name}" })
168
+ .route({
169
+ method: "GET",
170
+ path: "/extensions/{id}/processes/{name}",
171
+ summary: "Whether an extension's background process is up",
172
+ description: "The state of one process an extension declared, with the port it was given and its preview address if it has one.",
173
+ })
71
174
  .input(ExtensionProcessParamSchema)
72
175
  .output(ExtensionProcessStatusSchema),
73
- processStart: oc.route({ method: "POST", path: "/extensions/{id}/processes/{name}/start" }).input(ExtensionProcessParamSchema).output(OkSchema),
74
- processStop: oc.route({ method: "POST", path: "/extensions/{id}/processes/{name}/stop" }).input(ExtensionProcessParamSchema).output(OkSchema),
176
+ processStart: oc
177
+ .route({
178
+ method: "POST",
179
+ path: "/extensions/{id}/processes/{name}/start",
180
+ summary: "Start an extension's background process",
181
+ description: "Brings one of an extension's declared processes up in an attachable terminal.",
182
+ })
183
+ .input(ExtensionProcessParamSchema)
184
+ .output(OkSchema),
185
+ processStop: oc
186
+ .route({
187
+ method: "POST",
188
+ path: "/extensions/{id}/processes/{name}/stop",
189
+ summary: "Stop an extension's background process",
190
+ description: "Shuts one of an extension's declared processes down and frees its port.",
191
+ })
192
+ .input(ExtensionProcessParamSchema)
193
+ .output(OkSchema),
75
194
  };