@intentic/sandbox-contract 1.240.0 → 1.243.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 +52 -16
- package/dist/agent-catalog.d.ts +5 -28
- package/dist/agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog.js +21 -157
- package/dist/agent-catalog.js.map +1 -1
- package/dist/agent-run-model.d.ts +3 -2
- package/dist/agent-run-model.d.ts.map +1 -1
- package/dist/agent-run-model.js +9 -6
- package/dist/agent-run-model.js.map +1 -1
- package/dist/agent-runtimes.d.ts +27 -0
- package/dist/agent-runtimes.d.ts.map +1 -0
- package/dist/agent-runtimes.js +113 -0
- package/dist/agent-runtimes.js.map +1 -0
- package/dist/approvals-execution.d.ts +11 -0
- package/dist/approvals-execution.d.ts.map +1 -0
- package/dist/approvals-execution.js +44 -0
- package/dist/approvals-execution.js.map +1 -0
- package/dist/arrival.d.ts +151 -0
- package/dist/arrival.d.ts.map +1 -0
- package/dist/arrival.js +56 -0
- package/dist/arrival.js.map +1 -0
- package/dist/card-status.d.ts +5 -0
- package/dist/card-status.d.ts.map +1 -0
- package/dist/card-status.js +74 -0
- package/dist/card-status.js.map +1 -0
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js +1 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/command-classes.d.ts +0 -1
- package/dist/command-classes.d.ts.map +1 -1
- package/dist/command-classes.js +9 -2
- package/dist/command-classes.js.map +1 -1
- package/dist/command-run.d.ts +10 -0
- package/dist/command-run.d.ts.map +1 -0
- package/dist/command-run.js +46 -0
- package/dist/command-run.js.map +1 -0
- package/dist/contracts/agent.contract.d.ts +991 -771
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.d.ts +345 -337
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +20 -2
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/approvals.contract.d.ts +99 -0
- package/dist/contracts/approvals.contract.d.ts.map +1 -0
- package/dist/contracts/approvals.contract.js +32 -0
- package/dist/contracts/approvals.contract.js.map +1 -0
- package/dist/contracts/ci.contract.d.ts +1 -4
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.js +1 -9
- package/dist/contracts/ci.contract.js.map +1 -1
- package/dist/contracts/claude.contract.d.ts +9 -0
- package/dist/contracts/claude.contract.d.ts.map +1 -1
- package/dist/contracts/cursor.contract.d.ts +6 -0
- package/dist/contracts/cursor.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.d.ts +63 -1
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +22 -4
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/grok.contract.d.ts +3 -0
- package/dist/contracts/grok.contract.d.ts.map +1 -1
- package/dist/contracts/keys.contract.d.ts +81 -0
- package/dist/contracts/keys.contract.d.ts.map +1 -0
- package/dist/contracts/keys.contract.js +51 -0
- package/dist/contracts/keys.contract.js.map +1 -0
- package/dist/contracts/panels.contract.d.ts +7 -0
- package/dist/contracts/panels.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.js +2 -2
- package/dist/contracts/providers.contract.d.ts +2 -0
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.d.ts +84 -86
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/safety.contract.d.ts +35 -0
- package/dist/contracts/safety.contract.d.ts.map +1 -0
- package/dist/contracts/safety.contract.js +32 -0
- package/dist/contracts/safety.contract.js.map +1 -0
- package/dist/contracts/sessions.contract.d.ts +73 -337
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +30 -32
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +139 -337
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.d.ts +31 -3
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/usage.contract.d.ts +29 -20
- package/dist/contracts/usage.contract.d.ts.map +1 -1
- package/dist/contracts/usage.contract.js +13 -0
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +8 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/conversation-ids.d.ts +2 -0
- package/dist/conversation-ids.d.ts.map +1 -1
- package/dist/conversation-ids.js +8 -0
- package/dist/conversation-ids.js.map +1 -1
- package/dist/credential-material.d.ts +1 -0
- package/dist/credential-material.d.ts.map +1 -1
- package/dist/credential-material.js +24 -2
- package/dist/credential-material.js.map +1 -1
- package/dist/definition.d.ts +51 -93
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +6 -28
- package/dist/definition.js.map +1 -1
- package/dist/events.d.ts +1831 -2285
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +155 -55
- package/dist/events.js.map +1 -1
- package/dist/history-state.d.ts.map +1 -1
- package/dist/history-state.js +1 -0
- package/dist/history-state.js.map +1 -1
- package/dist/index.d.ts +1959 -1903
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/ingress-protocol.d.ts +13 -1
- package/dist/ingress-protocol.d.ts.map +1 -1
- package/dist/ingress-protocol.js +19 -0
- package/dist/ingress-protocol.js.map +1 -1
- package/dist/mentions.d.ts +3 -0
- package/dist/mentions.d.ts.map +1 -0
- package/dist/mentions.js +13 -0
- package/dist/mentions.js.map +1 -0
- package/dist/needs-action.d.ts +7 -0
- package/dist/needs-action.d.ts.map +1 -0
- package/dist/needs-action.js +3 -0
- package/dist/needs-action.js.map +1 -0
- package/dist/overlay-lint.d.ts +7 -0
- package/dist/overlay-lint.d.ts.map +1 -0
- package/dist/overlay-lint.js +68 -0
- package/dist/overlay-lint.js.map +1 -0
- package/dist/owner-ticket.d.ts +18 -0
- package/dist/owner-ticket.d.ts.map +1 -0
- package/dist/owner-ticket.js +51 -0
- package/dist/owner-ticket.js.map +1 -0
- package/dist/plan-pools.d.ts +13 -0
- package/dist/plan-pools.d.ts.map +1 -0
- package/dist/plan-pools.js +31 -0
- package/dist/plan-pools.js.map +1 -0
- package/dist/provider-specs.d.ts +228 -0
- package/dist/provider-specs.d.ts.map +1 -0
- package/dist/provider-specs.js +124 -0
- package/dist/provider-specs.js.map +1 -0
- package/dist/quick-model.d.ts.map +1 -1
- package/dist/quick-model.js +2 -1
- package/dist/quick-model.js.map +1 -1
- package/dist/runner-protocol.js +2 -2
- package/dist/runner-protocol.js.map +1 -1
- package/dist/runtime-state.d.ts +2 -2
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +1 -1
- package/dist/runtime-state.js.map +1 -1
- package/dist/safety-policy.d.ts +49 -0
- package/dist/safety-policy.d.ts.map +1 -0
- package/dist/safety-policy.js +52 -0
- package/dist/safety-policy.js.map +1 -0
- package/dist/schemas/agent.d.ts +21 -3
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +18 -8
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +19 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +15 -0
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/approvals.d.ts +241 -0
- package/dist/schemas/approvals.d.ts.map +1 -0
- package/dist/schemas/approvals.js +63 -0
- package/dist/schemas/approvals.js.map +1 -0
- package/dist/schemas/automations.d.ts +5 -0
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/ci.d.ts +5 -9
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/ci.js +3 -10
- package/dist/schemas/ci.js.map +1 -1
- package/dist/schemas/computers.d.ts +40 -5
- package/dist/schemas/computers.d.ts.map +1 -1
- package/dist/schemas/computers.js +16 -5
- package/dist/schemas/computers.js.map +1 -1
- package/dist/schemas/environment.d.ts +11 -131
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js +5 -42
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/git-history.d.ts +4 -0
- package/dist/schemas/git-history.d.ts.map +1 -1
- package/dist/schemas/git.d.ts +179 -0
- package/dist/schemas/git.d.ts.map +1 -1
- package/dist/schemas/git.js +39 -1
- package/dist/schemas/git.js.map +1 -1
- package/dist/schemas/panels.d.ts +21 -0
- package/dist/schemas/panels.d.ts.map +1 -1
- package/dist/schemas/panels.js +5 -0
- package/dist/schemas/panels.js.map +1 -1
- package/dist/schemas/plan-limits.d.ts +50 -3
- package/dist/schemas/plan-limits.d.ts.map +1 -1
- package/dist/schemas/plan-limits.js +11 -6
- package/dist/schemas/plan-limits.js.map +1 -1
- package/dist/schemas/provider-oauth.d.ts +6 -0
- package/dist/schemas/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/provider-subscriptions.d.ts +2 -1
- package/dist/schemas/provider-subscriptions.d.ts.map +1 -1
- package/dist/schemas/provider-subscriptions.js +2 -1
- package/dist/schemas/provider-subscriptions.js.map +1 -1
- package/dist/schemas/settings.d.ts +29 -16
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +13 -20
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/system.d.ts +3 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +5 -1
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/workspace-repos.d.ts +14 -0
- package/dist/schemas/workspace-repos.d.ts.map +1 -1
- package/dist/schemas/workspace-repos.js +5 -0
- package/dist/schemas/workspace-repos.js.map +1 -1
- package/dist/schemas/workspace-tree.d.ts +1 -0
- package/dist/schemas/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace-tree.js +3 -0
- package/dist/schemas/workspace-tree.js.map +1 -1
- package/dist/transcript-fold.d.ts +31 -0
- package/dist/transcript-fold.d.ts.map +1 -0
- package/dist/transcript-fold.js +457 -0
- package/dist/transcript-fold.js.map +1 -0
- package/dist/workspace-state.d.ts +20 -3
- package/dist/workspace-state.d.ts.map +1 -1
- package/dist/workspace-state.js +22 -2
- package/dist/workspace-state.js.map +1 -1
- package/package.json +27 -5
- package/src/agent-catalog.test.ts +1 -1
- package/src/agent-catalog.ts +76 -555
- package/src/agent-run-model.test.ts +31 -15
- package/src/agent-run-model.ts +26 -12
- package/src/agent-runtimes.ts +419 -0
- package/src/approvals-execution.ts +96 -0
- package/src/arrival.ts +160 -0
- package/src/capability-ledger.test.ts +6 -4
- package/src/card-status.ts +93 -0
- package/src/chores/chores.ts +6 -3
- package/src/command-classes.test.ts +25 -0
- package/src/command-classes.ts +47 -5
- package/src/command-run.ts +78 -0
- package/src/contract-lock.test.ts +1 -1
- package/src/contract-lock.ts +2 -2
- package/src/contracts/agents.contract.ts +35 -2
- package/src/contracts/approvals.contract.ts +37 -0
- package/src/contracts/ci.contract.ts +0 -13
- package/src/contracts/git.contract.ts +28 -3
- package/src/contracts/keys.contract.ts +79 -0
- package/src/contracts/prepush.contract.ts +3 -3
- package/src/contracts/safety.contract.ts +48 -0
- package/src/contracts/usage.contract.ts +22 -0
- package/src/conversation-ids.test.ts +31 -1
- package/src/conversation-ids.ts +37 -3
- package/src/credential-material.test.ts +69 -1
- package/src/credential-material.ts +86 -5
- package/src/definition.ts +25 -53
- package/src/events.ts +374 -173
- package/src/history-state.ts +6 -0
- package/src/index.ts +24 -5
- package/src/ingress-protocol.ts +52 -1
- package/src/mentions.test.ts +22 -0
- package/src/mentions.ts +25 -0
- package/src/needs-action.ts +14 -0
- package/src/overlay-lint.test.ts +89 -0
- package/src/overlay-lint.ts +116 -0
- package/src/owner-ticket.test.ts +54 -0
- package/src/owner-ticket.ts +102 -0
- package/src/plan-pools.test.ts +71 -0
- package/src/plan-pools.ts +92 -0
- package/src/provider-specs.test.ts +130 -0
- package/src/provider-specs.ts +352 -0
- package/src/quick-model.ts +9 -5
- package/src/runner-protocol.ts +2 -2
- package/src/runtime-state.ts +6 -6
- package/src/safety-policy.ts +165 -0
- package/src/schemas/agent.ts +62 -17
- package/src/schemas/agents.ts +71 -0
- package/src/schemas/approvals.ts +174 -0
- package/src/schemas/ci.ts +19 -26
- package/src/schemas/computers.ts +91 -15
- package/src/schemas/environment.ts +21 -100
- package/src/schemas/git.ts +121 -6
- package/src/schemas/issues.ts +1 -1
- package/src/schemas/panels.ts +20 -0
- package/src/schemas/plan-limits.ts +58 -11
- package/src/schemas/provider-subscriptions.ts +7 -2
- package/src/schemas/settings.ts +67 -93
- package/src/schemas/system.ts +12 -1
- package/src/schemas/workspace-repos.ts +9 -0
- package/src/schemas/workspace-tree.ts +11 -0
- package/src/transcript-fold.test.ts +493 -0
- package/src/transcript-fold.ts +655 -0
- package/src/workspace-state.test.ts +77 -29
- package/src/workspace-state.ts +99 -31
- package/dist/contracts/drafts.contract.d.ts +0 -57
- package/dist/contracts/drafts.contract.d.ts.map +0 -1
- package/dist/contracts/drafts.contract.js +0 -32
- package/dist/contracts/drafts.contract.js.map +0 -1
- package/dist/definition-action.d.ts +0 -7
- package/dist/definition-action.d.ts.map +0 -1
- package/dist/definition-action.js +0 -3
- package/dist/definition-action.js.map +0 -1
- package/dist/publish-drafts.d.ts +0 -7
- package/dist/publish-drafts.d.ts.map +0 -1
- package/dist/publish-drafts.js +0 -20
- package/dist/publish-drafts.js.map +0 -1
- package/dist/schemas/drafts.d.ts +0 -84
- package/dist/schemas/drafts.d.ts.map +0 -1
- package/dist/schemas/drafts.js +0 -44
- package/dist/schemas/drafts.js.map +0 -1
- package/src/contracts/drafts.contract.ts +0 -35
- package/src/definition-action.ts +0 -8
- package/src/publish-drafts.ts +0 -59
- package/src/schemas/drafts.ts +0 -108
|
@@ -1,21 +1,47 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { TRANSLATOR_PROVIDERS, type TranslatorProvider } from "../provider-specs.js";
|
|
2
3
|
import { AgentHarnessSchema, AgentProviderSchema, EditorContextSchema } from "./agent.js";
|
|
3
4
|
// Declared ABOVE both account shapes because both carry it: headroom is one idea in this product, not a Claude
|
|
4
5
|
// idea that other providers imitate. A native account (OauthAccount) and a routed subscription
|
|
5
6
|
// (TranslatorAccount) differ in who holds the credential and how the reading is taken, never in what a
|
|
6
7
|
// reading IS, so every surface that draws a percentage reads this one type and no other.
|
|
7
8
|
|
|
9
|
+
/* WHICH MODELS A POOL GATES, said by the reader that parsed it and carried on the wire, so every surface and
|
|
10
|
+
* every picker answers "does this pool stand between me and THIS model" from one fact instead of six rules.
|
|
11
|
+
*
|
|
12
|
+
* A plan is not one allowance. Google meters Gemini separately from the Claude and GPT models it serves off the
|
|
13
|
+
* same sign-in; a Claude plan carries a per-model weekly slice ("Opus", "Fable") beside its all-models pools;
|
|
14
|
+
* ChatGPT publishes a code-review limit that no chat turn spends. Before this field the relation lived in six
|
|
15
|
+
* places that disagreed (a static Google table, a Claude kind list, a max-over-everything ranking, a fullest-
|
|
16
|
+
* window reset, and two client-side matchers), so a Google account with its Gemini pool spent drew a red ring
|
|
17
|
+
* over Claude Opus, and a Claude account with its Opus slice spent was ranked "spent" for a Haiku call.
|
|
18
|
+
*
|
|
19
|
+
* "all" every model on this plan spends it: the 5-hour and weekly pools, Kimi's throttles.
|
|
20
|
+
* "none" nothing a turn here runs spends it: a code-review limit, a surface-scoped pool for another
|
|
21
|
+
* product. Still shown, never binding.
|
|
22
|
+
* { models } a slice scoped to the models the names match. Names are matched as runs of whole words against
|
|
23
|
+
* the model id AND its label ("opus" is in "claude-opus-4-6" and in "Claude Opus 4.6"; "gemini"
|
|
24
|
+
* is in "gemini-3-pro"), see plan-pools.ts, because the plan names a pool by the vendor's word for
|
|
25
|
+
* the tier and nothing else connects the two.
|
|
26
|
+
*
|
|
27
|
+
* Decided by the READER, never inferred later: the payload is the only place the grouping is known, and it is
|
|
28
|
+
* the plan's to change, so the fact travels with the reading it describes. */
|
|
29
|
+
export const WindowGatesSchema = z.union([z.literal("all"), z.literal("none"), z.object({ models: z.array(z.string().min(1)).min(1) })]);
|
|
30
|
+
export type WindowGates = z.infer<typeof WindowGatesSchema>;
|
|
31
|
+
|
|
8
32
|
// One plan-limit pool. `kind` is the provider's own key ('five_hour' | 'seven_day' | 'seven_day_opus' |
|
|
9
33
|
// 'seven_day_sonnet' | 'model:Fable' | …) rather than an enum we'd have to keep in step with the provider: an
|
|
10
34
|
// unrecognised pool is shown under its raw key, which is far better than being silently folded into a
|
|
11
35
|
// neighbour. `label` is the provider's OWN display name where it supplies one (the per-model buckets do), it
|
|
12
36
|
// wins over anything we'd infer, because the model names in a plan's limits are the provider's to rename.
|
|
13
|
-
// `resetsAt` is epoch SECONDS (matching the SDK's frame).
|
|
37
|
+
// `resetsAt` is epoch SECONDS (matching the SDK's frame). `gates` says which models the pool stands in the way
|
|
38
|
+
// of, see WindowGatesSchema.
|
|
14
39
|
export const UsageWindowSchema = z.object({
|
|
15
40
|
kind: z.string(),
|
|
16
41
|
label: z.string().optional(),
|
|
17
42
|
utilization: z.number(), // 0-100
|
|
18
43
|
resetsAt: z.number().optional(),
|
|
44
|
+
gates: WindowGatesSchema,
|
|
19
45
|
});
|
|
20
46
|
export type UsageWindow = z.infer<typeof UsageWindowSchema>;
|
|
21
47
|
// An account's headroom: EVERY window the provider reports, read together, plus when the reading was taken.
|
|
@@ -69,6 +95,10 @@ export const ProviderRefusalSchema = z.object({
|
|
|
69
95
|
message: z.string().describe("The provider's own words, verbatim. The only part that says which limit or which credential."),
|
|
70
96
|
// The account that was serving, when the daemon knows it (native turns only, see above).
|
|
71
97
|
account: z.string().optional().describe("Which account was serving, where that is known."),
|
|
98
|
+
// The model the refused turn ran, so a `limit` refusal can be read against the POOL that model spends
|
|
99
|
+
// (UsageWindow.gates) rather than against the account's fullest pool, which on a plan that meters models
|
|
100
|
+
// separately is routinely a different allowance from the one that said no.
|
|
101
|
+
model: z.string().optional().describe("Which model the refused turn was on, where that is known."),
|
|
72
102
|
});
|
|
73
103
|
export type ProviderRefusal = z.infer<typeof ProviderRefusalSchema>;
|
|
74
104
|
export const ProviderRefusalsSchema = z.object({
|
|
@@ -89,18 +119,35 @@ export const TranslatorAccountSchema = z.object({
|
|
|
89
119
|
// or one that did not answer, must still render as the connected account it is, with a dot instead of a
|
|
90
120
|
// ring.
|
|
91
121
|
usage: AccountUsageSchema.optional(),
|
|
122
|
+
/* THE TRANSLATOR'S OWN VERDICT ON THE CREDENTIAL, the one live fact no quota read can produce. CLIProxyAPI
|
|
123
|
+
* benches an auth file the moment upstream refuses it (a quota 429, an expired token) and routes around it
|
|
124
|
+
* until `until`; a reading taken five minutes ago cannot know that, and a green ring over a benched file is
|
|
125
|
+
* exactly the gap a refusal used to be the only way to see. Absent ⇒ the proxy is routing to it. */
|
|
126
|
+
cooling: z
|
|
127
|
+
.object({
|
|
128
|
+
// Epoch SECONDS, like every reset on this wire. Absent when the proxy named no retry instant.
|
|
129
|
+
until: z.number().optional(),
|
|
130
|
+
// The proxy's own sentence, when it gave one.
|
|
131
|
+
reason: z.string().optional(),
|
|
132
|
+
})
|
|
133
|
+
.optional(),
|
|
92
134
|
});
|
|
93
135
|
export type TranslatorAccount = z.infer<typeof TranslatorAccountSchema>;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
136
|
+
/* Which routed-provider subscriptions are connected in the translator, per provider, a LIST per provider, not
|
|
137
|
+
* a flag: CLIProxyAPI holds any number of auth files per provider side by side and balances requests across
|
|
138
|
+
* them, so connecting a second ChatGPT or Google account is more headroom, and each is disconnectable on its
|
|
139
|
+
* own. Drives the account rows in Sandbox ▸ Agent.
|
|
140
|
+
*
|
|
141
|
+
* ONE KEY PER TRANSLATOR PROVIDER, built over the derived list rather than typed out, because this object and
|
|
142
|
+
* the enum beside it (KeyedProviderSchema) are the same fact twice and the browser reads a provider's slot
|
|
143
|
+
* without checking it exists: a provider present in the enum and missing here is `undefined.length`, at the
|
|
144
|
+
* exact moment somebody is asking whether they can send. */
|
|
145
|
+
export const TranslatorAccountsSchema = z.object(
|
|
146
|
+
Object.fromEntries(TRANSLATOR_PROVIDERS.map((provider) => [provider, z.array(TranslatorAccountSchema)] as const)) as Record<
|
|
147
|
+
TranslatorProvider,
|
|
148
|
+
z.ZodArray<typeof TranslatorAccountSchema>
|
|
149
|
+
>,
|
|
150
|
+
);
|
|
104
151
|
export type TranslatorAccounts = z.infer<typeof TranslatorAccountsSchema>;
|
|
105
152
|
// The side-channel body that un-parks a turn waiting on the user. Every interactive card, plan approval,
|
|
106
153
|
// clarifying questions, a per-tool permission prompt, parks on the SAME registry keyed by `requestId`, so
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { TRANSLATOR_PROVIDERS, type TranslatorProvider } from "../provider-specs.js";
|
|
2
3
|
// The providers whose model can run UNDER the Claude Code harness through the bundled translator (CLIProxyAPI),
|
|
3
4
|
// which holds their SUBSCRIPTION OAuth and re-serves it behind an Anthropic endpoint. The `claude` provider is
|
|
4
5
|
// absent, native Anthropic OAuth serves it directly, without the translator. Codex, Grok and Gemini also have a
|
|
@@ -7,5 +8,9 @@ import { z } from "zod";
|
|
|
7
8
|
// Gemini is in BOTH camps and that is not a contradiction: its native runtime (OpenCode) reaches Google through
|
|
8
9
|
// this same translator and these same auth files. The harness axis picks the loop; the translator is the road
|
|
9
10
|
// under either.
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
//
|
|
12
|
+
// DERIVED from the provider table's `auth.kind`, never listed here: this enum and the accounts schema built on
|
|
13
|
+
// it (TranslatorAccountsSchema) and the daemon's CLIProxyAPI id map are three readings of one fact, and they
|
|
14
|
+
// used to be three hand-kept lists that had to agree.
|
|
15
|
+
export const KeyedProviderSchema = z.enum(TRANSLATOR_PROVIDERS);
|
|
16
|
+
export type KeyedProvider = TranslatorProvider;
|
package/src/schemas/settings.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// settings: per-sandbox agent settings (.intentic/config/settings.json)
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { AdmissionPolicySchema, AdmissionRuleSchema,
|
|
3
|
+
import { AdmissionPolicySchema, AdmissionRuleSchema, AgentRunPinSchema } from "./agent.js";
|
|
4
4
|
// Which prompt the agent is, before this turn composes anything on top. Two built-in bases and an escape
|
|
5
5
|
// hatch: Intentic's own (the default), Claude Code's preset, or the owner's text. Declared out here rather
|
|
6
6
|
// than inline in the settings object because both sides of the wire branch on it, the daemon to build the
|
|
@@ -27,9 +27,14 @@ export type DependencyFreshness = z.infer<typeof DependencyFreshnessSchema>;
|
|
|
27
27
|
* chores already wake on those and folding them into this table later must not mean renaming what users wrote.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
// WHERE a rule can stand.
|
|
30
|
+
// WHERE a rule can stand. Four, and each is a place the daemon already stopped to make a decision, this
|
|
31
31
|
// names those decisions rather than inventing new ones.
|
|
32
32
|
export const RuleMomentSchema = z.enum([
|
|
33
|
+
// The assistant has just written a file, with an edit tool or with a shell command; the tree says which. A
|
|
34
|
+
// command here runs on that one file (`{file}` in the command is its path) and what it prints on a non-zero
|
|
35
|
+
// exit rides back with the edit's own result, while the file is still in mind. The cheapest moment a defect
|
|
36
|
+
// can be caught at, and the one the per-edit linter and byte scan stand at.
|
|
37
|
+
"file.edited",
|
|
33
38
|
// The assistant is about to stop. A rule here can send it back to work, which is the only moment that can.
|
|
34
39
|
"turn.ending",
|
|
35
40
|
// Code is about to leave the machine. A rule here gates the push on its own exit code.
|
|
@@ -56,8 +61,10 @@ export type RuleMoment = z.infer<typeof RuleMomentSchema>;
|
|
|
56
61
|
* `verify-removals` weighs what a turn DELETED against what the repository's history says about those lines,
|
|
57
62
|
* which is a question `git log` answers and no shell one-liner an owner could type would, and
|
|
58
63
|
* `verify-ui-edits` weighs the rendered surfaces a turn changed against whether it ever looked at one, the one
|
|
59
|
-
* question a passing suite is structurally unable to answer
|
|
60
|
-
|
|
64
|
+
* question a passing suite is structurally unable to answer, and `verify-tests` weighs the test files a turn
|
|
65
|
+
* touched against two things a green suite cannot say: whether their assertions got weaker than the same files
|
|
66
|
+
* at HEAD, and whether a test the turn wrote would have passed before the change it covers. */
|
|
67
|
+
export const RuleBuiltinSchema = z.enum(["verify-edits", "verify-removals", "verify-ui-edits", "verify-tests"]);
|
|
61
68
|
export type RuleBuiltin = z.infer<typeof RuleBuiltinSchema>;
|
|
62
69
|
export const RuleActionSchema = z.discriminatedUnion("kind", [
|
|
63
70
|
z.object({
|
|
@@ -73,6 +80,13 @@ export const RuleActionSchema = z.discriminatedUnion("kind", [
|
|
|
73
80
|
z.object({ kind: z.literal("builtin"), name: RuleBuiltinSchema }),
|
|
74
81
|
]);
|
|
75
82
|
export type RuleAction = z.infer<typeof RuleActionSchema>;
|
|
83
|
+
/* HOW A TURN ENDED, as the `agent.finished` moment sees it. `clean`, `error` and `conflict` are the turn's own
|
|
84
|
+
* fate. `checks-failed` is a clean turn whose `turn.ending` command check went red on the tree it is about to
|
|
85
|
+
* land: the model was told, answered, and the last run still failed. It is named separately because a landing
|
|
86
|
+
* rule has to be able to speak about it, and because its default is not the others': work in that state is HELD
|
|
87
|
+
* unless a rule names `checks-failed` and says allow (rules/rules.ts landingVerdict). */
|
|
88
|
+
export const RuleOutcomeSchema = z.enum(["clean", "error", "conflict", "checks-failed"]);
|
|
89
|
+
export type RuleOutcome = z.infer<typeof RuleOutcomeSchema>;
|
|
76
90
|
// WHEN a rule narrows. Three keys, chosen because they cover the two things people reach for on day one,
|
|
77
91
|
// "only this repo" and "don't bother for a docs-only change", without opening a query language. Every key
|
|
78
92
|
// absent ⇒ the rule always matches at its moment, which is what the three replaced settings each did.
|
|
@@ -81,8 +95,8 @@ export const RuleConditionSchema = z.object({
|
|
|
81
95
|
repo: z.string().min(1).optional(),
|
|
82
96
|
// Globs the change has to touch for the rule to fire. Absent/empty ⇒ any.
|
|
83
97
|
paths: z.array(z.string().min(1)).max(20).optional(),
|
|
84
|
-
// How the turn ended. Absent/empty ⇒ any.
|
|
85
|
-
outcome: z.array(
|
|
98
|
+
// How the turn ended. Absent/empty ⇒ any, except that `checks-failed` never lands by omission.
|
|
99
|
+
outcome: z.array(RuleOutcomeSchema).optional(),
|
|
86
100
|
});
|
|
87
101
|
export type RuleCondition = z.infer<typeof RuleConditionSchema>;
|
|
88
102
|
/* ONE RULE. `id` is stable and owner-visible: it is what the activity feed names when the rule fires and what
|
|
@@ -91,8 +105,10 @@ export type RuleCondition = z.infer<typeof RuleConditionSchema>;
|
|
|
91
105
|
* WHICH ACTIONS FIT WHICH MOMENT is checked here rather than left to the consumer, because the alternative is
|
|
92
106
|
* a rule that saves cleanly and then quietly does nothing, the failure mode a settings screen can least
|
|
93
107
|
* afford. A verdict at `turn.ending` has nothing to decide; a command at `agent.finished` has no defined place
|
|
94
|
-
* in the landing pass and would be a promise this stage cannot keep.
|
|
108
|
+
* in the landing pass and would be a promise this stage cannot keep; an instruction at `file.edited` would be
|
|
109
|
+
* repeated on every save, which is noise by the third one. */
|
|
95
110
|
const MOMENT_ACTIONS: Record<RuleMoment, readonly RuleAction["kind"][]> = {
|
|
111
|
+
"file.edited": ["command"],
|
|
96
112
|
"turn.ending": ["builtin", "instruct", "command"],
|
|
97
113
|
"push.starting": ["command"],
|
|
98
114
|
"agent.finished": ["verdict"],
|
|
@@ -418,42 +434,9 @@ export const SandboxSettingsSchema = z.object({
|
|
|
418
434
|
*
|
|
419
435
|
* Off by default like every other flag here, and off means genuinely nothing: no hook is wired, and the
|
|
420
436
|
* sandbox makes no network call it would not otherwise have made. */
|
|
421
|
-
dependencyFreshness: DependencyFreshnessSchema.default("off")
|
|
422
|
-
.
|
|
423
|
-
|
|
424
|
-
),
|
|
425
|
-
/* DOES THE TEST IT JUST WROTE ACTUALLY TEST THE CHANGE?
|
|
426
|
-
*
|
|
427
|
-
* A model writes a test that passes, and a passing test is the thing it was asked for, so nothing in the loop
|
|
428
|
-
* objects. The failure this catches is the one where the test would have passed BEFORE the change too: it
|
|
429
|
-
* exercises the code without depending on the behaviour that was added, and it will keep passing when that
|
|
430
|
-
* behaviour is broken later. It type-checks, it lints, `pnpm verify` is green, and the suite has grown a test
|
|
431
|
-
* that can never fail.
|
|
432
|
-
*
|
|
433
|
-
* The check is a differential, and it is cheap for one specific reason: in an agent turn we already know
|
|
434
|
-
* exactly which source files changed. So the test is re-run with those files' HEAD contents served in place
|
|
435
|
-
* of the working copies, and the answer is one bit — did it still pass? A test that passes against the old
|
|
436
|
-
* code did not test the new code. This is one-mutant mutation testing where the mutant is "your change,
|
|
437
|
-
* reverted", which is the cheapest useful mutant there is and the only one already known for free.
|
|
438
|
-
*
|
|
439
|
-
* NOTHING IS WRITTEN TO THE TREE. The HEAD copies are served through a vite `load` hook in a generated config,
|
|
440
|
-
* never checked out over the working files — a hook that could leave a half-reverted tree behind on a crash
|
|
441
|
-
* would be trading a whole turn's work for a lint-grade signal.
|
|
442
|
-
*
|
|
443
|
-
* IT REPORTS AND GETS OUT OF THE WAY, for the same reason the freshness check above does. Two legitimate
|
|
444
|
-
* cases pass on HEAD and must not be fought: a test written BEFORE its implementation (it fails now, which
|
|
445
|
-
* the agent can see without help), and a pure refactor, where a test that keeps passing is the entire point.
|
|
446
|
-
* Distinguishing those from a weak test needs intent, so the fact rides back as context and the model decides.
|
|
447
|
-
*
|
|
448
|
-
* Scoped to source changed in the SAME package as the test, because that is what a package's own vitest run
|
|
449
|
-
* loads from source; a cross-package import resolves to the other package's built output, where there is
|
|
450
|
-
* nothing to swap. Off by default like every flag here, and off wires no hook at all. */
|
|
451
|
-
testFaultDetection: z
|
|
452
|
-
.boolean()
|
|
453
|
-
.default(false)
|
|
454
|
-
.describe(
|
|
455
|
-
"After the agent writes a test, re-run it against the code as it was before this turn's changes. A test that still passes did not test the change — it will pass just as happily when that behaviour breaks. Reports what it finds and lets the agent decide, because a test written before its implementation and a pure refactor both pass this honestly.",
|
|
456
|
-
),
|
|
437
|
+
dependencyFreshness: DependencyFreshnessSchema.default("off").describe(
|
|
438
|
+
"Whether a version the agent is about to pin is checked against the package's own registry first. Facts only, or facts plus the name of a maintained replacement where the registry agrees the current choice has been abandoned. It tells the agent and lets it decide rather than refusing, because matching a version your project already uses is usually the right answer and a gate would fight it.",
|
|
439
|
+
),
|
|
457
440
|
outputCleaners: z
|
|
458
441
|
.string()
|
|
459
442
|
.default("")
|
|
@@ -507,11 +490,17 @@ export const SandboxSettingsSchema = z.object({
|
|
|
507
490
|
),
|
|
508
491
|
/* WHAT AN AGENT RUN OPENS ON, the tier above quickModel, and the answer for every turn a SURFACE starts
|
|
509
492
|
* rather than a person at a composer: Fix with agent on a pipeline or a deployment, a Maintenance chore, a
|
|
510
|
-
* Documentation or Acceptance run, the fix a failed pre-push check proposes. An ORDERED list of
|
|
511
|
-
*
|
|
493
|
+
* Documentation or Acceptance run, the fix a failed pre-push check proposes. An ORDERED list of PINS, each
|
|
494
|
+
* naming a provider and model AND how that one is to be run (AgentRunPinSchema); EMPTY ⇒ whatever the chat
|
|
512
495
|
* composer would have started with, which is the honest floor because it is the model the user already
|
|
513
496
|
* chose to work with.
|
|
514
497
|
*
|
|
498
|
+
* EACH ENTRY CARRIES ITS OWN REASONING AND COST KNOBS, which is why these are objects rather than the
|
|
499
|
+
* `${provider}:${model}` keys the two lists around them still hold. The effort used to be one field beside
|
|
500
|
+
* the list, answering for every model in it, and the entries of this list are the least interchangeable
|
|
501
|
+
* things on the page: the head is the tier the owner wants the work done at and what follows it is the
|
|
502
|
+
* account that catches it when the first is spent. AgentRunPinSchema has the rest of the argument.
|
|
503
|
+
*
|
|
515
504
|
* A LIST, for the reason quickModel is one: the account at the head runs out, and every surface-started run
|
|
516
505
|
* in the sandbox then fails on a credential the user cannot see from the row they pressed. Written in order,
|
|
517
506
|
* the next one down catches it (turn-resume.ts walks it).
|
|
@@ -527,13 +516,12 @@ export const SandboxSettingsSchema = z.object({
|
|
|
527
516
|
* surface added tomorrow inherits it by saying what it is instead of re-deriving where models come from. A
|
|
528
517
|
* surface MAY still name one (the shared run button's caret, Acceptance's per-run pick), and that wins. */
|
|
529
518
|
agentRunModels: z
|
|
530
|
-
.array(
|
|
519
|
+
.array(AgentRunPinSchema)
|
|
531
520
|
.max(10)
|
|
532
521
|
.default([])
|
|
533
522
|
.describe(
|
|
534
|
-
"Which models run the work a screen starts rather than a person: fixing a red pipeline, a maintenance chore, an acceptance run. Tried in order, so one spent account does not take every such run down. Empty falls back to whatever the chat would have used, which is the honest floor because it is the model you already chose to work with.",
|
|
523
|
+
"Which models run the work a screen starts rather than a person: fixing a red pipeline, a maintenance chore, an acceptance run. Tried in order, so one spent account does not take every such run down, and each entry says how hard that model should think as well as which one it is. Empty falls back to whatever the chat would have used, which is the honest floor because it is the model you already chose to work with.",
|
|
535
524
|
),
|
|
536
|
-
agentRunEffort: z.string().default("").describe("How hard those runs should think."),
|
|
537
525
|
/* AUTOMATIC TIER SELECTION: may the daemon run an easy-looking turn on a cheaper rung of the provider the
|
|
538
526
|
* user is already on, instead of on the model they picked?
|
|
539
527
|
*
|
|
@@ -630,6 +618,25 @@ export const SandboxSettingsSchema = z.object({
|
|
|
630
618
|
.describe(
|
|
631
619
|
"Whether a turn killed by the model provider failing is re-run automatically, backing off between attempts. The sandbox-wide default; any one conversation can say otherwise. Off to begin with, because a retry spends your allowance on a turn you sent once and only you can say whether it was worth paying for twice. Worth turning on for a sandbox whose work mostly happens with nobody in the room.",
|
|
632
620
|
),
|
|
621
|
+
/* THE SANDBOX-WIDE DEFAULT for the blocker that is not a failure: "when a spent usage limit refuses a turn,
|
|
622
|
+
* send that turn again the moment the allowance comes back".
|
|
623
|
+
*
|
|
624
|
+
* The one automatic resume here that WAITS FOR A PUBLISHED INSTANT rather than guessing. Its neighbour above
|
|
625
|
+
* escalates a backoff at a provider nobody can predict; this one sleeps until the hour the provider itself
|
|
626
|
+
* named and fires once, at it. A limit that publishes no instant (Grok, Cursor) is never fired for at all,
|
|
627
|
+
* because there is nothing to wait for and a guess would be spending the user's money on arithmetic.
|
|
628
|
+
*
|
|
629
|
+
* OFF by default, and this is the setting the default matters most for. Every other blocker in this pair
|
|
630
|
+
* clears at nobody's expense, while this one clears into an allowance the user may have been holding back
|
|
631
|
+
* deliberately, so the shipped behaviour is to say when it reopens and let them decide. What arming it buys
|
|
632
|
+
* is the case a press cannot reach: the 2am wall on a board nobody is watching, where the alternative is a
|
|
633
|
+
* card that sat waiting eight hours for a press that was always going to come. */
|
|
634
|
+
resumeAfterLimit: z
|
|
635
|
+
.boolean()
|
|
636
|
+
.default(false)
|
|
637
|
+
.describe(
|
|
638
|
+
"Whether a turn a spent usage limit refused is sent again by itself once the allowance reopens. The sandbox-wide default; any one conversation can say otherwise. Off to begin with, because the allowance is your budget and a turn that spends it the second it comes back is not a decision to make for you. Worth turning on for a sandbox whose work mostly happens with nobody in the room.",
|
|
639
|
+
),
|
|
633
640
|
/* When the daemon dies under a running turn, re-run that turn once it is back (agent/turn-journal.ts records
|
|
634
641
|
* every in-flight turn; the boot pass in agent/turn-resume.ts re-runs what survived). OFF by default, like
|
|
635
642
|
* the outage resume above and for the same reason: a boot that re-runs turns spends the user's allowance on
|
|
@@ -697,7 +704,7 @@ export const SandboxSettingsSchema = z.object({
|
|
|
697
704
|
* `<provider>.<type>` ("discord.message.send") with `<provider>.*` as the per-provider wildcard; exact key
|
|
698
705
|
* wins. An action with no rule is allowed, the empty default wires no hook at all, so an unconfigured
|
|
699
706
|
* workspace pays nothing. "hold" cannot park a running turn (nobody may be there to answer); it refuses the
|
|
700
|
-
* live call and points the agent at the
|
|
707
|
+
* live call and points the agent at the approvals queue, which IS the held form of a send.
|
|
701
708
|
*
|
|
702
709
|
* The CHILD-AGENT surface reads the same book: `agents.spawn` covers starting, steering and answering
|
|
703
710
|
* child agents on every provider, `agents.spawn.<provider>` singles one out (the specific key wins), and
|
|
@@ -708,50 +715,17 @@ export const SandboxSettingsSchema = z.object({
|
|
|
708
715
|
.record(z.string(), AdmissionRuleSchema)
|
|
709
716
|
.default({})
|
|
710
717
|
.describe("What an agent may do out in the world, per kind of action: go ahead, ask first, or never."),
|
|
711
|
-
/* THE COMMAND GATE
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
* that has never opened this page is not one mistyped path away from a formatted disk. An explicit `allow`
|
|
723
|
-
* still wins, it is a decision about that exact class and the floor must not override the person who made
|
|
724
|
-
* it. Everything else stays as it was: unlisted is allowed and ordinary work is never asked about.
|
|
725
|
-
*
|
|
726
|
-
* Keys are the CommandClass enum, so a typo is a settings error rather than a rule that silently never
|
|
727
|
-
* matches. */
|
|
728
|
-
commandRules: z
|
|
729
|
-
.partialRecord(CommandClassSchema, AdmissionRuleSchema)
|
|
730
|
-
.default({})
|
|
731
|
-
.describe(
|
|
732
|
-
"What an agent may run inside the sandbox, for the six kinds of command that are hard to take back: rewriting git history, deleting recursively, wiping a disk or a container volume, reading credential files, publishing a package, reaching out to the network. Everything else is recoverable in a container that is itself disposable, and gating it would be friction bought with nothing. Leaving a kind unset is not the same as allowing it: wiping a disk is held for your approval until you say otherwise, because nothing here brings that back.",
|
|
733
|
-
),
|
|
734
|
-
/* WHETHER A HELD COMMAND IS TRANSLATED BEFORE YOU ANSWER FOR IT. Off by default, and the default is the
|
|
735
|
-
* argument: the card is already complete without this, and switching it on spends one quick-model call per
|
|
736
|
-
* card raised, on the owner's own connected account.
|
|
737
|
-
*
|
|
738
|
-
* It buys the case the card is worst at. A held command is regularly a hundred-plus characters of pipeline
|
|
739
|
-
* the agent assembled, and the question the card actually asks, "do you want this to happen", is not
|
|
740
|
-
* answerable by reading shell quickly. The classifier already marks WHICH fragment held it (the card paints
|
|
741
|
-
* those); a sentence is what says what the rest of it does and why the agent wanted it.
|
|
742
|
-
*
|
|
743
|
-
* NEVER THE AGENT'S OWN WORDS. The sentence comes from the quick model reading the command text, not from
|
|
744
|
-
* the model being gated: a card that let the asking agent write its own justification would be a safety
|
|
745
|
-
* prompt whose persuasive half is authored by the thing it is meant to gate.
|
|
746
|
-
*
|
|
747
|
-
* The command itself is never replaced by it, only folded behind a disclosure the sentence sits above, and
|
|
748
|
-
* the marked fragments stay on the card either way, see ChatMessageView's permission card. */
|
|
749
|
-
explainCommands: z
|
|
750
|
-
.boolean()
|
|
751
|
-
.default(false)
|
|
752
|
-
.describe(
|
|
753
|
-
"Have the quick model describe each held command in one plain sentence, above the command itself. Costs one quick-model call per card raised, on your own connected account. The command is always still there to read.",
|
|
754
|
-
),
|
|
718
|
+
/* THE COMMAND GATE IS NOT CONFIGURED HERE. It used to be: `commandRules` was a verdict per CommandClass and
|
|
719
|
+
* `explainCommands` decided whether a card carried a sentence. Both are gone, and the reason is the whole
|
|
720
|
+
* safety redesign (safety-policy.ts argues it): a regex verdict per class asked about `echo "rm -rf /"` and
|
|
721
|
+
* an actual delete in the same words, and no setting of six switches fixes that, because telling the two
|
|
722
|
+
* apart is an act of understanding rather than a threshold. What replaced them is the owner's written
|
|
723
|
+
* policy at .intentic/config/safety.md, read by a judge that also sees what the daemon knows about the turn,
|
|
724
|
+
* plus one typed hard rule the judge cannot waive. The Safety page edits that document; nothing about the
|
|
725
|
+
* command gate belongs in this object.
|
|
726
|
+
*
|
|
727
|
+
* The sentence on a card is no longer optional either: it is the judge's own reason for the verdict, so a
|
|
728
|
+
* card without one would be a card that could not say why it exists. */
|
|
755
729
|
/* HOW MUCH AN AGENT MAY DELEGATE, the three ceilings the Claude Code harness enforces on its own Agent
|
|
756
730
|
* tool, surfaced here because their defaults are tuned for a laptop and this is a container the owner sized.
|
|
757
731
|
*
|
package/src/schemas/system.ts
CHANGED
|
@@ -131,8 +131,19 @@ export const ManifestProblemSchema = z.object({
|
|
|
131
131
|
.describe(
|
|
132
132
|
"What to do about it. Unreadable means the whole file is being ignored and everything in it is at its default. An unknown key means only that key is ignored. An invalid entry means one item of a list was skipped and the rest is fine.",
|
|
133
133
|
),
|
|
134
|
-
detail: z.string().describe("What exactly was wrong."),
|
|
134
|
+
detail: z.string().describe("What exactly was wrong, as one sentence and nothing else. Never the remedy: that is `fix`."),
|
|
135
135
|
suggestion: z.string().optional().describe("The name it was probably meant to be, when one is close enough to guess honestly."),
|
|
136
|
+
/* THE REMEDY, ONLY WHEN THE DAEMON KNOWS ONE THE READER CANNOT GUESS. For nearly every problem here the fix
|
|
137
|
+
* is "open the file and correct the line", which the browser can say without being told; carrying that
|
|
138
|
+
* sentence over the wire per problem would be the daemon dictating copy it has no more information about
|
|
139
|
+
* than the reader. The exception is the version skew (store/manifest-problems.ts): there the file is
|
|
140
|
+
* probably RIGHT and editing it is the wrong move, which nothing on the reading side could work out on its
|
|
141
|
+
* own. Kept apart from `detail` so a renderer can put cause and action on separate lines instead of
|
|
142
|
+
* concatenating them into a paragraph, which is what it used to be. */
|
|
143
|
+
fix: z
|
|
144
|
+
.string()
|
|
145
|
+
.optional()
|
|
146
|
+
.describe("What to do about it, when that is something other than 'correct the file'. Absent whenever the file itself is the thing to edit."),
|
|
136
147
|
});
|
|
137
148
|
export type ManifestProblem = z.infer<typeof ManifestProblemSchema>;
|
|
138
149
|
// Workspace-relative path (`.intentic/config/settings.json`) and everything currently wrong with that file. A file
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { PanelLaunchSchema } from "./panels.js";
|
|
2
3
|
// Every discovered repo's id (root-relative dir under /work), sorted, roles included.
|
|
3
4
|
export const ReposListSchema = z.object({
|
|
4
5
|
repos: z
|
|
@@ -82,6 +83,14 @@ export const RepoAppSchema = z.object({
|
|
|
82
83
|
previewUrl: z.string().optional().describe("Where to open it. Absent when this sandbox has no outside address."),
|
|
83
84
|
running: z.boolean().describe("Whether its dev server is up."),
|
|
84
85
|
healthy: z.boolean().describe("Whether it is actually answering."),
|
|
86
|
+
// The same two facts a repository's panel row carries (PanelSummarySchema), for the same screens: an app
|
|
87
|
+
// installs at its monorepo's root, so `installed` is the root's node_modules.
|
|
88
|
+
installed: z
|
|
89
|
+
.boolean()
|
|
90
|
+
.describe("Whether its dependencies are installed, which is what decides whether a start takes seconds or an install first."),
|
|
91
|
+
launch: PanelLaunchSchema.optional().describe(
|
|
92
|
+
"Where a start the sandbox is running has got to: its shell coming up, installing, its dev command running with nothing listening yet, or exited back to a prompt. Absent when nothing is starting and once it serves.",
|
|
93
|
+
),
|
|
85
94
|
});
|
|
86
95
|
export type RepoApp = z.infer<typeof RepoAppSchema>;
|
|
87
96
|
export const AppsListSchema = z.object({ apps: z.array(RepoAppSchema).describe("The apps in this repository.") });
|
|
@@ -99,6 +99,17 @@ export const WorkspaceTreeSchema = z.object({
|
|
|
99
99
|
tree: z.array(WorkspaceTreeEntrySchema).describe("The workspace, one entry per file and folder."),
|
|
100
100
|
// How many of the ROOT's own entries the budget cut (0 = complete); per-dir cuts are counted on each dir entry.
|
|
101
101
|
hidden: z.number().describe("How many entries at the top level were cut for size. Zero means the listing is complete."),
|
|
102
|
+
/* Every folder holding nothing but empty folders, root-relative, in tree order. Answered by its own walk
|
|
103
|
+
* (workspace/empty-dirs.ts) precisely because it must NOT be read off `tree` above: that listing stops at
|
|
104
|
+
* the entry budget, so a directory below the cut arrives without `children`, which means "not looked at",
|
|
105
|
+
* and the emptiness question would silently shrink to whatever the budget happened to reach, the workspace
|
|
106
|
+
* root and little else. This list is complete, and it says nothing about whether the folders in it were
|
|
107
|
+
* listed. */
|
|
108
|
+
barren: z
|
|
109
|
+
.array(z.string())
|
|
110
|
+
.describe(
|
|
111
|
+
"Folders whose whole contents are empty folders, and nothing else. Complete for the workspace, however much of the tree above was listed, and ordered like the tree, so a parent comes before the branch below it.",
|
|
112
|
+
),
|
|
102
113
|
});
|
|
103
114
|
export type WorkspaceTree = z.infer<typeof WorkspaceTreeSchema>;
|
|
104
115
|
// Lazy-load one directory's children, for a dir the tree walk listed but didn't descend into. The ordinary
|