@intentic/sandbox-contract 1.223.0 → 1.225.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.
- package/README.md +14 -14
- package/dist/agent-catalog.js +3 -3
- package/dist/agent-catalog.js.map +1 -1
- package/dist/chores/chores.js +43 -43
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/extension-update.js +2 -2
- package/dist/chores/extension-update.js.map +1 -1
- package/dist/chores/fix-deps.js +1 -1
- package/dist/chores/fix-deps.js.map +1 -1
- package/dist/chores/probes.js +1 -1
- package/dist/chores/probes.js.map +1 -1
- package/dist/chores/prompt.d.ts.map +1 -1
- package/dist/chores/prompt.js +3 -3
- package/dist/chores/prompt.js.map +1 -1
- package/dist/chores/verdict.js +2 -2
- package/dist/chores/verdict.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +41 -0
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/exit.contract.d.ts +80 -0
- package/dist/contracts/exit.contract.d.ts.map +1 -0
- package/dist/contracts/exit.contract.js +13 -0
- package/dist/contracts/exit.contract.js.map +1 -0
- package/dist/contracts/ports.contract.d.ts +11 -0
- package/dist/contracts/ports.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +12 -0
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/events.d.ts +4 -4
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +5 -5
- package/dist/events.js.map +1 -1
- package/dist/fast-tier.d.ts +9 -0
- package/dist/fast-tier.d.ts.map +1 -0
- package/dist/fast-tier.js +19 -0
- package/dist/fast-tier.js.map +1 -0
- package/dist/history-state.js +3 -3
- package/dist/history-state.js.map +1 -1
- package/dist/index.d.ts +214 -68
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/model-order.d.ts +1 -0
- package/dist/model-order.d.ts.map +1 -1
- package/dist/model-order.js +5 -0
- package/dist/model-order.js.map +1 -1
- package/dist/output-fields.d.ts.map +1 -1
- package/dist/output-fields.js +2 -2
- package/dist/output-fields.js.map +1 -1
- package/dist/prompt-complexity.d.ts +19 -0
- package/dist/prompt-complexity.d.ts.map +1 -0
- package/dist/prompt-complexity.js +83 -0
- package/dist/prompt-complexity.js.map +1 -0
- package/dist/publish-drafts.js +2 -2
- package/dist/publish-drafts.js.map +1 -1
- package/dist/schemas.d.ts +236 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +116 -2
- package/dist/schemas.js.map +1 -1
- package/dist/workflow-faults.js +3 -3
- package/dist/workflow-faults.js.map +1 -1
- package/dist/workspace-state.d.ts +20 -20
- package/dist/workspace-state.d.ts.map +1 -1
- package/dist/workspace-state.js +20 -20
- package/dist/workspace-state.js.map +1 -1
- package/package.json +5 -5
- package/src/agent-catalog.test.ts +25 -25
- package/src/agent-catalog.ts +81 -81
- package/src/agent-run-model.test.ts +3 -3
- package/src/agent-run-model.ts +8 -8
- package/src/capability-env.ts +3 -3
- package/src/capability-ledger.test.ts +13 -13
- package/src/capability-secrets.ts +5 -5
- package/src/chores/chores.test.ts +1 -1
- package/src/chores/chores.ts +109 -109
- package/src/chores/digest.test.ts +1 -1
- package/src/chores/digest.ts +3 -3
- package/src/chores/extension-update.ts +5 -5
- package/src/chores/fix-deps.ts +4 -4
- package/src/chores/probes.test.ts +6 -6
- package/src/chores/probes.ts +17 -17
- package/src/chores/prompt.ts +9 -9
- package/src/chores/stack.test.ts +3 -3
- package/src/chores/stack.ts +17 -17
- package/src/chores/verdict.test.ts +20 -20
- package/src/chores/verdict.ts +25 -25
- package/src/contract-lock.test.ts +1 -1
- package/src/contract-lock.ts +7 -7
- package/src/contracts/activity.contract.ts +1 -1
- package/src/contracts/agent.contract.ts +2 -2
- package/src/contracts/agents.contract.ts +11 -11
- package/src/contracts/automations.contract.ts +5 -5
- package/src/contracts/capabilities.contract.ts +7 -7
- package/src/contracts/chores.contract.ts +3 -3
- package/src/contracts/ci.contract.ts +2 -2
- package/src/contracts/claude.contract.ts +3 -3
- package/src/contracts/drafts.contract.ts +1 -1
- package/src/contracts/endpoints.contract.ts +2 -2
- package/src/contracts/exit.contract.ts +42 -0
- package/src/contracts/extensions.contract.ts +8 -8
- package/src/contracts/git.contract.ts +6 -6
- package/src/contracts/grok.contract.ts +4 -4
- package/src/contracts/host.contract.ts +5 -5
- package/src/contracts/intentic.contract.ts +2 -2
- package/src/contracts/logs.contract.ts +1 -1
- package/src/contracts/loops.contract.ts +8 -8
- package/src/contracts/personas.contract.ts +8 -8
- package/src/contracts/ports.contract.ts +1 -1
- package/src/contracts/prepush.contract.ts +2 -2
- package/src/contracts/providers.contract.ts +4 -4
- package/src/contracts/public.contract.ts +1 -1
- package/src/contracts/push.contract.ts +2 -2
- package/src/contracts/secrets.contract.ts +2 -2
- package/src/contracts/sessions.contract.ts +2 -2
- package/src/contracts/settings.contract.ts +3 -3
- package/src/contracts/share.contract.ts +1 -1
- package/src/contracts/skills.contract.ts +2 -2
- package/src/contracts/system.contract.ts +9 -9
- package/src/contracts/usage.contract.ts +1 -1
- package/src/contracts/vpn.contract.ts +5 -5
- package/src/contracts/workflows.contract.ts +12 -12
- package/src/contracts/workspace.contract.ts +13 -13
- package/src/conversation-ids.ts +8 -8
- package/src/events.test.ts +3 -3
- package/src/events.ts +142 -142
- package/src/fast-tier.test.ts +88 -0
- package/src/fast-tier.ts +72 -0
- package/src/history-state.ts +15 -15
- package/src/host-protocol.ts +7 -7
- package/src/hostnames.test.ts +1 -1
- package/src/hostnames.ts +15 -15
- package/src/index.ts +13 -8
- package/src/listener-protocol.ts +12 -12
- package/src/model-order.test.ts +11 -11
- package/src/model-order.ts +52 -30
- package/src/output-fields.ts +11 -11
- package/src/path-refs.test.ts +4 -4
- package/src/path-refs.ts +6 -6
- package/src/prompt-complexity.test.ts +160 -0
- package/src/prompt-complexity.ts +271 -0
- package/src/publish-drafts.ts +8 -8
- package/src/quick-model.test.ts +11 -11
- package/src/quick-model.ts +15 -15
- package/src/routes.test.ts +11 -5
- package/src/routes.ts +19 -19
- package/src/runtime-state.test.ts +1 -1
- package/src/runtime-state.ts +22 -22
- package/src/schemas.test.ts +8 -8
- package/src/schemas.ts +1238 -921
- package/src/search-globs.test.ts +2 -2
- package/src/search-globs.ts +6 -6
- package/src/session-names.ts +5 -5
- package/src/share-paths.test.ts +1 -1
- package/src/share-paths.ts +7 -7
- package/src/sse.ts +1 -1
- package/src/state-portability.ts +8 -8
- package/src/terminal-protocol.ts +3 -3
- package/src/title.test.ts +9 -9
- package/src/title.ts +21 -21
- package/src/tunnel-ids.test.ts +3 -3
- package/src/tunnel-ids.ts +7 -7
- package/src/versions.test.ts +3 -3
- package/src/versions.ts +6 -6
- package/src/workflow-faults.test.ts +6 -6
- package/src/workflow-faults.ts +14 -14
- package/src/workspace-state.test.ts +32 -32
- package/src/workspace-state.ts +139 -139
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
// Pipelines on the workspace repos' github/gitlab remotes. `runs` serves the Pipelines rail view (cache +
|
|
13
13
|
// on-demand backfill; per-repo webhook warnings ride along); `rerun`/`cancel` proxy to the vendor; `fix`
|
|
14
14
|
// opens an isolated agent conversation seeded with the failure context. The public webhook receiver
|
|
15
|
-
// (/ci/webhook/:host) is a plain Hono route
|
|
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
18
|
runs: oc.route({ method: "GET", path: "/ci/runs" }).output(CiRunsResponseSchema),
|
|
@@ -20,7 +20,7 @@ export const ciContract = {
|
|
|
20
20
|
cancel: oc.route({ method: "POST", path: "/ci/runs/cancel" }).input(CiRunParamSchema).output(OkSchema),
|
|
21
21
|
jobs: oc.route({ method: "POST", path: "/ci/runs/jobs" }).input(CiRunParamSchema).output(CiJobsResponseSchema),
|
|
22
22
|
fix: oc.route({ method: "POST", path: "/ci/fix" }).input(CiFixParamSchema).output(CiFixResponseSchema),
|
|
23
|
-
// "I have looked at the pipelines"
|
|
23
|
+
// "I have looked at the pipelines", what silences the rail badge for breakages already read. No input:
|
|
24
24
|
// the surface is read as a whole, and the daemon stamps its own clock so a skewed browser can't mark
|
|
25
25
|
// future failures as already seen.
|
|
26
26
|
seen: oc.route({ method: "POST", path: "/ci/seen" }).output(CiSeenResponseSchema),
|
|
@@ -10,18 +10,18 @@ import {
|
|
|
10
10
|
OkSchema,
|
|
11
11
|
} from "../schemas.js";
|
|
12
12
|
|
|
13
|
-
// Claude subscription OAuth
|
|
13
|
+
// Claude subscription OAuth, the sandbox owns the credential. `start` hands the browser the authorize URL +
|
|
14
14
|
// PKCE material; `exchange` stores the resulting tokens as a new account and returns it; `accounts` lists the
|
|
15
15
|
// connected accounts; `rename` renames one; `disconnect` clears the one named by id. A sandbox can hold several
|
|
16
16
|
// Claude accounts.
|
|
17
17
|
//
|
|
18
18
|
// The model catalog is NOT here: it is the one thing every provider answers identically, so it lives on the
|
|
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
22
|
start: oc.route({ method: "POST", path: "/claude/oauth/start" }).output(AuthorizeChallengeSchema),
|
|
23
23
|
exchange: oc.route({ method: "POST", path: "/claude/oauth/exchange" }).input(OauthExchangeSchema).output(OauthAccountSchema),
|
|
24
|
-
// Each account carries its plan-limit reading. `force` re-measures before answering
|
|
24
|
+
// Each account carries its plan-limit reading. `force` re-measures before answering, see
|
|
25
25
|
// AccountListQuerySchema, and USAGE_WAIT_MS in claude.routes.ts for what an ordinary read waits.
|
|
26
26
|
accounts: oc.route({ method: "GET", path: "/claude/accounts" }).input(AccountListQuerySchema).output(OauthAccountListSchema),
|
|
27
27
|
rename: oc.route({ method: "POST", path: "/claude/account/rename" }).input(AccountRenameSchema).output(OauthAccountSchema),
|
|
@@ -2,7 +2,7 @@ import { oc } from "@orpc/contract";
|
|
|
2
2
|
import { DraftIdParamSchema, DraftsListSchema, DraftSummarySchema, OkSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
4
|
// The sandbox's post-drafts queue (agent-proposed posts awaiting approval). The agent creates draft files
|
|
5
|
-
// directly
|
|
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
8
|
list: oc.route({ method: "GET", path: "/drafts" }).output(DraftsListSchema),
|
|
@@ -2,12 +2,12 @@ import { oc } from "@orpc/contract";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { CapabilityIdParamSchema, ModelsSchema } from "../schemas.js";
|
|
4
4
|
|
|
5
|
-
// An `endpoint` capability's picker catalog
|
|
5
|
+
// An `endpoint` capability's picker catalog, the models the configured server itself publishes, read from its
|
|
6
6
|
// own /v1/models. Every other provider's catalog is one fixed route because there is one of each; endpoints are
|
|
7
7
|
// user-created and unbounded, so the id rides in the path. There is no seed floor and no static list: what a
|
|
8
8
|
// model API serves is knowable only by asking it, and an empty answer is the honest report that we could not.
|
|
9
9
|
|
|
10
|
-
/* The free trial's remaining allowance, on the endpoints contract because the trial IS an endpoint
|
|
10
|
+
/* The free trial's remaining allowance, on the endpoints contract because the trial IS an endpoint, the one
|
|
11
11
|
* the daemon provisions rather than the user (agent-catalog.ts TRIAL_ENDPOINT_ID). It is a separate read from
|
|
12
12
|
* the catalog above because it answers a different question and changes on a different clock: the model list is
|
|
13
13
|
* a property of the upstream, while this is a property of the ACCOUNT and moves with every message sent.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { eventIterator, oc } from "@orpc/contract";
|
|
2
|
+
import { IntenticLineSchema } from "../events.js";
|
|
3
|
+
import { ExitCountriesSchema, ExitIdParamSchema, ExitListSchema, ExitObservationSchema, ExitUseInputSchema, OkSchema } from "../schemas.js";
|
|
4
|
+
|
|
5
|
+
// The live GEO EXIT surface. An exit is ADDED as an `exit` capability (which provider, a resting country,
|
|
6
|
+
// whether it comes up on boot); it is STARTED, MOVED and ROTATED here. Same split as the vpn contract and for
|
|
7
|
+
// the same reason: switching country is a runtime operation performed many times over one stored pool, by the
|
|
8
|
+
// operator from the Status card and by the agent through `exit` on its PATH, which calls these very routes.
|
|
9
|
+
//
|
|
10
|
+
// The difference from vpn is what "success" means. A dial succeeds when the tunnel is up; a country switch
|
|
11
|
+
// succeeds only when the egress ADDRESS has moved, which is why `use` and `rotate` end by fetching an
|
|
12
|
+
// ExitObservation through the exit's own proxy and fail when it does not agree with what was asked for.
|
|
13
|
+
//
|
|
14
|
+
// Nothing here changes the sandbox's default route, ever. Each exit publishes a SOCKS proxy and callers opt
|
|
15
|
+
// in; the daemon's own traffic, the model endpoint and the tunnel that makes this sandbox reachable stay on
|
|
16
|
+
// the plain uplink no matter what is up.
|
|
17
|
+
export const exitContract = {
|
|
18
|
+
// Every configured exit with its live state, where it was asked to come out and where it actually does.
|
|
19
|
+
// Drives the Status card, the browser account picker and `geo list` (the CLI is `geo`: `exit` is a shell
|
|
20
|
+
// builtin, so a binary of that name is unreachable from a command line).
|
|
21
|
+
list: oc.route({ method: "GET", path: "/exit" }).output(ExitListSchema),
|
|
22
|
+
// What this exit can reach, ranked by how much capacity is actually there. Live from the provider when it
|
|
23
|
+
// answers (Tor's directory, VPN Gate's CSV, the pasted confs), from the baked fallback when it does not,
|
|
24
|
+
// 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),
|
|
26
|
+
// Bring the exit up at its stored country. Streams, because a first start pulls a catalog, brings up a
|
|
27
|
+
// tunnel and then verifies the address, which is tens of seconds on the free providers and can fail at
|
|
28
|
+
// 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)),
|
|
30
|
+
// Move to another country, starting the exit first if it was down. Streams for the same reason as start,
|
|
31
|
+
// and THROWS when the observed country does not end up matching: a switch that silently left traffic where
|
|
32
|
+
// 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)),
|
|
34
|
+
// A different address in the SAME country. Cheap on tor (a control-port signal), a re-dial to another
|
|
35
|
+
// 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)),
|
|
37
|
+
// What the world sees through this exit right now. Cheap, unstreamed, and the honest answer to "am I
|
|
38
|
+
// 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),
|
|
40
|
+
// 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),
|
|
42
|
+
};
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
WorkspaceExtensionCreateSchema,
|
|
20
20
|
} from "../schemas.js";
|
|
21
21
|
|
|
22
|
-
// Installed extensions resolved to their approved manifests
|
|
22
|
+
// Installed extensions resolved to their approved manifests, what the web extension host boots from. The
|
|
23
23
|
// bundle itself is a plain Hono route (GET /extensions/{id}/bundle): raw ESM bytes are not an oRPC payload.
|
|
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.
|
|
@@ -27,28 +27,28 @@ export const extensionsContract = {
|
|
|
27
27
|
list: oc.route({ method: "GET", path: "/extensions" }).output(ExtensionsListSchema),
|
|
28
28
|
// Author a new extension in place: writes a running one into .intentic/config/workspace-extensions/<name>/. The only
|
|
29
29
|
// creating route here, and it exists because that directory is otherwise reachable exclusively through an
|
|
30
|
-
// agent's file tools
|
|
30
|
+
// agent's file tools, which is a fine way to CHANGE an extension and a poor way to meet the idea of one.
|
|
31
31
|
create: oc.route({ method: "POST", path: "/extensions/workspace" }).input(WorkspaceExtensionCreateSchema).output(WorkspaceExtensionCreatedSchema),
|
|
32
32
|
settings: oc.route({ method: "GET", path: "/extensions/{id}/settings" }).input(CapabilityIdParamSchema).output(ExtensionSettingsSchema),
|
|
33
33
|
setSettings: oc.route({ method: "POST", path: "/extensions/{id}/settings" }).input(ExtensionSettingsInputSchema).output(OkSchema),
|
|
34
34
|
// The owner's on/off switch. Disabling stops the extension's declared processes here and now; its agent
|
|
35
35
|
// plugin dir and PATH entry are rebuilt per turn, and an `environment` fragment only at the next image
|
|
36
|
-
// rebuild
|
|
36
|
+
// rebuild, the Extensions tab states which of those an extension actually has.
|
|
37
37
|
setEnabled: oc.route({ method: "POST", path: "/extensions/{id}/enabled" }).input(ExtensionEnabledInputSchema).output(OkSchema),
|
|
38
38
|
// The host reporting which declared routes it just let through. Written by the browser because that is where
|
|
39
|
-
// the permission gate runs (apiImpl.ts)
|
|
39
|
+
// the permission gate runs (apiImpl.ts), the daemon sees an extension's traffic as ordinary authenticated
|
|
40
40
|
// requests and cannot tell which extension, or which declared entry, any of it belongs to.
|
|
41
41
|
recordUsage: oc.route({ method: "POST", path: "/extensions/{id}/usage" }).input(ExtensionUsageInputSchema).output(OkSchema),
|
|
42
|
-
/* Whether this extension is fit for somebody else to run
|
|
42
|
+
/* Whether this extension is fit for somebody else to run, the checks answerable from its files alone. Read
|
|
43
43
|
* on demand rather than carried on the list: it reads the bundle off disk per extension, and it is looked at
|
|
44
44
|
* when an author is about to publish, not every time the tab renders. */
|
|
45
45
|
readiness: oc.route({ method: "GET", path: "/extensions/{id}/readiness" }).input(CapabilityIdParamSchema).output(ExtensionReadinessSchema),
|
|
46
46
|
/* The update lifecycle for a GIT-INSTALLED extension. The list carries what the periodic registry check
|
|
47
47
|
* found (update/advisory/health per row); these are the verbs around it. `checkUpdates` runs the comparison
|
|
48
48
|
* now (the tab's "check now"). `updatePreview` stages the offered sha and answers with the version story +
|
|
49
|
-
* the mechanical powers diff
|
|
49
|
+
* the mechanical powers diff, the read BEFORE the click, costing one throwaway clone like a registry
|
|
50
50
|
* browse. `applyUpdate` is the transaction: re-clone, validate, quiesce, swap (keeping the outgoing
|
|
51
|
-
* checkout one back), restart, health-watch
|
|
51
|
+
* checkout one back), restart, health-watch, on the EXISTING capability config, so a private-source token
|
|
52
52
|
* survives what a bare re-add would lose. `revert` swaps the kept-previous checkout back. Update and revert
|
|
53
53
|
* change the code that runs, so like install they are owner-only. */
|
|
54
54
|
checkUpdates: oc.route({ method: "POST", path: "/extensions/updates/check" }).output(ExtensionUpdatesCheckedSchema),
|
|
@@ -61,7 +61,7 @@ export const extensionsContract = {
|
|
|
61
61
|
.input(ExtensionUpdateActionSchema)
|
|
62
62
|
.output(ExtensionUpdateAppliedSchema),
|
|
63
63
|
revert: oc.route({ method: "POST", path: "/extensions/{id}/revert" }).input(CapabilityIdParamSchema).output(ExtensionUpdateAppliedSchema),
|
|
64
|
-
// The owner's standing answer per extension (notify / agent / auto, and the advisory opt-out)
|
|
64
|
+
// The owner's standing answer per extension (notify / agent / auto, and the advisory opt-out), see
|
|
65
65
|
// ExtensionUpdatePolicySchema for what each rung means.
|
|
66
66
|
setUpdatePolicy: oc.route({ method: "POST", path: "/extensions/{id}/update-policy" }).input(ExtensionUpdatePolicyInputSchema).output(OkSchema),
|
|
67
67
|
// Declared background processes (contributes.processes): tmux-managed through the panel machinery
|
|
@@ -54,9 +54,9 @@ export const gitContract = {
|
|
|
54
54
|
changes: oc.route({ method: "GET", path: "/git/changes" }).output(GitChangesSchema),
|
|
55
55
|
// The git-history graph over one repo's real commits: the repo list (for the tree affordance + switcher),
|
|
56
56
|
// one repo's commit log, and lazy per-commit detail (changed files, then a file's before/after AT the
|
|
57
|
-
// commit). Read-only
|
|
57
|
+
// commit). Read-only, commit/discard on the working tree stay the write path (above).
|
|
58
58
|
repos: oc.route({ method: "GET", path: "/git/repos" }).output(GitReposSchema),
|
|
59
|
-
// The same repos with the host + project their remote names
|
|
59
|
+
// The same repos with the host + project their remote names, how a caller recognises a workspace repo in a
|
|
60
60
|
// list of `owner/name` strings that came from somewhere else. Kept off `repos` (a `git remote -v` per repo).
|
|
61
61
|
remoteRepos: oc.route({ method: "GET", path: "/git/remote-repos" }).output(GitRemoteReposSchema),
|
|
62
62
|
log: oc.route({ method: "GET", path: "/git/{repo}/log" }).input(GitLogQuerySchema).output(GitLogSchema),
|
|
@@ -67,13 +67,13 @@ export const gitContract = {
|
|
|
67
67
|
// GitActionResult so a conflict/clean-apply failure is a value, not a 500. Read routes above.
|
|
68
68
|
/* The halted-operation pair. `operation` is a READ every git surface can use to explain a worktree it cannot
|
|
69
69
|
* otherwise act on; `abort` is the single way out, and it is git's own `--abort` rather than anything
|
|
70
|
-
* clever. Neither is reachable from the daemon's own verbs
|
|
70
|
+
* clever. Neither is reachable from the daemon's own verbs, those abort themselves, so this exists purely
|
|
71
71
|
* for what a terminal left behind. */
|
|
72
72
|
operation: oc.route({ method: "GET", path: "/git/{repo}/operation" }).input(RepoParamSchema).output(GitOperationStateSchema),
|
|
73
73
|
abort: oc.route({ method: "POST", path: "/git/{repo}/abort" }).input(RepoParamSchema).output(GitActionResultSchema),
|
|
74
74
|
/* Walk the current branch back to where it was before its last action, off the branch's own reflog. The
|
|
75
75
|
* complement to the Checkpoints timeline, not a duplicate of it: a checkpoint restores the working tree,
|
|
76
|
-
* this moves the ref. The read carries `previousSha`, which the write sends back as a concurrency token
|
|
76
|
+
* this moves the ref. The read carries `previousSha`, which the write sends back as a concurrency token,
|
|
77
77
|
* an undo prepared against a stale view is refused rather than landing somewhere unlooked-at. */
|
|
78
78
|
undoable: oc.route({ method: "GET", path: "/git/{repo}/undo" }).input(RepoParamSchema).output(GitUndoStateSchema),
|
|
79
79
|
undo: oc.route({ method: "POST", path: "/git/{repo}/undo" }).input(GitUndoSchema).output(GitActionResultSchema),
|
|
@@ -101,7 +101,7 @@ export const gitContract = {
|
|
|
101
101
|
status: oc.route({ method: "GET", path: "/git/{repo}/status" }).input(RepoParamSchema).output(GitStatusSchema),
|
|
102
102
|
commit: oc.route({ method: "POST", path: "/git/{repo}/commit" }).input(CommitSchema).output(CommitResultSchema),
|
|
103
103
|
discard: oc.route({ method: "POST", path: "/git/{repo}/discard" }).input(DiscardSchema).output(OkSchema),
|
|
104
|
-
// Index moves. Per-path, worktree untouched, so they need no checkpoint and can't fail destructively
|
|
104
|
+
// Index moves. Per-path, worktree untouched, so they need no checkpoint and can't fail destructively,
|
|
105
105
|
// git's own error (an unmatched pathspec) propagates.
|
|
106
106
|
stage: oc.route({ method: "POST", path: "/git/{repo}/stage" }).input(GitStageSchema).output(OkSchema),
|
|
107
107
|
unstage: oc.route({ method: "POST", path: "/git/{repo}/unstage" }).input(GitStageSchema).output(OkSchema),
|
|
@@ -113,7 +113,7 @@ export const gitContract = {
|
|
|
113
113
|
deleteBranch: oc.route({ method: "POST", path: "/git/{repo}/branches/delete" }).input(GitBranchDeleteSchema).output(OkSchema),
|
|
114
114
|
// Remote sync. All three report a GitActionResult rather than throwing: no remote, no credentials and a
|
|
115
115
|
// non-fast-forwardable pull are ORDINARY outcomes the panel renders, not 500s. `remote` is the read
|
|
116
|
-
// (ahead/behind as of the last fetch
|
|
116
|
+
// (ahead/behind as of the last fetch, hence the Fetch button) the sync bar polls.
|
|
117
117
|
remote: oc.route({ method: "GET", path: "/git/{repo}/remote" }).input(RepoParamSchema).output(GitRemoteStateSchema),
|
|
118
118
|
fetch: oc.route({ method: "POST", path: "/git/{repo}/fetch" }).input(RepoParamSchema).output(GitActionResultSchema),
|
|
119
119
|
pull: oc.route({ method: "POST", path: "/git/{repo}/pull" }).input(RepoParamSchema).output(GitActionResultSchema),
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { oc } from "@orpc/contract";
|
|
2
2
|
import { AccountIdSchema, DeviceStartSchema, OauthAccountListSchema, OkSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
|
-
// xAI Grok (via OpenCode) uses subscription OAuth
|
|
4
|
+
// xAI Grok (via OpenCode) uses subscription OAuth, the sandbox owns the credential (OpenCode persists the
|
|
5
5
|
// tokens and refreshes them). `start` authorizes xAI's headless device-code method and returns the verification
|
|
6
6
|
// URL + instructions (which carry the one-time code the user enters at x.ai); OpenCode then polls to completion
|
|
7
|
-
|
|
8
|
-
// ponytail: OpenCode holds one xAI auth per data dir, so `accounts` is 0 or 1
|
|
7
|
+
//, there is no paste-back, and the UI polls `accounts` until connected. `disconnect` clears the tokens.
|
|
8
|
+
// ponytail: OpenCode holds one xAI auth per data dir, so `accounts` is 0 or 1, the list shape matches the
|
|
9
9
|
// other providers without paying for per-account OpenCode servers yet.
|
|
10
10
|
//
|
|
11
|
-
// Like Claude's, this contract is now the account handshake alone
|
|
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
14
|
start: oc.route({ method: "POST", path: "/grok/oauth/start" }).output(DeviceStartSchema),
|
|
@@ -6,7 +6,7 @@ import { HostFactsSchema, HostScopesSchema, MachineFlowLineSchema, MachineSandbo
|
|
|
6
6
|
*
|
|
7
7
|
* The direction is the unusual part: the machine is the oRPC SERVER and the daemon holds the client, even though
|
|
8
8
|
* the machine is the side that dialled. A personal computer sits behind NAT with a closing lid, so it can only
|
|
9
|
-
* ever be the one that connects
|
|
9
|
+
* ever be the one that connects, but everything is asked OF it. oRPC's websocket adapter takes any socket-like
|
|
10
10
|
* object on either side, so the roles are free to be the opposite of who placed the call.
|
|
11
11
|
*
|
|
12
12
|
* No `.route()` on these: HTTP method and path are for the daemon's own REST surface, and this contract never
|
|
@@ -14,12 +14,12 @@ import { HostFactsSchema, HostScopesSchema, MachineFlowLineSchema, MachineSandbo
|
|
|
14
14
|
*
|
|
15
15
|
* `mcp` IS THE DELIBERATE HOLE in the typing, and it is worth understanding before someone "fixes" it. The agent
|
|
16
16
|
* talks to a machine in MCP, over the daemon's loopback bridge; if this contract described each tool, then the
|
|
17
|
-
* daemon would have to know every tool's schema and translate
|
|
17
|
+
* daemon would have to know every tool's schema and translate, and a machine could no longer learn a tool
|
|
18
18
|
* without a matching daemon release. Keeping one opaque procedure is what buys the machine an independent
|
|
19
19
|
* release cycle. The payload is still validated where it is understood: on the machine, against the tool's own
|
|
20
20
|
* schema, and by the agent's MCP client on the way back. */
|
|
21
21
|
export const hostContract = {
|
|
22
|
-
// What this computer is
|
|
22
|
+
// What this computer is, pulled right after the socket authenticates, and again whenever the sandbox wants
|
|
23
23
|
// it fresh. The card shows it, and the agent's skill pack is written against it.
|
|
24
24
|
describe: oc.output(HostFactsSchema),
|
|
25
25
|
// The grant, pushed down on every connect and again whenever the owner edits the card. The machine ENFORCES
|
|
@@ -28,7 +28,7 @@ export const hostContract = {
|
|
|
28
28
|
// Liveness, driven by the daemon: it doubles as the keepalive that stops an idle tunnel from reaping the
|
|
29
29
|
// connection, and as the probe whose failure means the machine is gone rather than quiet.
|
|
30
30
|
ping: oc.output(OkSchema),
|
|
31
|
-
// One MCP JSON-RPC message in, its answer out
|
|
31
|
+
// One MCP JSON-RPC message in, its answer out, forwarded verbatim in both directions. See above.
|
|
32
32
|
mcp: oc.input(z.unknown()).output(z.unknown()),
|
|
33
33
|
/* One operation on one of this machine's sandboxes, narrated as it happens.
|
|
34
34
|
*
|
|
@@ -38,7 +38,7 @@ export const hostContract = {
|
|
|
38
38
|
* container, which is minutes of silence unless the lines travel while they are produced. A stream is what
|
|
39
39
|
* the browser needs, and a stream is the one thing an MCP tool result cannot be.
|
|
40
40
|
*
|
|
41
|
-
* The scope is still checked here, on the machine, by the same functions the MCP tools call
|
|
41
|
+
* The scope is still checked here, on the machine, by the same functions the MCP tools call, this adds a
|
|
42
42
|
* way of WATCHING an operation, never a way of skipping the switch that permits it. */
|
|
43
43
|
runSandboxFlow: oc.input(MachineSandboxFlowSchema).output(eventIterator(MachineFlowLineSchema)),
|
|
44
44
|
};
|
|
@@ -7,9 +7,9 @@ import { IntenticRunSchema, OkSchema } from "../schemas.js";
|
|
|
7
7
|
export const intenticContract = {
|
|
8
8
|
run: oc.route({ method: "POST", path: "/intentic" }).input(IntenticRunSchema).output(eventIterator(IntenticLineSchema)),
|
|
9
9
|
// Launch the minutes-long apply → adopt reconcile as a one-shot tmux job (session panel-infra-apply) and
|
|
10
|
-
// return immediately
|
|
10
|
+
// return immediately, progress is followed by attaching the terminal, not by holding this request open.
|
|
11
11
|
apply: oc.route({ method: "POST", path: "/intentic/apply" }).output(OkSchema),
|
|
12
|
-
// Tail the running (or just-finished) apply's structured event stream
|
|
12
|
+
// Tail the running (or just-finished) apply's structured event stream, the same ndjson lines the tmux pane
|
|
13
13
|
// renders as text, persisted to a durable file so the UI shows per-resource progress that survives a page
|
|
14
14
|
// refresh. Replays from the run's {kind:"start"} then follows live, closing on {kind:"exit"}. GET, like
|
|
15
15
|
// /events, because it takes no input; reuses the loose IntenticLine shape so no new schema is needed.
|
|
@@ -2,7 +2,7 @@ import { oc } from "@orpc/contract";
|
|
|
2
2
|
import { LogReadQuerySchema, LogReadSchema, LogsListSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
4
|
// Daemon-owned debug logs (historyRoot/logs): terminal pipe-pane captures, intentic CLI run logs, daemon.log.
|
|
5
|
-
// Read-only by design
|
|
5
|
+
// Read-only by design, the files are written by the daemon/tmux only, so the record stays trustworthy.
|
|
6
6
|
export const logsContract = {
|
|
7
7
|
list: oc.route({ method: "GET", path: "/logs" }).output(LogsListSchema),
|
|
8
8
|
read: oc.route({ method: "GET", path: "/logs/file" }).input(LogReadQuerySchema).output(LogReadSchema),
|
|
@@ -11,29 +11,29 @@ import {
|
|
|
11
11
|
OkSchema,
|
|
12
12
|
} from "../schemas.js";
|
|
13
13
|
|
|
14
|
-
/* The loop routes
|
|
14
|
+
/* The loop routes, "run this conversation again until the goal is met".
|
|
15
15
|
*
|
|
16
16
|
* TWO HALVES THAT LOOK LIKE ONE FEATURE AND ARE NOT, which is why they share a file and share nothing else.
|
|
17
17
|
*
|
|
18
18
|
* A RUNNING LOOP has no editor. It is started against a conversation, it converges or it gives up, and then it
|
|
19
|
-
* is history: `start`, `stop`, and a `list` of what has run. No upsert, no enabled toggle, no id of its own
|
|
19
|
+
* is history: `start`, `stop`, and a `list` of what has run. No upsert, no enabled toggle, no id of its own,
|
|
20
20
|
* the conversation IS the id.
|
|
21
21
|
*
|
|
22
22
|
* A SAVED LOOP is a manifest entry like a workflow, and gets the manifest treatment: list, save, remove. It is
|
|
23
23
|
* the loop's MACHINERY without its goal (LoopDesignSchema says why at length), so it is authored once and
|
|
24
|
-
* pointed at a different job every time. It has no `run` route of its own on purpose
|
|
24
|
+
* pointed at a different job every time. It has no `run` route of its own on purpose, running one is `start`
|
|
25
25
|
* with the design's fields and the composer's sentence, so there is exactly one way a loop begins and exactly
|
|
26
26
|
* one place that can refuse it.
|
|
27
27
|
*
|
|
28
28
|
* `start` acks immediately with the loop as recorded and runs detached, the same contract POST /agent keeps: the
|
|
29
29
|
* first iteration alone can take minutes, and every surface that would render progress is already attached to
|
|
30
|
-
* the conversation. What comes back is the record, not an outcome
|
|
30
|
+
* the conversation. What comes back is the record, not an outcome, the outcome arrives on the fleet card.
|
|
31
31
|
*/
|
|
32
32
|
export const loopsContract = {
|
|
33
|
-
// Every loop this workspace has run, newest first
|
|
33
|
+
// Every loop this workspace has run, newest first, the record is kept after the loop ends, because "why did
|
|
34
34
|
// it stop at iteration 4" is the question a loop is read for, and the answer is its iteration history.
|
|
35
35
|
list: oc.route({ method: "GET", path: "/loops" }).output(LoopsListSchema),
|
|
36
|
-
/* Start looping a conversation. Rejects when that conversation is already looping
|
|
36
|
+
/* Start looping a conversation. Rejects when that conversation is already looping, a second loop on one
|
|
37
37
|
* agent would have two pumps racing the same worktree and the same turn mutex, and the loser would spend a
|
|
38
38
|
* turn to discover it.
|
|
39
39
|
*
|
|
@@ -49,10 +49,10 @@ export const loopsContract = {
|
|
|
49
49
|
stop: oc.route({ method: "POST", path: "/loops/{conversationId}/stop" }).input(LoopIdParamSchema).output(OkSchema),
|
|
50
50
|
|
|
51
51
|
// Every saved loop. A literal path segment under /loops rather than a surface of its own, because a saved
|
|
52
|
-
// loop is not a different feature
|
|
52
|
+
// loop is not a different feature, it is the same loop with its goal left blank until somebody types one.
|
|
53
53
|
designs: oc.route({ method: "GET", path: "/loops/designs" }).output(LoopDesignsListSchema),
|
|
54
54
|
/* Create or replace a saved loop, with the operation explicit so a name collision cannot turn a create into
|
|
55
|
-
* a replacement. Refuses a design that could never finish
|
|
55
|
+
* a replacement. Refuses a design that could never finish, nothing to produce and nothing to check, with
|
|
56
56
|
* the same sentence `start` refuses an ad-hoc loop for, because it is the same mistake made earlier and
|
|
57
57
|
* catching it at save time is the whole advantage of saving. */
|
|
58
58
|
saveDesign: oc.route({ method: "POST", path: "/loops/designs" }).input(LoopDesignSaveSchema).output(LoopDesignSchema),
|
|
@@ -13,12 +13,12 @@ import {
|
|
|
13
13
|
|
|
14
14
|
/* The sandbox's named personas (PersonaSchema): which connected accounts each one speaks for, what a session
|
|
15
15
|
* wearing it may do, where it works, and what it is told. The card half is a plain three-verb CRUD with no apply
|
|
16
|
-
* step, because a card provisions NOTHING
|
|
16
|
+
* step, because a card provisions NOTHING, unlike a capability, saving one connects nothing, installs nothing
|
|
17
17
|
* and spends nothing. It records a decision about accounts that already exist.
|
|
18
18
|
*
|
|
19
19
|
* The file behind it is committed workspace config (personas/personas-store.ts), so these routes are one of
|
|
20
20
|
* two equally supported ways to edit them: this, and opening the file in the editor like any other project
|
|
21
|
-
* config. Neither is the "real" one
|
|
21
|
+
* config. Neither is the "real" one, which is why `save` is a whole-card upsert rather than a field patch, so
|
|
22
22
|
* a round trip through the UI leaves a diff a reviewer would recognise.
|
|
23
23
|
*
|
|
24
24
|
* THE KIT ROUTES BELOW EDIT FILES, not the card, and they are here rather than on the skills contract because
|
|
@@ -30,14 +30,14 @@ import {
|
|
|
30
30
|
* a save that shipped the whole folder would make an edit to one skill capable of deleting another. */
|
|
31
31
|
export const personasContract = {
|
|
32
32
|
list: oc.route({ method: "GET", path: "/personas" }).output(PersonasListSchema),
|
|
33
|
-
// Upsert by id
|
|
33
|
+
// Upsert by id, re-saving the same id edits that card.
|
|
34
34
|
save: oc.route({ method: "POST", path: "/personas" }).input(PersonaSchema).output(OkSchema),
|
|
35
35
|
/* Removing a card takes away a persona, never an account: the login it named stays connected and reachable from
|
|
36
|
-
* every other surface. What it CAN do is orphan a reference
|
|
37
|
-
* card that no longer exists
|
|
36
|
+
* every other surface. What it CAN do is orphan a reference, an automation pinned to this id now names a
|
|
37
|
+
* card that no longer exists, and the resolver reads that as "no accounts at all" rather than "all of
|
|
38
38
|
* them", so the automation goes quiet instead of posting as somebody unintended. */
|
|
39
39
|
/* Removing a card takes away a persona, never an account: the login it named stays connected and reachable from
|
|
40
|
-
* every other surface. It DOES take the card's kit with it
|
|
40
|
+
* every other surface. It DOES take the card's kit with it, a folder no card can reach is a folder no list
|
|
41
41
|
* shows, and leaving the owner's prompt and skills orphaned on disk is worse than deleting what they just
|
|
42
42
|
* asked to delete. */
|
|
43
43
|
remove: oc.route({ method: "DELETE", path: "/personas/{id}" }).input(PersonaIdParamSchema).output(OkSchema),
|
|
@@ -46,10 +46,10 @@ export const personasContract = {
|
|
|
46
46
|
|
|
47
47
|
kit: oc.route({ method: "GET", path: "/personas/{id}/kit" }).input(PersonaIdParamSchema).output(PersonaKitSchema),
|
|
48
48
|
// An empty prompt DELETES the file rather than storing a blank one, so "custom with nothing written" is one
|
|
49
|
-
// state instead of two
|
|
49
|
+
// state instead of two, the resolver falls back to the sandbox's prompt for it (personas.ts personaPrompt).
|
|
50
50
|
savePrompt: oc.route({ method: "POST", path: "/personas/{id}/prompt" }).input(PersonaPromptSchema).output(OkSchema),
|
|
51
51
|
readSkill: oc.route({ method: "GET", path: "/personas/{id}/skills/read" }).input(PersonaSkillNameSchema).output(PersonaSkillBodySchema),
|
|
52
|
-
// Upsert by name, like the sandbox's own skills
|
|
52
|
+
// Upsert by name, like the sandbox's own skills, and with no enabled list to write, because a kit skill is
|
|
53
53
|
// on exactly when its persona is worn. That is what "specific to that persona" has to mean.
|
|
54
54
|
saveSkill: oc.route({ method: "POST", path: "/personas/{id}/skills" }).input(PersonaSkillSchema).output(OkSchema),
|
|
55
55
|
removeSkill: oc.route({ method: "POST", path: "/personas/{id}/skills/remove" }).input(PersonaSkillNameSchema).output(OkSchema),
|
|
@@ -2,7 +2,7 @@ import { oc } from "@orpc/contract";
|
|
|
2
2
|
import { OkSchema, PortForwardResultSchema, PortParamSchema, PortsListSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
4
|
// Listening TCP ports in the sandbox + explicit forwarding through the preview proxy (see the ports section in
|
|
5
|
-
// schemas.ts). `forward` is idempotent
|
|
5
|
+
// schemas.ts). `forward` is idempotent, re-forwarding a port returns its existing slot's URL; `unforward`
|
|
6
6
|
// frees the slot immediately (the hostname keeps resolving, the proxy just stops mapping it).
|
|
7
7
|
export const portsContract = {
|
|
8
8
|
list: oc.route({ method: "GET", path: "/ports" }).output(PortsListSchema),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { oc } from "@orpc/contract";
|
|
2
2
|
import { OkSchema, PrepushRunSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
|
-
// The pre-push check
|
|
4
|
+
// The pre-push check, the command the workspace runs when the user pushes, before anything leaves the machine
|
|
5
5
|
// (see PrepushRunSchema for where this sits and why). Three verbs about ONE run: the check answers about the
|
|
6
6
|
// main working tree, of which there is exactly one, so nothing here is addressed by id.
|
|
7
7
|
//
|
|
8
|
-
// `run` starts the check and returns immediately
|
|
8
|
+
// `run` starts the check and returns immediately, a suite takes minutes, and an oRPC call held open for one
|
|
9
9
|
// would die on the first proxy timeout with the work still going. The dialog that started it polls `state` for
|
|
10
10
|
// the verdict, and opens the terminals panel on the `session` the first answer names: the suite runs in a real
|
|
11
11
|
// tmux window, so watching it is the terminal's job. `cancel` kills that window; the run settles as `cancelled`
|
|
@@ -3,21 +3,21 @@ import { ModelsSchema, NativeProviderParamSchema } from "../schemas.js";
|
|
|
3
3
|
|
|
4
4
|
// EVERY NATIVE PROVIDER'S PICKER CATALOG, ON ONE ROUTE.
|
|
5
5
|
//
|
|
6
|
-
// There were five of these
|
|
6
|
+
// There were five of these: /claude/models, /codex/models, /grok/models, /kimi/models, /gemini/models, one per
|
|
7
7
|
// provider, each a contract entry, a route factory and a service field wired separately. They differed in
|
|
8
8
|
// nothing: same method, same output schema, same "the daemon's catalog for this provider, never empty". Three of
|
|
9
9
|
// the five route files were the same fifteen lines with a name swapped, and the daemon paid for that shape twice
|
|
10
10
|
// more in the branch chains that had to fan back out over the providers to ask them all the same question.
|
|
11
11
|
//
|
|
12
|
-
// So the provider is a PARAMETER, not five routes. Adding one is a row in the daemon's catalog registry
|
|
13
|
-
// same discipline the adapter registry already applies to serving a turn
|
|
12
|
+
// So the provider is a PARAMETER, not five routes. Adding one is a row in the daemon's catalog registry, the
|
|
13
|
+
// same discipline the adapter registry already applies to serving a turn, rather than a vertical slice through
|
|
14
14
|
// the contract, the router, the service container and every test double.
|
|
15
15
|
//
|
|
16
16
|
// Endpoints keep their own route (endpoints.contract.ts) and should: they are user-created and unbounded, their
|
|
17
17
|
// id names a capability that may not exist, and a missing one is a NOT_FOUND rather than an empty catalog. That
|
|
18
18
|
// is a different question with a different failure, not a sixth provider.
|
|
19
19
|
export const providersContract = {
|
|
20
|
-
// One provider's models (+ its default id), never empty
|
|
20
|
+
// One provider's models (+ its default id), never empty, live discovery with a persisted/seed floor behind
|
|
21
21
|
// it. Order is the provider's own preference order and is not re-ranked here; see ModelsSchema.
|
|
22
22
|
models: oc.route({ method: "GET", path: "/providers/{provider}/models" }).input(NativeProviderParamSchema).output(ModelsSchema),
|
|
23
23
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { oc } from "@orpc/contract";
|
|
2
2
|
import { OkSchema, PublicListSchema, PublishResultSchema, PublishSchema, UnpublishSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
|
-
// The workspace outbox
|
|
4
|
+
// The workspace outbox, what `public/` currently holds and its address (see the public section in schemas.ts).
|
|
5
5
|
// `publish` copies a workspace file or directory in, creating the outbox if this is the first one; `unpublish`
|
|
6
6
|
// withdraws one and removes the outbox behind the last, so the directory's presence always means exactly "there
|
|
7
7
|
// is something published". There is no route to READ a published file: that is the whole point of the
|
|
@@ -5,10 +5,10 @@ import { OkSchema, PushChannelIdSchema, PushChannelSchema, PushConfigQuerySchema
|
|
|
5
5
|
// push/push-store.ts for why the key lives on the history volume), and sends on the three moments where the
|
|
6
6
|
// operator's attention is genuinely wanted: a turn finished, the agent is blocked on an answer, and an
|
|
7
7
|
// automation is waiting for approval. A channel is either a browser's web-push subscription or a native
|
|
8
|
-
// install reached through the platform's push relay
|
|
8
|
+
// install reached through the platform's push relay, see PushChannelSchema for the split and why.
|
|
9
9
|
//
|
|
10
10
|
// `test` exists because a notification pipeline has four independent failure points the user cannot inspect
|
|
11
|
-
// (device permission, service-worker or shell registration, the daemon's key, the push service itself)
|
|
11
|
+
// (device permission, service-worker or shell registration, the daemon's key, the push service itself), a
|
|
12
12
|
// button that proves the whole chain end-to-end is worth more than any amount of status rendering.
|
|
13
13
|
export const pushContract = {
|
|
14
14
|
config: oc.route({ method: "GET", path: "/push/config" }).input(PushConfigQuerySchema).output(PushConfigSchema),
|
|
@@ -2,9 +2,9 @@ import { oc } from "@orpc/contract";
|
|
|
2
2
|
import { OkSchema, SecretInventorySchema, SecretKeyParamSchema, SecretKeysSchema, SecretRevealSchema, SecretSetSchema } from "../schemas.js";
|
|
3
3
|
|
|
4
4
|
// User-supplied env-var secrets, written to the sandbox's gitignored desired-state/.env (which
|
|
5
|
-
// `apply` reloads each run
|
|
5
|
+
// `apply` reloads each run, no restart). `set` upserts one KEY=value, `remove` deletes it; `list` returns the
|
|
6
6
|
// keys present. `inventory` aggregates every secret store into one view (keys + status + provenance, never
|
|
7
|
-
// values). `reveal` is the single value-returning route
|
|
7
|
+
// values). `reveal` is the single value-returning route, owner-only, POST so the key never sits in a URL.
|
|
8
8
|
// set/remove/list/reveal refuse until DevOps has scaffolded the desired-state repo; inventory always answers.
|
|
9
9
|
export const secretsContract = {
|
|
10
10
|
set: oc.route({ method: "POST", path: "/secrets" }).input(SecretSetSchema).output(OkSchema),
|
|
@@ -3,12 +3,12 @@ import { z } from "zod";
|
|
|
3
3
|
import { SessionTranscriptSchema } from "../events.js";
|
|
4
4
|
import { SessionIdParamSchema, SessionsListSchema } from "../schemas.js";
|
|
5
5
|
|
|
6
|
-
// Past conversations in this workspace (the SDK-native session store, keyed on the working dir
|
|
6
|
+
// Past conversations in this workspace (the SDK-native session store, keyed on the working dir, which for a
|
|
7
7
|
// repo covers its linked worktrees too, so an isolated conversation's transcript is reachable from the
|
|
8
8
|
// workspace root). `list` returns summaries for the history menu (filtered by `query` when the search box is
|
|
9
9
|
// used); `get` restores one transcript for display.
|
|
10
10
|
//
|
|
11
|
-
// `caseSensitive` is the filter's Aa switch, on the same terms as the fleet search's
|
|
11
|
+
// `caseSensitive` is the filter's Aa switch, on the same terms as the fleet search's, off means the letters do
|
|
12
12
|
// not matter, and the two routes answer one query together (the board lists these rows under its own cards), so
|
|
13
13
|
// a switch either of them ignored would show as one field returning two different match sets.
|
|
14
14
|
export const sessionsContract = {
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
|
|
12
12
|
// Per-sandbox agent settings (.intentic/config/settings.json). `get` returns the current flags with defaults applied
|
|
13
13
|
// when the file is absent; `set` overwrites them. `savings` reports what each token-reduction mechanism was
|
|
14
|
-
// worth
|
|
14
|
+
// worth, the cleaners' realized per-command savings and the terse steer's measured A/B, over an inclusive
|
|
15
15
|
// UTC day window, the same one the spend ledger takes, so a screen can filter both with one calendar.
|
|
16
|
-
// `builtinPrompt` returns one of the two built-in system prompts as text
|
|
17
|
-
// read out of the installed CLI
|
|
16
|
+
// `builtinPrompt` returns one of the two built-in system prompts as text. Intentic's own, or Claude Code's
|
|
17
|
+
// read out of the installed CLI, so the settings page can SHOW the prompt behind a mode instead of asking the
|
|
18
18
|
// user to trust a description of it, and can fork either into a custom one.
|
|
19
19
|
export const settingsContract = {
|
|
20
20
|
get: oc.route({ method: "GET", path: "/settings" }).output(SandboxSettingsSchema),
|
|
@@ -8,7 +8,7 @@ import { OkSchema, ShareCreateSchema, ShareListSchema, ShareRemoveSchema, ShareU
|
|
|
8
8
|
* share takes a CONVERSATION ID and renders something that did not exist as a file until it was asked for.
|
|
9
9
|
* Folding them together would have `publish` accept two unrelated kinds of input distinguished by a flag.
|
|
10
10
|
*
|
|
11
|
-
* There is no route to read a share back. The page is the read
|
|
11
|
+
* There is no route to read a share back. The page is the read, it answers on the unauthenticated
|
|
12
12
|
* `public-<slot>` hostname like every other published file, which is the point of having made one. */
|
|
13
13
|
export const shareContract = {
|
|
14
14
|
list: oc.route({ method: "GET", path: "/share" }).output(ShareListSchema),
|
|
@@ -7,7 +7,7 @@ import { OkSchema, SkillBodySchema, SkillDraftSchema, SkillIdSchema, SkillRemove
|
|
|
7
7
|
* the settings file: the rest are the owner's own skill store, the plugin checkouts a capability cloned, and the
|
|
8
8
|
* skills folders inside installed extensions. `list` is the join of all four (skill-inventory.ts).
|
|
9
9
|
*
|
|
10
|
-
* The ENABLED half still rides the settings object's `skills` array
|
|
10
|
+
* The ENABLED half still rides the settings object's `skills` array, that array is what the reconciler
|
|
11
11
|
* converges and what the boot path already reads, so a switch on this list is an ordinary settings write and
|
|
12
12
|
* there is exactly one place that decides which skills exist on disk. `save` and `remove` write the text AND
|
|
13
13
|
* that array together, which is why they are here rather than being two calls a screen has to sequence.
|
|
@@ -18,7 +18,7 @@ export const skillsContract = {
|
|
|
18
18
|
list: oc.route({ method: "GET", path: "/skills" }).output(SkillsListSchema),
|
|
19
19
|
read: oc.route({ method: "GET", path: "/skills/read" }).input(SkillIdSchema).output(SkillBodySchema),
|
|
20
20
|
// Upsert by name: saving over an existing skill rewrites it, which is also how one is renamed (the old name
|
|
21
|
-
// is a different skill and is deleted on its own). A saved skill is switched ON
|
|
21
|
+
// is a different skill and is deleted on its own). A saved skill is switched ON, you wrote it to use it.
|
|
22
22
|
save: oc.route({ method: "POST", path: "/skills" }).input(SkillDraftSchema).output(OkSchema),
|
|
23
23
|
remove: oc.route({ method: "POST", path: "/skills/remove" }).input(SkillRemoveSchema).output(OkSchema),
|
|
24
24
|
};
|