@intentic/sandbox-contract 1.360.0 → 1.362.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/dist/contracts/agent.contract.d.ts +9 -0
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.d.ts +21 -0
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.d.ts +2 -0
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/needs.contract.d.ts +7 -0
- package/dist/contracts/needs.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.d.ts +3 -0
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +1 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +33 -30
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/events/agent-events.d.ts +4 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-transcript.d.ts +1 -0
- package/dist/events/agent-transcript.d.ts.map +1 -1
- package/dist/events/land-conflict.d.ts +11 -0
- package/dist/events/land-conflict.d.ts.map +1 -1
- package/dist/events/land-conflict.js +64 -0
- package/dist/events/land-conflict.js.map +1 -1
- package/dist/events/system-events.d.ts +2 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/transcript.d.ts +5 -0
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/models/agent-catalog.d.ts.map +1 -1
- package/dist/models/agent-catalog.js +1 -0
- package/dist/models/agent-catalog.js.map +1 -1
- package/dist/models/agent-lanes.d.ts +8 -3
- package/dist/models/agent-lanes.d.ts.map +1 -1
- package/dist/models/agent-lanes.js +16 -3
- package/dist/models/agent-lanes.js.map +1 -1
- package/dist/models/agent-runtimes.d.ts +7 -1
- package/dist/models/agent-runtimes.d.ts.map +1 -1
- package/dist/models/agent-runtimes.js +17 -8
- package/dist/models/agent-runtimes.js.map +1 -1
- package/dist/models/agent-stack.d.ts +12 -0
- package/dist/models/agent-stack.d.ts.map +1 -0
- package/dist/models/agent-stack.js +19 -0
- package/dist/models/agent-stack.js.map +1 -0
- package/dist/models/module-of.d.ts +3 -0
- package/dist/models/module-of.d.ts.map +1 -0
- package/dist/models/module-of.js +13 -0
- package/dist/models/module-of.js.map +1 -0
- package/dist/models/provider-specs.d.ts +2 -0
- package/dist/models/provider-specs.d.ts.map +1 -1
- package/dist/models/provider-specs.js +2 -0
- package/dist/models/provider-specs.js.map +1 -1
- package/dist/policy/persona-capability.d.ts.map +1 -1
- package/dist/policy/persona-capability.js +2 -1
- package/dist/policy/persona-capability.js.map +1 -1
- package/dist/schemas/agents-list.d.ts +2 -0
- package/dist/schemas/agents-list.d.ts.map +1 -1
- package/dist/schemas/agents.d.ts +3 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +5 -1
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/automation-events.d.ts +40 -0
- package/dist/schemas/automation-events.d.ts.map +1 -0
- package/dist/schemas/automation-events.js +20 -0
- package/dist/schemas/automation-events.js.map +1 -0
- package/dist/schemas/automations.d.ts +4 -38
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/automations.js +8 -18
- package/dist/schemas/automations.js.map +1 -1
- package/dist/schemas/device-commands.d.ts.map +1 -1
- package/dist/schemas/device-commands.js.map +1 -1
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/needs.d.ts +8 -0
- package/dist/schemas/needs.d.ts.map +1 -1
- package/dist/schemas/organisation.d.ts.map +1 -1
- package/dist/schemas/organisation.js.map +1 -1
- package/dist/schemas/personas.d.ts +13 -0
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/personas.js +9 -0
- package/dist/schemas/personas.js.map +1 -1
- package/dist/schemas/providers/plan-limits.js +2 -2
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/repo-checks.d.ts +84 -0
- package/dist/schemas/repo-checks.d.ts.map +1 -0
- package/dist/schemas/repo-checks.js +50 -0
- package/dist/schemas/repo-checks.js.map +1 -0
- package/dist/schemas/run-targets.d.ts.map +1 -1
- package/dist/schemas/run-targets.js.map +1 -1
- package/dist/schemas/settings.d.ts +2 -82
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +7 -49
- package/dist/schemas/settings.js.map +1 -1
- package/dist/state/daemon-floor.d.ts.map +1 -1
- package/dist/state/daemon-floor.js.map +1 -1
- package/dist/text/preview-guide.d.ts.map +1 -1
- package/dist/text/preview-guide.js.map +1 -1
- package/package.json +13 -13
- package/src/events/land-conflict.test.ts +23 -0
- package/src/events/land-conflict.ts +104 -3
- package/src/models/agent-catalog.test.ts +10 -7
- package/src/models/agent-catalog.ts +1 -0
- package/src/models/agent-lanes.ts +37 -12
- package/src/models/agent-runtimes.ts +50 -14
- package/src/models/agent-stack.test.ts +86 -0
- package/src/models/agent-stack.ts +48 -0
- package/src/models/capability-ledger.test.ts +4 -1
- package/src/models/module-of.ts +20 -0
- package/src/models/provider-specs.test.ts +6 -2
- package/src/models/provider-specs.ts +7 -0
- package/src/policy/persona-capability.ts +10 -3
- package/src/schemas/agents.ts +8 -1
- package/src/schemas/automation-events.ts +35 -0
- package/src/schemas/automations.ts +12 -33
- package/src/schemas/device-commands.ts +5 -17
- package/src/schemas/hosts.ts +4 -27
- package/src/schemas/organisation.ts +4 -16
- package/src/schemas/personas.ts +27 -0
- package/src/schemas/providers/plan-limits.ts +3 -3
- package/src/schemas/repo-checks.ts +81 -0
- package/src/schemas/run-targets.ts +3 -19
- package/src/schemas/settings.ts +9 -88
- package/src/state/daemon-floor.ts +4 -15
- package/src/text/preview-guide.ts +4 -16
|
@@ -4,6 +4,8 @@ import { AgentOriginSchema, ModelPinSchema } from "./agent.js";
|
|
|
4
4
|
import { entryId } from "./internal.js";
|
|
5
5
|
import { IssuesConfigSchema } from "./issues.js";
|
|
6
6
|
import { ZoneSchema } from "../time/zone.js";
|
|
7
|
+
import { WorkspaceEventKindSchema } from "./automation-events.js";
|
|
8
|
+
export { WorkspaceEventKindSchema, WorkspaceEventSchema, type WorkspaceEventKind, type WorkspaceEvent } from "./automation-events.js";
|
|
7
9
|
// An automation wakes the agent: the daemon fires each enabled one on its trigger, runs the optional guard command
|
|
8
10
|
// (non-zero exit skips the wake), then runs one turn with the prompt. The manifest is user config; run history is
|
|
9
11
|
// daemon-recorded.
|
|
@@ -23,39 +25,6 @@ import { ZoneSchema } from "../time/zone.js";
|
|
|
23
25
|
// pushes one branch per agent
|
|
24
26
|
// workspace: fires from the sandbox's own codebase (WorkspaceEventKindSchema)
|
|
25
27
|
|
|
26
|
-
// What the daemon emits as the fleet works, for a code chore to react to; no token or route, since only the daemon
|
|
27
|
-
// reads these.
|
|
28
|
-
// turn.settled: fires once per isolated turn regardless of outcome, while the diff is still on screen
|
|
29
|
-
// agent.landed: fires only once work reaches the main tree, including a later manual Land
|
|
30
|
-
// deps.broken/deps.fixed: retired with the check that ran after every land (2026-09-27). Nothing emits them any more;
|
|
31
|
-
// they stay so an automation written for them still reads, and it never fires. Main's failing CI is the `ci` listener's.
|
|
32
|
-
export const WorkspaceEventKindSchema = z.enum(["turn.settled", "agent.landed", "deps.broken", "deps.fixed"]);
|
|
33
|
-
export type WorkspaceEventKind = z.infer<typeof WorkspaceEventKindSchema>;
|
|
34
|
-
// Payload of a workspace-triggered wake, delivered as JSON in $AUTOMATION_PAYLOAD and appended to the prompt.
|
|
35
|
-
// `repos[].from` is each repo's state before the turn; the span runs to the working tree, not a commit, so an errored
|
|
36
|
-
// turn's uncommitted work still shows.
|
|
37
|
-
export const WorkspaceEventSchema = z.object({
|
|
38
|
-
event: WorkspaceEventKindSchema,
|
|
39
|
-
agentId: z.string(),
|
|
40
|
-
title: z.string().optional(),
|
|
41
|
-
branch: z.string(),
|
|
42
|
-
// `ready` is a clean turn held on the branch (auto-land off): the moment right before a deliberate Land, when a
|
|
43
|
-
// pre-land review wants to run.
|
|
44
|
-
outcome: z.enum(["landed", "conflict", "ready", "idle", "error"]),
|
|
45
|
-
repos: z.array(z.object({ repo: z.string(), from: z.string(), dir: z.string() })),
|
|
46
|
-
// Present only for `deps.*` events: which project broke, the command and exit code, a bounded log tail, and
|
|
47
|
-
// `attempt` counting consecutive failures since the last pass.
|
|
48
|
-
deps: z
|
|
49
|
-
.object({
|
|
50
|
-
project: z.string(),
|
|
51
|
-
command: z.string(),
|
|
52
|
-
exitCode: z.number(),
|
|
53
|
-
attempt: z.number(),
|
|
54
|
-
logTail: z.string(),
|
|
55
|
-
})
|
|
56
|
-
.optional(),
|
|
57
|
-
});
|
|
58
|
-
export type WorkspaceEvent = z.infer<typeof WorkspaceEventSchema>;
|
|
59
28
|
export const TriggerSchema = z.discriminatedUnion("kind", [
|
|
60
29
|
z.object({
|
|
61
30
|
kind: z.literal("schedule").describe("On a clock."),
|
|
@@ -446,6 +415,16 @@ export const AutomationSchema = z.object({
|
|
|
446
415
|
.boolean()
|
|
447
416
|
.optional()
|
|
448
417
|
.describe("This automation is a maintenance job, which is what files it under chores rather than among ordinary automations."),
|
|
418
|
+
// Pure filing, like `chore`: the daemon never reads it. Absent, the panel files it by its persona instead, so a set
|
|
419
|
+
// of jobs one role runs reads as one shelf without anybody naming it.
|
|
420
|
+
group: z
|
|
421
|
+
.string()
|
|
422
|
+
.min(1)
|
|
423
|
+
.max(40)
|
|
424
|
+
.optional()
|
|
425
|
+
.describe(
|
|
426
|
+
"Which shelf of the Automations panel it is filed on, like 'Marketing' or 'Releases'. Automations naming the same group are listed together. Absent files it under its persona, or with the code chores.",
|
|
427
|
+
),
|
|
449
428
|
enabled: z.boolean().describe("Whether it fires at all."),
|
|
450
429
|
});
|
|
451
430
|
export type Automation = z.infer<typeof AutomationSchema>;
|
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
// Closed
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// `dev-restart`, `dev-rebuild` and `sync-install` are the three whose argv the daemon fills from what only it knows — the
|
|
8
|
-
// dev checkout on that machine, a freshly minted pairing token — which is also why none takes a path or a token from the
|
|
9
|
-
// caller. The two dev commands are also why a machine-side op is the wrong shape for them: this door carries a COMMAND
|
|
10
|
-
// STRING to a tool every released agent already has, so a sandbox can drive a machine whose agent predates the feature.
|
|
11
|
-
// `dev-rebuild-log` is the read side of `dev-rebuild`: the build is detached out there, so its log is the only place its
|
|
12
|
-
// progress exists, and polling this is what turns a fired-and-forgotten command into something with a progress bar.
|
|
13
|
-
// `sync-clean` removes the build output left in directories the sandbox has deleted, which is what stops those
|
|
14
|
-
// deletions from ever landing. It deletes only content the session already ignores, so it is the one command here whose
|
|
15
|
-
// worst outcome is a rebuild — which is why it is a button and not a turn.
|
|
16
|
-
// `mirror-ignore`/`mirror-unignore` are `mirror-off`'s per-port form, and the reason they exist: a port number that is
|
|
17
|
-
// permanently taken on one machine's localhost has no answer in an all-or-nothing switch, so the choice lives where the
|
|
18
|
-
// conflict does — one port, one device, durable — instead of muting every port the pairing serves.
|
|
3
|
+
// Closed names let the daemon build argv without granting arbitrary shell access; dev/sync commands never accept caller paths or tokens.
|
|
4
|
+
// Use existing run_command for older-agent compatibility; poll dev-rebuild-log because rebuilds are detached.
|
|
5
|
+
// sync-unpair terminates sessions/revokes enrollment; sync-clean removes ignored build residue only.
|
|
6
|
+
// mirror-ignore/unignore persists per-device port choices without muting all mirrored ports.
|
|
19
7
|
export const DeviceCommandSchema = z.enum([
|
|
20
8
|
"mirror-off",
|
|
21
9
|
"mirror-on",
|
|
@@ -55,7 +43,7 @@ export const DeviceLocalDirSchema = z
|
|
|
55
43
|
.string()
|
|
56
44
|
.min(1)
|
|
57
45
|
.max(4096)
|
|
58
|
-
// The curly quotes as escapes: bun's transpiler rewrites a literal one in a regex to its escape and
|
|
46
|
+
// The curly quotes as escapes: bun's transpiler rewrites a literal one in a regex to its escape and tsc keeps it,
|
|
59
47
|
// so spelled literally the pattern reads differently from source and from dist, and contract.lock.json can match
|
|
60
48
|
// only one of them.
|
|
61
49
|
.regex(/^(?:~|\/|[A-Za-z]:[\\/])[^"'`$;|&\n\r\u201C\u201D\u201E\u2018\u2019\u201A\u201B]*$/);
|
package/src/schemas/hosts.ts
CHANGED
|
@@ -107,33 +107,10 @@ export const DeviceFactsSchema = z.object({
|
|
|
107
107
|
});
|
|
108
108
|
export type DeviceFacts = z.infer<typeof DeviceFactsSchema>;
|
|
109
109
|
|
|
110
|
-
//
|
|
111
|
-
// -
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
// which check it. REMOVE IN v1.314.0, with the old `reshape` op it gates.
|
|
115
|
-
// - `set-shape`: the `set-shape`/`forget-shape` ops, and `start`/`restart` applying a saved shape, all through an `ic`
|
|
116
|
-
// whose `ic sandbox shape` takes the contract's own shape (`--set`); advertised only when the agent's `ic` does.
|
|
117
|
-
// Both features ride that verb, so an agent advertises both or neither.
|
|
118
|
-
// - `rollback-to`: the `rollback` op's `to`, going back to an older version kept on the machine rather than the
|
|
119
|
-
// previous one; advertised only when the agent's `ic sandbox rollback` takes `--to`.
|
|
120
|
-
// - `loopback-catch`: the `catchLoopback` procedure, a sign-in's loopback redirect caught on this machine
|
|
121
|
-
// (loopback-catch.ts); an agent without it rejects the call as an unknown procedure.
|
|
122
|
-
// - `background-prepare`: the `prepare-background` op, the next update downloaded under the unattended rules of the
|
|
123
|
-
// agent's own timer (`ic sandbox prepare --auto`), which the update card sends when it opens; advertised only when
|
|
124
|
-
// the agent's `ic sandbox prepare` takes `--auto`.
|
|
125
|
-
// - `programs`: the `stageArtifact` procedure and the app_* tools, a program this sandbox built pushed to the machine and
|
|
126
|
-
// run under the agent's supervision (device-artifacts.ts); an agent without it is told to update rather than sent one.
|
|
127
|
-
// - `project-delivery`: the `deliverProject` procedure, landed work written into a folder attached to this computer's
|
|
128
|
-
// sandbox (project-delivery.ts); an agent without it is never sent one, and the land waits for Bring back.
|
|
129
|
-
// - `keyring`: the keyring* procedures, intentic-keyring on this computer reached through the machine (keyring.ts);
|
|
130
|
-
// advertised only while a keyring is installed, so a sandbox never offers a computer without one as a place to keep or
|
|
131
|
-
// type a secret.
|
|
132
|
-
// - `sleep`: the `sleep` op, a sandbox put to sleep now (`ic sandbox sleep <slug>`): stopped, and started again by
|
|
133
|
-
// itself when somebody opens it; advertised only when the agent's `ic` has `sandbox sleep`.
|
|
134
|
-
// - `reachable-ways-back`: not an op but what a listing means: a sandbox's `rollbackTargets` are only the ways back a
|
|
135
|
-
// rollback can reach (ic 2026-10-19 on). Said by ic itself (`ic features`, golden/ic-features.json); without it the
|
|
136
|
-
// rows are an older ic's, which also listed pruned dev builds no download can bring back (state/ways-back.ts).
|
|
110
|
+
// Optional device capabilities gate calls to older agents: never send an operation unless its advertised feature permits it.
|
|
111
|
+
// set-shape, rollback-to, background-prepare and sleep depend on ic support; keyring also requires a local installation.
|
|
112
|
+
// reshape-later protects legacy deferred reshapes from becoming immediate; project-delivery otherwise waits for Bring back.
|
|
113
|
+
// reachable-ways-back means rollbackTargets excludes unrecoverable builds. Other features gate the procedures named below.
|
|
137
114
|
export const DeviceFeatureSchema = z.enum([
|
|
138
115
|
"reshape-later",
|
|
139
116
|
"set-shape",
|
|
@@ -30,22 +30,10 @@ export type OrgSection = z.infer<typeof OrgSectionSchema>;
|
|
|
30
30
|
export const OrgSectionModeSchema = z.enum(["open", "locked", "hidden"]);
|
|
31
31
|
export type OrgSectionMode = z.infer<typeof OrgSectionModeSchema>;
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// PRESET_GROUPS; which settings a group holds is the daemon's compliance/preset.ts) is applied to what the sandbox READS,
|
|
38
|
-
// whatever its files say, and a change that would undo it is refused. Strings on the wire, not the enum: a group a newer
|
|
39
|
-
// platform names and this daemon does not know is skipped and reported (`unenforced`), never a reason to refuse the
|
|
40
|
-
// whole policy, which would stop every later edition reaching an older daemon. The platform validates the names an
|
|
41
|
-
// admin saves.
|
|
42
|
-
//
|
|
43
|
-
// `membersOnly` makes the organisation's member list the outer fence of every bound sandbox's roster: a person the
|
|
44
|
-
// organisation removes is taken off each sandbox's roster by its daemon at the next fetch, and a grant to someone who
|
|
45
|
-
// is not a member is refused. The sandbox's owner is not on a roster, so this never reaches them.
|
|
46
|
-
//
|
|
47
|
-
// Both are optional rather than defaulted, so every policy written before them (a stored row, a held file, a literal)
|
|
48
|
-
// still reads as the same type: absent is no pin and an open roster.
|
|
33
|
+
// Omitted policy sections stay open. preset pins effective settings and refuses undoing writes, regardless of underlying files.
|
|
34
|
+
// Unknown preset groups are skipped/reported as unenforced so newer policies still reach older daemons; the platform validates saved names.
|
|
35
|
+
// membersOnly fences roster grants/removals by organisation membership, excluding the owner who is not a roster entry.
|
|
36
|
+
// Both fields remain optional for stored-policy compatibility: absence means no pins and an open roster.
|
|
49
37
|
export const OrgPolicyRulesSchema = z.object({
|
|
50
38
|
sections: z
|
|
51
39
|
.partialRecord(OrgSectionSchema, OrgSectionModeSchema)
|
package/src/schemas/personas.ts
CHANGED
|
@@ -253,6 +253,33 @@ export const personaModels = (card: Pick<Persona, "models">, sources: readonly M
|
|
|
253
253
|
// The one stock persona id; lives here because the daemon and the automations form are separate packages that must
|
|
254
254
|
// agree on it exactly, or a Visitor chat pins to a card nobody creates.
|
|
255
255
|
export const VISITOR_CHAT_PERSONA = "visitor-chat";
|
|
256
|
+
// THE TWO BUILT-IN PERSONAS. Every turn acts as somebody: a turn naming no card wears one of these, picked by whether a
|
|
257
|
+
// person is watching (personas.ts `turnPersona` in the daemon). They are constants rather than cards in personas.json:
|
|
258
|
+
// that file is tracked in git, and "every account" is not something a card's account list can say, since the list is
|
|
259
|
+
// written once and accounts are connected later. Neither can be edited or removed, and no card may take either id.
|
|
260
|
+
// Full access: every tool and every signed-in account, what a chat a person starts without picking anyone acts as.
|
|
261
|
+
export const FULL_ACCESS_PERSONA = "full-access";
|
|
262
|
+
// No accounts: every tool but no signed-in account, what a run nobody watches acts as when it names no one, since
|
|
263
|
+
// whatever woke it may have put somebody else's words in its prompt.
|
|
264
|
+
export const NO_ACCOUNTS_PERSONA = "no-accounts";
|
|
265
|
+
export type BuiltInPersonaId = typeof FULL_ACCESS_PERSONA | typeof NO_ACCOUNTS_PERSONA;
|
|
266
|
+
export interface BuiltInPersona {
|
|
267
|
+
readonly id: BuiltInPersonaId;
|
|
268
|
+
// English, for the daemon's own words (a turn's standing, its notes); every screen says it through its own catalog.
|
|
269
|
+
readonly label: string;
|
|
270
|
+
// Whether its turns reach the sandbox's signed-in accounts: all of them, or none.
|
|
271
|
+
readonly accounts: "all" | "none";
|
|
272
|
+
}
|
|
273
|
+
const FULL_ACCESS: BuiltInPersona = { id: FULL_ACCESS_PERSONA, label: "Full access", accounts: "all" };
|
|
274
|
+
const NO_ACCOUNTS: BuiltInPersona = { id: NO_ACCOUNTS_PERSONA, label: "No accounts", accounts: "none" };
|
|
275
|
+
export const BUILT_IN_PERSONAS: readonly BuiltInPersona[] = [FULL_ACCESS, NO_ACCOUNTS];
|
|
276
|
+
export const isBuiltInPersona = (id: string | undefined): id is BuiltInPersonaId => id === FULL_ACCESS_PERSONA || id === NO_ACCOUNTS_PERSONA;
|
|
277
|
+
export const builtInPersona = (id: BuiltInPersonaId): BuiltInPersona => (id === FULL_ACCESS_PERSONA ? FULL_ACCESS : NO_ACCOUNTS);
|
|
278
|
+
// Who a turn naming no card acts as: Full access with a person watching, No accounts without.
|
|
279
|
+
export const defaultPersona = (unattended: boolean): BuiltInPersonaId => (unattended ? NO_ACCOUNTS_PERSONA : FULL_ACCESS_PERSONA);
|
|
280
|
+
// An unwatched run's persona pick with No accounts read as no pick: an unwatched turn naming none wears No accounts
|
|
281
|
+
// anyway, so the two are one choice, and a form shows them as one row.
|
|
282
|
+
export const unwatchedPick = (actsAs: string | undefined): string | undefined => (actsAs === NO_ACCOUNTS_PERSONA ? undefined : actsAs);
|
|
256
283
|
// One phrase describing how bounded a card is, shared so the Personas page and the automation picker can't grow
|
|
257
284
|
// different vocabularies for the same card. "Read-only"/"no shell" are named; everything else collapses to a count.
|
|
258
285
|
export const personaBounds = (persona: Persona): string => {
|
|
@@ -387,10 +387,10 @@ export const ResumeRoutingSchema = z.object({
|
|
|
387
387
|
.describe(
|
|
388
388
|
"Which of that provider's accounts pays for it. Leave it out to keep the account the conversation runs on, or, on another provider, to take whichever of its accounts can serve with the most room. Moving to another account of the same provider is `switchAccount`'s job; naming one here still works.",
|
|
389
389
|
),
|
|
390
|
-
//
|
|
391
|
-
model: z.string().optional().describe("Which model. Leave it out to keep the
|
|
390
|
+
// An unloaded catalog keeps the held model only on its own provider.
|
|
391
|
+
model: z.string().optional().describe("Which model. Leave it out to keep the refused turn's model on the same provider, or use the new provider's default."),
|
|
392
392
|
// A tier named for one model may mean nothing on another, so a move onto a ladder rung carries that rung's own.
|
|
393
|
-
effort: z.string().optional().describe("How hard the model should think on the re-run. Leave it out to keep the refused turn's."),
|
|
393
|
+
effort: z.string().optional().describe("How hard the model should think on the re-run. Leave it out to keep the refused turn's on the same provider and model, or use the new model's default."),
|
|
394
394
|
// A session is a file the daemon keeps; a credential is an env var. That's what lets a same-provider account switch
|
|
395
395
|
// resume the existing session instead of opening a fresh one.
|
|
396
396
|
carry: z
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Checks a repository declares; sandbox settings decide whether the owner adopts them.
|
|
2
|
+
import { STATE_DIR } from "@intentic/constants";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
// Where a repository declares them, under the same `.intentic/` folder a directory already uses for its own UI. One
|
|
6
|
+
// spelling for the daemon that reads it, the screen that names it and the demo that mimics it.
|
|
7
|
+
export const REPO_CHECKS_FILE = `${STATE_DIR}/checks.json`;
|
|
8
|
+
|
|
9
|
+
// Named for the occasion as a repository would say it: `edit` is `file.edited` and `turn` is `turn.ending`
|
|
10
|
+
// (rules/repo-checks.ts maps them). `edit` runs on one file (`{file}`) and its output rides back in the edit's own
|
|
11
|
+
// response, so a command declared there is paid per edit and has to take the file. `turn` runs once when an isolated
|
|
12
|
+
// turn is about to stop, on the whole tree, and what it prints when it fails is said back to the model once, which may
|
|
13
|
+
// fix it or say why not. `land` is retired: nothing runs after work lands any more (CI checks what the owner pushes), and
|
|
14
|
+
// a declaration naming it still reads but runs nothing. No check refuses a land, a commit or a push.
|
|
15
|
+
export const RepoCheckMomentSchema = z.enum(["edit", "turn", "land"]);
|
|
16
|
+
export type RepoCheckMoment = z.infer<typeof RepoCheckMomentSchema>;
|
|
17
|
+
|
|
18
|
+
export const RepoCheckSchema = z.object({
|
|
19
|
+
when: RepoCheckMomentSchema.describe(
|
|
20
|
+
"When to run it: `edit` on each file as it is written (`{file}` is its path); `turn` once when an isolated turn is about to stop, for at most three minutes, with what it prints on failure said back to the model once. Neither holds or refuses anything. `land` is retired and runs nothing, since CI checks what is pushed.",
|
|
21
|
+
),
|
|
22
|
+
run: z.string().min(1).max(500).describe("The command, run in this repository's own directory, so it reads as it would in a terminal there."),
|
|
23
|
+
label: z.string().min(1).max(80).optional().describe("What to call it on screen. Absent names it after the command."),
|
|
24
|
+
// Same ceiling as a rule's own command; past it the process group is killed and the run is a failure.
|
|
25
|
+
timeoutMs: z.number().min(60_000).max(3_600_000).optional().describe("How long it may take before it is killed and counted as failed."),
|
|
26
|
+
// Repo-relative; the daemon prefixes the repo id before matching, since a rule's globs are workspace-relative.
|
|
27
|
+
paths: z
|
|
28
|
+
.array(z.string().min(1))
|
|
29
|
+
.max(20)
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Only run it when the change touches these paths, written relative to this repository. Absent runs it on every change here."),
|
|
32
|
+
});
|
|
33
|
+
export type RepoCheck = z.infer<typeof RepoCheckSchema>;
|
|
34
|
+
|
|
35
|
+
// The file itself. One key, so a second concern can be added later without breaking a file anyone has written.
|
|
36
|
+
export const RepoChecksFileSchema = z.object({
|
|
37
|
+
checks: z
|
|
38
|
+
.array(RepoCheckSchema)
|
|
39
|
+
.max(10)
|
|
40
|
+
.default([]),
|
|
41
|
+
});
|
|
42
|
+
export type RepoChecksFile = z.infer<typeof RepoChecksFileSchema>;
|
|
43
|
+
|
|
44
|
+
// One repository, as a screen reads it: what it declares, and where that stands with the owner.
|
|
45
|
+
export const RepoChecksSummarySchema = z.object({
|
|
46
|
+
repo: z.string().describe('Which repository, by its workspace id ("root" is the workspace itself).'),
|
|
47
|
+
path: z.string().describe("Where the declaration lives, relative to the workspace, whether or not the file exists yet."),
|
|
48
|
+
checks: z.array(RepoCheckSchema).describe("What it declares, in the order the file lists them."),
|
|
49
|
+
fired: z
|
|
50
|
+
.array(z.number().nullable())
|
|
51
|
+
.describe(
|
|
52
|
+
"When each declared check last reported something, in the file's order, as epoch milliseconds; null for one that never has, or for a retired one, which runs nothing.",
|
|
53
|
+
),
|
|
54
|
+
adopted: z
|
|
55
|
+
.boolean()
|
|
56
|
+
.describe("Whether these are running. False means declared and inert: nothing a repository writes runs until the owner switches it on."),
|
|
57
|
+
changed: z
|
|
58
|
+
.boolean()
|
|
59
|
+
.describe(
|
|
60
|
+
"Whether the declaration gained or rewrote a check since it was adopted. What changed waits until the owner looks again; the checks the owner already agreed to, word for word, keep running (`held` says which is which). True only for a repository that was adopted before.",
|
|
61
|
+
),
|
|
62
|
+
held: z
|
|
63
|
+
.array(z.boolean())
|
|
64
|
+
.optional()
|
|
65
|
+
.describe(
|
|
66
|
+
"For a changed declaration, which of its checks wait for the owner, in the file's order: true for one that is new or rewritten since they agreed, false for one still running as agreed, or retired. Absent when nothing changed, and from a sandbox that holds a changed declaration whole.",
|
|
67
|
+
),
|
|
68
|
+
error: z.string().optional().describe("Why the file could not be read, when it exists but does not parse. The checks list is empty in that case."),
|
|
69
|
+
});
|
|
70
|
+
export type RepoChecksSummary = z.infer<typeof RepoChecksSummarySchema>;
|
|
71
|
+
export const RepoChecksListSchema = z.object({
|
|
72
|
+
repos: z.array(RepoChecksSummarySchema).describe("Every repository that declares checks, in id order."),
|
|
73
|
+
});
|
|
74
|
+
export type RepoChecksList = z.infer<typeof RepoChecksListSchema>;
|
|
75
|
+
export const RepoChecksAdoptSchema = z.object({
|
|
76
|
+
repo: z.string().min(1).describe("Which repository's declaration to switch."),
|
|
77
|
+
on: z
|
|
78
|
+
.boolean()
|
|
79
|
+
.describe("On adopts what it declares as it stands now; off stops running it. Adopting again is how a changed declaration is accepted."),
|
|
80
|
+
});
|
|
81
|
+
export type RepoChecksAdopt = z.infer<typeof RepoChecksAdoptSchema>;
|
|
@@ -2,25 +2,9 @@ import { STATE_DIR } from "@intentic/constants";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { ArtifactNameSchema } from "./device-artifacts.js";
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// that very command in a terminal the owner watches. Each run builds in the sandbox, carries the build to the device
|
|
9
|
-
// (`devices push`), opens the device ports the target says the sandbox needs (`devices reach`), and starts the program
|
|
10
|
-
// there (the device's app_start). Nothing here runs by itself: a target runs when someone runs it.
|
|
11
|
-
//
|
|
12
|
-
// {
|
|
13
|
-
// "targets": [{
|
|
14
|
-
// "name": "desktop",
|
|
15
|
-
// "device": "rog",
|
|
16
|
-
// "build": "bash _tools/scripts/desktop/build-desktop.sh 0.0.0 --windows-only",
|
|
17
|
-
// "artifact": {
|
|
18
|
-
// "intentic-desktop.exe": "_editor/desktop-app/src-tauri/target/x86_64-pc-windows-msvc/release/intentic-desktop.exe",
|
|
19
|
-
// "intentic-files.exe": "_editor/desktop-app/src-tauri/binaries/intentic-files-x86_64-pc-windows-msvc.exe"
|
|
20
|
-
// },
|
|
21
|
-
// "program": "intentic-desktop.exe"
|
|
22
|
-
// }]
|
|
23
|
-
// }
|
|
5
|
+
// <repo>/.intentic/run.json declares tracked targets shared by devices run <target> and the editor's Run on <device> terminal command.
|
|
6
|
+
// Each explicit run builds in the sandbox, pushes artifacts, reaches the declared device ports and starts the program via app_start.
|
|
7
|
+
// Targets name device, build, artifact mappings and program; declaring one never starts it automatically.
|
|
24
8
|
|
|
25
9
|
export const RUN_TARGETS_FILE = `${STATE_DIR}/run.json`;
|
|
26
10
|
|
package/src/schemas/settings.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// itself, which those settings adopt.
|
|
3
|
-
import { STATE_DIR } from "@intentic/constants";
|
|
1
|
+
// Per-sandbox agent settings (.intentic/config/settings.json) and the repository checks they adopt.
|
|
4
2
|
import { z } from "zod";
|
|
5
3
|
import { claudeExperimentSettings, iqSearchSettings } from "./settings-experiments.js";
|
|
6
4
|
import { CommandJudgeModeSchema, ProjectInstallModeSchema } from "../policy/safety-policy.js";
|
|
@@ -197,11 +195,17 @@ export const SkillIdSchema = z.object({
|
|
|
197
195
|
"Which skill. It travels in the query rather than the address, because an id can name the owner it came from and that will not fit in a path.",
|
|
198
196
|
),
|
|
199
197
|
});
|
|
198
|
+
// The trigger line rides every turn's skill list, so it is capped; the form counts against the same number.
|
|
199
|
+
export const SKILL_DESCRIPTION_MAX = 1024;
|
|
200
200
|
// Three fields because a skill is three things: name, when to reach for it, what to do. The daemon assembles
|
|
201
201
|
// frontmatter from the first two, so a saved skill can never be one the loader skips.
|
|
202
202
|
export const SkillDraftSchema = z.object({
|
|
203
203
|
name: SkillNameSchema.describe("What to call it. Saving over an existing name rewrites it, which is also how one is renamed."),
|
|
204
|
-
description: z
|
|
204
|
+
description: z
|
|
205
|
+
.string()
|
|
206
|
+
.min(1)
|
|
207
|
+
.max(SKILL_DESCRIPTION_MAX)
|
|
208
|
+
.describe("What it is for, which is what the agent reads to decide whether to reach for it."),
|
|
205
209
|
body: z.string().min(1).describe("The skill itself."),
|
|
206
210
|
});
|
|
207
211
|
export type SkillDraft = z.infer<typeof SkillDraftSchema>;
|
|
@@ -678,87 +682,4 @@ export type BuiltinPromptText = z.infer<typeof BuiltinPromptTextSchema>;
|
|
|
678
682
|
// What each token-reduction mechanism saved, and the comparisons that measure the turn-level ones, in a file of their own.
|
|
679
683
|
export * from "./settings-savings.js";
|
|
680
684
|
|
|
681
|
-
|
|
682
|
-
// Here rather than in a file of its own because the line between these shapes and the settings above is authority, not
|
|
683
|
-
// subject matter: a repository may declare WHAT to run, because the command belongs beside the scripts it names and
|
|
684
|
-
// travels with the checkout; only the sandbox owner decides whether it runs at all (`adoptedChecks` above) and what
|
|
685
|
-
// happens when it fails, and that stays in settings.json. Both halves of that one decision read together here, and the
|
|
686
|
-
// routes that carry them are the settings routes.
|
|
687
|
-
|
|
688
|
-
// Where a repository declares them, under the same `.intentic/` folder a directory already uses for its own UI. One
|
|
689
|
-
// spelling for the daemon that reads it, the screen that names it and the demo that mimics it.
|
|
690
|
-
export const REPO_CHECKS_FILE = `${STATE_DIR}/checks.json`;
|
|
691
|
-
|
|
692
|
-
// Named for the occasion as a repository would say it: `edit` is `file.edited` and `turn` is `turn.ending`
|
|
693
|
-
// (rules/repo-checks.ts maps them). `edit` runs on one file (`{file}`) and its output rides back in the edit's own
|
|
694
|
-
// response, so a command declared there is paid per edit and has to take the file. `turn` runs once when an isolated
|
|
695
|
-
// turn is about to stop, on the whole tree, and what it prints when it fails is said back to the model once, which may
|
|
696
|
-
// fix it or say why not. `land` is retired: nothing runs after work lands any more (CI checks what the owner pushes), and
|
|
697
|
-
// a declaration naming it still reads but runs nothing. No check refuses a land, a commit or a push.
|
|
698
|
-
export const RepoCheckMomentSchema = z.enum(["edit", "turn", "land"]);
|
|
699
|
-
export type RepoCheckMoment = z.infer<typeof RepoCheckMomentSchema>;
|
|
700
|
-
|
|
701
|
-
export const RepoCheckSchema = z.object({
|
|
702
|
-
when: RepoCheckMomentSchema.describe(
|
|
703
|
-
"When to run it: `edit` on each file as it is written (`{file}` is its path); `turn` once when an isolated turn is about to stop, for at most three minutes, with what it prints on failure said back to the model once. Neither holds or refuses anything. `land` is retired and runs nothing, since CI checks what is pushed.",
|
|
704
|
-
),
|
|
705
|
-
run: z.string().min(1).max(500).describe("The command, run in this repository's own directory, so it reads as it would in a terminal there."),
|
|
706
|
-
label: z.string().min(1).max(80).optional().describe("What to call it on screen. Absent names it after the command."),
|
|
707
|
-
// Same ceiling as a rule's own command; past it the process group is killed and the run is a failure.
|
|
708
|
-
timeoutMs: z.number().min(60_000).max(3_600_000).optional().describe("How long it may take before it is killed and counted as failed."),
|
|
709
|
-
// Repo-relative; the daemon prefixes the repo id before matching, since a rule's globs are workspace-relative.
|
|
710
|
-
paths: z
|
|
711
|
-
.array(z.string().min(1))
|
|
712
|
-
.max(20)
|
|
713
|
-
.optional()
|
|
714
|
-
.describe("Only run it when the change touches these paths, written relative to this repository. Absent runs it on every change here."),
|
|
715
|
-
});
|
|
716
|
-
export type RepoCheck = z.infer<typeof RepoCheckSchema>;
|
|
717
|
-
|
|
718
|
-
// The file itself. One key, so a second concern can be added later without breaking a file anyone has written.
|
|
719
|
-
export const RepoChecksFileSchema = z.object({
|
|
720
|
-
checks: z
|
|
721
|
-
.array(RepoCheckSchema)
|
|
722
|
-
.max(10)
|
|
723
|
-
.default([]),
|
|
724
|
-
});
|
|
725
|
-
export type RepoChecksFile = z.infer<typeof RepoChecksFileSchema>;
|
|
726
|
-
|
|
727
|
-
// One repository, as a screen reads it: what it declares, and where that stands with the owner.
|
|
728
|
-
export const RepoChecksSummarySchema = z.object({
|
|
729
|
-
repo: z.string().describe('Which repository, by its workspace id ("root" is the workspace itself).'),
|
|
730
|
-
path: z.string().describe("Where the declaration lives, relative to the workspace, whether or not the file exists yet."),
|
|
731
|
-
checks: z.array(RepoCheckSchema).describe("What it declares, in the order the file lists them."),
|
|
732
|
-
fired: z
|
|
733
|
-
.array(z.number().nullable())
|
|
734
|
-
.describe(
|
|
735
|
-
"When each declared check last reported something, in the file's order, as epoch milliseconds; null for one that never has, or for a retired one, which runs nothing.",
|
|
736
|
-
),
|
|
737
|
-
adopted: z
|
|
738
|
-
.boolean()
|
|
739
|
-
.describe("Whether these are running. False means declared and inert: nothing a repository writes runs until the owner switches it on."),
|
|
740
|
-
changed: z
|
|
741
|
-
.boolean()
|
|
742
|
-
.describe(
|
|
743
|
-
"Whether the declaration gained or rewrote a check since it was adopted. What changed waits until the owner looks again; the checks the owner already agreed to, word for word, keep running (`held` says which is which). True only for a repository that was adopted before.",
|
|
744
|
-
),
|
|
745
|
-
held: z
|
|
746
|
-
.array(z.boolean())
|
|
747
|
-
.optional()
|
|
748
|
-
.describe(
|
|
749
|
-
"For a changed declaration, which of its checks wait for the owner, in the file's order: true for one that is new or rewritten since they agreed, false for one still running as agreed, or retired. Absent when nothing changed, and from a sandbox that holds a changed declaration whole.",
|
|
750
|
-
),
|
|
751
|
-
error: z.string().optional().describe("Why the file could not be read, when it exists but does not parse. The checks list is empty in that case."),
|
|
752
|
-
});
|
|
753
|
-
export type RepoChecksSummary = z.infer<typeof RepoChecksSummarySchema>;
|
|
754
|
-
export const RepoChecksListSchema = z.object({
|
|
755
|
-
repos: z.array(RepoChecksSummarySchema).describe("Every repository that declares checks, in id order."),
|
|
756
|
-
});
|
|
757
|
-
export type RepoChecksList = z.infer<typeof RepoChecksListSchema>;
|
|
758
|
-
export const RepoChecksAdoptSchema = z.object({
|
|
759
|
-
repo: z.string().min(1).describe("Which repository's declaration to switch."),
|
|
760
|
-
on: z
|
|
761
|
-
.boolean()
|
|
762
|
-
.describe("On adopts what it declares as it stands now; off stops running it. Adopting again is how a changed declaration is accepted."),
|
|
763
|
-
});
|
|
764
|
-
export type RepoChecksAdopt = z.infer<typeof RepoChecksAdoptSchema>;
|
|
685
|
+
export * from "./repo-checks.js";
|
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
import { compareVersions, DEV_VERSION, parseVersion } from "./versions.js";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// update, instead of the faults that page would otherwise be built from.
|
|
8
|
-
//
|
|
9
|
-
// Raise it deliberately, with a dated line below naming what the editor now depends on and the first release that has
|
|
10
|
-
// it (`git tag --contains <sha> | sort -V | head -1`). COMPATIBILITY.md quotes the current value.
|
|
11
|
-
//
|
|
12
|
-
// 2026-10-15: 1.249.0, the first release whose /events stream carries everything the editor reads off it. The hello's
|
|
13
|
-
// route list and its `build`, which opens with the version (1.0.0), the hello's shape fingerprints (1.187.0), and the
|
|
14
|
-
// roster revision on every heartbeat (`rev`, 1.249.0). Against a daemon without `rev`, every heartbeat reads as a
|
|
15
|
-
// missed roster snapshot, so the editor reads GET /agents again every two seconds and logs `fleet.roster-behind`
|
|
16
|
-
// each time. Since 1.249.0 every frame has only gained optional fields and new kinds, which daemon-floor.test.ts
|
|
17
|
-
// holds to.
|
|
3
|
+
// Below this floor, show the update page; above it, use hello route/shape fingerprints to negotiate individual features.
|
|
4
|
+
// Raise deliberately with a dated dependency reason and first supporting release; keep COMPATIBILITY.md aligned.
|
|
5
|
+
// 2026-10-15: 1.249.0 supplies heartbeat roster rev, avoiding a full agents refetch every two seconds on older streams.
|
|
6
|
+
// daemon-floor.test.ts checks that later frames remain additive.
|
|
18
7
|
export const OLDEST_SUPPORTED_DAEMON = `1.249.0`;
|
|
19
8
|
|
|
20
9
|
// The version a hello's `build` names. The daemon's build id is `<version>:<newest mtime of its compiled tree>`
|
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// print it, show a Copy button over it, and say which of its files are missing:
|
|
8
|
-
// - `localStorage`, `sessionStorage` and `document.cookie` throw in an opaque origin, and a page that touches them at
|
|
9
|
-
// load stops dead; each is stood in for by one held in memory for the page's life.
|
|
10
|
-
// - A Vite build whose base is an absolute path preloads chunks from the server's root, outside the ticket; its
|
|
11
|
-
// `vite:preloadError` is cancelled, so the import itself, which is relative, goes ahead.
|
|
12
|
-
// - `new Worker(url)` refuses any script an opaque origin did not make, which is every one; a worker is started from a
|
|
13
|
-
// script made here that loads the real one, its own relative imports and fetches resolved against where it lives.
|
|
14
|
-
// - A link to another site opens in a new tab (most refuse to be framed); a link within the page's own files is
|
|
15
|
-
// followed in the frame, as a browser would.
|
|
16
|
-
// - Every file it loads from beside itself is told, so the editor redraws it when one changes, and every one that
|
|
17
|
-
// fails, so the editor can name it.
|
|
18
|
-
// - `intenticPrint` is answered with the page as it stands, addresses made absolute and canvases drawn as pictures.
|
|
3
|
+
// Inject into opaque-origin previews: in-memory storage/cookies, cancelled Vite preload errors and worker wrappers keep static pages working.
|
|
4
|
+
// Worker-relative imports/fetches resolve from the real script; external links open tabs and internal links stay framed.
|
|
5
|
+
// Report loaded/missing adjacent files for refresh/error UI; intenticPrint returns current DOM with absolute URLs and rasterized canvases.
|
|
6
|
+
// Keep allow-same-origin off so previews cannot reach editor/daemon storage or APIs.
|
|
19
7
|
export const PREVIEW_GUIDE_SCRIPT = `(() => {
|
|
20
8
|
const say = (message) => parent.postMessage({ intenticHtmlPreview: message }, "*");
|
|
21
9
|
const memory = () => {
|