@intentic/sandbox-contract 1.226.0 → 1.227.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) 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 +19 -2
  5. package/dist/contracts/agent.contract.d.ts.map +1 -1
  6. package/dist/contracts/agent.contract.js +71 -8
  7. package/dist/contracts/agent.contract.js.map +1 -1
  8. package/dist/contracts/agents.contract.d.ts +59 -0
  9. package/dist/contracts/agents.contract.d.ts.map +1 -1
  10. package/dist/contracts/agents.contract.js +164 -19
  11. package/dist/contracts/agents.contract.js.map +1 -1
  12. package/dist/contracts/automations.contract.d.ts.map +1 -1
  13. package/dist/contracts/automations.contract.js +78 -9
  14. package/dist/contracts/automations.contract.js.map +1 -1
  15. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  16. package/dist/contracts/capabilities.contract.js +98 -11
  17. package/dist/contracts/capabilities.contract.js.map +1 -1
  18. package/dist/contracts/chores.contract.d.ts.map +1 -1
  19. package/dist/contracts/chores.contract.js +26 -3
  20. package/dist/contracts/chores.contract.js.map +1 -1
  21. package/dist/contracts/ci.contract.d.ts.map +1 -1
  22. package/dist/contracts/ci.contract.js +52 -6
  23. package/dist/contracts/ci.contract.js.map +1 -1
  24. package/dist/contracts/claude.contract.d.ts.map +1 -1
  25. package/dist/contracts/claude.contract.js +44 -5
  26. package/dist/contracts/claude.contract.js.map +1 -1
  27. package/dist/contracts/drafts.contract.d.ts.map +1 -1
  28. package/dist/contracts/drafts.contract.js +26 -3
  29. package/dist/contracts/drafts.contract.js.map +1 -1
  30. package/dist/contracts/endpoints.contract.d.ts +1 -0
  31. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  32. package/dist/contracts/endpoints.contract.js +17 -2
  33. package/dist/contracts/endpoints.contract.js.map +1 -1
  34. package/dist/contracts/exit.contract.d.ts.map +1 -1
  35. package/dist/contracts/exit.contract.js +62 -7
  36. package/dist/contracts/exit.contract.js.map +1 -1
  37. package/dist/contracts/extensions.contract.d.ts +1 -0
  38. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  39. package/dist/contracts/extensions.contract.js +124 -15
  40. package/dist/contracts/extensions.contract.js.map +1 -1
  41. package/dist/contracts/git.contract.d.ts.map +1 -1
  42. package/dist/contracts/git.contract.js +384 -43
  43. package/dist/contracts/git.contract.js.map +1 -1
  44. package/dist/contracts/grok.contract.d.ts.map +1 -1
  45. package/dist/contracts/grok.contract.js +25 -3
  46. package/dist/contracts/grok.contract.js.map +1 -1
  47. package/dist/contracts/history.contract.d.ts.map +1 -1
  48. package/dist/contracts/history.contract.js +35 -4
  49. package/dist/contracts/history.contract.js.map +1 -1
  50. package/dist/contracts/intentic.contract.d.ts.map +1 -1
  51. package/dist/contracts/intentic.contract.js +25 -3
  52. package/dist/contracts/intentic.contract.js.map +1 -1
  53. package/dist/contracts/inventory.contract.d.ts.map +1 -1
  54. package/dist/contracts/inventory.contract.js +26 -3
  55. package/dist/contracts/inventory.contract.js.map +1 -1
  56. package/dist/contracts/logs.contract.d.ts +17 -0
  57. package/dist/contracts/logs.contract.d.ts.map +1 -1
  58. package/dist/contracts/logs.contract.js +27 -3
  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 +1 -0
  76. package/dist/contracts/providers.contract.d.ts.map +1 -1
  77. package/dist/contracts/providers.contract.js +9 -1
  78. package/dist/contracts/providers.contract.js.map +1 -1
  79. package/dist/contracts/public.contract.d.ts.map +1 -1
  80. package/dist/contracts/public.contract.js +26 -3
  81. package/dist/contracts/public.contract.js.map +1 -1
  82. package/dist/contracts/push.contract.d.ts.map +1 -1
  83. package/dist/contracts/push.contract.js +35 -4
  84. package/dist/contracts/push.contract.js.map +1 -1
  85. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  86. package/dist/contracts/secrets.contract.js +43 -5
  87. package/dist/contracts/secrets.contract.js.map +1 -1
  88. package/dist/contracts/sessions.contract.d.ts +3 -0
  89. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  90. package/dist/contracts/sessions.contract.js +15 -2
  91. package/dist/contracts/sessions.contract.js.map +1 -1
  92. package/dist/contracts/settings.contract.d.ts +19 -0
  93. package/dist/contracts/settings.contract.d.ts.map +1 -1
  94. package/dist/contracts/settings.contract.js +43 -5
  95. package/dist/contracts/settings.contract.js.map +1 -1
  96. package/dist/contracts/share.contract.d.ts.map +1 -1
  97. package/dist/contracts/share.contract.js +35 -4
  98. package/dist/contracts/share.contract.js.map +1 -1
  99. package/dist/contracts/skills.contract.d.ts.map +1 -1
  100. package/dist/contracts/skills.contract.js +35 -4
  101. package/dist/contracts/skills.contract.js.map +1 -1
  102. package/dist/contracts/system.contract.d.ts +7 -0
  103. package/dist/contracts/system.contract.d.ts.map +1 -1
  104. package/dist/contracts/system.contract.js +107 -14
  105. package/dist/contracts/system.contract.js.map +1 -1
  106. package/dist/contracts/translator.contract.d.ts.map +1 -1
  107. package/dist/contracts/translator.contract.js +29 -4
  108. package/dist/contracts/translator.contract.js.map +1 -1
  109. package/dist/contracts/usage.contract.d.ts.map +1 -1
  110. package/dist/contracts/usage.contract.js +9 -1
  111. package/dist/contracts/usage.contract.js.map +1 -1
  112. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  113. package/dist/contracts/vpn.contract.js +32 -4
  114. package/dist/contracts/vpn.contract.js.map +1 -1
  115. package/dist/contracts/workflows.contract.d.ts.map +1 -1
  116. package/dist/contracts/workflows.contract.js +70 -8
  117. package/dist/contracts/workflows.contract.js.map +1 -1
  118. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  119. package/dist/contracts/workspace.contract.js +216 -25
  120. package/dist/contracts/workspace.contract.js.map +1 -1
  121. package/dist/events.d.ts +46 -0
  122. package/dist/events.d.ts.map +1 -1
  123. package/dist/events.js +193 -88
  124. package/dist/events.js.map +1 -1
  125. package/dist/history-state.d.ts.map +1 -1
  126. package/dist/history-state.js +1 -0
  127. package/dist/history-state.js.map +1 -1
  128. package/dist/index.d.ts +197 -70
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +2 -0
  131. package/dist/index.js.map +1 -1
  132. package/dist/prompt-complexity.d.ts +9 -1
  133. package/dist/prompt-complexity.d.ts.map +1 -1
  134. package/dist/prompt-complexity.js +13 -5
  135. package/dist/prompt-complexity.js.map +1 -1
  136. package/dist/request-id.d.ts +3 -0
  137. package/dist/request-id.d.ts.map +1 -0
  138. package/dist/request-id.js +3 -0
  139. package/dist/request-id.js.map +1 -0
  140. package/dist/schemas.d.ts +89 -0
  141. package/dist/schemas.d.ts.map +1 -1
  142. package/dist/schemas.js +2912 -1276
  143. package/dist/schemas.js.map +1 -1
  144. package/dist/starter.d.ts +3 -0
  145. package/dist/starter.d.ts.map +1 -0
  146. package/dist/starter.js +3 -0
  147. package/dist/starter.js.map +1 -0
  148. package/package.json +5 -4
  149. package/src/contract-lock.test.ts +8 -2
  150. package/src/contracts/activity.contract.ts +18 -2
  151. package/src/contracts/agent.contract.ts +78 -8
  152. package/src/contracts/agents.contract.ts +180 -19
  153. package/src/contracts/automations.contract.ts +80 -9
  154. package/src/contracts/capabilities.contract.ts +106 -11
  155. package/src/contracts/chores.contract.ts +29 -3
  156. package/src/contracts/ci.contract.ts +55 -6
  157. package/src/contracts/claude.contract.ts +47 -5
  158. package/src/contracts/drafts.contract.ts +26 -3
  159. package/src/contracts/endpoints.contract.ts +19 -2
  160. package/src/contracts/exit.contract.ts +69 -7
  161. package/src/contracts/extensions.contract.ts +134 -15
  162. package/src/contracts/git.contract.ts +421 -43
  163. package/src/contracts/grok.contract.ts +26 -3
  164. package/src/contracts/history.contract.ts +37 -4
  165. package/src/contracts/intentic.contract.ts +28 -3
  166. package/src/contracts/inventory.contract.ts +27 -3
  167. package/src/contracts/logs.contract.ts +41 -4
  168. package/src/contracts/loops.contract.ts +58 -6
  169. package/src/contracts/panels.contract.ts +26 -3
  170. package/src/contracts/personas.contract.ts +77 -8
  171. package/src/contracts/ports.contract.ts +27 -3
  172. package/src/contracts/prepush.contract.ts +26 -3
  173. package/src/contracts/providers.contract.ts +10 -1
  174. package/src/contracts/public.contract.ts +29 -3
  175. package/src/contracts/push.contract.ts +37 -4
  176. package/src/contracts/secrets.contract.ts +46 -5
  177. package/src/contracts/sessions.contract.ts +16 -2
  178. package/src/contracts/settings.contract.ts +46 -5
  179. package/src/contracts/share.contract.ts +37 -4
  180. package/src/contracts/skills.contract.ts +39 -4
  181. package/src/contracts/system.contract.ts +119 -14
  182. package/src/contracts/translator.contract.ts +32 -4
  183. package/src/contracts/usage.contract.ts +10 -1
  184. package/src/contracts/vpn.contract.ts +35 -4
  185. package/src/contracts/workflows.contract.ts +77 -8
  186. package/src/contracts/workspace.contract.ts +231 -25
  187. package/src/events.ts +259 -89
  188. package/src/history-state.ts +6 -0
  189. package/src/index.ts +2 -0
  190. package/src/prompt-complexity.test.ts +69 -0
  191. package/src/prompt-complexity.ts +102 -39
  192. package/src/request-id.ts +41 -0
  193. package/src/schemas.ts +3700 -1260
  194. package/src/starter.ts +13 -0
@@ -51,17 +51,68 @@ import {
51
51
  // NOT_FOUND; a path that escapes the repo is a BAD_REQUEST. `changes` is the workspace-wide review set the
52
52
  // Changes panel renders; commit/discard take optional `paths` for per-file actions.
53
53
  export const gitContract = {
54
- changes: oc.route({ method: "GET", path: "/git/changes" }).output(GitChangesSchema),
54
+ changes: oc
55
+ .route({
56
+ method: "GET",
57
+ path: "/git/changes",
58
+ summary: "Uncommitted work across every repo",
59
+ description:
60
+ "The workspace's whole review set in one answer: every repo that has something uncommitted, and within it every changed file with its status and line counts. This is what the Changes panel draws, and it is the call to make when you want to know whether a workspace is clean without walking the repos yourself.",
61
+ })
62
+ .output(GitChangesSchema),
55
63
  // The git-history graph over one repo's real commits: the repo list (for the tree affordance + switcher),
56
64
  // one repo's commit log, and lazy per-commit detail (changed files, then a file's before/after AT the
57
65
  // commit). Read-only, commit/discard on the working tree stay the write path (above).
58
- repos: oc.route({ method: "GET", path: "/git/repos" }).output(GitReposSchema),
66
+ repos: oc
67
+ .route({
68
+ method: "GET",
69
+ path: "/git/repos",
70
+ summary: "Every git repo in the workspace",
71
+ description:
72
+ "The repos the daemon found under the workspace root, each with the id every other call in this group expects as its `{repo}` segment. The workspace root itself is always present as `root`.",
73
+ })
74
+ .output(GitReposSchema),
59
75
  // The same repos with the host + project their remote names, how a caller recognises a workspace repo in a
60
76
  // list of `owner/name` strings that came from somewhere else. Kept off `repos` (a `git remote -v` per repo).
61
- remoteRepos: oc.route({ method: "GET", path: "/git/remote-repos" }).output(GitRemoteReposSchema),
62
- log: oc.route({ method: "GET", path: "/git/{repo}/log" }).input(GitLogQuerySchema).output(GitLogSchema),
63
- commitDiff: oc.route({ method: "GET", path: "/git/{repo}/commit-diff" }).input(GitCommitDiffQuerySchema).output(GitCommitDiffSchema),
64
- commitFileDiff: oc.route({ method: "GET", path: "/git/{repo}/commit-file-diff" }).input(GitCommitFileDiffQuerySchema).output(FileDiffSchema),
77
+ remoteRepos: oc
78
+ .route({
79
+ method: "GET",
80
+ path: "/git/remote-repos",
81
+ summary: "Repos matched to their remotes",
82
+ description:
83
+ "The same repo list, but with the forge host and `owner/name` each one's remote points at. Use it to recognise a workspace repo in a list of names that came from somewhere else, such as a set of pull requests. Costs a remote lookup per repo, which is why it is separate from the plain repo list.",
84
+ })
85
+ .output(GitRemoteReposSchema),
86
+ log: oc
87
+ .route({
88
+ method: "GET",
89
+ path: "/git/{repo}/log",
90
+ summary: "Commit history for one repo",
91
+ description:
92
+ "A page of commits on the current branch, newest first, each with its author, subject, timestamp and the refs pointing at it. Paginate with the cursor the answer hands back rather than by offset, so a commit landing mid-scroll does not shift the page under you.",
93
+ })
94
+ .input(GitLogQuerySchema)
95
+ .output(GitLogSchema),
96
+ commitDiff: oc
97
+ .route({
98
+ method: "GET",
99
+ path: "/git/{repo}/commit-diff",
100
+ summary: "What one commit changed",
101
+ description:
102
+ "The list of files a single commit touched, with per-file status and line counts but not the content. Fetch the content of any one of them with the commit file diff call, so a commit with a thousand files stays one cheap answer.",
103
+ })
104
+ .input(GitCommitDiffQuerySchema)
105
+ .output(GitCommitDiffSchema),
106
+ commitFileDiff: oc
107
+ .route({
108
+ method: "GET",
109
+ path: "/git/{repo}/commit-file-diff",
110
+ summary: "One file's before and after at a commit",
111
+ description:
112
+ "Both sides of a single file as of one commit: the content its parent had and the content that commit left. The daemon returns whole sides rather than a patch, so a caller can render the comparison however it likes.",
113
+ })
114
+ .input(GitCommitFileDiffQuerySchema)
115
+ .output(FileDiffSchema),
65
116
  // Write actions from the graph's commit context menu (VSCode "Git Graph" parity). Non-destructive refs
66
117
  // (branch/tag) return Ok and let git's errors propagate; the sequence + HEAD-moving ops return a
67
118
  // GitActionResult so a conflict/clean-apply failure is a value, not a 500. Read routes above.
@@ -69,60 +120,387 @@ export const gitContract = {
69
120
  * otherwise act on; `abort` is the single way out, and it is git's own `--abort` rather than anything
70
121
  * clever. Neither is reachable from the daemon's own verbs, those abort themselves, so this exists purely
71
122
  * for what a terminal left behind. */
72
- operation: oc.route({ method: "GET", path: "/git/{repo}/operation" }).input(RepoParamSchema).output(GitOperationStateSchema),
73
- abort: oc.route({ method: "POST", path: "/git/{repo}/abort" }).input(RepoParamSchema).output(GitActionResultSchema),
123
+ operation: oc
124
+ .route({
125
+ method: "GET",
126
+ path: "/git/{repo}/operation",
127
+ summary: "Whether a merge or rebase is halted mid-flight",
128
+ description:
129
+ "Names the git operation the worktree is stuck inside, if any: a conflicted merge, an interrupted rebase, a half-applied cherry-pick. Check this first when another call refuses, because a halted worktree is the usual reason and the abort call is the way out.",
130
+ })
131
+ .input(RepoParamSchema)
132
+ .output(GitOperationStateSchema),
133
+ abort: oc
134
+ .route({
135
+ method: "POST",
136
+ path: "/git/{repo}/abort",
137
+ summary: "Abandon a halted merge or rebase",
138
+ description:
139
+ "Runs git's own abort for whichever operation has the worktree halted, putting the repo back where it stood before the operation started. Nothing else clears that state.",
140
+ })
141
+ .input(RepoParamSchema)
142
+ .output(GitActionResultSchema),
74
143
  /* Walk the current branch back to where it was before its last action, off the branch's own reflog. The
75
144
  * complement to the Checkpoints timeline, not a duplicate of it: a checkpoint restores the working tree,
76
145
  * this moves the ref. The read carries `previousSha`, which the write sends back as a concurrency token,
77
146
  * an undo prepared against a stale view is refused rather than landing somewhere unlooked-at. */
78
- undoable: oc.route({ method: "GET", path: "/git/{repo}/undo" }).input(RepoParamSchema).output(GitUndoStateSchema),
79
- undo: oc.route({ method: "POST", path: "/git/{repo}/undo" }).input(GitUndoSchema).output(GitActionResultSchema),
147
+ undoable: oc
148
+ .route({
149
+ method: "GET",
150
+ path: "/git/{repo}/undo",
151
+ summary: "What undoing the last action would do",
152
+ description:
153
+ "Reads the branch's reflog to describe the move that undo would reverse, and hands back the commit it would land on. Pass that commit to the undo call as proof you looked, and an undo prepared against a view that has since moved is refused rather than landing somewhere unexamined.",
154
+ })
155
+ .input(RepoParamSchema)
156
+ .output(GitUndoStateSchema),
157
+ undo: oc
158
+ .route({
159
+ method: "POST",
160
+ path: "/git/{repo}/undo",
161
+ summary: "Move the branch back one step",
162
+ description:
163
+ "Walks the current branch back to where it pointed before its last action. This moves the branch ref and leaves the working tree alone, which is the opposite of restoring a checkpoint. Requires the commit the matching read handed you.",
164
+ })
165
+ .input(GitUndoSchema)
166
+ .output(GitActionResultSchema),
80
167
  /* The stash. Read as a list plus a per-entry diff, mirroring the commit log and commit-diff pair above,
81
168
  * because a stash entry is a commit and the graph renders it as one. The writes are git's own four verbs;
82
169
  * only `drop` is unrecoverable, and the route checkpoints before it. */
83
- stashes: oc.route({ method: "GET", path: "/git/{repo}/stashes" }).input(RepoParamSchema).output(StashListSchema),
84
- stashDiff: oc.route({ method: "GET", path: "/git/{repo}/stash-diff" }).input(StashDiffQuerySchema).output(GitCommitDiffSchema),
85
- stashPush: oc.route({ method: "POST", path: "/git/{repo}/stash" }).input(StashPushSchema).output(GitActionResultSchema),
86
- stashApply: oc.route({ method: "POST", path: "/git/{repo}/stash/apply" }).input(StashApplySchema).output(GitActionResultSchema),
87
- stashDrop: oc.route({ method: "POST", path: "/git/{repo}/stash/drop" }).input(StashRefParamSchema).output(OkSchema),
88
- createBranch: oc.route({ method: "POST", path: "/git/{repo}/branch" }).input(GitBranchCreateSchema).output(OkSchema),
89
- createTag: oc.route({ method: "POST", path: "/git/{repo}/tag" }).input(GitTagCreateSchema).output(OkSchema),
170
+ stashes: oc
171
+ .route({
172
+ method: "GET",
173
+ path: "/git/{repo}/stashes",
174
+ summary: "Everything set aside in the stash",
175
+ description:
176
+ "The repo's stash entries, newest first, each with the message and the commit behind it. A stash entry is a commit, so it reads the same way a log entry does and its contents come back from the stash diff call.",
177
+ })
178
+ .input(RepoParamSchema)
179
+ .output(StashListSchema),
180
+ stashDiff: oc
181
+ .route({
182
+ method: "GET",
183
+ path: "/git/{repo}/stash-diff",
184
+ summary: "What one stash entry holds",
185
+ description:
186
+ "The files a single stash entry would bring back, with per-file status and line counts. The same shape a commit diff has, because a stash entry is a commit.",
187
+ })
188
+ .input(StashDiffQuerySchema)
189
+ .output(GitCommitDiffSchema),
190
+ stashPush: oc
191
+ .route({
192
+ method: "POST",
193
+ path: "/git/{repo}/stash",
194
+ summary: "Set the current changes aside",
195
+ description:
196
+ "Moves the working tree's changes onto the stash and leaves a clean tree behind. Nothing is lost: the entry is a commit you can inspect, apply or drop afterwards.",
197
+ })
198
+ .input(StashPushSchema)
199
+ .output(GitActionResultSchema),
200
+ stashApply: oc
201
+ .route({
202
+ method: "POST",
203
+ path: "/git/{repo}/stash/apply",
204
+ summary: "Bring a stash entry back",
205
+ description:
206
+ "Replays one stash entry onto the working tree. A conflict is reported in the answer rather than raised as a failure, because a conflicting apply is an ordinary outcome a screen has to render.",
207
+ })
208
+ .input(StashApplySchema)
209
+ .output(GitActionResultSchema),
210
+ stashDrop: oc
211
+ .route({
212
+ method: "POST",
213
+ path: "/git/{repo}/stash/drop",
214
+ summary: "Discard a stash entry",
215
+ description:
216
+ "Deletes one stash entry. This is the only unrecoverable call in the stash set, so the daemon takes a checkpoint of the workspace first.",
217
+ })
218
+ .input(StashRefParamSchema)
219
+ .output(OkSchema),
220
+ createBranch: oc
221
+ .route({
222
+ method: "POST",
223
+ path: "/git/{repo}/branch",
224
+ summary: "Start a branch at a commit",
225
+ description: "Points a new branch name at any commit, without moving HEAD. Use the checkout call if you also want to switch to it.",
226
+ })
227
+ .input(GitBranchCreateSchema)
228
+ .output(OkSchema),
229
+ createTag: oc
230
+ .route({
231
+ method: "POST",
232
+ path: "/git/{repo}/tag",
233
+ summary: "Tag a commit",
234
+ description: "Puts a tag on any commit. Local only: pushing it to the remote is a separate call.",
235
+ })
236
+ .input(GitTagCreateSchema)
237
+ .output(OkSchema),
90
238
  // The other two things one does with a tag, so the graph's tag pills are not a create-only affordance.
91
- deleteTag: oc.route({ method: "POST", path: "/git/{repo}/tag/delete" }).input(GitTagDeleteSchema).output(OkSchema),
92
- pushTag: oc.route({ method: "POST", path: "/git/{repo}/tag/push" }).input(GitTagPushSchema).output(GitActionResultSchema),
93
- checkout: oc.route({ method: "POST", path: "/git/{repo}/checkout" }).input(GitCheckoutSchema).output(GitActionResultSchema),
94
- cherryPick: oc.route({ method: "POST", path: "/git/{repo}/cherry-pick" }).input(GitCommitActionSchema).output(GitActionResultSchema),
95
- revert: oc.route({ method: "POST", path: "/git/{repo}/revert" }).input(GitCommitActionSchema).output(GitActionResultSchema),
96
- drop: oc.route({ method: "POST", path: "/git/{repo}/drop" }).input(GitCommitActionSchema).output(GitActionResultSchema),
97
- merge: oc.route({ method: "POST", path: "/git/{repo}/merge" }).input(GitCommitActionSchema).output(GitActionResultSchema),
98
- rebase: oc.route({ method: "POST", path: "/git/{repo}/rebase" }).input(GitCommitActionSchema).output(GitActionResultSchema),
99
- reset: oc.route({ method: "POST", path: "/git/{repo}/reset" }).input(GitResetSchema).output(GitActionResultSchema),
100
- fileDiff: oc.route({ method: "GET", path: "/git/{repo}/file-diff" }).input(GitFileDiffQuerySchema).output(FileDiffSchema),
101
- status: oc.route({ method: "GET", path: "/git/{repo}/status" }).input(RepoParamSchema).output(GitStatusSchema),
102
- commit: oc.route({ method: "POST", path: "/git/{repo}/commit" }).input(CommitSchema).output(CommitResultSchema),
103
- discard: oc.route({ method: "POST", path: "/git/{repo}/discard" }).input(DiscardSchema).output(OkSchema),
239
+ deleteTag: oc
240
+ .route({
241
+ method: "POST",
242
+ path: "/git/{repo}/tag/delete",
243
+ summary: "Remove a tag",
244
+ description: "Deletes a tag locally. A tag already pushed stays on the remote until it is deleted there too.",
245
+ })
246
+ .input(GitTagDeleteSchema)
247
+ .output(OkSchema),
248
+ pushTag: oc
249
+ .route({
250
+ method: "POST",
251
+ path: "/git/{repo}/tag/push",
252
+ summary: "Send a tag to the remote",
253
+ description:
254
+ "Pushes one tag to the repo's remote. Reports the outcome rather than failing, since a missing remote or missing credentials are ordinary answers here.",
255
+ })
256
+ .input(GitTagPushSchema)
257
+ .output(GitActionResultSchema),
258
+ checkout: oc
259
+ .route({
260
+ method: "POST",
261
+ path: "/git/{repo}/checkout",
262
+ summary: "Switch to a branch or commit",
263
+ description:
264
+ "Moves HEAD to a branch, tag or commit and reshapes the working tree to match. The daemon takes a checkpoint first, so an unexpected result is recoverable. Uncommitted work that would be overwritten is reported instead of being trampled.",
265
+ })
266
+ .input(GitCheckoutSchema)
267
+ .output(GitActionResultSchema),
268
+ cherryPick: oc
269
+ .route({
270
+ method: "POST",
271
+ path: "/git/{repo}/cherry-pick",
272
+ summary: "Replay one commit onto this branch",
273
+ description:
274
+ "Applies a single commit's changes on top of the current branch as a new commit. A conflict comes back in the answer, with the halted state readable from the operation call.",
275
+ })
276
+ .input(GitCommitActionSchema)
277
+ .output(GitActionResultSchema),
278
+ revert: oc
279
+ .route({
280
+ method: "POST",
281
+ path: "/git/{repo}/revert",
282
+ summary: "Undo a commit with a new commit",
283
+ description:
284
+ "Adds a commit that reverses an earlier one, leaving the history intact. This is the safe way to take something back on a branch other people have pulled.",
285
+ })
286
+ .input(GitCommitActionSchema)
287
+ .output(GitActionResultSchema),
288
+ drop: oc
289
+ .route({
290
+ method: "POST",
291
+ path: "/git/{repo}/drop",
292
+ summary: "Remove a commit from history",
293
+ description:
294
+ "Rewrites the branch so one commit is no longer in it. History changes, so this is for branches nobody else has pulled. A checkpoint is taken first.",
295
+ })
296
+ .input(GitCommitActionSchema)
297
+ .output(GitActionResultSchema),
298
+ merge: oc
299
+ .route({
300
+ method: "POST",
301
+ path: "/git/{repo}/merge",
302
+ summary: "Merge another branch in",
303
+ description:
304
+ "Merges a branch or commit into the current one. Conflicts are reported in the answer and leave the worktree halted, which the operation call explains and the abort call clears.",
305
+ })
306
+ .input(GitCommitActionSchema)
307
+ .output(GitActionResultSchema),
308
+ rebase: oc
309
+ .route({
310
+ method: "POST",
311
+ path: "/git/{repo}/rebase",
312
+ summary: "Replay this branch onto another",
313
+ description:
314
+ "Moves the current branch's commits on top of a different base. History changes. Conflicts halt the rebase and are reported rather than raised, so the operation and abort calls are the way through.",
315
+ })
316
+ .input(GitCommitActionSchema)
317
+ .output(GitActionResultSchema),
318
+ reset: oc
319
+ .route({
320
+ method: "POST",
321
+ path: "/git/{repo}/reset",
322
+ summary: "Move the branch to a commit",
323
+ description:
324
+ "Repoints the current branch at another commit, optionally reshaping the working tree to match. The destructive modes take a checkpoint first.",
325
+ })
326
+ .input(GitResetSchema)
327
+ .output(GitActionResultSchema),
328
+ fileDiff: oc
329
+ .route({
330
+ method: "GET",
331
+ path: "/git/{repo}/file-diff",
332
+ summary: "One file's committed and working copies",
333
+ description:
334
+ "Both sides of a file as it stands right now: what the last commit holds and what is on disk. This is what a review pane shows for an uncommitted change.",
335
+ })
336
+ .input(GitFileDiffQuerySchema)
337
+ .output(FileDiffSchema),
338
+ status: oc
339
+ .route({
340
+ method: "GET",
341
+ path: "/git/{repo}/status",
342
+ summary: "One repo's branch and pending changes",
343
+ description:
344
+ "The current branch, its sync position against the remote, and every staged, unstaged and untracked path. The single-repo counterpart to the workspace-wide changes call.",
345
+ })
346
+ .input(RepoParamSchema)
347
+ .output(GitStatusSchema),
348
+ commit: oc
349
+ .route({
350
+ method: "POST",
351
+ path: "/git/{repo}/commit",
352
+ summary: "Commit the pending changes",
353
+ description:
354
+ "Records a commit with your message. Give it a list of paths to commit only those, or leave it out to commit everything pending. The answer carries the commit it created.",
355
+ })
356
+ .input(CommitSchema)
357
+ .output(CommitResultSchema),
358
+ discard: oc
359
+ .route({
360
+ method: "POST",
361
+ path: "/git/{repo}/discard",
362
+ summary: "Throw away pending changes",
363
+ description:
364
+ "Restores files to their committed state and deletes untracked ones. Give it paths to discard only those. The daemon checkpoints the workspace first, so this is recoverable from the timeline.",
365
+ })
366
+ .input(DiscardSchema)
367
+ .output(OkSchema),
104
368
  // Index moves. Per-path, worktree untouched, so they need no checkpoint and can't fail destructively,
105
369
  // git's own error (an unmatched pathspec) propagates.
106
- stage: oc.route({ method: "POST", path: "/git/{repo}/stage" }).input(GitStageSchema).output(OkSchema),
107
- unstage: oc.route({ method: "POST", path: "/git/{repo}/unstage" }).input(GitStageSchema).output(OkSchema),
370
+ stage: oc
371
+ .route({
372
+ method: "POST",
373
+ path: "/git/{repo}/stage",
374
+ summary: "Mark paths for the next commit",
375
+ description: "Adds paths to the index. Nothing on disk changes, so this is always safe and always reversible with the unstage call.",
376
+ })
377
+ .input(GitStageSchema)
378
+ .output(OkSchema),
379
+ unstage: oc
380
+ .route({
381
+ method: "POST",
382
+ path: "/git/{repo}/unstage",
383
+ summary: "Take paths back out of the next commit",
384
+ description: "Removes paths from the index and leaves the file itself untouched. The exact reverse of staging.",
385
+ })
386
+ .input(GitStageSchema)
387
+ .output(OkSchema),
108
388
  // Local branch management for the switcher. `branches` also carries per-branch ahead/behind, so the list
109
389
  // is enough to render sync state without a call per branch. Checkout is above (it moves HEAD, so it is
110
390
  // checkpointed with the other HEAD-movers).
111
- branches: oc.route({ method: "GET", path: "/git/{repo}/branches" }).input(RepoParamSchema).output(GitBranchesSchema),
112
- createBranchAt: oc.route({ method: "POST", path: "/git/{repo}/branches" }).input(GitBranchCreateAtSchema).output(OkSchema),
113
- deleteBranch: oc.route({ method: "POST", path: "/git/{repo}/branches/delete" }).input(GitBranchDeleteSchema).output(OkSchema),
391
+ branches: oc
392
+ .route({
393
+ method: "GET",
394
+ path: "/git/{repo}/branches",
395
+ summary: "Local branches and how far each has drifted",
396
+ description:
397
+ "Every local branch with how many commits it sits ahead of and behind its remote counterpart, so a branch switcher can show sync state without a call per branch.",
398
+ })
399
+ .input(RepoParamSchema)
400
+ .output(GitBranchesSchema),
401
+ createBranchAt: oc
402
+ .route({
403
+ method: "POST",
404
+ path: "/git/{repo}/branches",
405
+ summary: "Create a branch from a starting point",
406
+ description:
407
+ "Makes a branch at a named start point and optionally switches to it. The branch-switcher counterpart to creating a branch at a specific commit.",
408
+ })
409
+ .input(GitBranchCreateAtSchema)
410
+ .output(OkSchema),
411
+ deleteBranch: oc
412
+ .route({
413
+ method: "POST",
414
+ path: "/git/{repo}/branches/delete",
415
+ summary: "Delete a local branch",
416
+ description:
417
+ "Removes a branch from the repo. Unmerged work is refused unless you ask for it to be forced, and the remote branch is untouched either way.",
418
+ })
419
+ .input(GitBranchDeleteSchema)
420
+ .output(OkSchema),
114
421
  // Remote sync. All three report a GitActionResult rather than throwing: no remote, no credentials and a
115
422
  // non-fast-forwardable pull are ORDINARY outcomes the panel renders, not 500s. `remote` is the read
116
423
  // (ahead/behind as of the last fetch, hence the Fetch button) the sync bar polls.
117
- remote: oc.route({ method: "GET", path: "/git/{repo}/remote" }).input(RepoParamSchema).output(GitRemoteStateSchema),
118
- fetch: oc.route({ method: "POST", path: "/git/{repo}/fetch" }).input(RepoParamSchema).output(GitActionResultSchema),
119
- pull: oc.route({ method: "POST", path: "/git/{repo}/pull" }).input(RepoParamSchema).output(GitActionResultSchema),
120
- push: oc.route({ method: "POST", path: "/git/{repo}/push" }).input(PushSchema).output(GitActionResultSchema),
121
- files: oc.route({ method: "GET", path: "/git/{repo}/files" }).input(RepoParamSchema).output(GitFilesSchema),
122
- readFile: oc.route({ method: "GET", path: "/git/{repo}/file" }).input(GitFileQuerySchema).output(GitFileSchema),
123
- writeFile: oc.route({ method: "PUT", path: "/git/{repo}/file" }).input(GitFileWriteSchema).output(OkSchema),
424
+ remote: oc
425
+ .route({
426
+ method: "GET",
427
+ path: "/git/{repo}/remote",
428
+ summary: "Sync position against the remote",
429
+ description:
430
+ "How far the current branch sits ahead of and behind its remote, as of the last fetch, plus whether a remote and working credentials exist at all. This is a read of what the daemon already knows, not a network call, which is why fetching is a separate button.",
431
+ })
432
+ .input(RepoParamSchema)
433
+ .output(GitRemoteStateSchema),
434
+ fetch: oc
435
+ .route({
436
+ method: "POST",
437
+ path: "/git/{repo}/fetch",
438
+ summary: "Refresh what the remote holds",
439
+ description:
440
+ "Contacts the remote and updates the daemon's picture of it without touching your branch. Run this before trusting the sync position.",
441
+ })
442
+ .input(RepoParamSchema)
443
+ .output(GitActionResultSchema),
444
+ pull: oc
445
+ .route({
446
+ method: "POST",
447
+ path: "/git/{repo}/pull",
448
+ summary: "Bring remote commits down",
449
+ description:
450
+ "Fetches and integrates the remote's commits into the current branch. A pull that cannot fast-forward is reported in the answer rather than raised, because that is an ordinary thing to be told.",
451
+ })
452
+ .input(RepoParamSchema)
453
+ .output(GitActionResultSchema),
454
+ push: oc
455
+ .route({
456
+ method: "POST",
457
+ path: "/git/{repo}/push",
458
+ summary: "Send commits to the remote",
459
+ description:
460
+ "Pushes the current branch, setting its upstream on first push. A rejected push, a missing remote and missing credentials all come back as reported outcomes rather than failures.",
461
+ })
462
+ .input(PushSchema)
463
+ .output(GitActionResultSchema),
464
+ files: oc
465
+ .route({
466
+ method: "GET",
467
+ path: "/git/{repo}/files",
468
+ summary: "Every tracked path in the repo",
469
+ description:
470
+ "The flat list of files git tracks, which is what a file picker or a search box wants. Ignored and untracked files are not in it.",
471
+ })
472
+ .input(RepoParamSchema)
473
+ .output(GitFilesSchema),
474
+ readFile: oc
475
+ .route({
476
+ method: "GET",
477
+ path: "/git/{repo}/file",
478
+ summary: "Read a file from the repo",
479
+ description: "The contents of one file as it stands on disk. A path that climbs out of the repo is refused.",
480
+ })
481
+ .input(GitFileQuerySchema)
482
+ .output(GitFileSchema),
483
+ writeFile: oc
484
+ .route({
485
+ method: "PUT",
486
+ path: "/git/{repo}/file",
487
+ summary: "Write a file into the repo",
488
+ description:
489
+ "Replaces one file's contents, creating it and its parent folders if they are missing. Nothing is committed: the change shows up as pending work.",
490
+ })
491
+ .input(GitFileWriteSchema)
492
+ .output(OkSchema),
124
493
  // Write + commit-that-path-only + push, as one step with one answer. Reports rather than throws for the
125
494
  // same reason the remote trio above does: no remote, no credentials and "you are on a side branch" are
126
495
  // ordinary outcomes a screen renders, not 500s.
127
- publishFile: oc.route({ method: "POST", path: "/git/{repo}/publish-file" }).input(GitPublishFileSchema).output(GitPublishFileResultSchema),
496
+ publishFile: oc
497
+ .route({
498
+ method: "POST",
499
+ path: "/git/{repo}/publish-file",
500
+ summary: "Write, commit and push one file",
501
+ description:
502
+ "The three steps as a single call with a single answer, committing only the path you named and leaving any other pending work alone. Being on a side branch, having no remote and having no credentials are all reported rather than raised.",
503
+ })
504
+ .input(GitPublishFileSchema)
505
+ .output(GitPublishFileResultSchema),
128
506
  };
@@ -11,7 +11,30 @@ import { AccountIdSchema, DeviceStartSchema, OauthAccountListSchema, OkSchema }
11
11
  // Like Claude's, this contract is now the account handshake alone, the model catalog answers on the shared
12
12
  // /providers/{provider}/models route (providers.contract.ts).
13
13
  export const grokContract = {
14
- start: oc.route({ method: "POST", path: "/grok/oauth/start" }).output(DeviceStartSchema),
15
- accounts: oc.route({ method: "GET", path: "/grok/accounts" }).output(OauthAccountListSchema),
16
- disconnect: oc.route({ method: "POST", path: "/grok/account/disconnect" }).input(AccountIdSchema).output(OkSchema),
14
+ start: oc
15
+ .route({
16
+ method: "POST",
17
+ path: "/grok/oauth/start",
18
+ summary: "Begin connecting a Grok account",
19
+ description:
20
+ "Hands back the page to open and the one-time code to type there. Nothing is pasted back afterwards: the sandbox waits for the sign-in to complete on its own, so poll the accounts call until it appears.",
21
+ })
22
+ .output(DeviceStartSchema),
23
+ accounts: oc
24
+ .route({
25
+ method: "GET",
26
+ path: "/grok/accounts",
27
+ summary: "Connected Grok account",
28
+ description: "What is signed in. A list for consistency with the other providers, though there is at most one.",
29
+ })
30
+ .output(OauthAccountListSchema),
31
+ disconnect: oc
32
+ .route({
33
+ method: "POST",
34
+ path: "/grok/account/disconnect",
35
+ summary: "Disconnect the Grok account",
36
+ description: "Clears the stored tokens.",
37
+ })
38
+ .input(AccountIdSchema)
39
+ .output(OkSchema),
17
40
  };
@@ -5,8 +5,41 @@ import { FileDiffSchema, OkSchema, SnapshotDiffSchema, SnapshotFileDiffQuerySche
5
5
  // the previous visible checkpoint (everything that happened since it, hidden interval captures included); an
6
6
  // unknown id is a handler-thrown NOT_FOUND.
7
7
  export const historyContract = {
8
- list: oc.route({ method: "GET", path: "/history/snapshots" }).output(SnapshotsListSchema),
9
- diff: oc.route({ method: "GET", path: "/history/diff" }).input(SnapshotIdSchema).output(SnapshotDiffSchema),
10
- fileDiff: oc.route({ method: "GET", path: "/history/file-diff" }).input(SnapshotFileDiffQuerySchema).output(FileDiffSchema),
11
- restore: oc.route({ method: "POST", path: "/history/restore" }).input(SnapshotIdSchema).output(OkSchema),
8
+ list: oc
9
+ .route({
10
+ method: "GET",
11
+ path: "/history/snapshots",
12
+ summary: "Points you can go back to",
13
+ description:
14
+ "The saved states of the whole workspace, taken automatically as work happens. This is the timeline behind undoing a change that was never committed.",
15
+ })
16
+ .output(SnapshotsListSchema),
17
+ diff: oc
18
+ .route({
19
+ method: "GET",
20
+ path: "/history/diff",
21
+ summary: "What changed since a saved point",
22
+ description: "The files that differ between one saved point and the one before it, taking in everything that happened in between.",
23
+ })
24
+ .input(SnapshotIdSchema)
25
+ .output(SnapshotDiffSchema),
26
+ fileDiff: oc
27
+ .route({
28
+ method: "GET",
29
+ path: "/history/file-diff",
30
+ summary: "One file's before and after across a saved point",
31
+ description: "Both sides of a single file at one point in the timeline.",
32
+ })
33
+ .input(SnapshotFileDiffQuerySchema)
34
+ .output(FileDiffSchema),
35
+ restore: oc
36
+ .route({
37
+ method: "POST",
38
+ path: "/history/restore",
39
+ summary: "Put the workspace back",
40
+ description:
41
+ "Returns every file to how it stood at a saved point. This restores the files; moving a branch is a different thing and lives with the git calls.",
42
+ })
43
+ .input(SnapshotIdSchema)
44
+ .output(OkSchema),
12
45
  };
@@ -5,13 +5,38 @@ import { IntenticRunSchema, OkSchema } from "../schemas.js";
5
5
  // Run the in-sandbox intentic CLI (resolve/plan/apply/deployments/…) and stream its ndjson lines as they
6
6
  // arrive, so the UI sees live progress. A non-zero exit surfaces as a thrown error once the stream ends.
7
7
  export const intenticContract = {
8
- run: oc.route({ method: "POST", path: "/intentic" }).input(IntenticRunSchema).output(eventIterator(IntenticLineSchema)),
8
+ run: oc
9
+ .route({
10
+ method: "POST",
11
+ path: "/intentic",
12
+ summary: "Run an infrastructure command",
13
+ description:
14
+ "Runs the sandbox's own command-line tool and streams its output as it arrives, so progress is visible rather than arriving all at once at the end. A failure surfaces once the stream closes.",
15
+ })
16
+ .input(IntenticRunSchema)
17
+ .output(eventIterator(IntenticLineSchema)),
9
18
  // Launch the minutes-long apply → adopt reconcile as a one-shot tmux job (session panel-infra-apply) and
10
19
  // return immediately, progress is followed by attaching the terminal, not by holding this request open.
11
- apply: oc.route({ method: "POST", path: "/intentic/apply" }).output(OkSchema),
20
+ apply: oc
21
+ .route({
22
+ method: "POST",
23
+ path: "/intentic/apply",
24
+ summary: "Bring the infrastructure into line",
25
+ description:
26
+ "Starts the long reconcile that makes the running world match what was declared, and answers immediately. It takes minutes, so it runs in a terminal you attach to rather than on a held-open request.",
27
+ })
28
+ .output(OkSchema),
12
29
  // Tail the running (or just-finished) apply's structured event stream, the same ndjson lines the tmux pane
13
30
  // renders as text, persisted to a durable file so the UI shows per-resource progress that survives a page
14
31
  // refresh. Replays from the run's {kind:"start"} then follows live, closing on {kind:"exit"}. GET, like
15
32
  // /events, because it takes no input; reuses the loose IntenticLine shape so no new schema is needed.
16
- applyEvents: oc.route({ method: "GET", path: "/intentic/apply/events" }).output(eventIterator(IntenticLineSchema)),
33
+ applyEvents: oc
34
+ .route({
35
+ method: "GET",
36
+ path: "/intentic/apply/events",
37
+ summary: "Follow the reconcile",
38
+ description:
39
+ "The same progress the terminal shows, as structured events, kept on disk so a page refresh does not lose it. It replays from the start of the run and then follows live, closing when the run ends.",
40
+ })
41
+ .output(eventIterator(IntenticLineSchema)),
17
42
  };