@intentic/sandbox-contract 1.338.0 → 1.339.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +5 -0
  2. package/dist/contracts/agents.contract.d.ts +4 -0
  3. package/dist/contracts/agents.contract.d.ts.map +1 -1
  4. package/dist/contracts/agents.contract.js +10 -1
  5. package/dist/contracts/agents.contract.js.map +1 -1
  6. package/dist/contracts/phone.contract.d.ts +1 -0
  7. package/dist/contracts/phone.contract.d.ts.map +1 -1
  8. package/dist/contracts/system.contract.d.ts +3 -0
  9. package/dist/contracts/system.contract.d.ts.map +1 -1
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/models/agent-lanes.d.ts +30 -0
  13. package/dist/models/agent-lanes.d.ts.map +1 -0
  14. package/dist/models/agent-lanes.js +67 -0
  15. package/dist/models/agent-lanes.js.map +1 -0
  16. package/dist/models/agent-standing.d.ts +55 -0
  17. package/dist/models/agent-standing.d.ts.map +1 -0
  18. package/dist/models/agent-standing.js +82 -0
  19. package/dist/models/agent-standing.js.map +1 -0
  20. package/dist/models/agent-starter.d.ts +10 -0
  21. package/dist/models/agent-starter.d.ts.map +1 -0
  22. package/dist/models/agent-starter.js +16 -0
  23. package/dist/models/agent-starter.js.map +1 -0
  24. package/dist/netd/generated/wire.d.ts +1 -1
  25. package/dist/netd/generated/wire.d.ts.map +1 -1
  26. package/dist/policy/persona-capability.d.ts +14 -0
  27. package/dist/policy/persona-capability.d.ts.map +1 -0
  28. package/dist/policy/persona-capability.js +23 -0
  29. package/dist/policy/persona-capability.js.map +1 -0
  30. package/dist/protocol/doors/phone-links.d.ts +5 -0
  31. package/dist/protocol/doors/phone-links.d.ts.map +1 -1
  32. package/dist/protocol/doors/phone-links.js +3 -1
  33. package/dist/protocol/doors/phone-links.js.map +1 -1
  34. package/dist/protocol/raw/raw-json-routes.d.ts +1 -0
  35. package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -1
  36. package/dist/schemas/agents-list.d.ts +5 -0
  37. package/dist/schemas/agents-list.d.ts.map +1 -1
  38. package/dist/schemas/agents-list.js +8 -0
  39. package/dist/schemas/agents-list.js.map +1 -1
  40. package/dist/schemas/devices.d.ts +9 -0
  41. package/dist/schemas/devices.d.ts.map +1 -1
  42. package/dist/schemas/devices.js +3 -0
  43. package/dist/schemas/devices.js.map +1 -1
  44. package/dist/schemas/intentic-os.d.ts +218 -0
  45. package/dist/schemas/intentic-os.d.ts.map +1 -1
  46. package/dist/schemas/intentic-os.js +166 -0
  47. package/dist/schemas/intentic-os.js.map +1 -1
  48. package/dist/schemas/phone.d.ts +3 -0
  49. package/dist/schemas/phone.d.ts.map +1 -1
  50. package/dist/schemas/phone.js +1 -0
  51. package/dist/schemas/phone.js.map +1 -1
  52. package/dist/schemas/system.d.ts +2 -0
  53. package/dist/schemas/system.d.ts.map +1 -1
  54. package/dist/schemas/system.js +1 -1
  55. package/dist/schemas/system.js.map +1 -1
  56. package/dist/state/history-state.d.ts.map +1 -1
  57. package/dist/state/history-state.js +1 -0
  58. package/dist/state/history-state.js.map +1 -1
  59. package/package.json +5 -5
  60. package/src/contracts/agents.contract.ts +13 -1
  61. package/src/models/agent-lanes.ts +152 -0
  62. package/src/models/agent-standing.ts +279 -0
  63. package/src/models/agent-starter.ts +26 -0
  64. package/src/netd/generated/netd-wire.json +2 -1
  65. package/src/netd/generated/wire.ts +1 -1
  66. package/src/policy/persona-capability.ts +57 -0
  67. package/src/protocol/doors/phone-links.ts +11 -2
  68. package/src/protocol/doors/phone-protocol.test.ts +8 -1
  69. package/src/schemas/agents-list.ts +13 -0
  70. package/src/schemas/devices.ts +7 -0
  71. package/src/schemas/intentic-os.test.ts +148 -0
  72. package/src/schemas/intentic-os.ts +259 -0
  73. package/src/schemas/phone.ts +3 -0
  74. package/src/schemas/system.ts +5 -2
  75. package/src/state/history-state.ts +3 -0
@@ -1 +1 @@
1
- {"version":3,"file":"history-state.js","sourceRoot":"","sources":["../../src/state/history-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"history-state.js","sourceRoot":"","sources":["../../src/state/history-state.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/sandbox-contract",
3
- "version": "1.338.0",
3
+ "version": "1.339.0",
4
4
  "description": "oRPC wire contract for the intentic sandbox daemon, shared by the daemon and its browser client",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -361,10 +361,10 @@
361
361
  }
362
362
  },
363
363
  "dependencies": {
364
- "@intentic/base": "1.338.0",
365
- "@intentic/constants": "1.338.0",
366
- "@intentic/extension-manifest": "1.338.0",
367
- "@intentic/registry": "1.338.0",
364
+ "@intentic/base": "1.339.0",
365
+ "@intentic/constants": "1.339.0",
366
+ "@intentic/extension-manifest": "1.339.0",
367
+ "@intentic/registry": "1.339.0",
368
368
  "@orpc/contract": "1.15.4",
369
369
  "tslib": "2.8.1",
370
370
  "zod": "4.6.5"
@@ -26,7 +26,7 @@ import {
26
26
  AgentUnsentSchema,
27
27
  LandResultSchema,
28
28
  } from "../schemas/agents.js";
29
- import { AgentsListSchema } from "../schemas/agents-list.js";
29
+ import { AgentsAttentionSchema, AgentsListSchema } from "../schemas/agents-list.js";
30
30
  import { AgentChangesSchema, AgentConflictsSchema, AgentIgnoredSchema, AgentScratchSchema, AgentHistorySchema } from "../schemas/git/git.js";
31
31
  import { FileDiffSchema } from "../schemas/history.js";
32
32
  import { OkSchema } from "../schemas/shared.js";
@@ -51,6 +51,18 @@ export const agentsContract = {
51
51
  })
52
52
  .meta({ guest: true })
53
53
  .output(AgentsListSchema),
54
+ // The owner's only, and never a program's or a panel's: it is how the machine that runs the sandbox reads it with a
55
+ // session it minted for the owner (`ic sandbox attention`), and a member's count would not be the owner's anyway.
56
+ attention: procedure
57
+ .route({
58
+ method: "GET",
59
+ path: "/agents/attention",
60
+ summary: "What needs you, and what is working",
61
+ description:
62
+ "Two counts over the live fleet, by the board's own rules: the cards in its Attention lane plus the automations waiting for a yes, and the conversations producing something right now. What a status bar shows without reading the whole fleet.",
63
+ })
64
+ .meta({ floor: "owner", control: "never", panel: false })
65
+ .output(AgentsAttentionSchema),
54
66
  archived: procedure
55
67
  .route({
56
68
  method: "GET",
@@ -0,0 +1,152 @@
1
+ import type { AgentAttention } from "../schemas/agents.js";
2
+ import type { AutomationApproval } from "../schemas/automations.js";
3
+ import { parentOf } from "./agent-starter.js";
4
+ import {
5
+ type AgentStanding,
6
+ blocked,
7
+ heardByParent,
8
+ limitScheduled,
9
+ onlyOwnerCanAnswer,
10
+ scheduledSend,
11
+ turnInFlight,
12
+ turnWorking,
13
+ watching,
14
+ } from "./agent-standing.js";
15
+
16
+ // The lane every surface files a conversation in, and what of a fleet calls the person. Moved here from the editor
17
+ // (_editor/web/src/models/agent-status/agentStatus-lanes.ts, which re-exports it) on 2026-10-16, so the daemon's
18
+ // `agents.attention` (what the desktop app's status bar and `ic sandbox attention` read) counts by the board's own rules.
19
+
20
+ // Whether what a child agent stopped on is the reader's to answer rather than its parent's, given the lanes both stand
21
+ // in and when the parent last moved. An ask only the owner can answer always is; anything else it stopped on (a spent
22
+ // allowance, a failure, a stop, a question, a land conflict) is its parent's news while the parent supervises, and the
23
+ // reader's once it no longer does: nothing running there to hear it and nothing armed to wake it, which is a parent out
24
+ // of Active. That holds only until the parent moves past it (heardByParent). After that the stop is the family's
25
+ // history, drawn in the tray, and no longer something the reader owes a press. The sandbox draws the same line for a
26
+ // child's land news (subagents/child-lands.ts): the parent's while it has a live turn, the owner's after.
27
+ export const callsOwner = (
28
+ child: AgentStanding & { readonly updatedAt: number },
29
+ family: { readonly child: FleetLane; readonly parent: FleetLane; readonly parentAt: number },
30
+ ): boolean => onlyOwnerCanAnswer(child) || (family.child === "attention" && family.parent !== "active" && !heardByParent(child, family.parentAt));
31
+
32
+ export type FleetLane = "attention" | "active" | "finished";
33
+
34
+ // Nothing owed to the user. The one "no attention" block in the app: a client-only card has no daemon account of
35
+ // what a turn asked, and two copies of this would let two surfaces place the same conversation differently.
36
+ export const NO_ATTENTION: AgentAttention = {
37
+ plan: false,
38
+ question: false,
39
+ permission: false,
40
+ capability: false,
41
+ credential: false,
42
+ conflict: false,
43
+ };
44
+
45
+ // The lane projection every surface must agree with (see the header). Pure reading of the state machine:
46
+ // "finished" needs no explicit timer since auto-land already flips a cleanly-completed turn to landed/idle within
47
+ // ms, and any follow-up message moves the card back to active. Unread stays a badge, not a lane.
48
+ export const laneOf = (agent: AgentStanding): FleetLane => {
49
+ // A spent allowance nothing is booked for reaches Attention through `blocked` alone, no branch of its own, and ahead
50
+ // of the `watching` branch below: a watch is the agent's own plan for waiting, a spent allowance an obstacle in
51
+ // the way of it, and a watch firing into a shut window runs nothing (turn-admission.ts holds its words back).
52
+ if (blocked(agent) || agent.status === "awaiting" || agent.status === "conflict") {
53
+ return "attention";
54
+ }
55
+ // Settled from the press, ahead of the in-flight check below, rather than routed through Active: a waved-away turn
56
+ // is one the user is already done with (unlike `stopping`, which rests in Attention), and a land spends no model at
57
+ // all. Active means a turn in progress, so a land must end in the lane it was pressed in.
58
+ if (agent.status === "dismissing" || agent.status === "landing") {
59
+ return "finished";
60
+ }
61
+ // `resuming` is why in-flight must outrank the settled readings below: without this order the card would drop
62
+ // into Finished for the seconds a credential takes to re-mint, then climb back out.
63
+ if (turnInFlight(agent) || agent.status === "draft") {
64
+ return "active";
65
+ }
66
+ // An armed watch is Active, not Finished: nothing is running, but the conversation restarts itself later, and
67
+ // filing it Finished would announce as over work that resumes at 3am. Active rather than Attention since nothing
68
+ // is owed by the user. Checked after the in-flight readings: an agent that armed a watch and is now running again
69
+ // is running.
70
+ if (watching(agent)) {
71
+ return "active";
72
+ }
73
+ // A stranded turn booked to go again is Active: at the reset, or on the resume pass's next beat for a move to another
74
+ // account. Reached only because `blocked` let it through; stated explicitly or the card would fall through to
75
+ // Finished, which would announce as over work that resumes by itself.
76
+ if (limitScheduled(agent)) {
77
+ return "active";
78
+ }
79
+ // Messages booked for later are the same: the conversation starts again by itself, at a time or once the agent it
80
+ // waits for has landed, so filing it Finished would announce as done work that has not started yet.
81
+ if (scheduledSend(agent)) {
82
+ return "active";
83
+ }
84
+ // `landed`/`idle`/`ready` all finish here: `ready` is work held on the branch because auto-land is off, still
85
+ // finished rather than attention since nothing is failing. `resumed` lands here too: nothing running, nothing
86
+ // owed.
87
+ return "finished";
88
+ };
89
+
90
+ // How many cards the board's Attention lane draws for one fleet, as the board folds child agents under their parents
91
+ // (models/fleet/board/childFold.ts): an agent in Attention is a card of its own, except a child agent whose parent is in the
92
+ // fleet, which rides under its family's one card and lifts that card to Attention only when it calls the reader
93
+ // (callsOwner). A family counts once however many of its children call, and not again when its own card is in
94
+ // Attention already; a child with words left in its composer keeps a card of its own, as on the board. The rail
95
+ // badge's count, for this sandbox's fleet and another's alike, so the badge cannot disagree with the lane it names.
96
+ export const attentionCards = (agents: readonly CallerStanding[]): number => new Set(attentionCalls(agents).map((call) => call.card)).size;
97
+
98
+ // Enough of a fleet's agent to say whether it calls the reader, and through which card.
99
+ export type CallerStanding = AgentStanding & {
100
+ readonly id: string;
101
+ readonly updatedAt: number;
102
+ readonly startedBy?: string | undefined;
103
+ readonly unsent?: boolean | undefined;
104
+ };
105
+
106
+ // Every agent calling the reader, each with the card it is drawn on: its own, or its family's where it rides one. The
107
+ // count above is the cards; the browser tab's chime wants the callers, so a second child calling under a family already
108
+ // in Attention is news although the lane's count does not move.
109
+ export const attentionCalls = (agents: readonly CallerStanding[]): readonly { readonly id: string; readonly card: string }[] => {
110
+ type Standing = (typeof agents)[number];
111
+ const byId = new Map(agents.map((agent) => [agent.id, agent] as const));
112
+ const parentIn = (agent: Standing): Standing | undefined => {
113
+ const id = parentOf(agent.startedBy);
114
+ return id === undefined ? undefined : byId.get(id);
115
+ };
116
+ // The card a child rides under: its eldest ancestor in this fleet, walked with a guard against a record naming its
117
+ // own descendant as its parent.
118
+ const familyOf = (agent: Standing): string => {
119
+ const seen = new Set([agent.id]);
120
+ let top = agent;
121
+ for (let above = parentIn(top); above !== undefined && !seen.has(above.id); above = parentIn(top)) {
122
+ seen.add(above.id);
123
+ top = above;
124
+ }
125
+ return top.id;
126
+ };
127
+ const calls: { readonly id: string; readonly card: string }[] = [];
128
+ for (const agent of agents) {
129
+ const parent = parentIn(agent);
130
+ if (parent === undefined || agent.unsent === true) {
131
+ if (laneOf(agent) === "attention") {
132
+ calls.push({ id: agent.id, card: agent.id });
133
+ }
134
+ } else if (callsOwner(agent, { child: laneOf(agent), parent: laneOf(parent), parentAt: parent.updatedAt })) {
135
+ calls.push({ id: agent.id, card: familyOf(agent) });
136
+ }
137
+ }
138
+ return calls;
139
+ };
140
+
141
+ // What one fleet owes the person and how much of it is under way, as the desktop app's status bar and the sandbox
142
+ // switcher count it: the Attention lane's cards as the board draws them (attentionCards) plus held automation wakes,
143
+ // which lead that lane with no card of their own; and the turns producing something right now (turnWorking).
144
+ export interface FleetAttention {
145
+ readonly needsYou: number;
146
+ readonly working: number;
147
+ }
148
+
149
+ export const fleetAttention = (agents: readonly CallerStanding[], held: readonly Pick<AutomationApproval, "id">[]): FleetAttention => ({
150
+ needsYou: attentionCards(agents) + held.length,
151
+ working: agents.filter(turnWorking).length,
152
+ });
@@ -0,0 +1,279 @@
1
+ import {
2
+ type AgentAttention,
3
+ type AgentJob,
4
+ type AgentStatus,
5
+ type AgentWatch,
6
+ awaitsWake,
7
+ type LandConflictReason,
8
+ type LandFailure,
9
+ } from "../schemas/agents.js";
10
+ import type { QueuePause } from "../schemas/agent.js";
11
+
12
+ // (2026-10-16) Moved here from the editor (_editor/web/src/models/agent-status/agentStatus-standing.ts, which re-exports
13
+ // it), so the daemon counts what needs the person by the very rules the board draws with (models/agent-lanes.ts): the
14
+ // desktop app's status bar asks the daemon (`agents.attention`), and the board and the bar must never disagree.
15
+
16
+ // Every projection of a fleet agent's state (lane, attention label, drill-in verb, glyphs). Nothing else may
17
+ // derive these from `status` alone: a parked turn is `idle` with an attention flag raised. Pure functions over
18
+ // plain data, no store, no Vue.
19
+
20
+ // Four standings a conversation gets when the daemon has not registered it. `draft`: not sent yet. `starting`:
21
+ // sent but not yet filed as an agent. `failed`: send refused, never became an agent. `resumed`: a past conversation
22
+ // reopened from History with no surviving registry entry. All four have no registry entry, so nothing to archive,
23
+ // review, land or drop (`unregistered` below). None may be widened into `AgentStatus`: that enum is only the
24
+ // daemon's account of agents it has.
25
+ export type ClientAgentStatus = "draft" | "starting" | "failed" | "resumed";
26
+
27
+ // Enough of an agent to place one; every predicate below takes only this, so a FleetAgent, a roster AgentSummary,
28
+ // or a test literal can all answer the same question. Each optional field also takes `undefined`, as the contract's own
29
+ // AgentSummary spells it, so the daemon (strict about the difference) hands its roster over as it is.
30
+ export interface AgentStanding {
31
+ readonly status: AgentStatus | ClientAgentStatus;
32
+ readonly attention: AgentAttention;
33
+ // Outside conditions this conversation is parked on (AgentSummary.watches); `laneOf` reads it alongside `status`
34
+ // and `attention`. Absent for nearly every conversation.
35
+ readonly watches?: readonly AgentWatch[] | undefined;
36
+ // Whether it runs again by itself (AgentSummary.awaitingWake): the daemon's one reading, which `watching` asks.
37
+ readonly awaitingWake?: boolean | undefined;
38
+ // The commands it left running and how the recent ones ended (AgentSummary.jobs); `heldByPrompt` reads which of its
39
+ // watches a job at a prompt holds. Absent for nearly every conversation.
40
+ readonly jobs?: readonly AgentJob[] | undefined;
41
+ // Why a refused land is still refusing (AgentSummary.conflictCauses), which decides whose press can clear it.
42
+ // Absent for every card but one refusing to merge.
43
+ readonly conflictCauses?: readonly LandConflictReason[] | undefined;
44
+ // Which kind of failure ended the last turn. `status: "error"` alone conflates a broken harness with a spent
45
+ // allowance; both belong in Attention, but this says which so the card can tell them apart. `laneOf` reads it too,
46
+ // so the lane, badge and chip stay in agreement.
47
+ readonly failureCode?: string | undefined;
48
+ // The words that turn died on (AgentSummary.failure), cleared with the code when it runs again.
49
+ readonly failure?: string | undefined;
50
+ /** When the spent allowance reopens, in epoch SECONDS (the wire's unit). Absent when nobody published one. */
51
+ readonly limitResetsAt?: number | undefined;
52
+ /** Whether the refused turn is held whole, so a press re-runs it rather than sending a new message after it. */
53
+ readonly limitHeld?: boolean | undefined;
54
+ /** Whether a fire is already booked for it (at the reset, or a move now), so no press is needed. */
55
+ readonly limitScheduled?: boolean | undefined;
56
+ /** The account the owner's policy is moving the held turn to, while that move is booked (a scheduled card's sentence). */
57
+ readonly limitMoving?: string | undefined;
58
+ // A land that broke (AgentSummary.landFailure), standing until one goes through whatever turns run after it. Absent
59
+ // from a sandbox older than it, where only a turn's own `failure` can say so.
60
+ readonly landFailure?: LandFailure | undefined;
61
+ // What waits for its next turn (AgentSummary.queue), read here only for its hold: messages booked to go by
62
+ // themselves at a time or once another agent's work lands (`scheduled`), which make the conversation one that runs
63
+ // again by itself. Never the words.
64
+ readonly queue?: QueueHold | undefined;
65
+ }
66
+
67
+ // The part of a conversation's queue the board reads: why it holds, and what a scheduled hold waits for. A queue-level
68
+ // `scheduled` with its `until` or `after` is the soonest booked message's; a Stop's or a refusal's hold on the messages
69
+ // with no booking takes that place, so each message's own booking (`items`, from sandboxes that book each message on its
70
+ // own) is read then.
71
+ export interface QueueHold {
72
+ readonly paused?: QueuePause | undefined;
73
+ readonly until?: number | undefined;
74
+ readonly after?: string | undefined;
75
+ readonly items?: readonly { readonly until?: number | undefined; readonly after?: string | undefined }[] | undefined;
76
+ }
77
+
78
+ // The soonest booking a queue holds, as a scheduled hold: the queue's own while it reads `scheduled`, else the earliest
79
+ // message's time, else the first message waiting on a land; undefined when nothing is booked. One thing, never both.
80
+ export const soonestHold = (queue: QueueHold | undefined): QueueHold | undefined => {
81
+ if (queue?.paused === "scheduled") {
82
+ if (queue.after !== undefined) {
83
+ return { paused: "scheduled", after: queue.after };
84
+ }
85
+ return queue.until === undefined ? { paused: "scheduled" } : { paused: "scheduled", until: queue.until };
86
+ }
87
+ const items = queue?.items ?? [];
88
+ const instants = items.flatMap((item) => (item.until === undefined ? [] : [item.until]));
89
+ if (instants.length > 0) {
90
+ return { paused: "scheduled", until: Math.min(...instants) };
91
+ }
92
+ const after = items.find((item) => item.after !== undefined)?.after;
93
+ return after === undefined ? undefined : { paused: "scheduled", after };
94
+ };
95
+
96
+ // Messages booked to go by themselves (sendLater.ts, or a spent allowance's reopen): the conversation runs again with
97
+ // nobody pressing anything, so it is not finished, and nothing is owed by the reader for it to.
98
+ export const scheduledSend = (agent: Pick<AgentStanding, "queue">): boolean => soonestHold(agent.queue) !== undefined;
99
+
100
+ // How many messages are booked to go by themselves: each by its own booking, or all of them when an older sandbox booked
101
+ // the queue whole. What an archive by hand cancels (the sandbox's archive.ts), which the card's Archive says first.
102
+ export const scheduledCount = (agent: Pick<AgentStanding, "queue">): number => {
103
+ const items = agent.queue?.items ?? [];
104
+ return agent.queue?.paused === "scheduled" ? items.length : items.filter((item) => item.until !== undefined || item.after !== undefined).length;
105
+ };
106
+
107
+ // A spent allowance, not a failure to fix: nothing broken, and it comes back. Read off `failureCode` rather than
108
+ // the provider's own sentence, which varies per provider; the code is the daemon's own classification
109
+ // (error-frames.ts).
110
+ export const limited = (agent: AgentStanding): boolean => agent.status === "error" && agent.failureCode === "rate_limit";
111
+
112
+ // A message held at the door because the sandbox is short of memory (turn-admission): nothing ran and nothing failed,
113
+ // it waits for a person's "send anyway". The daemon files it as an `error`, so this is read off the code, as `limited`
114
+ // is, and the chip and glyph say held rather than error; the lane stays Attention, since the press is the reader's.
115
+ export const memoryHeld = (agent: Pick<AgentStanding, "status" | "failureCode">): boolean =>
116
+ agent.status === "error" && agent.failureCode === "sandbox-memory-low";
117
+
118
+ // Whether the window is still shut, feeding only the card's countdown, never the lane: a stranded card stays in
119
+ // Attention shut or open. No published instant means never closed, not a guessed one.
120
+ export const limitClosed = (agent: AgentStanding, now: number = Date.now()): boolean =>
121
+ limited(agent) && agent.limitResetsAt !== undefined && agent.limitResetsAt * 1_000 > now;
122
+
123
+ // A booked fire needs no press: the held turn goes again at the reset by itself. Only where this conversation's answer
124
+ // for the limit says so (`resend` or `move`); that answer starts at `wait`. Nothing is owed then, so it leaves Attention
125
+ // for Active, as an armed watch does: a card counted in the badge and the tab title for the hours until a reset the
126
+ // reader already answered was a call nobody could answer. The stall still shows, on the card's own chip and clock.
127
+ export const limitScheduled = (agent: AgentStanding): boolean => limited(agent) && agent.limitScheduled === true;
128
+
129
+ // A booked move: the owner's policy is already carrying the held turn to another account, on the resume pass's next
130
+ // beat, seconds away, so the card names where it is going rather than when it goes.
131
+ export const limitMoveBooked = (agent: AgentStanding): boolean => limitScheduled(agent) && agent.limitMoving !== undefined;
132
+
133
+ // A refused land nothing the agent does can clear: every blocker left is a file the user has uncommitted edits on,
134
+ // which only a commit or stash releases (git cannot merge through unstaged work, and the agent's checkout cannot
135
+ // even see it). The distinction the board used to lack: it offered "have the agent resolve it" for every conflict,
136
+ // including the ones where that press was refused the moment it was made.
137
+ // False when the daemon named no causes, which is a build that predates them or a refusal it could not attribute;
138
+ // the board then falls back to offering the agent, as it always did.
139
+ export const conflictIsYours = (agent: AgentStanding): boolean =>
140
+ agent.conflictCauses !== undefined && agent.conflictCauses.length > 0 && agent.conflictCauses.every((cause) => cause === "workspace");
141
+
142
+ // This conversation runs again by itself, with nobody pressing anything: its last turn ended (status is `idle`/`landed`,
143
+ // never `ready`, since the daemon holds the land for the wake), but the conversation is not over. The daemon's own
144
+ // reading (a watch, or a wake waiting in its queue); a daemon older than it is read by its watches.
145
+ export const watching = (agent: AgentStanding): boolean => awaitsWake(agent);
146
+
147
+ // The running job behind one of its armed watches that sits at a prompt (AgentJob.inputWait: blocked reading its
148
+ // terminal, nothing moving), the first such where there are several. Its watch fires only on an exit that will not
149
+ // come, so the card names it and offers to end it.
150
+ export const promptHeldJob = (agent: AgentStanding): AgentJob | undefined => {
151
+ const armed = new Set((agent.watches ?? []).map((watch) => watch.id));
152
+ return agent.jobs?.find((job) => job.endedAt === undefined && job.inputWait !== undefined && job.watch !== undefined && armed.has(job.watch));
153
+ };
154
+
155
+ // Parked only on jobs at a prompt: every watch it holds waits on an exit nobody in the sandbox will bring about, so the
156
+ // conversation is not resuming by itself, it is stuck until the reader ends the command (or types into its terminal).
157
+ // Not while a turn runs, whose own readout says what it is doing. On 2026-10-04 such a card sat in Active for hours
158
+ // under a six-hour countdown, with its Land press hidden behind the wake it was waiting for.
159
+ export const heldByPrompt = (agent: AgentStanding): boolean => {
160
+ const watches = agent.watches ?? [];
161
+ if (watches.length === 0 || turnInFlight(agent)) {
162
+ return false;
163
+ }
164
+ const prompts = new Set(
165
+ (agent.jobs ?? [])
166
+ .filter((job) => job.endedAt === undefined && job.inputWait !== undefined && job.watch !== undefined)
167
+ .map((job) => job.watch),
168
+ );
169
+ return watches.every((watch) => prompts.has(watch.id));
170
+ };
171
+
172
+ // No registry entry behind this card: archiving, reviewing, landing, discarding and dropping all address an agent
173
+ // by id through the daemon, and none of these ids name anything there.
174
+ // Takes the status alone, unlike the lane predicates: callers like the tab's `open` and the detail page's
175
+ // `registered` hold a status without an attention block to pair it with.
176
+ export const unregistered = (status: AgentStatus | ClientAgentStatus): boolean =>
177
+ status === "draft" || status === "starting" || status === "failed" || status === "resumed";
178
+
179
+ // A turn is in flight: running, unwinding after a Stop, or repairing itself after its daemon died. Every hands-off
180
+ // guard (its worktree is a live turn's working state) and the live readouts (elapsed, activity line) key off this.
181
+ // `starting` counts even though nothing is registered yet, elapsed should tick from the send. `dismissing` and
182
+ // `landing` count for the guards only; both settle in Finished, so their lane is decided separately (see laneOf).
183
+ // A land runs no turn, but the daemon holds the worktree exactly as a turn would, and every guard wants the same answer.
184
+ // `awaiting` is deliberately excluded: it's live but parked, handled by `awaitingUser` instead.
185
+ export const turnInFlight = (agent: AgentStanding): boolean =>
186
+ agent.status === "running" ||
187
+ agent.status === "starting" ||
188
+ agent.status === "stopping" ||
189
+ agent.status === "dismissing" ||
190
+ agent.status === "resuming" ||
191
+ agent.status === "landing";
192
+
193
+ // The two standings a person's ending unwinds as, from the press until the turn has let go: Stop, or waving away the
194
+ // question it was parked on. Both differ only in the lane they settle in (see laneOf).
195
+ export type EndingByHand = Extract<AgentStatus, "stopping" | "dismissing">;
196
+
197
+ // How a person ended this turn, while it unwinds; undefined for a turn nobody ended. The one reading both the board's
198
+ // card and the chat's live line are drawn from, so the two say the same word about the same press.
199
+ export const endingOf = (agent: AgentStanding): EndingByHand | undefined =>
200
+ agent.status === "stopping" || agent.status === "dismissing" ? agent.status : undefined;
201
+
202
+ // A person already ended this turn and it's unwinding. Narrower than `turnInFlight`, which also covers turns nobody
203
+ // ended.
204
+ export const endingByHand = (agent: AgentStanding): boolean => endingOf(agent) !== undefined;
205
+
206
+ // A turn actually producing something, as a card's readouts mean it: `landing` is in flight for the hands-off guards
207
+ // but spends no model, and its `startedAt` belongs to the turn before it, so an elapsed clock would be someone else's.
208
+ // A turn a person already ended produces nothing more either: its readout is the ending itself (the card's chip, the
209
+ // chat's line), not the step it was on under a clock still counting, which reads as a Stop that did not take.
210
+ export const turnWorking = (agent: AgentStanding): boolean => turnInFlight(agent) && agent.status !== "landing" && !endingByHand(agent);
211
+
212
+ // The browser's copy of the daemon's `writing` guard (agents-registry.ts); exists for Land, where typing vs.
213
+ // parked matters (everything else treats them alike). `stopping` and `resuming` are excluded because the provider
214
+ // isn't producing anything then; the two sides must stay in step or the UI offers a press the daemon refuses.
215
+ export const writingNow = (agent: AgentStanding): boolean => agent.status === "running" || agent.status === "starting";
216
+
217
+ // "Blocked on you": the agent cannot proceed (or has failed) until the user acts. Not the same as unread.
218
+ // `stopped`/`interrupted` leave a half-written worktree only a new message can carry forward; `stopping` is
219
+ // counted the moment the press lands rather than once the unwind finishes, since it settles in the same lane
220
+ // either way; `failed` is the same kind of dead end one step earlier, before a worktree existed. A spent allowance
221
+ // counts until something is booked to carry it on (limitScheduled): a resend at the reset, or a move now.
222
+ const BLOCKING_ENDINGS: ReadonlySet<AgentStatus | ClientAgentStatus> = new Set(["error", "interrupted", "stopping", "stopped", "failed"]);
223
+
224
+ // A land that broke and still stands: its work is stuck on the branch, whatever the turn after it did, so the card is
225
+ // the reader's to look at. Not while a turn or a land is under way, which ends in another land of its own.
226
+ export const landBroken = (agent: AgentStanding): boolean => agent.landFailure !== undefined && !turnInFlight(agent);
227
+
228
+ export const blocked = (agent: AgentStanding): boolean =>
229
+ limitScheduled(agent)
230
+ ? false
231
+ : agent.attention.plan ||
232
+ agent.attention.question ||
233
+ agent.attention.permission ||
234
+ agent.attention.capability ||
235
+ agent.attention.conflict ||
236
+ // A need outlives its turn (docs/architecture/needs.md): a conversation still running carries on beside it
237
+ // and stays in Active, one that stopped is waiting on nothing but the answer.
238
+ (agent.attention.need === true && agent.status !== "running") ||
239
+ landBroken(agent) ||
240
+ heldByPrompt(agent) ||
241
+ BLOCKING_ENDINGS.has(agent.status);
242
+
243
+ // The half of `blocked` that is literally waiting on an answer (plan, question, permission, capability), narrower
244
+ // than `blocked`: dead ends (a failed turn, an unlandable conflict) want looking at but owe the user nothing, so
245
+ // ending the agent loses no answer.
246
+ export const awaitingUser = (agent: AgentStanding): boolean =>
247
+ agent.attention.plan || agent.attention.question || agent.attention.permission || agent.attention.capability || agent.status === "awaiting";
248
+
249
+ // An ask only the owner may answer: a plan to approve, a permission, a setup, a credential release, a hand-off to a
250
+ // browser or terminal (a bare `awaiting`), or a refused land only their own commit clears. The parent a child agent
251
+ // works for can answer its question (subagents/children.ts) and hears how its turns end, but none of these, so these
252
+ // are what reach the reader from a child whatever its parent is doing (callsOwner).
253
+ export const onlyOwnerCanAnswer = (agent: AgentStanding): boolean =>
254
+ agent.attention.plan ||
255
+ agent.attention.permission ||
256
+ agent.attention.capability ||
257
+ agent.attention.credential ||
258
+ agent.attention.need === true ||
259
+ (agent.status === "awaiting" && !agent.attention.question) ||
260
+ ((agent.attention.conflict || agent.status === "conflict") && conflictIsYours(agent));
261
+
262
+ // Whether a child agent's stop is news its parent has already had. Every ending of a turn the parent started reaches
263
+ // the parent (subagents/child-report.ts: a parked `wait` takes it, or it wakes the parent like any wake), so a parent
264
+ // that moved after the child stopped (ran a turn, landed) heard it, and its own ending is the account the reader gets:
265
+ // an orchestrator that worked around three spent allowances and landed is done, not stuck. Only a turn's ending
266
+ // counts. A question is still parked and waits for an answer whoever has moved since, and a land refused or broken
267
+ // leaves work stuck on the child's branch that no report settles. A turn a person ran in the child's own chat is never
268
+ // reported to the parent, and it ends after the parent's last move, so it still reads as unheard here.
269
+ // `updatedAt` is the clock on both sides: a rename keeps it (agents-registry), and reading does not move it.
270
+ export const heardByParent = (child: AgentStanding & { readonly updatedAt: number }, parentAt: number): boolean =>
271
+ BLOCKING_ENDINGS.has(child.status) &&
272
+ // Still unwinding: its ending has not reached anyone yet.
273
+ child.status !== "stopping" &&
274
+ // Booked to run again by itself: not over, whatever its parent made of the pause.
275
+ !limitScheduled(child) &&
276
+ !child.attention.question &&
277
+ !child.attention.conflict &&
278
+ !landBroken(child) &&
279
+ child.updatedAt < parentAt;
@@ -0,0 +1,26 @@
1
+ // Who started a conversation when it was not a person, read off the summary's `startedBy` (the daemon's
2
+ // auth/principal.ts writes these prefixes). Moved here from the editor's ownership.ts (2026-10-16), which re-exports it,
3
+ // because which card a child agent rides under (models/agent-lanes.ts) is the daemon's count too.
4
+
5
+ // A starter that is not a person: a program holding a control token, or the conversation that spawned this one.
6
+ export type StarterLook = { readonly kind: "token"; readonly label: string } | { readonly kind: "child"; readonly parent: string };
7
+
8
+ const TOKEN_PREFIX = "token:";
9
+ const CHILD_PREFIX = "agent:";
10
+
11
+ export const starterLook = (startedBy: string | undefined): StarterLook | undefined => {
12
+ if (startedBy?.startsWith(TOKEN_PREFIX) === true) {
13
+ return { kind: "token", label: startedBy.slice(TOKEN_PREFIX.length) };
14
+ }
15
+ if (startedBy?.startsWith(CHILD_PREFIX) === true) {
16
+ return { kind: "child", parent: startedBy.slice(CHILD_PREFIX.length) };
17
+ }
18
+ return undefined;
19
+ };
20
+
21
+ // The conversation that spawned this one, when one did. A fact apart from whose it is: a child inherits its parent's
22
+ // owner, so on the reader's own work an ownership mark would never get to say it.
23
+ export const parentOf = (startedBy: string | undefined): string | undefined => {
24
+ const look = starterLook(startedBy);
25
+ return look?.kind === "child" ? look.parent : undefined;
26
+ };
@@ -648,7 +648,8 @@
648
648
  },
649
649
  "headers": [
650
650
  "x-intentic-preview",
651
- "x-intentic-preview-unreachable"
651
+ "x-intentic-preview-unreachable",
652
+ "x-intentic-listener"
652
653
  ],
653
654
  "toNode": {
654
655
  "$defs": {
@@ -41,7 +41,7 @@ export type NetdAnswer = { "answer": "sync", generations: Array<number | null>,
41
41
  * Request headers only netd sets on what it forwards to Node; it strips them from everything arriving outside.
42
42
  * Exported as a literal type, so a Node constant naming one that drifts from this spelling fails to compile.
43
43
  */
44
- export type NetdHeader = "x-intentic-preview" | "x-intentic-preview-unreachable";
44
+ export type NetdHeader = "x-intentic-preview" | "x-intentic-preview-unreachable" | "x-intentic-listener";
45
45
 
46
46
  /**
47
47
  * A question Node asks netd.
@@ -0,0 +1,57 @@
1
+ // WHETHER A PERSONA LETS A TURN ACT THROUGH ONE CONNECTED CAPABILITY. Pure and shared, because the daemon mounts a turn's
2
+ // tools on this answer (personas/personas.ts `turnPersona`) and the Sandbox ▸ Map view draws who reaches what from it,
3
+ // and two implementations would disagree at exactly the boundary that matters.
4
+
5
+ // The two fields of a connection the rule reads; structural, so neither side has to hand over its own record type.
6
+ export interface CapabilityRef {
7
+ readonly id: string;
8
+ readonly kind: string;
9
+ }
10
+
11
+ // The persona's shelves the rule reads, fully resolved (PersonaPowersSchema's defaults applied): a list absent means
12
+ // every connection of its kind, an empty one none.
13
+ export interface PersonaShelves {
14
+ readonly sandbox: boolean;
15
+ readonly delegate: boolean;
16
+ readonly connectors?: readonly string[] | undefined;
17
+ readonly devices?: readonly string[] | undefined;
18
+ readonly mcp?: readonly string[] | undefined;
19
+ }
20
+
21
+ /** The kinds that are someone signed in: a site account, and the identity whose browser holds every account born of it. */
22
+ export const isSignedInAccount = (kind: string): boolean => kind === "browser" || kind === "identity";
23
+
24
+ const listed = (list: readonly string[] | undefined, id: string): boolean => list === undefined || list.includes(id);
25
+
26
+ /**
27
+ * Whether a persona carrying these accounts (its `capabilities`) and these shelves may act through a capability. A kind
28
+ * absent from the switch (an agent runtime, a devops entry, a VPN) passes untouched, so a new kind is never silently
29
+ * denied.
30
+ */
31
+ export const personaAllowsCapability = (capability: CapabilityRef, accounts: readonly string[], shelves: PersonaShelves): boolean => {
32
+ switch (capability.kind) {
33
+ // The signed-in browsers: the persona's own `capabilities` list, and the field that predates the shelves. Granting
34
+ // an account (`reddit-work`) grants its hands; granting the identity itself grants the someone.
35
+ case "browser":
36
+ case "identity":
37
+ return accounts.includes(capability.id);
38
+ // Connector credentials reach the shell; an ungranted id keeps its env vars out of the turn entirely.
39
+ case "cli":
40
+ return listed(shelves.connectors, capability.id);
41
+ // A phone is one of the owner's own devices, on the same shelf as their computers.
42
+ case "device":
43
+ case "phone":
44
+ return listed(shelves.devices, capability.id);
45
+ case "mcp":
46
+ return listed(shelves.mcp, capability.id);
47
+ // Making sandboxes on the owner's account is administering what this one runs beside: the sandbox shelf.
48
+ case "fleet":
49
+ return shelves.sandbox;
50
+ // Another of the owner's sandboxes sits on the devices list beside their computers, picked one by one, and handing
51
+ // it a task is delegating, as spawning a subagent is.
52
+ case "link":
53
+ return shelves.delegate && listed(shelves.devices, capability.id);
54
+ default:
55
+ return true;
56
+ }
57
+ };