@intentic/sandbox-contract 1.303.0 → 1.305.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 +5 -3
- package/dist/contracts/agent.contract.d.ts +195 -41
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +8 -8
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +217 -3
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +30 -2
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +18 -5
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +3 -3
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/{host.contract.d.ts → device.contract.d.ts} +75 -2
- package/dist/contracts/device.contract.d.ts.map +1 -0
- package/dist/contracts/device.contract.js +17 -0
- package/dist/contracts/device.contract.js.map +1 -0
- package/dist/contracts/extensions.contract.d.ts +2 -2
- package/dist/contracts/git.contract.d.ts +24 -0
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/panels.contract.d.ts +1 -1
- package/dist/contracts/personas.contract.d.ts +0 -9
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.js +1 -10
- package/dist/contracts/personas.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +138 -98
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.js +1 -0
- package/dist/contracts/runner.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.js +2 -2
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +23 -3
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +0 -23
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +109 -8
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +11 -2
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +85 -10
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +26 -10
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/agent-words.d.ts +20 -0
- package/dist/events/agent-words.d.ts.map +1 -0
- package/dist/events/agent-words.js +82 -0
- package/dist/events/agent-words.js.map +1 -0
- package/dist/events/{cards.d.ts → requests.d.ts} +18 -18
- package/dist/events/requests.d.ts.map +1 -0
- package/dist/events/{cards.js → requests.js} +26 -26
- package/dist/events/requests.js.map +1 -0
- package/dist/events/resume.d.ts +1 -0
- package/dist/events/resume.d.ts.map +1 -1
- package/dist/events/resume.js +2 -0
- package/dist/events/resume.js.map +1 -1
- package/dist/events/system-events.d.ts +21 -3
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/transcript.d.ts +165 -25
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +34 -15
- package/dist/events/transcript.js.map +1 -1
- package/dist/events/watch-wake.d.ts.map +1 -1
- package/dist/events/watch-wake.js +4 -0
- package/dist/events/watch-wake.js.map +1 -1
- package/dist/index.d.ts +629 -129
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/models/model-offer.d.ts +2 -1
- package/dist/models/model-offer.d.ts.map +1 -1
- package/dist/models/model-offer.js +5 -4
- package/dist/models/model-offer.js.map +1 -1
- package/dist/models/model-roles.d.ts +2 -9
- package/dist/models/model-roles.d.ts.map +1 -1
- package/dist/models/model-roles.js +2 -9
- package/dist/models/model-roles.js.map +1 -1
- package/dist/policy/command-classes.d.ts +1 -0
- package/dist/policy/command-classes.d.ts.map +1 -1
- package/dist/policy/command-classes.js +8 -0
- package/dist/policy/command-classes.js.map +1 -1
- package/dist/policy/persona-home.d.ts +10 -0
- package/dist/policy/persona-home.d.ts.map +1 -0
- package/dist/policy/persona-home.js +11 -0
- package/dist/policy/persona-home.js.map +1 -0
- package/dist/policy/request-status.d.ts +5 -0
- package/dist/policy/request-status.d.ts.map +1 -0
- package/dist/policy/{card-status.js → request-status.js} +3 -3
- package/dist/policy/request-status.js.map +1 -0
- package/dist/policy/safety-policy.d.ts +1 -1
- package/dist/policy/safety-policy.d.ts.map +1 -1
- package/dist/policy/safety-policy.js +1 -0
- package/dist/policy/safety-policy.js.map +1 -1
- package/dist/policy/turned-away.d.ts +2 -0
- package/dist/policy/turned-away.d.ts.map +1 -0
- package/dist/policy/turned-away.js +13 -0
- package/dist/policy/turned-away.js.map +1 -0
- package/dist/protocol/peer-dial.d.ts +9 -0
- package/dist/protocol/peer-dial.d.ts.map +1 -1
- package/dist/protocol/peer-dial.js +12 -4
- package/dist/protocol/peer-dial.js.map +1 -1
- package/dist/protocol/peer-mcp-server.d.ts +1 -0
- package/dist/protocol/peer-mcp-server.d.ts.map +1 -1
- package/dist/protocol/peer-mcp-server.js +14 -1
- package/dist/protocol/peer-mcp-server.js.map +1 -1
- package/dist/schemas/agent.d.ts +2 -1
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +7 -0
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +29 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +18 -0
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/automations.d.ts +9 -0
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/capabilities.d.ts +25 -12
- package/dist/schemas/capabilities.d.ts.map +1 -1
- package/dist/schemas/capabilities.js +11 -6
- package/dist/schemas/capabilities.js.map +1 -1
- package/dist/schemas/chat-route.d.ts +49 -0
- package/dist/schemas/chat-route.d.ts.map +1 -0
- package/dist/schemas/{model-route.js → chat-route.js} +17 -5
- package/dist/schemas/chat-route.js.map +1 -0
- package/dist/schemas/context-trim.d.ts +9 -0
- package/dist/schemas/context-trim.d.ts.map +1 -0
- package/dist/schemas/context-trim.js +18 -0
- package/dist/schemas/context-trim.js.map +1 -0
- package/dist/schemas/devices.d.ts +21 -8
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +8 -9
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts +4 -4
- package/dist/schemas/extension-updates.js +1 -1
- package/dist/schemas/extension-updates.js.map +1 -1
- package/dist/schemas/git/git.d.ts +83 -0
- package/dist/schemas/git/git.d.ts.map +1 -1
- package/dist/schemas/git/git.js +40 -0
- package/dist/schemas/git/git.js.map +1 -1
- package/dist/schemas/hosts.d.ts +36 -5
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +7 -5
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/metrics.d.ts +108 -0
- package/dist/schemas/metrics.d.ts.map +1 -0
- package/dist/schemas/metrics.js +77 -0
- package/dist/schemas/metrics.js.map +1 -0
- package/dist/schemas/panels.d.ts +2 -2
- package/dist/schemas/panels.js +1 -1
- package/dist/schemas/panels.js.map +1 -1
- package/dist/schemas/personas.d.ts +1 -13
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/personas.js +3 -20
- package/dist/schemas/personas.js.map +1 -1
- package/dist/schemas/providers/plan-limits.d.ts +1 -0
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.js +6 -0
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/secrets.d.ts +1 -1
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js +1 -1
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/settings.d.ts +0 -42
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +1 -16
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/shared.d.ts +2 -2
- package/dist/schemas/shared.d.ts.map +1 -1
- package/dist/schemas/shared.js +3 -3
- package/dist/schemas/shared.js.map +1 -1
- package/dist/schemas/system-prompt.d.ts +104 -0
- package/dist/schemas/system-prompt.d.ts.map +1 -0
- package/dist/schemas/system-prompt.js +25 -0
- package/dist/schemas/system-prompt.js.map +1 -0
- package/dist/schemas/workflows.d.ts +2 -2
- package/dist/schemas/workflows.d.ts.map +1 -1
- package/dist/schemas/workflows.js +2 -2
- package/dist/schemas/workflows.js.map +1 -1
- package/dist/state/definition.d.ts +18 -10
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/fix-attempt-plan.d.ts +4 -0
- package/dist/state/fix-attempt-plan.d.ts.map +1 -1
- package/dist/state/fix-attempt-plan.js +3 -2
- package/dist/state/fix-attempt-plan.js.map +1 -1
- package/dist/state/fix-stance.d.ts +1 -0
- package/dist/state/fix-stance.d.ts.map +1 -1
- package/dist/state/fix-stance.js +11 -0
- package/dist/state/fix-stance.js.map +1 -1
- package/dist/state/history-state.d.ts.map +1 -1
- package/dist/state/history-state.js +8 -1
- package/dist/state/history-state.js.map +1 -1
- package/dist/state/runtime-state.d.ts +0 -1
- package/dist/state/runtime-state.d.ts.map +1 -1
- package/dist/state/runtime-state.js +0 -1
- package/dist/state/runtime-state.js.map +1 -1
- package/dist/state/workspace-state.d.ts +4 -4
- package/dist/state/workspace-state.d.ts.map +1 -1
- package/dist/state/workspace-state.js +4 -4
- package/dist/state/workspace-state.js.map +1 -1
- package/dist/text/documents.d.ts +2 -2
- package/dist/text/documents.d.ts.map +1 -1
- package/dist/text/documents.js.map +1 -1
- package/dist/text/mentions.d.ts +1 -0
- package/dist/text/mentions.d.ts.map +1 -1
- package/dist/text/mentions.js +5 -1
- package/dist/text/mentions.js.map +1 -1
- package/dist/text/transcript-fold.d.ts +8 -3
- package/dist/text/transcript-fold.d.ts.map +1 -1
- package/dist/text/transcript-fold.js +83 -28
- package/dist/text/transcript-fold.js.map +1 -1
- package/package.json +9 -9
- package/src/chores/chores.test.ts +1 -1
- package/src/chores/digest.test.ts +1 -1
- package/src/chores/probes.test.ts +5 -2
- package/src/chores/stack.test.ts +1 -1
- package/src/chores/verdict.test.ts +6 -5
- package/src/contracts/agent.contract.ts +10 -9
- package/src/contracts/agents.contract.ts +35 -2
- package/src/contracts/capabilities.contract.ts +3 -3
- package/src/contracts/{host.contract.ts → device.contract.ts} +8 -6
- package/src/contracts/personas.contract.ts +1 -13
- package/src/contracts/runner.contract.ts +3 -2
- package/src/contracts/secrets.contract.ts +2 -2
- package/src/contracts/system.contract.ts +13 -2
- package/src/contracts/webext.contract.ts +1 -1
- package/src/events/agent-events.ts +37 -14
- package/src/events/agent-words.test.ts +68 -0
- package/src/events/agent-words.ts +124 -0
- package/src/events/{cards.ts → requests.ts} +44 -44
- package/src/events/resume.test.ts +8 -1
- package/src/events/resume.ts +4 -0
- package/src/events/transcript.ts +51 -22
- package/src/events/watch-wake.test.ts +3 -2
- package/src/events/watch-wake.ts +4 -0
- package/src/ids/conversation-ids.test.ts +3 -3
- package/src/ids/hostnames.test.ts +1 -1
- package/src/ids/share-paths.test.ts +1 -1
- package/src/ids/tunnel-ids.test.ts +1 -1
- package/src/index.ts +10 -4
- package/src/models/agent-catalog.test.ts +1 -1
- package/src/models/capability-ledger.test.ts +1 -1
- package/src/models/model-offer.test.ts +9 -2
- package/src/models/model-offer.ts +10 -7
- package/src/models/model-order.test.ts +1 -1
- package/src/models/model-pins.test.ts +1 -1
- package/src/models/model-roles.test.ts +1 -1
- package/src/models/model-roles.ts +6 -12
- package/src/models/plan-pools.test.ts +1 -1
- package/src/models/provider-specs.test.ts +3 -3
- package/src/policy/batch-runs.test.ts +1 -1
- package/src/policy/command-classes.test.ts +37 -2
- package/src/policy/command-classes.ts +16 -0
- package/src/policy/credential-material.test.ts +6 -10
- package/src/policy/fence-paths.test.ts +1 -1
- package/src/policy/overlay-lint.test.ts +1 -1
- package/src/policy/owner-ticket.test.ts +1 -1
- package/src/policy/persona-home.test.ts +52 -0
- package/src/policy/persona-home.ts +39 -0
- package/src/policy/{card-status.ts → request-status.ts} +6 -6
- package/src/policy/safety-policy.test.ts +1 -1
- package/src/policy/safety-policy.ts +1 -0
- package/src/policy/search-globs.test.ts +1 -1
- package/src/policy/turned-away.ts +18 -0
- package/src/protocol/container-requirements.test.ts +1 -1
- package/src/protocol/ingress-contract.test.ts +8 -2
- package/src/protocol/ingress-protocol.test.ts +5 -4
- package/src/protocol/peer-dial.test.ts +111 -41
- package/src/protocol/peer-dial.ts +39 -4
- package/src/protocol/peer-mcp-server.test.ts +37 -7
- package/src/protocol/peer-mcp-server.ts +22 -1
- package/src/protocol/routes.test.ts +4 -2
- package/src/schemas/agent.ts +13 -0
- package/src/schemas/agents.ts +33 -0
- package/src/schemas/areas.test.ts +2 -8
- package/src/schemas/automations.ts +5 -5
- package/src/schemas/capabilities.ts +20 -9
- package/src/schemas/chat-route.ts +61 -0
- package/src/schemas/context-trim.test.ts +38 -0
- package/src/schemas/context-trim.ts +29 -0
- package/src/schemas/dev-rebuild-log.test.ts +1 -1
- package/src/schemas/devices.ts +25 -22
- package/src/schemas/extension-updates.ts +1 -1
- package/src/schemas/git/git.test.ts +11 -0
- package/src/schemas/git/git.ts +66 -0
- package/src/schemas/hosts.ts +15 -8
- package/src/schemas/issues.ts +1 -1
- package/src/schemas/metrics.ts +107 -0
- package/src/schemas/panels.ts +2 -2
- package/src/schemas/personas.ts +5 -28
- package/src/schemas/providers/plan-limits.ts +9 -0
- package/src/schemas/secrets.ts +1 -1
- package/src/schemas/settings.test.ts +1 -1
- package/src/schemas/settings.ts +9 -36
- package/src/schemas/shared.ts +6 -6
- package/src/schemas/system-prompt.ts +41 -0
- package/src/schemas/version-seam.test.ts +1 -1
- package/src/schemas/webext.ts +1 -1
- package/src/schemas/workflows.ts +4 -4
- package/src/state/contract-lock.test.ts +15 -11
- package/src/state/fix-attempt-plan.test.ts +10 -1
- package/src/state/fix-attempt-plan.ts +6 -2
- package/src/state/fix-stance.test.ts +10 -1
- package/src/state/fix-stance.ts +13 -0
- package/src/state/history-state.ts +17 -1
- package/src/state/runtime-state.test.ts +3 -9
- package/src/state/runtime-state.ts +0 -4
- package/src/state/versions.test.ts +1 -1
- package/src/state/workspace-state.test.ts +12 -7
- package/src/state/workspace-state.ts +4 -4
- package/src/text/archives.test.ts +1 -1
- package/src/text/documents.test.ts +1 -1
- package/src/text/documents.ts +2 -2
- package/src/text/embed.test.ts +17 -6
- package/src/text/emoji.test.ts +1 -1
- package/src/text/mentions.test.ts +20 -2
- package/src/text/mentions.ts +10 -1
- package/src/text/path-refs.test.ts +1 -1
- package/src/text/title.test.ts +1 -1
- package/src/text/transcript-fold.test.ts +183 -1
- package/src/text/transcript-fold.ts +146 -39
- package/src/text/whisper.test.ts +1 -1
- package/src/text/workflow-faults.test.ts +1 -1
- package/src/time/zone.test.ts +6 -6
- package/dist/contracts/host.contract.d.ts.map +0 -1
- package/dist/contracts/host.contract.js +0 -16
- package/dist/contracts/host.contract.js.map +0 -1
- package/dist/events/cards.d.ts.map +0 -1
- package/dist/events/cards.js.map +0 -1
- package/dist/policy/card-status.d.ts +0 -5
- package/dist/policy/card-status.d.ts.map +0 -1
- package/dist/policy/card-status.js.map +0 -1
- package/dist/schemas/model-route.d.ts +0 -27
- package/dist/schemas/model-route.d.ts.map +0 -1
- package/dist/schemas/model-route.js.map +0 -1
- package/src/schemas/model-route.ts +0 -43
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// context-trim: what a window too small for a full turn made the sandbox leave out
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
// The only disclosure of a note that never rode; without it a turn runs thinner and nothing on screen says why.
|
|
5
|
+
export const ContextTrimSchema = z.object({
|
|
6
|
+
window: z.number().int().positive().describe("The window that decided it, in tokens, as the model's server declared it."),
|
|
7
|
+
omitted: z
|
|
8
|
+
.array(z.string())
|
|
9
|
+
.describe("What was left out, under the same label the chat would have drawn it with, in the order a full turn would have read them."),
|
|
10
|
+
base: z
|
|
11
|
+
.boolean()
|
|
12
|
+
.describe(
|
|
13
|
+
"Whether the agent loop's own base instructions were swapped for a short paragraph as well, which only a replacing runtime can do.",
|
|
14
|
+
),
|
|
15
|
+
});
|
|
16
|
+
export type ContextTrim = z.infer<typeof ContextTrimSchema>;
|
|
17
|
+
|
|
18
|
+
// 16k, 32k; a server's own odd number spelled out in full.
|
|
19
|
+
const windowLabel = (tokens: number): string => (tokens % 1024 === 0 ? `${tokens / 1024}k` : tokens.toLocaleString("en-US"));
|
|
20
|
+
|
|
21
|
+
// The closing clause is load-bearing: without it the row reads as "my AGENTS.md may not have arrived".
|
|
22
|
+
export const contextTrimLine = ({ window, omitted, base }: ContextTrim): string => {
|
|
23
|
+
const swapped = base ? ` The agent's own base instructions were swapped for a short paragraph, too.` : ``;
|
|
24
|
+
const left = omitted.length === 0 ? `` : ` — left out: ${omitted.join(`, `)}`;
|
|
25
|
+
return (
|
|
26
|
+
`Sent thin for this model's ${windowLabel(window)} window${left}.${swapped}` +
|
|
27
|
+
` Your workspace rules, this turn's persona and where its files live still rode.`
|
|
28
|
+
);
|
|
29
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { test, expect } from "bun:test";
|
|
2
2
|
import { DEV_REBUILD_EXIT_MARK, DEV_REBUILD_QUIET_MARK, devRebuildLogPath, readDevRebuildLog } from "./devices.js";
|
|
3
3
|
|
|
4
4
|
// The one account a detached rebuild gives of itself. The daemon builds the shell that writes this text and the browser
|
package/src/schemas/devices.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// What one of the user's own machines is running.
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { hostEntryOf, hostEnvironmentOf, type DeviceFacts, DeviceFactsSchema, WSL_SYSTEM_DISTROS, WslEnvironmentSchema } from "./hosts.js";
|
|
4
4
|
import { DEV_VERSION } from "../state/versions.js";
|
|
5
|
-
// Desktop-sync report shape shared by the agent, daemon and browser, produced only by
|
|
5
|
+
// Desktop-sync report shape shared by the agent, daemon and browser, produced only by the agent's own `deviceReport`.
|
|
6
6
|
// The agent never reports `sandboxes`; the docker half is filled in by whoever reads the report, scoped to the reader's
|
|
7
7
|
// own pairing.
|
|
8
8
|
|
|
@@ -64,15 +64,20 @@ export const DeviceSandboxOpSchema = z.enum([
|
|
|
64
64
|
"reshape",
|
|
65
65
|
"remove",
|
|
66
66
|
"logs",
|
|
67
|
-
//
|
|
67
|
+
// The two ops that redeem a fresh setup code; every other one recreates a container from its own existing env.
|
|
68
|
+
// They differ only in which row the claim names — an existing sandbox on this machine, or one that has never run
|
|
69
|
+
// anywhere — which is why each checks the opposite thing about the slug before spending the code.
|
|
68
70
|
"reconnect",
|
|
71
|
+
"create",
|
|
69
72
|
"runner-up",
|
|
70
73
|
"runner-remove",
|
|
71
74
|
]);
|
|
72
75
|
export type DeviceSandboxOp = z.infer<typeof DeviceSandboxOpSchema>;
|
|
73
76
|
export const DeviceSandboxFlowSchema = z.object({
|
|
74
77
|
op: DeviceSandboxOpSchema,
|
|
75
|
-
// Sandbox slug,
|
|
78
|
+
// Sandbox slug, the runner's name for the runner ops (as `/system/runners`/`ic runner list` know it), or for
|
|
79
|
+
// `create` the name the claim is about to produce — the one op where the slug is an expectation rather than a
|
|
80
|
+
// lookup, and the device refuses if anything already answers to it.
|
|
76
81
|
slug: z.string().min(1),
|
|
77
82
|
// Approved overlay's sha256, required only by `rebuild`; only content matching it is ever built.
|
|
78
83
|
hash: z.string().optional(),
|
|
@@ -81,7 +86,7 @@ export const DeviceSandboxFlowSchema = z.object({
|
|
|
81
86
|
// `runner-up` only, daemon-filled, never by the caller: the browser never holds the pairing credential.
|
|
82
87
|
parentUrl: z.string().optional(),
|
|
83
88
|
pair: z.string().optional().meta({ secret: true }),
|
|
84
|
-
// Required by `reconnect`
|
|
89
|
+
// Required by `reconnect` and `create`; single-sandbox and short-lived, so a leak only buys one recreate.
|
|
85
90
|
setupCode: z.string().optional().meta({ secret: true }),
|
|
86
91
|
// `runner-up` only, daemon-filled: `definition` carries no capabilities or secrets; `overlay`/`overlayHash` are
|
|
87
92
|
// re-verified by hash before build.
|
|
@@ -101,9 +106,13 @@ export const DeviceFlowLineSchema = z.discriminatedUnion("kind", [
|
|
|
101
106
|
z.object({ kind: z.literal("error"), message: z.string() }),
|
|
102
107
|
]);
|
|
103
108
|
export type DeviceFlowLine = z.infer<typeof DeviceFlowLineSchema>;
|
|
104
|
-
//
|
|
109
|
+
// Every op stops the resident process mid-command; a stream ending with no terminal frame is normal, not a failure, and
|
|
105
110
|
// confirmation is the version moving on the next poll. `restart` is just a bare `intentic-machine run`.
|
|
106
|
-
|
|
111
|
+
// `forget-unreachable` drops the machine's links to sandboxes that have answered nothing for long enough to be gone
|
|
112
|
+
// (peer-dial's LONG_OUTAGE_ATTEMPTS) — never the link carrying the request, which is by definition answering. Never
|
|
113
|
+
// automatic either: a laptop closed for a fortnight must find its sandboxes again, so nothing expires on its own and
|
|
114
|
+
// dropping one is always somebody's decision.
|
|
115
|
+
export const DeviceAgentOpSchema = z.enum(["upgrade", "restart", "forget-unreachable"]);
|
|
107
116
|
export type DeviceAgentOp = z.infer<typeof DeviceAgentOpSchema>;
|
|
108
117
|
export const DeviceAgentFlowSchema = z.object({ op: DeviceAgentOpSchema });
|
|
109
118
|
export type DeviceAgentFlow = z.infer<typeof DeviceAgentFlowSchema>;
|
|
@@ -114,7 +123,7 @@ export type DeviceAgentFlowInput = z.infer<typeof DeviceAgentFlowInputSchema>;
|
|
|
114
123
|
// command: the same socket carries `run_command`, which would grant a shell on the user's machine.
|
|
115
124
|
// `sync-unpair` runs the machine's own `sync uninstall --sandbox` (terminates both Mutagen sessions, drops the pairing,
|
|
116
125
|
// self-revokes enrollment); revoking from the sandbox side is a different route.
|
|
117
|
-
// `dev-
|
|
126
|
+
// `dev-restart`, `dev-rebuild` and `sync-install` are the three whose argv the daemon fills from what only it knows — the
|
|
118
127
|
// dev checkout on that machine, a freshly minted pairing token — which is also why none takes a path or a token from the
|
|
119
128
|
// caller. The two dev commands are also why a machine-side op is the wrong shape for them: this door carries a COMMAND
|
|
120
129
|
// STRING to a tool every released agent already has, so a sandbox can drive a machine whose agent predates the feature.
|
|
@@ -135,7 +144,7 @@ export const DeviceCommandSchema = z.enum([
|
|
|
135
144
|
"sync-resume",
|
|
136
145
|
"sync-unpair",
|
|
137
146
|
"sync-clean",
|
|
138
|
-
"dev-
|
|
147
|
+
"dev-restart",
|
|
139
148
|
"dev-rebuild",
|
|
140
149
|
"dev-rebuild-log",
|
|
141
150
|
"sync-install",
|
|
@@ -144,7 +153,7 @@ export type DeviceCommand = z.infer<typeof DeviceCommandSchema>;
|
|
|
144
153
|
// The reversible sync switches: the subset a device's own row drives with a pair of buttons, as opposed to the two
|
|
145
154
|
// commands a card elsewhere issues once. Its own type so those button tables stay total without carrying entries for
|
|
146
155
|
// commands they can never send.
|
|
147
|
-
export const DeviceSyncSwitchSchema = DeviceCommandSchema.exclude(["dev-
|
|
156
|
+
export const DeviceSyncSwitchSchema = DeviceCommandSchema.exclude(["dev-restart", "dev-rebuild", "dev-rebuild-log", "sync-install", "sync-clean"]);
|
|
148
157
|
export type DeviceSyncSwitch = z.infer<typeof DeviceSyncSwitchSchema>;
|
|
149
158
|
|
|
150
159
|
// WHERE A DETACHED REBUILD REPORTS ITSELF. `dev-rebuild` returns the moment the build is under way and nothing streams
|
|
@@ -368,7 +377,7 @@ export const reportQuiet = (report: DeviceReport, receivedAt: number): boolean =
|
|
|
368
377
|
// distro, `native` for an install on the metal. Connect-time facts are read first, since no scope can withhold them;
|
|
369
378
|
// facts from an agent too old to carry `hostname` say nothing, and a report without `wsl` is native, as it always
|
|
370
379
|
// was. Undefined is an absence of evidence, never read as agreement.
|
|
371
|
-
export const environmentOf = (facts: Pick<
|
|
380
|
+
export const environmentOf = (facts: Pick<DeviceFacts, "hostname" | "wsl"> | undefined, report: DeviceReport | undefined): string | undefined => {
|
|
372
381
|
const wsl = facts?.wsl ?? report?.wsl;
|
|
373
382
|
if (wsl !== undefined) {
|
|
374
383
|
return `wsl:${wsl.distro}`;
|
|
@@ -398,9 +407,7 @@ export const DeviceGapSchema = z.enum([
|
|
|
398
407
|
// Connected, but "Run commands" is off on its capability card, so it won't describe itself: no folders, no
|
|
399
408
|
// ports, no agent health. Says nothing about its containers, which ride their own switch (`Device.sandboxes`).
|
|
400
409
|
"scope-off",
|
|
401
|
-
//
|
|
402
|
-
"no-agent",
|
|
403
|
-
// Sync-enrolled but has not posted a report yet; unlike `no-agent`, the agent is there and syncing.
|
|
410
|
+
// The agent is there but gave no report: never posted since enrolling, or refused `report` other than by its switch.
|
|
404
411
|
"unreported",
|
|
405
412
|
]);
|
|
406
413
|
export type DeviceGap = z.infer<typeof DeviceGapSchema>;
|
|
@@ -431,7 +438,7 @@ export const DeviceSchema = z.object({
|
|
|
431
438
|
// Carried beside the report so a device with no report still has an OS; `platform` is the normalised slug, `facts`
|
|
432
439
|
// its connect-time self-description.
|
|
433
440
|
platform: z.string().optional(),
|
|
434
|
-
facts:
|
|
441
|
+
facts: DeviceFactsSchema.optional(),
|
|
435
442
|
// Announced at connect; matches `report.agent.build` when known, the only version a report-less device has.
|
|
436
443
|
agentVersion: z.string().optional(),
|
|
437
444
|
lastSeen: z.number().optional(),
|
|
@@ -483,7 +490,7 @@ const hostnameKey = (device: Device): string | undefined => deviceHostname(devic
|
|
|
483
490
|
|
|
484
491
|
// The card a device's door hangs off: one card is one computer, so two doors naming the same card are one machine
|
|
485
492
|
// whatever either has said about itself — which is the whole of what an environment that has never connected says.
|
|
486
|
-
const cardKey = (device: Device): string | undefined => (device.hostId === undefined ? undefined :
|
|
493
|
+
const cardKey = (device: Device): string | undefined => (device.hostId === undefined ? undefined : hostEntryOf(device.hostId));
|
|
487
494
|
|
|
488
495
|
// What makes two devices one computer: a shared card, or a shared hostname where a distro answers to it, since WSL
|
|
489
496
|
// hands a distro the Windows machine's name. Two native installs that merely share a name stay two machines.
|
|
@@ -568,10 +575,6 @@ export const hostRunningSandbox = (devices: readonly Device[], slug: string | un
|
|
|
568
575
|
// the line naming it would work under.
|
|
569
576
|
const windowsPath = (path: string): boolean => /^([A-Za-z]:[\\/]|\\\\)/.test(path);
|
|
570
577
|
|
|
571
|
-
// Docker Desktop's own distros. `wsl -l -q` lists them like any other and neither ever holds a checkout, so counting
|
|
572
|
-
// them would make every Docker Desktop PC look ambiguous.
|
|
573
|
-
const SYSTEM_DISTROS: ReadonlySet<string> = new Set(["docker-desktop", "docker-desktop-data"]);
|
|
574
|
-
|
|
575
578
|
// How a line written for a host path reaches the environment that holds it, through one door. `none` carries the
|
|
576
579
|
// distros that were candidates, since "this PC has two and nothing says which" is a different answer for the reader
|
|
577
580
|
// than "there is no way in".
|
|
@@ -589,11 +592,11 @@ export type PathReach =
|
|
|
589
592
|
// an argument it would reject. Two real distros stay a refusal that names them — nothing here knows which one has the
|
|
590
593
|
// folder, and the distro's own door, once connected, answers directly.
|
|
591
594
|
// A platform that never said what it is stays a candidate, as every other reading of device evidence does.
|
|
592
|
-
export const pathReach = (platform: string | undefined, facts:
|
|
595
|
+
export const pathReach = (platform: string | undefined, facts: DeviceFacts | undefined, path: string): PathReach => {
|
|
593
596
|
if (platform === undefined || (platform === "windows") === windowsPath(path)) {
|
|
594
597
|
return { kind: "direct" };
|
|
595
598
|
}
|
|
596
|
-
const distros = platform === "windows" ? (facts?.wslDistros ?? []).filter((distro) => !
|
|
599
|
+
const distros = platform === "windows" ? (facts?.wslDistros ?? []).filter((distro) => !WSL_SYSTEM_DISTROS.has(distro)) : [];
|
|
597
600
|
const only = distros.length === 1 ? distros[0] : undefined;
|
|
598
601
|
return only === undefined ? { kind: "none", distros } : { kind: "wsl", distro: only };
|
|
599
602
|
};
|
|
@@ -264,7 +264,7 @@ export const WorkspaceExtensionCreatedSchema = z.object({
|
|
|
264
264
|
export const ExtensionRemovalConnectionSchema = z.object({
|
|
265
265
|
id: z.string().describe("The name the owner gave it, which is also the agent's handle for it."),
|
|
266
266
|
kind: z.string().describe("Which core kind it is underneath: cli, browser, host or webext."),
|
|
267
|
-
|
|
267
|
+
entry: z.string().describe("The catalog entry it was added from, named as the grid names it."),
|
|
268
268
|
secrets: z
|
|
269
269
|
.array(z.string())
|
|
270
270
|
.describe("Credential fields stored for it, by name. The values are deleted with the entry and cannot be recovered from here."),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { test, expect } from "bun:test";
|
|
2
|
+
import { isScratch } from "./git.js";
|
|
3
|
+
|
|
4
|
+
test("a scratch directory entry covers everything under it, and a file entry only itself", () => {
|
|
5
|
+
const scratch = [{ path: ".trun/" }, { path: "src/debug.log" }];
|
|
6
|
+
|
|
7
|
+
expect(isScratch(".trun/deep/x.log", scratch)).toBe(true);
|
|
8
|
+
expect(isScratch(".trunk/x", scratch)).toBe(false);
|
|
9
|
+
expect(isScratch("src/debug.log", scratch)).toBe(true);
|
|
10
|
+
expect(isScratch("src/debug.log.txt", scratch)).toBe(false);
|
|
11
|
+
});
|
package/src/schemas/git/git.ts
CHANGED
|
@@ -233,6 +233,23 @@ export const GitOperationStateSchema = z.object({
|
|
|
233
233
|
),
|
|
234
234
|
});
|
|
235
235
|
export type GitOperationState = z.infer<typeof GitOperationStateSchema>;
|
|
236
|
+
// Judged by shape alone: the names scratch arrives under are made up fresh every time, so no list of names could hold.
|
|
237
|
+
export const ScratchReasonSchema = z
|
|
238
|
+
.enum(["hidden", "byproduct", "checkout", "oversized", "root"])
|
|
239
|
+
.describe(
|
|
240
|
+
"Why it looks like scratch. A new hidden directory that is not one a project keeps on purpose (like `.github`). A log, dump, backup or editor leftover. A git checkout of its own. A new file past the size source code reaches. Or a new dotfile at the top of a workspace whose projects are the repositories inside it.",
|
|
241
|
+
);
|
|
242
|
+
export type ScratchReason = z.infer<typeof ScratchReasonSchema>;
|
|
243
|
+
export const ScratchPathSchema = z.object({
|
|
244
|
+
path: z.string().describe("Relative to its repository. A directory ends in a slash and stands for everything inside it."),
|
|
245
|
+
reason: ScratchReasonSchema,
|
|
246
|
+
files: z.number().optional().describe("How many files it holds. Absent for a checkout of its own, whose contents are not walked."),
|
|
247
|
+
bytes: z.number().optional().describe("Their total size in bytes. Absent exactly when `files` is."),
|
|
248
|
+
});
|
|
249
|
+
export type ScratchPath = z.infer<typeof ScratchPathSchema>;
|
|
250
|
+
// Whether a scratch entry covers `path`: a directory entry everything under it, a file entry only itself.
|
|
251
|
+
export const isScratch = (path: string, scratch: readonly Pick<ScratchPath, "path">[]): boolean =>
|
|
252
|
+
scratch.some((entry) => (entry.path.endsWith("/") ? path.startsWith(entry.path) : path === entry.path));
|
|
236
253
|
export const RepoChangesSchema = z.object({
|
|
237
254
|
// The {repo} param the per-repo git routes accept: "root" or a repo id (its root-relative dir).
|
|
238
255
|
repo: z.string(),
|
|
@@ -267,6 +284,14 @@ export const RepoChangesSchema = z.object({
|
|
|
267
284
|
.describe(
|
|
268
285
|
"How many changes were cut from each of the two lists above. A freshly cloned monorepo or a mass delete runs to six figures, which no screen can draw, so past a budget the lists arrive short and this says by how much on each side. Absent means they are complete.",
|
|
269
286
|
),
|
|
287
|
+
// A subset of `unstaged`'s untracked rows, restated by the entry that covers them rather than flagged per row, since
|
|
288
|
+
// one scratch directory can stand for thousands of files.
|
|
289
|
+
scratch: z
|
|
290
|
+
.array(ScratchPathSchema)
|
|
291
|
+
.optional()
|
|
292
|
+
.describe(
|
|
293
|
+
"Untracked paths that look like scratch. Staging or committing everything leaves them out, while staging one by its own path takes it like any other file. Absent when there are none.",
|
|
294
|
+
),
|
|
270
295
|
// 0 for `ahead`/`behind` with no remote or no upstream.
|
|
271
296
|
remote: GitRemoteStateSchema.optional().describe("Where this repository stands against its remote."),
|
|
272
297
|
// Keyed by path, not on each change, since one path can appear on two sides with the same origin. Ids only; look up
|
|
@@ -394,9 +419,50 @@ export const AgentChangesSchema = z.object({
|
|
|
394
419
|
.describe(
|
|
395
420
|
"Why the last merge refused, when one did. Carried here as well as in the merge's own answer, because a conflict is found the moment a turn ends and dealt with hours later on this surface, which would otherwise open with nothing to explain what it promised to resolve.",
|
|
396
421
|
),
|
|
422
|
+
// On the response, not on a repository's own row: a repository whose branch holds nothing gets no row at all, and
|
|
423
|
+
// that is exactly the case where the conversation did all of its work on the other branch.
|
|
424
|
+
elsewhere: z
|
|
425
|
+
.array(
|
|
426
|
+
z.object({
|
|
427
|
+
repo: z.string().describe("Which repository."),
|
|
428
|
+
branch: z
|
|
429
|
+
.string()
|
|
430
|
+
.optional()
|
|
431
|
+
.describe("The branch its copy is standing on. Absent where it stands on no branch at all, which is a state git allows."),
|
|
432
|
+
}),
|
|
433
|
+
)
|
|
434
|
+
.optional()
|
|
435
|
+
.describe(
|
|
436
|
+
"Repositories whose copy the conversation left standing on a different branch of its own. What is listed for them is this conversation's branch as it was last left, not what its copy holds now, and anything it has written since went to the other branch.",
|
|
437
|
+
),
|
|
438
|
+
// Read off the live copy, so a retired one has none: its scratch went with it.
|
|
439
|
+
scratch: z
|
|
440
|
+
.array(
|
|
441
|
+
z.object({
|
|
442
|
+
repo: z.string().describe("Which repository."),
|
|
443
|
+
paths: z.array(ScratchPathSchema).describe("What it keeps out there."),
|
|
444
|
+
}),
|
|
445
|
+
)
|
|
446
|
+
.optional()
|
|
447
|
+
.describe(
|
|
448
|
+
"Untracked files the conversation left in its copy that look like scratch: logs, probe scripts, dumps, a checkout of its own. They are not in the list above and no merge carries them. They stay in its copy until they are included or deleted, and go with the copy when it is archived or retired. Absent when there are none.",
|
|
449
|
+
),
|
|
397
450
|
});
|
|
398
451
|
export type AgentChanges = z.infer<typeof AgentChangesSchema>;
|
|
399
452
|
|
|
453
|
+
// Names scratch exactly as `AgentChanges.scratch` lists it; anything else is refused, so a stale list cannot reach a
|
|
454
|
+
// file that was never scratch.
|
|
455
|
+
export const AgentScratchSchema = z.object({
|
|
456
|
+
id: z.string().min(1).describe("Which conversation."),
|
|
457
|
+
repo: z.string().min(1).describe("Which repository of its composition."),
|
|
458
|
+
paths: z
|
|
459
|
+
.array(z.string().min(1))
|
|
460
|
+
.min(1)
|
|
461
|
+
.max(MAX_ACTION_PATHS)
|
|
462
|
+
.describe("Paths exactly as the review lists them under scratch, a directory with its trailing slash."),
|
|
463
|
+
});
|
|
464
|
+
export type AgentScratch = z.infer<typeof AgentScratchSchema>;
|
|
465
|
+
|
|
400
466
|
// Own read (a `git log` per repo), not folded into the review, whose rows are differences against main and these are
|
|
401
467
|
// not. A commit CARRIES the work without authoring it: a path is attributed to the newest commit that left it there.
|
|
402
468
|
export const AgentHistoryCommitSchema = z.object({
|
package/src/schemas/hosts.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type WslEnvironment = z.infer<typeof WslEnvironmentSchema>;
|
|
|
11
11
|
|
|
12
12
|
// What a machine reports once at connect (`host.describe`), cached until it reconnects: the skill pack says how to
|
|
13
13
|
// drive Windows, this says which Windows it is.
|
|
14
|
-
export const
|
|
14
|
+
export const DeviceFactsSchema = z.object({
|
|
15
15
|
// The OS's own name for itself, e.g. "Windows 11 Pro 24H2".
|
|
16
16
|
os: z.string(),
|
|
17
17
|
arch: z.string(),
|
|
@@ -31,8 +31,15 @@ export const HostFactsSchema = z.object({
|
|
|
31
31
|
wsl: WslEnvironmentSchema.optional(),
|
|
32
32
|
// Windows only: the distros `wsl -l -q` lists, the names `run_command`'s `in: "wsl:<name>"` accepts.
|
|
33
33
|
wslDistros: z.array(z.string()).optional(),
|
|
34
|
+
// What this machine's agent is holding links to, and how much of it is answering nothing. COUNTS AND AN AGE ONLY:
|
|
35
|
+
// the rest are other sandboxes' addresses, and a sandbox has no business learning its siblings'. Absent from an
|
|
36
|
+
// agent older than this field, which is why "none unreachable" is not the same value as "did not say".
|
|
37
|
+
links: z.object({ total: z.number(), unreachable: z.number(), unreachableSince: z.number().optional() }).optional(),
|
|
34
38
|
});
|
|
35
|
-
export type
|
|
39
|
+
export type DeviceFacts = z.infer<typeof DeviceFactsSchema>;
|
|
40
|
+
|
|
41
|
+
// Docker Desktop's own distros: `wsl -l -q` lists them like any other, and none ever runs an agent or holds a checkout.
|
|
42
|
+
export const WSL_SYSTEM_DISTROS: ReadonlySet<string> = new Set(["docker-desktop", "docker-desktop-data"]);
|
|
36
43
|
|
|
37
44
|
// One folder, two names. Windows sees a distro's files under a UNC share and a distro sees the Windows drives under
|
|
38
45
|
// /mnt, so a path handed across the boundary is translated here rather than by hand at every call site.
|
|
@@ -54,13 +61,13 @@ const ENVIRONMENT_SEPARATOR = "::";
|
|
|
54
61
|
// Which environment a machine is describing when it connects: the distro by the name WSL registered (what `wsl -l -q`
|
|
55
62
|
// prints and `in: "wsl:<name>"` takes), or the metal. Facts arrive at connect and no scope withholds them, so this is
|
|
56
63
|
// always answerable — unlike `environmentOf` (devices.ts), which weighs a report too and may hold no evidence at all.
|
|
57
|
-
export const environmentKeyOf = (facts: Pick<
|
|
64
|
+
export const environmentKeyOf = (facts: Pick<DeviceFacts, "wsl">): string =>
|
|
58
65
|
facts.wsl === undefined ? HOST_NATIVE_ENVIRONMENT : `wsl:${facts.wsl.distro}`;
|
|
59
66
|
|
|
60
|
-
export const hostConnectionKey = (
|
|
61
|
-
environment === HOST_NATIVE_ENVIRONMENT ?
|
|
67
|
+
export const hostConnectionKey = (entry: string, environment: string): string =>
|
|
68
|
+
environment === HOST_NATIVE_ENVIRONMENT ? entry : `${entry}${ENVIRONMENT_SEPARATOR}${environment}`;
|
|
62
69
|
|
|
63
|
-
export const
|
|
70
|
+
export const hostEntryOf = (connection: string): string => connection.split(ENVIRONMENT_SEPARATOR)[0] ?? connection;
|
|
64
71
|
|
|
65
72
|
export const hostEnvironmentOf = (connection: string): string => {
|
|
66
73
|
const at = connection.indexOf(ENVIRONMENT_SEPARATOR);
|
|
@@ -75,7 +82,7 @@ export const HostEnvironmentSchema = z.object({
|
|
|
75
82
|
online: z.boolean(),
|
|
76
83
|
version: z.string().optional(),
|
|
77
84
|
lastSeen: z.number().optional(),
|
|
78
|
-
facts:
|
|
85
|
+
facts: DeviceFactsSchema.optional(),
|
|
79
86
|
});
|
|
80
87
|
export type HostEnvironment = z.infer<typeof HostEnvironmentSchema>;
|
|
81
88
|
|
|
@@ -92,7 +99,7 @@ export const HostSummarySchema = z.object({
|
|
|
92
99
|
version: z.string().optional(),
|
|
93
100
|
// Epoch ms of the last held socket; absent means not since this daemon booted (liveness resets on restart).
|
|
94
101
|
lastSeen: z.number().optional(),
|
|
95
|
-
facts:
|
|
102
|
+
facts: DeviceFactsSchema.optional(),
|
|
96
103
|
});
|
|
97
104
|
export type HostSummary = z.infer<typeof HostSummarySchema>;
|
|
98
105
|
export const HostsListSchema = z.object({ hosts: z.array(HostSummarySchema) });
|
package/src/schemas/issues.ts
CHANGED
|
@@ -193,7 +193,7 @@ export const IssueIntakeIdParamSchema = z.object({ automationId: entryId.describ
|
|
|
193
193
|
|
|
194
194
|
// Constants both the editor and the route need, so a limit is visible to the owner before it is hit.
|
|
195
195
|
|
|
196
|
-
// Default daily ceiling; higher than the
|
|
196
|
+
// Default daily ceiling; higher than the Visitor chat's 200 since a report is only sometimes a turn (dedup decides),
|
|
197
197
|
// unlike a visitor message.
|
|
198
198
|
export const ISSUES_DAILY_MAX_DEFAULT = 2000;
|
|
199
199
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// What the sandbox is using right now, measured only when asked (GET /system/metrics). CPU percentages are of ONE core
|
|
4
|
+
// unless the field says otherwise; memory is resident bytes.
|
|
5
|
+
|
|
6
|
+
// The kinds of process a sandbox runs, as the daemon classifies them by command line.
|
|
7
|
+
export const PROCESS_ROLES = [
|
|
8
|
+
"languageServer",
|
|
9
|
+
"searchEngine",
|
|
10
|
+
"agentRuntime",
|
|
11
|
+
"browser",
|
|
12
|
+
"git",
|
|
13
|
+
"translator",
|
|
14
|
+
"extension",
|
|
15
|
+
"terminal",
|
|
16
|
+
// A build, test, typecheck or lint run and the package manager driving it: the fan-out shape, which is what every
|
|
17
|
+
// memory peak the resource log has recorded was made of.
|
|
18
|
+
"toolchain",
|
|
19
|
+
// An inference server this sandbox runs for itself.
|
|
20
|
+
"localModel",
|
|
21
|
+
// A process of a nested Docker container: charged to this cgroup, visible to nothing else here.
|
|
22
|
+
"container",
|
|
23
|
+
"other",
|
|
24
|
+
] as const;
|
|
25
|
+
export const ProcessRoleSchema = z.enum(PROCESS_ROLES);
|
|
26
|
+
export type ProcessRole = z.infer<typeof ProcessRoleSchema>;
|
|
27
|
+
|
|
28
|
+
export const ProcessGroupMetricsSchema = z.object({
|
|
29
|
+
processes: z.number().describe("How many processes."),
|
|
30
|
+
rssBytes: z
|
|
31
|
+
.number()
|
|
32
|
+
.describe(
|
|
33
|
+
"Their resident memory added up, in bytes. Memory two processes share is counted in each, so this can exceed what they cost together.",
|
|
34
|
+
),
|
|
35
|
+
});
|
|
36
|
+
export type ProcessGroupMetrics = z.infer<typeof ProcessGroupMetricsSchema>;
|
|
37
|
+
|
|
38
|
+
export const SessionMetricsSchema = ProcessGroupMetricsSchema.extend({
|
|
39
|
+
cpuPercent: z
|
|
40
|
+
.number()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe(
|
|
43
|
+
"CPU its processes used over the window, as a percentage of one core, so a conversation busy on four cores reads 400. Counts commands that finished inside the window too. Absent on a first reading, which has nothing earlier to measure from.",
|
|
44
|
+
),
|
|
45
|
+
});
|
|
46
|
+
export type SessionMetrics = z.infer<typeof SessionMetricsSchema>;
|
|
47
|
+
|
|
48
|
+
// Linux pressure stall information: the share of the last ten seconds in which some task waited on the resource.
|
|
49
|
+
export const PressureMetricsSchema = z.object({
|
|
50
|
+
cpu: z.number().describe("Percent of the last ten seconds in which something was waiting for a CPU."),
|
|
51
|
+
memory: z.number().describe("Percent of the last ten seconds in which something was waiting on memory: reclaim, swap-in, or a refault."),
|
|
52
|
+
io: z.number().describe("Percent of the last ten seconds in which something was waiting on disk."),
|
|
53
|
+
});
|
|
54
|
+
export type PressureMetrics = z.infer<typeof PressureMetricsSchema>;
|
|
55
|
+
|
|
56
|
+
export const SandboxUsageSchema = z.object({
|
|
57
|
+
cpuPercent: z
|
|
58
|
+
.number()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("CPU the whole sandbox used over the window, as a percentage of all it may use (`cores`). Absent on a first reading."),
|
|
61
|
+
cores: z.number().describe("How many cores the sandbox may use: its CPU quota, or every core it is allowed to run on when it has none."),
|
|
62
|
+
memoryBytes: z
|
|
63
|
+
.number()
|
|
64
|
+
.describe("Memory in use, less the file cache the kernel takes back on demand: the figure that runs into the limit."),
|
|
65
|
+
memoryLimitBytes: z.number().describe("The memory limit: the container's own, or the machine's memory when the container has none."),
|
|
66
|
+
swapBytes: z.number().optional().describe("Memory pushed out to swap. Absent where the sandbox cannot see its own swap."),
|
|
67
|
+
diskBytes: z.number().optional().describe("Space used on the volume the workspace lives on. Absent when the volume would not say."),
|
|
68
|
+
diskTotalBytes: z.number().optional().describe("That volume's size. Absent when the volume would not say."),
|
|
69
|
+
loadAverage: z
|
|
70
|
+
.tuple([z.number(), z.number(), z.number()])
|
|
71
|
+
.describe("The load average over 1, 5 and 15 minutes. It is the machine's, so other sandboxes on it count too."),
|
|
72
|
+
processes: z.number().describe("How many processes are running in the sandbox."),
|
|
73
|
+
pressure: PressureMetricsSchema.optional().describe("How much work waited on CPU, memory or disk lately. Absent where the kernel does not report it."),
|
|
74
|
+
});
|
|
75
|
+
export type SandboxUsage = z.infer<typeof SandboxUsageSchema>;
|
|
76
|
+
|
|
77
|
+
export const DaemonUsageSchema = z.object({
|
|
78
|
+
rssBytes: z.number().describe("The daemon's own resident memory."),
|
|
79
|
+
heapUsedBytes: z.number().describe("Of that, JavaScript objects in use."),
|
|
80
|
+
cpuPercent: z.number().optional().describe("CPU the daemon itself used over the window, as a percentage of one core. Absent on a first reading."),
|
|
81
|
+
eventLoopPercent: z
|
|
82
|
+
.number()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe(
|
|
85
|
+
"How much of the window the daemon spent busy rather than waiting. Near 100, every request queues behind whatever it is doing. Absent on a first reading.",
|
|
86
|
+
),
|
|
87
|
+
});
|
|
88
|
+
export type DaemonUsage = z.infer<typeof DaemonUsageSchema>;
|
|
89
|
+
|
|
90
|
+
export const SandboxMetricsSchema = z.object({
|
|
91
|
+
at: z.number().describe("When this reading was taken, in milliseconds."),
|
|
92
|
+
windowMs: z
|
|
93
|
+
.number()
|
|
94
|
+
.optional()
|
|
95
|
+
.describe("How long the CPU figures were measured over, in milliseconds. Absent on a first reading, and then so is every CPU figure."),
|
|
96
|
+
sandbox: SandboxUsageSchema.describe("The sandbox as a whole."),
|
|
97
|
+
daemon: DaemonUsageSchema.describe("The daemon that runs it, which none of the other figures include."),
|
|
98
|
+
sessions: z
|
|
99
|
+
.record(z.string(), SessionMetricsSchema)
|
|
100
|
+
.describe(
|
|
101
|
+
"What each conversation's processes use, by conversation id: the agent's own process and everything it started. Only conversations with processes running, and only those the caller may see.",
|
|
102
|
+
),
|
|
103
|
+
roles: z
|
|
104
|
+
.partialRecord(ProcessRoleSchema, ProcessGroupMetricsSchema)
|
|
105
|
+
.describe("Every process in the sandbox but the daemon, by what kind of work it is. A kind with nothing running is absent."),
|
|
106
|
+
});
|
|
107
|
+
export type SandboxMetrics = z.infer<typeof SandboxMetricsSchema>;
|
package/src/schemas/panels.ts
CHANGED
|
@@ -70,14 +70,14 @@ export const PanelSummarySchema = z.object({
|
|
|
70
70
|
// desiredState: desired-state.json (present after the first resolve).
|
|
71
71
|
// directoryUi: .intentic/ui/index.html.
|
|
72
72
|
// monorepo: pnpm-workspace.yaml + turbo.json.
|
|
73
|
-
//
|
|
73
|
+
// tests: a root `test` script or runner config (vitest.config.ts, bunfig.toml), or "vitest" in the workspace catalog.
|
|
74
74
|
// userStories: docs/user-stories.
|
|
75
75
|
// docs: docs/architecture.
|
|
76
76
|
deployConfig: z.boolean().describe("It declares infrastructure."),
|
|
77
77
|
desiredState: z.boolean().describe("That declaration has been resolved at least once."),
|
|
78
78
|
directoryUi: z.boolean().describe("It carries a small interface of its own."),
|
|
79
79
|
monorepo: z.boolean().describe("It holds several packages."),
|
|
80
|
-
|
|
80
|
+
tests: z.boolean().describe("It has tests that can be run."),
|
|
81
81
|
userStories: z
|
|
82
82
|
.boolean()
|
|
83
83
|
.describe("It carries stories an agent could test the running app against. The one fact here that says nothing about the language."),
|
package/src/schemas/personas.ts
CHANGED
|
@@ -65,7 +65,7 @@ export const PersonaContextSchema = z.object({
|
|
|
65
65
|
.array(z.string().min(1).max(200))
|
|
66
66
|
.max(50)
|
|
67
67
|
.describe(
|
|
68
|
-
"Which nested repositories a conversation
|
|
68
|
+
"Which nested repositories a conversation on this persona carries, by workspace-relative path. The workspace itself is always carried; empty means the workspace alone.",
|
|
69
69
|
),
|
|
70
70
|
});
|
|
71
71
|
export type PersonaContext = z.infer<typeof PersonaContextSchema>;
|
|
@@ -177,7 +177,7 @@ export const PersonaBriefingSchema = z.object({
|
|
|
177
177
|
.array(TurnBriefingNoteIdSchema)
|
|
178
178
|
.max(20)
|
|
179
179
|
.describe(
|
|
180
|
-
"Which of the notes the sandbox prepends to each message a conversation
|
|
180
|
+
"Which of the notes the sandbox prepends to each message a conversation on this persona does NOT get. Everything not named here is sent as usual; the notes that keep a turn inside its own branch or explain a missing account cannot be named at all.",
|
|
181
181
|
),
|
|
182
182
|
});
|
|
183
183
|
export type PersonaBriefing = z.infer<typeof PersonaBriefingSchema>;
|
|
@@ -229,33 +229,10 @@ export type Persona = z.infer<typeof PersonaSchema>;
|
|
|
229
229
|
// has no opinion — the caller decides, not "run nothing".
|
|
230
230
|
export const personaModels = (card: Pick<Persona, "models">, sources: readonly ModelSource[]): readonly ModelPin[] =>
|
|
231
231
|
readyChain(sources, card.models ?? []);
|
|
232
|
-
//
|
|
233
|
-
// `folder`/`paths` are the facts a card's `context`/`startIn` can be matched against that words alone can't supply.
|
|
234
|
-
export const PersonaRouteAskSchema = z.object({
|
|
235
|
-
prompt: z.string().min(1).max(20000).describe("The message a new chat is about to open with."),
|
|
236
|
-
folder: z.string().max(200).optional().describe("The workspace folder the chat was opened in, when it was opened in one."),
|
|
237
|
-
paths: z
|
|
238
|
-
.array(z.string().min(1).max(500))
|
|
239
|
-
.max(50)
|
|
240
|
-
.default([])
|
|
241
|
-
.describe("Workspace paths the message names: uploads, @-mentions, the editor's own file."),
|
|
242
|
-
});
|
|
243
|
-
export type PersonaRouteAsk = z.infer<typeof PersonaRouteAskSchema>;
|
|
244
|
-
export const PersonaRouteSchema = z.object({
|
|
245
|
-
persona: entryId.optional().describe("The card this message belongs to, or absent when none does and the chat should stay open to everything."),
|
|
246
|
-
reason: z.string().describe("Why, in the one line a chat can show. Present whether or not a card was named."),
|
|
247
|
-
// Absent means nothing was spent: matched on the folder, or answered before any model was reached.
|
|
248
|
-
model: z
|
|
249
|
-
.string()
|
|
250
|
-
.optional()
|
|
251
|
-
.describe(
|
|
252
|
-
"Which model answered, as `provider:model`, so the chat can name what the reading cost. Absent when no model was asked at all, which a folder match and an empty persona list both are.",
|
|
253
|
-
),
|
|
254
|
-
});
|
|
255
|
-
export type PersonaRoute = z.infer<typeof PersonaRouteSchema>;
|
|
232
|
+
// Which persona a new chat belongs to is asked with what it runs on, in one reading: chat-route.ts.
|
|
256
233
|
// The one stock persona id; lives here because the daemon and the automations form are separate packages that must
|
|
257
|
-
// agree on it exactly, or a
|
|
258
|
-
export const
|
|
234
|
+
// agree on it exactly, or a Visitor chat pins to a card nobody creates.
|
|
235
|
+
export const VISITOR_CHAT_PERSONA = "visitor-chat";
|
|
259
236
|
// One phrase describing how bounded a card is, shared so the Personas page and the automation picker can't grow
|
|
260
237
|
// different vocabularies for the same card. "Read-only"/"no shell" are named; everything else collapses to a count.
|
|
261
238
|
export const personaBounds = (persona: Persona): string => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { TRANSLATOR_PROVIDERS, type TranslatorProvider } from "../../models/provider-specs.js";
|
|
3
3
|
import { AgentHarnessSchema, AgentProviderSchema, EditorContextSchema } from "../agent.js";
|
|
4
|
+
import { MENTION_LIMIT } from "../../text/mentions.js";
|
|
4
5
|
// Headroom is one shape shared by every provider, not a Claude idea others imitate: a native account and a routed
|
|
5
6
|
// subscription differ in who holds the credential, never in what a reading is. Every surface that draws a percentage
|
|
6
7
|
// reads this one type.
|
|
@@ -218,6 +219,14 @@ export const SteerSchema = z
|
|
|
218
219
|
.max(20)
|
|
219
220
|
.optional()
|
|
220
221
|
.describe("Files to send with it, as workspace paths. A screenshot dropped in mid-turn with no words is a legitimate thing to send."),
|
|
222
|
+
// Same split as a turn's: a guessed path is dropped, only a chosen attachment can refuse the steer.
|
|
223
|
+
mentions: z
|
|
224
|
+
.array(z.string().min(1))
|
|
225
|
+
.max(MENTION_LIMIT)
|
|
226
|
+
.optional()
|
|
227
|
+
.describe(
|
|
228
|
+
"Workspace paths the message mentions with `@`. Unlike attachments, one that escapes the workspace or names no file is ignored rather than refused.",
|
|
229
|
+
),
|
|
221
230
|
editorContext: EditorContextSchema.optional().describe("What you have open, folded in so that pointing words resolve."),
|
|
222
231
|
})
|
|
223
232
|
// An attachment-only steer (a screenshot dropped in mid-turn) is legal; an entirely empty one is not.
|
package/src/schemas/secrets.ts
CHANGED
|
@@ -62,7 +62,7 @@ export const CredentialGatesSchema = z.object({
|
|
|
62
62
|
});
|
|
63
63
|
export type CredentialGates = z.infer<typeof CredentialGatesSchema>;
|
|
64
64
|
|
|
65
|
-
export const
|
|
65
|
+
export const CredentialGuardSubjectParamSchema = z.object({
|
|
66
66
|
subject: z.string().min(1).describe("Which gate, by the secret name or capability id it covers."),
|
|
67
67
|
});
|
|
68
68
|
|