@intentic/sandbox-contract 1.225.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 (172) hide show
  1. package/dist/agent-catalog.d.ts +2 -0
  2. package/dist/agent-catalog.d.ts.map +1 -1
  3. package/dist/agent-catalog.js +16 -0
  4. package/dist/agent-catalog.js.map +1 -1
  5. package/dist/contracts/activity.contract.d.ts.map +1 -1
  6. package/dist/contracts/activity.contract.js +17 -2
  7. package/dist/contracts/activity.contract.js.map +1 -1
  8. package/dist/contracts/agent.contract.d.ts.map +1 -1
  9. package/dist/contracts/agent.contract.js +71 -8
  10. package/dist/contracts/agent.contract.js.map +1 -1
  11. package/dist/contracts/agents.contract.d.ts +1 -0
  12. package/dist/contracts/agents.contract.d.ts.map +1 -1
  13. package/dist/contracts/agents.contract.js +164 -19
  14. package/dist/contracts/agents.contract.js.map +1 -1
  15. package/dist/contracts/automations.contract.d.ts.map +1 -1
  16. package/dist/contracts/automations.contract.js +78 -9
  17. package/dist/contracts/automations.contract.js.map +1 -1
  18. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  19. package/dist/contracts/capabilities.contract.js +98 -11
  20. package/dist/contracts/capabilities.contract.js.map +1 -1
  21. package/dist/contracts/chores.contract.d.ts.map +1 -1
  22. package/dist/contracts/chores.contract.js +26 -3
  23. package/dist/contracts/chores.contract.js.map +1 -1
  24. package/dist/contracts/ci.contract.d.ts.map +1 -1
  25. package/dist/contracts/ci.contract.js +52 -6
  26. package/dist/contracts/ci.contract.js.map +1 -1
  27. package/dist/contracts/claude.contract.d.ts.map +1 -1
  28. package/dist/contracts/claude.contract.js +44 -5
  29. package/dist/contracts/claude.contract.js.map +1 -1
  30. package/dist/contracts/drafts.contract.d.ts.map +1 -1
  31. package/dist/contracts/drafts.contract.js +26 -3
  32. package/dist/contracts/drafts.contract.js.map +1 -1
  33. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  34. package/dist/contracts/endpoints.contract.js +17 -2
  35. package/dist/contracts/endpoints.contract.js.map +1 -1
  36. package/dist/contracts/exit.contract.d.ts.map +1 -1
  37. package/dist/contracts/exit.contract.js +62 -7
  38. package/dist/contracts/exit.contract.js.map +1 -1
  39. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  40. package/dist/contracts/extensions.contract.js +124 -15
  41. package/dist/contracts/extensions.contract.js.map +1 -1
  42. package/dist/contracts/git.contract.d.ts.map +1 -1
  43. package/dist/contracts/git.contract.js +384 -43
  44. package/dist/contracts/git.contract.js.map +1 -1
  45. package/dist/contracts/grok.contract.d.ts.map +1 -1
  46. package/dist/contracts/grok.contract.js +25 -3
  47. package/dist/contracts/grok.contract.js.map +1 -1
  48. package/dist/contracts/history.contract.d.ts.map +1 -1
  49. package/dist/contracts/history.contract.js +35 -4
  50. package/dist/contracts/history.contract.js.map +1 -1
  51. package/dist/contracts/intentic.contract.d.ts.map +1 -1
  52. package/dist/contracts/intentic.contract.js +25 -3
  53. package/dist/contracts/intentic.contract.js.map +1 -1
  54. package/dist/contracts/inventory.contract.d.ts.map +1 -1
  55. package/dist/contracts/inventory.contract.js +26 -3
  56. package/dist/contracts/inventory.contract.js.map +1 -1
  57. package/dist/contracts/logs.contract.d.ts.map +1 -1
  58. package/dist/contracts/logs.contract.js +17 -2
  59. package/dist/contracts/logs.contract.js.map +1 -1
  60. package/dist/contracts/loops.contract.d.ts.map +1 -1
  61. package/dist/contracts/loops.contract.js +52 -6
  62. package/dist/contracts/loops.contract.js.map +1 -1
  63. package/dist/contracts/panels.contract.d.ts.map +1 -1
  64. package/dist/contracts/panels.contract.js +26 -3
  65. package/dist/contracts/panels.contract.js.map +1 -1
  66. package/dist/contracts/personas.contract.d.ts.map +1 -1
  67. package/dist/contracts/personas.contract.js +71 -8
  68. package/dist/contracts/personas.contract.js.map +1 -1
  69. package/dist/contracts/ports.contract.d.ts.map +1 -1
  70. package/dist/contracts/ports.contract.js +26 -3
  71. package/dist/contracts/ports.contract.js.map +1 -1
  72. package/dist/contracts/prepush.contract.d.ts.map +1 -1
  73. package/dist/contracts/prepush.contract.js +24 -3
  74. package/dist/contracts/prepush.contract.js.map +1 -1
  75. package/dist/contracts/providers.contract.d.ts.map +1 -1
  76. package/dist/contracts/providers.contract.js +9 -1
  77. package/dist/contracts/providers.contract.js.map +1 -1
  78. package/dist/contracts/public.contract.d.ts.map +1 -1
  79. package/dist/contracts/public.contract.js +26 -3
  80. package/dist/contracts/public.contract.js.map +1 -1
  81. package/dist/contracts/push.contract.d.ts.map +1 -1
  82. package/dist/contracts/push.contract.js +35 -4
  83. package/dist/contracts/push.contract.js.map +1 -1
  84. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  85. package/dist/contracts/secrets.contract.js +43 -5
  86. package/dist/contracts/secrets.contract.js.map +1 -1
  87. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  88. package/dist/contracts/sessions.contract.js +15 -2
  89. package/dist/contracts/sessions.contract.js.map +1 -1
  90. package/dist/contracts/settings.contract.d.ts.map +1 -1
  91. package/dist/contracts/settings.contract.js +43 -5
  92. package/dist/contracts/settings.contract.js.map +1 -1
  93. package/dist/contracts/share.contract.d.ts.map +1 -1
  94. package/dist/contracts/share.contract.js +35 -4
  95. package/dist/contracts/share.contract.js.map +1 -1
  96. package/dist/contracts/skills.contract.d.ts.map +1 -1
  97. package/dist/contracts/skills.contract.js +35 -4
  98. package/dist/contracts/skills.contract.js.map +1 -1
  99. package/dist/contracts/system.contract.d.ts.map +1 -1
  100. package/dist/contracts/system.contract.js +107 -14
  101. package/dist/contracts/system.contract.js.map +1 -1
  102. package/dist/contracts/translator.contract.d.ts.map +1 -1
  103. package/dist/contracts/translator.contract.js +29 -4
  104. package/dist/contracts/translator.contract.js.map +1 -1
  105. package/dist/contracts/usage.contract.d.ts.map +1 -1
  106. package/dist/contracts/usage.contract.js +9 -1
  107. package/dist/contracts/usage.contract.js.map +1 -1
  108. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  109. package/dist/contracts/vpn.contract.js +32 -4
  110. package/dist/contracts/vpn.contract.js.map +1 -1
  111. package/dist/contracts/workflows.contract.d.ts.map +1 -1
  112. package/dist/contracts/workflows.contract.js +70 -8
  113. package/dist/contracts/workflows.contract.js.map +1 -1
  114. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  115. package/dist/contracts/workspace.contract.js +216 -25
  116. package/dist/contracts/workspace.contract.js.map +1 -1
  117. package/dist/events.d.ts.map +1 -1
  118. package/dist/events.js +179 -88
  119. package/dist/events.js.map +1 -1
  120. package/dist/history-state.d.ts.map +1 -1
  121. package/dist/history-state.js +1 -0
  122. package/dist/history-state.js.map +1 -1
  123. package/dist/index.d.ts +1 -0
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/schemas.d.ts +1 -0
  126. package/dist/schemas.d.ts.map +1 -1
  127. package/dist/schemas.js +2856 -1276
  128. package/dist/schemas.js.map +1 -1
  129. package/package.json +4 -4
  130. package/src/agent-catalog.test.ts +48 -3
  131. package/src/agent-catalog.ts +88 -0
  132. package/src/capability-ledger.test.ts +21 -2
  133. package/src/contracts/activity.contract.ts +18 -2
  134. package/src/contracts/agent.contract.ts +78 -8
  135. package/src/contracts/agents.contract.ts +180 -19
  136. package/src/contracts/automations.contract.ts +80 -9
  137. package/src/contracts/capabilities.contract.ts +106 -11
  138. package/src/contracts/chores.contract.ts +29 -3
  139. package/src/contracts/ci.contract.ts +55 -6
  140. package/src/contracts/claude.contract.ts +47 -5
  141. package/src/contracts/drafts.contract.ts +26 -3
  142. package/src/contracts/endpoints.contract.ts +19 -2
  143. package/src/contracts/exit.contract.ts +69 -7
  144. package/src/contracts/extensions.contract.ts +134 -15
  145. package/src/contracts/git.contract.ts +421 -43
  146. package/src/contracts/grok.contract.ts +26 -3
  147. package/src/contracts/history.contract.ts +37 -4
  148. package/src/contracts/intentic.contract.ts +28 -3
  149. package/src/contracts/inventory.contract.ts +27 -3
  150. package/src/contracts/logs.contract.ts +18 -2
  151. package/src/contracts/loops.contract.ts +58 -6
  152. package/src/contracts/panels.contract.ts +26 -3
  153. package/src/contracts/personas.contract.ts +77 -8
  154. package/src/contracts/ports.contract.ts +27 -3
  155. package/src/contracts/prepush.contract.ts +26 -3
  156. package/src/contracts/providers.contract.ts +10 -1
  157. package/src/contracts/public.contract.ts +29 -3
  158. package/src/contracts/push.contract.ts +37 -4
  159. package/src/contracts/secrets.contract.ts +46 -5
  160. package/src/contracts/sessions.contract.ts +16 -2
  161. package/src/contracts/settings.contract.ts +46 -5
  162. package/src/contracts/share.contract.ts +37 -4
  163. package/src/contracts/skills.contract.ts +39 -4
  164. package/src/contracts/system.contract.ts +119 -14
  165. package/src/contracts/translator.contract.ts +32 -4
  166. package/src/contracts/usage.contract.ts +10 -1
  167. package/src/contracts/vpn.contract.ts +35 -4
  168. package/src/contracts/workflows.contract.ts +77 -8
  169. package/src/contracts/workspace.contract.ts +231 -25
  170. package/src/events.ts +207 -88
  171. package/src/history-state.ts +6 -0
  172. package/src/schemas.ts +3506 -1260
@@ -43,75 +43,281 @@ export const workspaceContract = {
43
43
  // `agent` names whose copy of the workspace to read (WorkspaceScopeSchema); omitted is the shared /work
44
44
  // tree. Every read route below takes it, so a link into a conversation's own checkout browses as one tree
45
45
  // rather than as one openable file surrounded by the shared one.
46
- tree: oc.route({ method: "GET", path: "/workspace/tree" }).input(WorkspaceScopeSchema).output(WorkspaceTreeSchema),
46
+ tree: oc
47
+ .route({
48
+ method: "GET",
49
+ path: "/workspace/tree",
50
+ summary: "The workspace file tree",
51
+ description:
52
+ "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.",
53
+ })
54
+ .input(WorkspaceScopeSchema)
55
+ .output(WorkspaceTreeSchema),
47
56
  // Lazy-load one directory's children, the tree returns ignored dirs (node_modules, .git, …) without children,
48
57
  // and the client fetches them here on expand so a giant node_modules can't blow the tree walk's entry budget.
49
- children: oc.route({ method: "GET", path: "/workspace/children" }).input(WorkspaceChildrenQuerySchema).output(WorkspaceChildrenSchema),
58
+ children: oc
59
+ .route({
60
+ method: "GET",
61
+ path: "/workspace/children",
62
+ summary: "One folder's contents",
63
+ description:
64
+ "The entries directly inside a single folder. This is how you open a folder the full tree walk deliberately left closed, such as an installed-packages directory with a hundred thousand files in it.",
65
+ })
66
+ .input(WorkspaceChildrenQuerySchema)
67
+ .output(WorkspaceChildrenSchema),
50
68
  // One WINDOW of a file's text (plus the file's total size), never the whole file: the browser reads text
51
69
  // through here, and an unbounded read on an HTTP route is a way for any open log to stall the daemon.
52
- file: oc.route({ method: "GET", path: "/workspace/file" }).input(WorkspaceFileReadQuerySchema).output(WorkspaceFileSchema),
70
+ file: oc
71
+ .route({
72
+ method: "GET",
73
+ path: "/workspace/file",
74
+ summary: "Read part of a text file",
75
+ description:
76
+ "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.",
77
+ })
78
+ .input(WorkspaceFileReadQuerySchema)
79
+ .output(WorkspaceFileSchema),
53
80
  /* The ticket a media element presents to GET /workspace/media (a plain Hono route, like /workspace/raw,
54
81
  * it answers a streamed byte RANGE, which oRPC has no shape for). Minting is here rather than beside it so
55
82
  * it rides the bearer middleware and the contract's route advertisement: a browser can tell whether the
56
83
  * sandbox in front of it can stream video at all, instead of learning it from a 404 mid-playback. */
57
84
  mediaTicket: oc
58
- .route({ method: "POST", path: "/workspace/media-ticket" })
85
+ .route({
86
+ method: "POST",
87
+ path: "/workspace/media-ticket",
88
+ summary: "Get a pass for streaming a media file",
89
+ description:
90
+ "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.",
91
+ })
59
92
  .input(WorkspaceMediaTicketQuerySchema)
60
93
  .output(WorkspaceMediaTicketSchema),
61
94
  // Which file a NAMED reference means, the lookup behind every clickable path in the UI. A path an agent
62
95
  // wrote in prose is often only a suffix of the real one, so it is matched against the workspace tree rather
63
96
  // than trusted as root-relative.
64
- resolve: oc.route({ method: "GET", path: "/workspace/resolve" }).input(WorkspaceResolveQuerySchema).output(WorkspaceResolveSchema),
97
+ resolve: oc
98
+ .route({
99
+ method: "GET",
100
+ path: "/workspace/resolve",
101
+ summary: "Turn a written path into a real file",
102
+ description:
103
+ "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.",
104
+ })
105
+ .input(WorkspaceResolveQuerySchema)
106
+ .output(WorkspaceResolveSchema),
65
107
  // Ranked groups, match-reason tags, freshness, resumable cursor. `mode` narrows to one verb; default is
66
108
  // auto-mode fusion. (Implementation detail: the daemon backs this with a resident in-process iq engine.)
67
- search: oc.route({ method: "GET", path: "/workspace/search" }).input(WorkspaceSearchQuerySchema).output(WorkspaceSearchResultSchema),
109
+ search: oc
110
+ .route({
111
+ method: "GET",
112
+ path: "/workspace/search",
113
+ summary: "Search the code",
114
+ description:
115
+ "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.",
116
+ })
117
+ .input(WorkspaceSearchQuerySchema)
118
+ .output(WorkspaceSearchResultSchema),
68
119
  // One repository's health in numbers: churn × complexity per file, index totals, and the import graph's
69
120
  // top modules, the `hotspots` and `map` rankings the CLI prints, shaped for a panel. Repo-scoped, because
70
121
  // "the codebase" is a repo, not the whole /work drop.
71
- health: oc.route({ method: "GET", path: "/workspace/health" }).input(WorkspaceHealthQuerySchema).output(WorkspaceHealthSchema),
122
+ health: oc
123
+ .route({
124
+ method: "GET",
125
+ path: "/workspace/health",
126
+ summary: "A repo's shape in numbers",
127
+ description:
128
+ "Where one repo's risk sits: the files that change often and are complicated at once, what the index holds, and which modules the rest of the code leans on most. Scoped to a repo, because a codebase is a repo rather than the whole drop.",
129
+ })
130
+ .input(WorkspaceHealthQuerySchema)
131
+ .output(WorkspaceHealthSchema),
72
132
  // Deterministic, no-LLM classification of the dropped workspace into coarse buckets (repositories / documents
73
133
  // / media / archives / other). Read-only proposal: the browser renders it and applies accepted moves via the
74
134
  // existing /workspace/move route, this route never touches the tree.
75
- classify: oc.route({ method: "GET", path: "/workspace/classify" }).output(WorkspaceClassificationSchema),
135
+ classify: oc
136
+ .route({
137
+ method: "GET",
138
+ path: "/workspace/classify",
139
+ summary: "Sort a messy drop into buckets",
140
+ description:
141
+ "Proposes which of the loose things in the workspace are code, documents, media or archives. A read-only suggestion by fixed rules, with no model involved: nothing moves until a caller applies the moves it likes through the move call.",
142
+ })
143
+ .output(WorkspaceClassificationSchema),
76
144
  // Direct file management the browser drives against the /work tree (byte writes go through POST
77
145
  // /workspace/upload). oRPC's OpenAPI codec reads non-GET input from the JSON body, so delete sends {path}
78
146
  // in the body too (not the query), same as the POST routes.
79
- mkdir: oc.route({ method: "POST", path: "/workspace/dir" }).input(WorkspaceDirSchema).output(OkSchema),
80
- delete: oc.route({ method: "DELETE", path: "/workspace/entry" }).input(WorkspaceFileQuerySchema).output(OkSchema),
81
- move: oc.route({ method: "POST", path: "/workspace/move" }).input(WorkspaceMoveSchema).output(OkSchema),
82
- copy: oc.route({ method: "POST", path: "/workspace/copy" }).input(WorkspaceMoveSchema).output(OkSchema),
147
+ mkdir: oc
148
+ .route({
149
+ method: "POST",
150
+ path: "/workspace/dir",
151
+ summary: "Create a folder",
152
+ description: "Makes a folder, and any missing folders above it.",
153
+ })
154
+ .input(WorkspaceDirSchema)
155
+ .output(OkSchema),
156
+ delete: oc
157
+ .route({
158
+ method: "DELETE",
159
+ path: "/workspace/entry",
160
+ summary: "Delete a file or folder",
161
+ description:
162
+ "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.",
163
+ })
164
+ .input(WorkspaceFileQuerySchema)
165
+ .output(OkSchema),
166
+ move: oc
167
+ .route({
168
+ method: "POST",
169
+ path: "/workspace/move",
170
+ summary: "Move or rename something",
171
+ description: "Moves one entry to a new path, which is also how you rename it.",
172
+ })
173
+ .input(WorkspaceMoveSchema)
174
+ .output(OkSchema),
175
+ copy: oc
176
+ .route({
177
+ method: "POST",
178
+ path: "/workspace/copy",
179
+ summary: "Copy a file or folder",
180
+ description: "Duplicates one entry at a new path, recursively for a folder.",
181
+ })
182
+ .input(WorkspaceMoveSchema)
183
+ .output(OkSchema),
83
184
  // Dependency readiness for every project under /work, and the install that fixes it. An imported project
84
185
  // arrives without node_modules/.venv (the drop omits them), so "the files landed" is not "this works":
85
186
  // until setup says ready, its type-checks and tests can only lie. The install runs as a one-shot tmux panel
86
187
  // like a dev server or add-app, attachable, survives a reload, output kept in the terminal logs.
87
- setup: oc.route({ method: "GET", path: "/workspace/setup" }).output(WorkspaceSetupSchema),
88
- install: oc.route({ method: "POST", path: "/workspace/setup/install" }).input(WorkspaceInstallSchema).output(WorkspaceInstallResultSchema),
89
- repos: oc.route({ method: "GET", path: "/workspace/repos" }).output(ReposListSchema),
90
- addRepo: oc.route({ method: "POST", path: "/workspace/repos" }).input(CloneRepoSchema).output(CloneResultSchema),
188
+ setup: oc
189
+ .route({
190
+ method: "GET",
191
+ path: "/workspace/setup",
192
+ summary: "Which projects have their dependencies installed",
193
+ description:
194
+ "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.",
195
+ })
196
+ .output(WorkspaceSetupSchema),
197
+ install: oc
198
+ .route({
199
+ method: "POST",
200
+ path: "/workspace/setup/install",
201
+ summary: "Install a project's dependencies",
202
+ description:
203
+ "Starts the install for one or more projects in a terminal you can attach to, and answers immediately. The run survives a page reload and its output stays in the terminal history.",
204
+ })
205
+ .input(WorkspaceInstallSchema)
206
+ .output(WorkspaceInstallResultSchema),
207
+ repos: oc
208
+ .route({
209
+ method: "GET",
210
+ path: "/workspace/repos",
211
+ summary: "Repos in the workspace",
212
+ description: "Every git repo the daemon found in the workspace, with where each one sits and what it is called.",
213
+ })
214
+ .output(ReposListSchema),
215
+ addRepo: oc
216
+ .route({
217
+ method: "POST",
218
+ path: "/workspace/repos",
219
+ summary: "Clone a repo in",
220
+ description: "Clones a repository into the workspace beside the others, using whatever forge credentials the sandbox already holds.",
221
+ })
222
+ .input(CloneRepoSchema)
223
+ .output(CloneResultSchema),
91
224
  // Force-fetch + guarded fast-forward every repo with a remote (mutates the tree ⇒ POST). The turn hook syncs
92
225
  // automatically each turn; this is the on-demand refresh (and how you re-sync a dirty/diverged repo after committing).
93
- sync: oc.route({ method: "POST", path: "/workspace/sync" }).output(WorkspaceSyncSchema),
226
+ sync: oc
227
+ .route({
228
+ method: "POST",
229
+ path: "/workspace/sync",
230
+ summary: "Pull every repo up to date",
231
+ description:
232
+ "Fetches every repo that has a remote and fast-forwards the ones that can move safely, reporting what happened to each. This runs by itself at the start of a turn; call it directly to refresh on demand, or to re-sync a repo that had drifted.",
233
+ })
234
+ .output(WorkspaceSyncSchema),
94
235
  // The addable app types the configured source repo offers (its templates.json), drives the apps
95
236
  // extension's Add-app picker.
96
- templates: oc.route({ method: "GET", path: "/workspace/templates" }).output(TemplatesListSchema),
237
+ templates: oc
238
+ .route({
239
+ method: "GET",
240
+ path: "/workspace/templates",
241
+ summary: "App templates you can add",
242
+ description: "The kinds of app the configured source repo knows how to scaffold, which is what an add-app picker lists.",
243
+ })
244
+ .output(TemplatesListSchema),
97
245
  // Per-monorepo apps, driven by the web app's apps extension (owner-authed; {repo} is validated in the
98
246
  // handler): add one or more apps into an existing monorepo, list them with per-app preview URL + status,
99
247
  // and start/stop each app's preview dev server. `addApps` kicks off a one-shot tmux job (session
100
248
  // panel-<repo>--add_apps) that runs `intentic scaffold add-app`, the attachable terminal is the progress/error
101
249
  // surface; the extension polls the session's `running` for completion. It returns immediately (an ack).
102
- addApps: oc.route({ method: "POST", path: "/workspace/repos/{repo}/apps" }).input(AddAppsSchema).output(OkSchema),
103
- appsList: oc.route({ method: "GET", path: "/workspace/repos/{repo}/apps" }).input(RepoAppsParamSchema).output(AppsListSchema),
250
+ addApps: oc
251
+ .route({
252
+ method: "POST",
253
+ path: "/workspace/repos/{repo}/apps",
254
+ summary: "Scaffold new apps into a repo",
255
+ description:
256
+ "Starts scaffolding one or more apps inside an existing multi-package repo and answers straight away. Watch the terminal it opens for progress and for anything that goes wrong.",
257
+ })
258
+ .input(AddAppsSchema)
259
+ .output(OkSchema),
260
+ appsList: oc
261
+ .route({
262
+ method: "GET",
263
+ path: "/workspace/repos/{repo}/apps",
264
+ summary: "Apps inside a repo",
265
+ description: "The apps in one multi-package repo, each with its preview address and whether its dev server is up.",
266
+ })
267
+ .input(RepoAppsParamSchema)
268
+ .output(AppsListSchema),
104
269
  // The monorepo's workspace package dependency graph (pnpm-workspace.yaml globs + per-package package.json
105
270
  // workspace deps), drives the apps extension's Dependencies view.
106
- packageGraph: oc.route({ method: "GET", path: "/workspace/repos/{repo}/graph" }).input(RepoAppsParamSchema).output(WorkspaceGraphSchema),
271
+ packageGraph: oc
272
+ .route({
273
+ method: "GET",
274
+ path: "/workspace/repos/{repo}/graph",
275
+ summary: "How a repo's packages depend on each other",
276
+ description: "Every package in one multi-package repo and which of its siblings each one uses, which is what a dependency view draws.",
277
+ })
278
+ .input(RepoAppsParamSchema)
279
+ .output(WorkspaceGraphSchema),
107
280
  // Every repo's modules (the dirs owning a named package.json), what the review panels group changed files
108
281
  // under when the reader has asked for modules instead of paths. Whole-workspace rather than per-repo: a
109
282
  // review list spans repos, and one request per repo group would be a fan-out the panel pays on every open.
110
- modules: oc.route({ method: "GET", path: "/workspace/modules" }).output(WorkspaceModulesSchema),
111
- startApp: oc.route({ method: "POST", path: "/workspace/repos/{repo}/apps/{app}/start" }).input(AppParamSchema).output(OkSchema),
112
- stopApp: oc.route({ method: "POST", path: "/workspace/repos/{repo}/apps/{app}/stop" }).input(AppParamSchema).output(OkSchema),
283
+ modules: oc
284
+ .route({
285
+ method: "GET",
286
+ path: "/workspace/modules",
287
+ summary: "Every package across every repo",
288
+ description:
289
+ "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.",
290
+ })
291
+ .output(WorkspaceModulesSchema),
292
+ startApp: oc
293
+ .route({
294
+ method: "POST",
295
+ path: "/workspace/repos/{repo}/apps/{app}/start",
296
+ summary: "Start an app's dev server",
297
+ description: "Brings up one app's preview server in an attachable terminal, so its address starts answering.",
298
+ })
299
+ .input(AppParamSchema)
300
+ .output(OkSchema),
301
+ stopApp: oc
302
+ .route({
303
+ method: "POST",
304
+ path: "/workspace/repos/{repo}/apps/{app}/stop",
305
+ summary: "Stop an app's dev server",
306
+ description: "Shuts one app's preview server down and frees its port.",
307
+ })
308
+ .input(AppParamSchema)
309
+ .output(OkSchema),
113
310
  // Run vitest for the given repo-relative project dirs in a one-shot tmux panel session
114
311
  // (panel-<repo>--<session>), drives the apps extension's per-app / per-package / library Run-tests actions.
115
312
  // Mirrors addApps: it returns an ack; the attachable terminal is the result surface.
116
- runTests: oc.route({ method: "POST", path: "/workspace/repos/{repo}/tests" }).input(RunTestsSchema).output(OkSchema),
313
+ runTests: oc
314
+ .route({
315
+ method: "POST",
316
+ path: "/workspace/repos/{repo}/tests",
317
+ summary: "Run a project's tests",
318
+ description:
319
+ "Starts the test run for the projects you name in an attachable terminal and answers straight away. The terminal is where the results appear.",
320
+ })
321
+ .input(RunTestsSchema)
322
+ .output(OkSchema),
117
323
  };