@xingular/harness 1.2.0 → 1.3.1-unstable.1
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/CHANGELOG.md +63 -0
- package/README.md +26 -17
- package/builtin/skills/plugin-authoring/SKILL.md +34 -0
- package/dist/cli.js +7362 -6239
- package/dist/sdk/agents/builtin.js +3 -3
- package/dist/sdk/agents/planResearch.d.ts +23 -1
- package/dist/sdk/agents/planResearch.js +71 -8
- package/dist/sdk/agents/profiles.d.ts +16 -4
- package/dist/sdk/agents/profiles.js +75 -12
- package/dist/sdk/annotations/bridge.d.ts +2 -0
- package/dist/sdk/annotations/bridge.js +4 -0
- package/dist/sdk/annotations/capture.d.ts +44 -2
- package/dist/sdk/annotations/capture.js +104 -3
- package/dist/sdk/annotations/delivery.d.ts +24 -17
- package/dist/sdk/annotations/delivery.js +82 -49
- package/dist/sdk/annotations/inspect.js +7 -6
- package/dist/sdk/annotations/pageScript.js +4 -4
- package/dist/sdk/annotations/part.d.ts +0 -2
- package/dist/sdk/annotations/part.js +4 -33
- package/dist/sdk/annotations/queue.d.ts +2 -2
- package/dist/sdk/annotations/queue.js +12 -7
- package/dist/sdk/annotations/serverMethods.js +11 -7
- package/dist/sdk/annotations/store.d.ts +13 -21
- package/dist/sdk/annotations/store.js +47 -37
- package/dist/sdk/capabilities/runSnapshot.js +10 -4
- package/dist/sdk/commands/list.js +2 -0
- package/dist/sdk/commands/registry.d.ts +11 -3
- package/dist/sdk/commands/registry.js +3 -2
- package/dist/sdk/core/links.d.ts +51 -0
- package/dist/sdk/core/links.js +155 -0
- package/dist/sdk/core/shell.d.ts +20 -0
- package/dist/sdk/core/shell.js +73 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +17 -1
- package/dist/sdk/core/workspaceBashTool.js +16 -2
- package/dist/sdk/core/workspaceSandbox.d.ts +10 -0
- package/dist/sdk/core/workspaceSandbox.js +52 -12
- package/dist/sdk/core/workspaceWriteOperations.d.ts +11 -0
- package/dist/sdk/core/workspaceWriteOperations.js +26 -8
- package/dist/sdk/doctor/checks.js +71 -12
- package/dist/sdk/harness.d.ts +5 -0
- package/dist/sdk/harness.js +11 -6
- package/dist/sdk/hub/hub.js +5 -3
- package/dist/sdk/index.d.ts +3 -2
- package/dist/sdk/index.js +2 -1
- package/dist/sdk/plugins/builtin.js +14 -9
- package/dist/sdk/plugins/builtinRegistry.d.ts +3 -1
- package/dist/sdk/plugins/builtinRegistry.js +9 -3
- package/dist/sdk/plugins/discover.d.ts +7 -1
- package/dist/sdk/plugins/discover.js +41 -2
- package/dist/sdk/plugins/identity.js +1 -1
- package/dist/sdk/plugins/install.d.ts +6 -2
- package/dist/sdk/plugins/install.js +29 -5
- package/dist/sdk/plugins/inventory.js +3 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +21 -4
- package/dist/sdk/plugins/plugins.d.ts +2 -0
- package/dist/sdk/plugins/plugins.js +1 -0
- package/dist/sdk/plugins/proposals.d.ts +17 -0
- package/dist/sdk/plugins/proposals.js +147 -0
- package/dist/sdk/plugins/types.d.ts +1 -1
- package/dist/sdk/plugins/types.js +1 -1
- package/dist/sdk/prompt/compile.d.ts +13 -4
- package/dist/sdk/prompt/compile.js +46 -20
- package/dist/sdk/prompt/standard.d.ts +1 -1
- package/dist/sdk/prompt/standard.js +1 -1
- package/dist/sdk/server/methods.js +14 -2
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +3 -3
- package/dist/sdk/sessions/compactionCheckpoint.js +12 -12
- package/dist/sdk/sessions/continuation.d.ts +4 -2
- package/dist/sdk/sessions/continuation.js +7 -6
- package/dist/sdk/sessions/contracts.d.ts +22 -4
- package/dist/sdk/sessions/contracts.js +12 -7
- package/dist/sdk/sessions/planMode.js +2 -2
- package/dist/sdk/sessions/runStore.js +3 -1
- package/dist/sdk/sessions/runner.js +2 -2
- package/dist/sdk/sessions/sessionState.d.ts +13 -0
- package/dist/sdk/sessions/sessionState.js +31 -0
- package/dist/sdk/sessions/sessions.d.ts +7 -0
- package/dist/sdk/sessions/sessions.js +73 -15
- package/dist/sdk/sessions/subagentService.d.ts +15 -0
- package/dist/sdk/sessions/subagentService.js +195 -55
- package/dist/sdk/sessions/subagents.d.ts +10 -1
- package/dist/sdk/sessions/subagents.js +4 -0
- package/dist/sdk/sessions/workSlice.d.ts +8 -5
- package/dist/sdk/sessions/workSlice.js +77 -45
- package/dist/sdk/terminal/controller.d.ts +20 -0
- package/dist/sdk/terminal/controller.js +43 -18
- package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
- package/dist/sdk/terminal/opentui/ansi.js +192 -0
- package/dist/sdk/terminal/opentui/model.d.ts +163 -0
- package/dist/sdk/terminal/opentui/model.js +482 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
- package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
- package/dist/sdk/terminal/opentui/theme.d.ts +2 -0
- package/dist/sdk/terminal/opentui/theme.js +2 -0
- package/dist/sdk/terminal/piExtension.js +98 -15
- package/dist/sdk/terminal/subagentMonitor.d.ts +17 -4
- package/dist/sdk/terminal/subagentMonitor.js +29 -8
- package/dist/sdk/terminal/terminals.d.ts +16 -0
- package/dist/sdk/terminal/terminals.js +130 -26
- package/dist/sdk/terminal/trajectory.d.ts +6 -1
- package/dist/sdk/terminal/trajectory.js +8 -0
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +5 -1
- package/dist/sdk/terminal/tui/annotateCommand.js +21 -7
- package/dist/sdk/terminal/tui/annotateSend.d.ts +30 -0
- package/dist/sdk/terminal/tui/annotateSend.js +40 -0
- package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
- package/dist/sdk/terminal/tui/chrome.js +13 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +1 -1
- package/dist/sdk/terminal/tui/commandPages.js +16 -11
- package/dist/sdk/terminal/tui/commands.d.ts +4 -0
- package/dist/sdk/terminal/tui/commands.js +12 -2
- package/dist/sdk/terminal/tui/dialogs.js +1 -0
- package/dist/sdk/terminal/tui/pageOverlay.d.ts +3 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +25 -7
- package/dist/sdk/terminal/tui/pages/agentsPage.js +5 -2
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +70 -16
- package/dist/sdk/terminal/tui/pages/annotatePage.js +349 -115
- package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
- package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +295 -25
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +8 -5
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +4 -2
- package/dist/sdk/terminal/tui/pages/usagePage.js +39 -12
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +1 -1
- package/dist/sdk/terminal/tui/pluginCommands.js +13 -3
- package/dist/sdk/tools/defaultSkills.d.ts +4 -0
- package/dist/sdk/tools/defaultSkills.js +20 -0
- package/dist/sdk/tools/definitions.d.ts +3 -1
- package/dist/sdk/tools/definitions.js +17 -1
- package/dist/sdk/tools/dispatch.js +12 -0
- package/dist/sdk/tools/harnessTools.js +1 -1
- package/dist/sdk/tools/sessionName.d.ts +9 -0
- package/dist/sdk/tools/sessionName.js +58 -11
- package/dist/sdk/tools/spawnSubagent.js +9 -7
- package/dist/sdk/tools/todo.d.ts +15 -0
- package/dist/sdk/tools/todo.js +64 -0
- package/dist/sdk/world/world.d.ts +0 -2
- package/dist/terminal-opentui.js +3331 -1584
- package/dist/terminal-pi.js +421 -133
- package/docs/README.md +3 -0
- package/docs/architecture/00-overview.md +1 -1
- package/docs/architecture/01-extension-points.md +1 -1
- package/docs/architecture/02-sessions-and-runs.md +73 -36
- package/docs/architecture/03-variants.md +1 -3
- package/docs/architecture/04-prompt.md +24 -13
- package/docs/architecture/06-plugins-and-capabilities.md +46 -10
- package/docs/architecture/07-tools-and-gate.md +49 -8
- package/docs/architecture/09-accounts-and-connectors.md +8 -2
- package/docs/architecture/10-server-protocol.md +68 -16
- package/docs/architecture/11-terminal.md +94 -45
- package/docs/architecture/12-storage.md +1 -0
- package/docs/architecture/13-world-tools.md +8 -6
- package/docs/architecture/14-surfaces-and-parity.md +4 -1
- package/docs/architecture/README.md +20 -18
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +6 -2
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +32 -21
- package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
- package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
- package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
- package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
- package/docs/architecture/proposals/PROP-0048-simple-annotate.md +85 -0
- package/docs/architecture/proposals/README.md +11 -6
- package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
- package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
- package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
- package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
- package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
- package/docs/decisions/ADR-0044-annotations-pending-or-sent.md +24 -0
- package/docs/decisions/ADR-0045-default-plugin-authoring-skill.md +9 -0
- package/docs/decisions/ADR-0046-hash-bound-plugin-proposals.md +20 -0
- package/docs/decisions/ADR-0047-links-open-with-the-os-handler.md +47 -0
- package/docs/doctor.md +14 -1
- package/docs/parity.md +16 -13
- package/docs/releases/1.3.0.md +21 -0
- package/docs/releases/1.3.1-unstable.1.md +8 -0
- package/docs/releases/README.md +9 -6
- package/docs/terminal-tui.md +127 -65
- package/package.json +1 -1
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +0 -75
- package/dist/sdk/terminal/tui/pages/notesPage.js +0 -201
- package/dist/sdk/tools/checklist.d.ts +0 -9
- package/dist/sdk/tools/checklist.js +0 -55
|
@@ -59,8 +59,9 @@ mechanism below is **run execution**, which the harness owns.
|
|
|
59
59
|
|
|
60
60
|
A foundation policy, on by default for every run (interactive, automatic, plan, probe, subagent):
|
|
61
61
|
|
|
62
|
-
- `workSlice.enabled` true; `workSlice.maxToolCalls`
|
|
63
|
-
`workSlice.maxNewTokens`
|
|
62
|
+
- `workSlice.enabled` true; `workSlice.maxToolCalls` 320, `workSlice.maxMinutes` 60,
|
|
63
|
+
`workSlice.maxNewTokens` 0, so no token cap by default (the values were raised by PROP-0044).
|
|
64
|
+
`enabled: false`, or `XINGULAR_WORK_SLICE=off` at launch,
|
|
64
65
|
removes the guard from a run: no budget, no stall notes, no continuation. Any
|
|
65
66
|
limit reached, or `0` to disable that one, ends the slice. A token cap counts new input, cache
|
|
66
67
|
writes and output; counting the cached prefix made one large read end a reply before any work
|
|
@@ -120,20 +121,29 @@ A foundation extension (`src/sessions/workSlice.ts`), registered where the compa
|
|
|
120
121
|
- Signatures are `toolName + canonicalised args`, hashed, so every argument participates and a
|
|
121
122
|
changed argument (a checklist whose steps moved on, a different path) is a different call. Detect,
|
|
122
123
|
per reply:
|
|
123
|
-
- the same signature 3 times (`checkpoint_write
|
|
124
|
-
`subagents.*` polling exempt);
|
|
125
|
-
- the same Bash
|
|
126
|
-
-
|
|
127
|
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
-
|
|
135
|
-
|
|
136
|
-
|
|
124
|
+
- the same signature 3 times (`checkpoint_write` and `session_name` are handoff calls when a
|
|
125
|
+
checkpoint is available; `todo_write`, `wait_subagents` and `subagents.*` polling are exempt);
|
|
126
|
+
- the same Bash check failing twice;
|
|
127
|
+
- four successful native `edit`/`write` results on one path without an intervening passing check;
|
|
128
|
+
the next edit attempt is refused, and a further trigger ends the slice;
|
|
129
|
+
- context-compaction thrash at the third compaction.
|
|
130
|
+
- Only a `tool_result` with `isError === false` and a path counts as a successful edit or write. A
|
|
131
|
+
failed or blocked attempt consumes no edit-churn allowance. A successful edit/write clears failed
|
|
132
|
+
check counts, exact-repeat counts for Bash check calls, and the pending nudge so that a fixed check
|
|
133
|
+
may run against changed code. It leaves per-file edit counts and exact-repeat counts for other
|
|
134
|
+
calls intact. A passing check clears edit churn and the reply's repetition state.
|
|
135
|
+
- There is no general 25-call file-change/check no-progress trigger. The work-slice call/time budget
|
|
136
|
+
and the targeted repeated-call, repeated-failing-check, edit-churn and compaction-thrash protections
|
|
137
|
+
remain. `todo_write` is excluded from repeated-call detection and does not reset loop state, but it
|
|
138
|
+
remains subject to the tool-call budget. Counts and the nudge start fresh in each reply, because
|
|
139
|
+
each reply is one slice.
|
|
140
|
+
- With `checkpoint_write`, the first targeted trigger is refused with a bounded nudge; repeating the
|
|
141
|
+
trigger ends the reply as `stalled` and the runner derives a checkpoint when the model wrote none.
|
|
142
|
+
A plan-research child keeps its frozen read-only capability set even though it lacks
|
|
143
|
+
`checkpoint_write`: it receives the same configured work-slice bound, is told to stop and return a
|
|
144
|
+
concise partial research report on its first budget or stall refusal, and a further tool call ends
|
|
145
|
+
the reply. The runner records an evidence-derived checkpoint; the child is not auto-continued and
|
|
146
|
+
receives no additional tool or connector permission.
|
|
137
147
|
|
|
138
148
|
### 5. Command budget
|
|
139
149
|
|
|
@@ -194,7 +204,7 @@ A foundation extension (`src/sessions/workSlice.ts`), registered where the compa
|
|
|
194
204
|
## Consequences
|
|
195
205
|
|
|
196
206
|
- More runs per long task, each with its own record and pins. Continuation already supports this, so
|
|
197
|
-
session and thread views group them; a person sees a checkpoint every ≤
|
|
207
|
+
session and thread views group them; a person sees a checkpoint every ≤ 60 minutes instead of
|
|
198
208
|
nothing.
|
|
199
209
|
- Two new tools/events and two new settings, which the App must present for parity. The compiled tool
|
|
200
210
|
manifest gains one entry, which changes the provider-cache prefix once (INV-PRM-8: measure with real
|
|
@@ -230,10 +240,11 @@ Implemented in this tree:
|
|
|
230
240
|
|
|
231
241
|
- `checkpoint_write` (`src/tools/checkpoint.ts`) with its plugin descriptor, frozen capability entry,
|
|
232
242
|
prompt group and terminal socket bridge; the run records `checkpoint`.
|
|
233
|
-
- The slice guard (`src/sessions/workSlice.ts`): budget refusal, checkpoint
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
243
|
+
- The slice guard (`src/sessions/workSlice.ts`): budget refusal, checkpoint-aware handoff, targeted
|
|
244
|
+
repeated-call and repeated-failure notes, success-only edit churn with progress-aware check retry
|
|
245
|
+
resets, compaction-thrash guard, and per-reply reset. The broad file/check no-progress trigger is
|
|
246
|
+
removed; plan-research children without `checkpoint_write` use the derived-checkpoint handoff and
|
|
247
|
+
the same configured bounds without gaining tools. Wired for structured and terminal replies.
|
|
237
248
|
- The runner's `heartbeat`, derived fallback checkpoint, `slice_complete`/`stalled` terminal reasons
|
|
238
249
|
and the third `finish` argument.
|
|
239
250
|
- Auto-continue with `maxSlices` 8, a fruitless-slice stop and a blocked stop, off for automatic,
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: PROP-0044
|
|
3
|
+
title: Raise the work-slice defaults to 320 tool calls and 60 minutes, with no token cap
|
|
4
|
+
status: Accepted
|
|
5
|
+
created: 2026-10-26
|
|
6
|
+
updated: 2026-10-26
|
|
7
|
+
affects: [INV-RUN-13, 02-sessions-and-runs.md, 10-server-protocol.md, 11-terminal.md, PROP-0041]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PROP-0044: Raise the work-slice defaults to 320 tool calls and 60 minutes, with no token cap
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
`DEFAULT_SLICE_POLICY` (`src/sessions/workSlice.ts`) and `INV-RUN-13` set 160 tool calls, 40 minutes
|
|
15
|
+
and 320 000 new tokens, whichever comes first. Two of those defaults are wrong for ordinary work.
|
|
16
|
+
|
|
17
|
+
- **The token cap is the earliest limit, and it is not the bound it claims to be.** Its own comment
|
|
18
|
+
called 320 000 "a safety net, not the bound", yet it counts new input, cache writes and output, so a
|
|
19
|
+
few large reads in a big context cross it before the work is done. The "Confirm plan model support"
|
|
20
|
+
thread counted 76 807 new tokens after four requests, and `workSlice.test.ts` still carried a case
|
|
21
|
+
asserting a 320k stop. A cap that fires on reading is a false stop, and the stall rules — not the
|
|
22
|
+
token count — are what detect an unbounded reply.
|
|
23
|
+
- **40 minutes is tighter than the field and tighter than the evidence.** The measured failure in
|
|
24
|
+
STUDY-0003 was a reply that ran 114 minutes with no text and 448 calls, not one that ran 40 minutes.
|
|
25
|
+
OpenHands allows 500 agent steps per run by default; Claude's Agent SDK has no default `maxTurns`;
|
|
26
|
+
Cursor documents no tool-call limit; SWE-agent's caps are benchmark stops ($3, 1800 s) that
|
|
27
|
+
auto-submit and exit. A checkpoint every 40 minutes turns one healthy task into a series of runs
|
|
28
|
+
without a measured benefit.
|
|
29
|
+
|
|
30
|
+
The rule stays: a reply is bounded and hands off. What changes is where the boundary sits.
|
|
31
|
+
|
|
32
|
+
## Affected rules
|
|
33
|
+
|
|
34
|
+
- **INV-RUN-13** says: "The foundation defaults are 160 tool calls, 40 minutes and 320 000 new tokens,
|
|
35
|
+
whichever comes first." The invariant's requirement — a bounded reply, a handoff at the limit and a
|
|
36
|
+
continuation — is unchanged; its stated numbers and the default token cap change.
|
|
37
|
+
- **PROP-0041** §1 states the same numbers and §Consequences says "a checkpoint every ≤ 40 minutes";
|
|
38
|
+
both are corrected to point here.
|
|
39
|
+
|
|
40
|
+
## Proposal
|
|
41
|
+
|
|
42
|
+
`DEFAULT_SLICE_POLICY` becomes:
|
|
43
|
+
|
|
44
|
+
| Setting | Was | Now |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `maxToolCalls` | 160 | **320** |
|
|
47
|
+
| `maxMinutes` | 40 | **60** |
|
|
48
|
+
| `maxNewTokens` | 320 000 | **0** (no cap) |
|
|
49
|
+
| `maxSlices` | 8 | 8 (unchanged) |
|
|
50
|
+
| `continue` | true | true (unchanged) |
|
|
51
|
+
|
|
52
|
+
- Calls and the clock are the bound, whichever comes first: about 80 minutes of ordinary work at 15 s a
|
|
53
|
+
call, with 60 minutes as the ceiling.
|
|
54
|
+
- A token cap stays available to whoever wants a cost ceiling: `workSlice.maxNewTokens` per run, still
|
|
55
|
+
counted on new input, cache writes and output and never on the cached prefix.
|
|
56
|
+
- Nothing else changes: the refusal and `checkpoint_write`, the exemption for a handoff call, the
|
|
57
|
+
stall rules and their per-reply reset, the terminal's behaviour, and automatic continuation.
|
|
58
|
+
|
|
59
|
+
## Alternatives
|
|
60
|
+
|
|
61
|
+
- **Do nothing.** Rejected: the token cap was the first limit a large read crossed, and its stop is
|
|
62
|
+
visible to the person as an arbitrary end of a useful reply.
|
|
63
|
+
- **Keep a 320 000 safety net and raise only the calls and the clock.** Rejected: the same false stop
|
|
64
|
+
stays, and two limits that are never reached in ordinary work are enough.
|
|
65
|
+
- **Turn the guard off by default.** Rejected for now: the stall rules are the evidence-backed part
|
|
66
|
+
(repeated identical calls, repeated failures, edit churn, compaction thrash), and the budget itself
|
|
67
|
+
is what bounds a reply. Only its size changes.
|
|
68
|
+
- **Bound cost in dollars instead of tokens.** Not adopted here: the harness records cost per request,
|
|
69
|
+
but a dollar ceiling belongs with the account's usage limits (`usage/limits`, PROP-0042), not with a
|
|
70
|
+
reply's work slice.
|
|
71
|
+
|
|
72
|
+
## Consequences
|
|
73
|
+
|
|
74
|
+
- A healthy task reaches its first checkpoint after roughly 80 minutes of ordinary work instead of 40,
|
|
75
|
+
and no token count ends a reply on its own. The longest a task runs unattended is still eight slices,
|
|
76
|
+
so the slice cap now allows up to about eight hours instead of about five.
|
|
77
|
+
- With no token cap, only calls and time bound an expensive reply; a person who wants a token ceiling
|
|
78
|
+
sets one, and the heartbeat still reports `steps` against `maxToolCalls`.
|
|
79
|
+
- No stored-data, protocol or event change: an absent `workSlice` simply resolves to the new defaults,
|
|
80
|
+
and a run already recorded keeps the policy it ran under.
|
|
81
|
+
|
|
82
|
+
## Migration
|
|
83
|
+
|
|
84
|
+
None. Undo by restoring the three values in `DEFAULT_SLICE_POLICY`, or by passing `workSlice` on
|
|
85
|
+
`sessions.run`. A continuation inherits the policy as it always did.
|
|
86
|
+
|
|
87
|
+
## Checks
|
|
88
|
+
|
|
89
|
+
- `npx vitest run src/sessions/workSlice.test.ts src/sessions/sessions.test.ts` (the defaults
|
|
90
|
+
assertion and the limit-selection test change with the values; the token-cap test keeps an explicit
|
|
91
|
+
override)
|
|
92
|
+
- `npm run typecheck`, `npm test`, `npm run prove`
|
|
93
|
+
- App: `npm run typecheck`, `npm test`, `npm run check:layers`, `cd src-tauri && cargo test`
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: PROP-0045
|
|
3
|
+
title: Rename the run checklist to todo and add the /todo command
|
|
4
|
+
status: Accepted; implemented
|
|
5
|
+
created: 2026-10-26
|
|
6
|
+
updated: 2026-10-26
|
|
7
|
+
affects: [02-sessions-and-runs.md, 04-prompt.md, 06-plugins-and-capabilities.md, 07-tools-and-gate.md, 10-server-protocol.md, 11-terminal.md, 14-surfaces-and-parity.md, parity.md, terminal-tui.md, README.md, PROP-0006]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PROP-0045: Rename the run checklist to todo and add the /todo command
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
One run concept is named "checklist": the `checklist_write` tool, its `checklist.updated` event,
|
|
15
|
+
`ChecklistItem`, `checklistOf`, the `todo` list's `runs.checklist` method, the `checklist` field of
|
|
16
|
+
`runs.continuation`, the `checklist` plugin, and the terminal's checklist block and `checklist`
|
|
17
|
+
telemetry. Every agent framework a person meets elsewhere calls the same idea a todo list, and
|
|
18
|
+
Claude Code's `/todos` made the word familiar: `todo`, `todo_write`, `/todo`. PROP-0006 chose
|
|
19
|
+
"checklist" explicitly to avoid an application concept (`PROP-0006-run-checklist.md:28`), but
|
|
20
|
+
"todo" is generic vocabulary, not a product name, and the current name makes the tool harder to
|
|
21
|
+
recognise for both the model and the person.
|
|
22
|
+
|
|
23
|
+
The list is also only visible where the model last wrote it: the terminal transcript and (nowhere) in
|
|
24
|
+
the App. A person who scrolled past a write, resumed a session, or is watching a long reply has no
|
|
25
|
+
way to ask for the current list. The terminal already has a slash-command surface for this kind of
|
|
26
|
+
read (`/help`, `/subagents`, `/trajectory`); there is no `/todo`.
|
|
27
|
+
|
|
28
|
+
## Affected rules
|
|
29
|
+
|
|
30
|
+
- **02-sessions-and-runs.md, Data** defines `checklist.updated` and `checklistOf(events)`.
|
|
31
|
+
- **04-prompt.md** defines the Progress paragraph that names `checklist_write`.
|
|
32
|
+
- **07-tools-and-gate.md** defines `checklistTool` and its event.
|
|
33
|
+
- **10-server-protocol.md** defines `runs.checklist`.
|
|
34
|
+
- **11-terminal.md** defines the checklist block, the telemetry call and the terminal's tool.
|
|
35
|
+
- **14-surfaces-and-parity.md** and **parity.md** (PAR-001) define the terminal and App surfaces.
|
|
36
|
+
- No invariant's rule changes: the tool remains read-only and plan-safe, the event remains a
|
|
37
|
+
whole-list replacement, and the list remains one bounded run event. Only the names and one added
|
|
38
|
+
read command change.
|
|
39
|
+
|
|
40
|
+
## Proposal
|
|
41
|
+
|
|
42
|
+
### 1. The concept is named todo
|
|
43
|
+
|
|
44
|
+
| Was | Becomes |
|
|
45
|
+
|---|---|
|
|
46
|
+
| tool `checklist_write` | `todo_write` |
|
|
47
|
+
| event `checklist.updated` | `todo.updated` |
|
|
48
|
+
| `ChecklistItem`, `checklistItemSchema`, `MAX_CHECKLIST_ITEMS` | `TodoItem`, `todoItemSchema`, `MAX_TODO_ITEMS` |
|
|
49
|
+
| `checklistOf`, `describeChecklist`, `checklistTool` | `todoOf`, `describeTodo`, `todoTool` |
|
|
50
|
+
| plugin id `checklist`, title "Checklist" | plugin id `todo`, title "Todo" |
|
|
51
|
+
| method `runs.checklist { runId }` | `runs.todo { runId }` |
|
|
52
|
+
| `Continuation.checklist` | `Continuation.todo` |
|
|
53
|
+
| terminal telemetry `checklist` | `terminal.todo` |
|
|
54
|
+
| transcript kind `checklist`, header "Checklist" | kind `todo`, header "Todo" |
|
|
55
|
+
| `TerminalSubagentActivity.checklist` | `.todo` |
|
|
56
|
+
|
|
57
|
+
The tool keeps its behaviour: the model sends the whole list, the latest event replaces every
|
|
58
|
+
earlier one, at most 50 items, `pending`, `in_progress` and `completed`, read-only for the gate and
|
|
59
|
+
allowed in plan mode. The prompt's Progress paragraph asks for a todo list in the same places.
|
|
60
|
+
|
|
61
|
+
### 2. `/todo` shows the current list
|
|
62
|
+
|
|
63
|
+
`/todo` is a core command (`src/commands/registry.ts`), `group: 'Inspect'`, `kind: 'session'`,
|
|
64
|
+
`methods: ['runs.todo']`, with `/checklist` as a compatibility alias for one release.
|
|
65
|
+
|
|
66
|
+
- It reads the latest non-side-question run of the current native session and returns that run's
|
|
67
|
+
latest todo. It makes no model request, asks for no approval, and is available in plan mode.
|
|
68
|
+
- The terminal appends a snapshot card to the transcript: `Todo · n of m done`, then one row per
|
|
69
|
+
item with the existing glyphs and colours (`✓` completed, `●` in progress, `○` pending). An empty
|
|
70
|
+
list is a one-line notice, not an empty card.
|
|
71
|
+
- The App offers the same read through `runs.todo` as a read-only picker with the same marks. It does
|
|
72
|
+
not render each `todo_write` in its transcript; that presentation difference is recorded in
|
|
73
|
+
PAR-001.
|
|
74
|
+
|
|
75
|
+
### 3. Compatibility
|
|
76
|
+
|
|
77
|
+
Stored run events are never rewritten. For one minor release:
|
|
78
|
+
|
|
79
|
+
- `runEventTypeSchema` accepts `checklist.updated` beside `todo.updated`, both with the same payload;
|
|
80
|
+
`todoOf` reads both. New events are written only as `todo.updated`.
|
|
81
|
+
- A replayed native history whose tool call is `checklist_write` still renders the todo card.
|
|
82
|
+
- `runs.checklist` remains as a deprecated alias returning the same list as `runs.todo`.
|
|
83
|
+
- `runs.continuation` returns `todo` and keeps `checklist` as a deprecated mirror field.
|
|
84
|
+
- A pinned capability set containing `checklist_write` is read as `todo_write`, so an interrupted
|
|
85
|
+
run recorded before the rename can still continue with a todo tool.
|
|
86
|
+
- The exported `checklistOf` and `CHECKLIST_WRITE` names stay as deprecated aliases for embedders.
|
|
87
|
+
|
|
88
|
+
The aliases and the legacy event type can be removed in the next major release.
|
|
89
|
+
|
|
90
|
+
## Alternatives
|
|
91
|
+
|
|
92
|
+
- **Rename only the labels the person sees.** Rejected: the tool name the model sees, the event, the
|
|
93
|
+
method and the docs would disagree, which is the drift the specification exists to prevent.
|
|
94
|
+
- **Keep both names indefinitely.** Rejected: two names for one concept in the prompt and the
|
|
95
|
+
protocol, and a permanent compatibility branch. One release is enough for stored data that is
|
|
96
|
+
never rewritten.
|
|
97
|
+
- **Rewrite stored events to the new type.** Rejected: `events.jsonl` is append-only evidence; a
|
|
98
|
+
read alias is enough and cannot corrupt a run.
|
|
99
|
+
- **Make `/todo` a live panel or a full-screen page.** Rejected for this change: a transcript
|
|
100
|
+
snapshot matches `/help`, reuses the existing block, and leaves the person's scrollback intact.
|
|
101
|
+
A live panel can be a later presentation change; it is not needed to show the list.
|
|
102
|
+
- **Do nothing.** Rejected by the owner's request and by the missing read surface.
|
|
103
|
+
|
|
104
|
+
## Consequences
|
|
105
|
+
|
|
106
|
+
- One tool name and one prompt paragraph change, so the compiled tool manifest and the provider
|
|
107
|
+
cache prefix change once. The cost is measurable only with real requests (`INV-PRM-8`), and the
|
|
108
|
+
change does not alter any model-visible behaviour besides the name.
|
|
109
|
+
- Applications built on the harness keep working through the method, field and capability aliases;
|
|
110
|
+
they should move to the new names. The App's event schema accepts both event types, so old run logs
|
|
111
|
+
keep displaying.
|
|
112
|
+
- Runs created before the rename keep their recorded events. `todoOf` and the terminal renderer read
|
|
113
|
+
them without a rewrite.
|
|
114
|
+
- PAR-001 narrows: both surfaces can now show the current todo; the App still does not draw an inline
|
|
115
|
+
block for each write.
|
|
116
|
+
|
|
117
|
+
## Migration
|
|
118
|
+
|
|
119
|
+
No data migration and no file rewrite. Old events, old pinned capability sets and old native
|
|
120
|
+
histories are read through the aliases above. Rolling back is reverting the commit; new
|
|
121
|
+
`todo.updated` events would then need a reverse alias if they were already written, so the rollback
|
|
122
|
+
is safe only before new runs write the event.
|
|
123
|
+
|
|
124
|
+
## Checks
|
|
125
|
+
|
|
126
|
+
- `npm run typecheck`, `npm test`, `npm run prove`.
|
|
127
|
+
- New tests: the todo tool, a legacy `checklist.updated` read, a legacy pinned capability, the
|
|
128
|
+
`runs.todo` method and its alias, the terminal `/todo` card, and a replayed `checklist_write` call.
|
|
129
|
+
- `python3 scripts/verify-terminal.py --todo-only` at 80x24 and 100x30: the card, the alignment of
|
|
130
|
+
wrapped rows, and no model request for `/todo`.
|
|
131
|
+
- App: `npm run typecheck`, `npm test`, `npm run check:layers`, `npm run check:ui`,
|
|
132
|
+
`cd src-tauri && cargo test`.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: PROP-0046
|
|
3
|
+
title: Progress-aware stall guards and bounded plan research children
|
|
4
|
+
status: Implemented
|
|
5
|
+
created: 2026-10-27
|
|
6
|
+
updated: 2026-10-27
|
|
7
|
+
affects: [INV-RUN-13, 02-sessions-and-runs.md, PROP-0041, terminal-tui.md, ADR-0039]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PROP-0046: Progress-aware stall guards and bounded plan research children
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
The stall guard currently has a broad 25-call rule: it nudges after substantive calls without a file change or passing check. It is disabled for plan-mode research, but remains active for ordinary runs. A long, legitimate sequence of reads can be stopped in normal mode but not plan mode; the rule imposes a mode-specific file/check-progress boundary rather than detecting a loop.
|
|
15
|
+
|
|
16
|
+
Two targeted rules also ignore successful code changes. Failed-check counts and identical Bash-check calls can persist after an edit, so a fixed test command may be blocked even though its input code has changed. The per-file edit-churn count is incremented in `tool_call`, before the edit runs, so a denied or failed attempt can count as an edit.
|
|
17
|
+
|
|
18
|
+
Finally, plan-research children receive only the explicit read-only research tool intersection, which excludes `checkpoint_write` (`src/agents/planResearch.ts`). `Sessions` installs the work-slice guard only when that tool is in the frozen capability set (`src/sessions/sessions.ts`). These children consequently lack the call/time boundary that the work-slice proposal says applies to subagent runs. The terminal guide also says plan-mode shell commands are unavailable even though the parent may run OS-sandboxed read-only Bash (`docs/terminal-tui.md`; PROP-0043).
|
|
19
|
+
|
|
20
|
+
## Affected rules
|
|
21
|
+
|
|
22
|
+
- **INV-RUN-13** currently says: “The file-change/check-based no-progress detector does not apply to plan-mode read-only research.” This proposal removes the detector for all runs, rather than preserving a mode-specific exception. It also clarifies how successful edits affect the remaining stall counters and how a bounded child without `checkpoint_write` hands back.
|
|
23
|
+
- **PROP-0041, §4 Stall guard** currently includes “25 non-bookkeeping tool calls without a file change or passing check,” counts edit attempts before execution, and describes repeated Bash failures without resetting for a changed code state. Its stall-guard description must match the new rule.
|
|
24
|
+
- **INV-RUN-8** remains unchanged: plan-research children keep their existing frozen, read-only capability intersection, with no connectors, questions, writes, commands or nested subagents. The child work-slice bound does not add a tool or widen that set.
|
|
25
|
+
- **`docs/terminal-tui.md`** must distinguish the parent's sandboxed read-only Bash from the child's no-command restriction.
|
|
26
|
+
|
|
27
|
+
## Proposal
|
|
28
|
+
|
|
29
|
+
### 1. Remove the broad no-progress trigger
|
|
30
|
+
|
|
31
|
+
Remove the 25-call file-change/check detector from every run. Remove its counter and plan-mode exception; do not replace it with another general “no file change” threshold. The tool-call/time work-slice budget remains.
|
|
32
|
+
|
|
33
|
+
Keep the targeted stall protections: the same exact call signature still receives one nudge at its existing threshold and ends the reply on a subsequent trigger; the same Bash check failing twice remains a trigger; per-file edit churn remains limited to four successful edits without a passing check; and the existing third-compaction thrash guard remains. Todo bookkeeping remains exempt from repeated-call detection and remains counted toward the work-slice tool-call budget.
|
|
34
|
+
|
|
35
|
+
### 2. Tie check retries and edit churn to observed results
|
|
36
|
+
|
|
37
|
+
Use the post-execution `tool_result` for native `edit` and `write` tools. A result with `isError === false` and a path is a successful edit for this rule; a blocked or failed call does not count. After four successful edits to one path without a passing check, the next edit attempt for that path receives the existing nudge/block, and a further trigger ends the slice. A passing check continues to clear the per-file edit counts.
|
|
38
|
+
|
|
39
|
+
A successful native edit/write starts a fresh check-retry episode: clear failed-check counts, the exact-repeat count for Bash check calls, and the pending one-shot nudge so the same check can run against changed code. Exact-repeat protection remains active for unchanged code and for other calls. The successful-edit counts used by the per-file churn rule are not cleared by this reset; only a passing check clears them. Failed or denied edits reset none of these counters.
|
|
40
|
+
|
|
41
|
+
The cross-surface success signal is the tool result, not a byte-level file comparison. The guard must count only a confirmed non-error result and use its path; no filesystem watcher or new event schema is introduced.
|
|
42
|
+
|
|
43
|
+
### 3. Bound read-only plan-research children
|
|
44
|
+
|
|
45
|
+
When work-slice policy is enabled, attach the existing guard to plan-research child runs even when their frozen capabilities omit `checkpoint_write`. Use the existing policy/defaults (320 calls and 60 minutes, no token cap); inherit an explicit parent policy override. Plan and subagent runs still do not auto-continue.
|
|
46
|
+
|
|
47
|
+
A child without `checkpoint_write` must not be told to call an unavailable tool. The first budget or stall refusal tells it to stop using tools and return a concise partial research report; if it attempts another tool, the existing termination rule applies. The runner's existing evidence-derived checkpoint records the handoff when the model did not write one. The child receives no additional tool or connector permissions. This proposal bounds each child, not the aggregate number of siblings; the existing parent-controlled fan-out is unchanged. The time limit remains checked at tool-call boundaries and is not a cancellation timer for an in-flight tool.
|
|
48
|
+
|
|
49
|
+
### 4. Keep plan-mode action restrictions
|
|
50
|
+
|
|
51
|
+
Do not enable generic browser clicks or `mcp_call_tool` in plan mode. Existing per-call safety classifications and read-only restrictions remain unchanged. A future need for connected-app research must add server-validated read-only classification rather than admitting the generic broker call.
|
|
52
|
+
|
|
53
|
+
Clarify `docs/terminal-tui.md`: an interactive plan parent may run Bash in the OS-enforced read-only sandbox (PROP-0043); plan-research children still cannot run commands. Writes, network access and generic connected-app actions remain unavailable in plan mode.
|
|
54
|
+
|
|
55
|
+
## Alternatives
|
|
56
|
+
|
|
57
|
+
- **Keep the 25-call trigger outside plan mode.** Rejected: it still mistakes legitimate read/research sequences for lack of progress and preserves an arbitrary mode distinction.
|
|
58
|
+
- **Remove all stall protections.** Rejected: exact repeated calls, repeated failing checks, edit churn, compaction thrash detection and the independent work-slice budget remain useful, targeted bounds.
|
|
59
|
+
- **Give plan-research children `checkpoint_write` or broader tools.** Rejected: the existing derived-checkpoint path is sufficient and preserves the frozen read-only capability intersection.
|
|
60
|
+
- **Add a tighter child-only budget or sibling concurrency cap.** Deferred: this change applies the established work-slice policy per child; aggregate fan-out remains a separate decision.
|
|
61
|
+
- **Detect byte-level file changes.** Rejected for this change: the post-execution native tool result is the consistent signal available to the shared guard across surfaces.
|
|
62
|
+
|
|
63
|
+
## Consequences
|
|
64
|
+
|
|
65
|
+
A run may make any number of distinct reads without hitting a file/check-based no-progress stall, subject to the work-slice budget and the retained targeted loop protections. After a successful edit, the same Bash check can be retried against the changed code; unsuccessful edit attempts do not consume the four-edit churn allowance.
|
|
66
|
+
|
|
67
|
+
Plan-research children can stop at the same call/time boundary without receiving a new capability. A child that reaches the bound is recorded as an interrupted slice with the runner-derived checkpoint and can return partial findings; it is not automatically restarted. No server method, run-event schema, stored-data layout or App presentation changes are required. Existing plan-mode browser and connector restrictions remain in force.
|
|
68
|
+
|
|
69
|
+
This lasting foundation guardrail decision is recorded in [ADR-0039](../../decisions/ADR-0039-progress-aware-stall-guards.md).
|
|
70
|
+
|
|
71
|
+
## Migration
|
|
72
|
+
|
|
73
|
+
None. Existing run records and checkpoints remain readable. The proposal changes only future run behavior; no event or capability snapshot is rewritten. A child stopped at its slice boundary uses the existing `checkpoint` event and terminal reason contracts.
|
|
74
|
+
|
|
75
|
+
## Checks
|
|
76
|
+
|
|
77
|
+
After acceptance:
|
|
78
|
+
|
|
79
|
+
- Focused Harness tests: `npx vitest run src/sessions/workSlice.test.ts src/sessions/sessions.test.ts src/sessions/subagentService.test.ts src/sessions/planMode.test.ts`.
|
|
80
|
+
- Add regressions for more than 25 distinct reads in normal and plan runs; unchanged exact repeats; failures followed by a successful edit and a retry of the same Bash check; failed/blocked edits not counting; four successful edits to one path; and a plan child receiving a work-slice bound without gaining `checkpoint_write` or other tools, using a derived checkpoint and no auto-continuation.
|
|
81
|
+
- Run Harness `npm run typecheck`, `npm test`, `npm run prove`, and `git diff --check`.
|
|
82
|
+
- Run Xingular Agent `npm run typecheck`, `npm test`, `npm run check:layers`, and `cd src-tauri && cargo test`.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: PROP-0047
|
|
3
|
+
title: Separate local plugin management from Community Hub discovery
|
|
4
|
+
status: Implemented
|
|
5
|
+
created: 2026-10-27
|
|
6
|
+
updated: 2026-10-27
|
|
7
|
+
affects: [INV-MCP-4, INV-TUI-2, INV-TUI-4, INV-PAR-1/2, 06-plugins-and-capabilities.md, 09-accounts-and-connectors.md, 10-server-protocol.md, 11-terminal.md, 14-surfaces-and-parity.md, terminal-tui.md, parity.md]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PROP-0047: Separate local plugin management from Community Hub discovery
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
`/plugins` and `/hub` currently open the same `BrowserPage` (`src/terminal/tui/commandPages.ts`),
|
|
15
|
+
with different initial filters. That page combines local plugin controls with public catalog
|
|
16
|
+
browsing. Separate `PluginsPage` and `HubPage` implementations already exist but are not routed by
|
|
17
|
+
the commands. The App similarly presents local plugins and the public catalog in one Capability
|
|
18
|
+
Hub view.
|
|
19
|
+
|
|
20
|
+
The distinction matters operationally: direct plugin operations use `plugins.install`,
|
|
21
|
+
`plugins.update` and `plugins.remove`; catalog installs use exact Hub versions and create receipts
|
|
22
|
+
through `Hub.install`. A direct `plugins.remove` currently removes the package without updating a
|
|
23
|
+
Hub receipt (`src/server/methods.ts`, `src/plugins/install.ts`), whereas `Hub.uninstall` owns both
|
|
24
|
+
package removal and receipt cleanup (`src/hub/hub.ts`). Pi packages also have no JSON payload to
|
|
25
|
+
preview (`Hub.preview` rejects them), and a failed remote refresh must not make cached catalog data
|
|
26
|
+
look current or successful.
|
|
27
|
+
|
|
28
|
+
The requested product behavior is: `/plugins` manages local installed plugins and their package
|
|
29
|
+
lifecycle; `/hub` is a separate public-catalog page showing Community entries across supported
|
|
30
|
+
catalog types. Hub's Installed view retains receipts from every channel, labeled by channel. Opening
|
|
31
|
+
Hub first shows cached/bundled entries and then refreshes remotely, retaining visible origin and
|
|
32
|
+
stale/error status.
|
|
33
|
+
|
|
34
|
+
## Affected rules
|
|
35
|
+
|
|
36
|
+
The current terminal-page contract says that `/plugins` and `/hub` are shortcuts into the unified
|
|
37
|
+
resource browser (`docs/architecture/11-terminal.md`, “Resource browser”):
|
|
38
|
+
|
|
39
|
+
> `/skills`, `/plugins`, `/connections` (`/mcp`), `/tools`, `/hub` and `/components` are shortcuts into that browser.
|
|
40
|
+
|
|
41
|
+
The terminal guide also says the resource sections share Installed/Discover and source filters, and
|
|
42
|
+
that `/hub` selects Discover (`docs/terminal-tui.md`, “The Harness resource browser”). This proposal
|
|
43
|
+
replaces those two route-specific statements; the broad `/harness` browser remains available.
|
|
44
|
+
|
|
45
|
+
Receipt handling must continue to obey **INV-MCP-4**:
|
|
46
|
+
|
|
47
|
+
> Hub installation grants no attachment, trust, credential or permission. Writes are serialized;
|
|
48
|
+
> existing registry files are never overwritten; uninstall removes only the exact receipt's
|
|
49
|
+
> resources and revokes its attachment choices.
|
|
50
|
+
|
|
51
|
+
The proposal does not weaken **INV-PLG-3**: package installation runs no code and grants no
|
|
52
|
+
attachment, trust, credential or permission. Nor does it change **INV-TUI-4**: terminal mutations
|
|
53
|
+
continue through the control-key-protected routes. **INV-PAR-1/2** continue to require the same
|
|
54
|
+
capabilities and acceptance on terminal and host surfaces.
|
|
55
|
+
|
|
56
|
+
## Proposal
|
|
57
|
+
|
|
58
|
+
1. Route the direct terminal commands to distinct pages: `/plugins` to the local plugin manager and
|
|
59
|
+
`/hub` to the public Hub catalog. Keep `/harness` as the broader resource browser. The pages are
|
|
60
|
+
distinct presentations, not new capabilities or loaders.
|
|
61
|
+
2. The Plugins page manages local installed packages and their contributions: inventory, switching,
|
|
62
|
+
code trust, settings, direct package installation, update and removal. Public catalog discovery
|
|
63
|
+
is not part of this page. Ordinary local packages use the existing `plugins.*` services.
|
|
64
|
+
3. A package recorded in a Hub receipt is owned for removal by Hub: a `plugins.remove` request for
|
|
65
|
+
that package must go through Hub's receipt-aware uninstall path so the package and its exact
|
|
66
|
+
receipt cannot diverge. Do not use a floating `plugins.update` for a Hub-managed package. Its
|
|
67
|
+
replacement must be an explicit operation against an exact catalog version and must retain
|
|
68
|
+
receipt ownership; if no safe replacement operation exists, require uninstall then install of the
|
|
69
|
+
selected exact version.
|
|
70
|
+
4. The Hub page's Catalog view contains Community entries only, across catalog types supported by
|
|
71
|
+
the active product. This does not restore the deprecated agent-template application flow. The
|
|
72
|
+
Installed view contains receipts from all channels with the entry's channel visible; existing
|
|
73
|
+
Official receipts therefore remain reviewable and uninstallable. The underlying catalog and
|
|
74
|
+
`hub.list` contract remain unfiltered for other callers.
|
|
75
|
+
5. On Hub entry, load cached/bundled content first, then request a remote refresh. Keep the last
|
|
76
|
+
known entries and show whether they are remote, cached or bundled, when they were refreshed, and
|
|
77
|
+
any refresh error. An explicit refresh remains available. Keep bounded payload Preview for
|
|
78
|
+
registry/document entries, but do not expose Preview for Pi packages; install and uninstall
|
|
79
|
+
remain pinned to the selected receipt/catalog version.
|
|
80
|
+
6. Host surfaces use the same catalog filtering, receipt, refresh and lifecycle semantics in their
|
|
81
|
+
own page layouts. No host-only surface, new loader, data store or server response schema is added.
|
|
82
|
+
|
|
83
|
+
## Alternatives
|
|
84
|
+
|
|
85
|
+
- **Keep the shared browser for both commands.** Rejected: it leaves local management and public
|
|
86
|
+
discovery coupled, contrary to the requested ownership and page distinction.
|
|
87
|
+
- **Make `/hub` Community-only but keep `/plugins` as the browser's Installed/Discover shortcut.**
|
|
88
|
+
Rejected: public discovery would remain inside the command meant for local plugin management.
|
|
89
|
+
- **Hide non-Community receipts in Installed.** Rejected: it would strand existing Official Hub
|
|
90
|
+
installations from the dedicated management view.
|
|
91
|
+
- **Do nothing.** Rejected: it retains the current refresh-status and package-lifecycle gaps.
|
|
92
|
+
|
|
93
|
+
## Consequences
|
|
94
|
+
|
|
95
|
+
- The terminal and host frontends need separate Plugins and Hub presentations, but continue to call
|
|
96
|
+
the same Harness-owned services. Their layouts need not match.
|
|
97
|
+
- `plugins.remove` behavior changes only for a package owned by a Hub receipt: Hub remains the sole
|
|
98
|
+
writer that removes that receipt. Its method shape and response schema need not change.
|
|
99
|
+
- Community filtering is a presentation rule. Catalog metadata, receipts, and the unfiltered Hub
|
|
100
|
+
service remain unchanged. Existing official receipts require no migration.
|
|
101
|
+
- The public catalog currently has a Community skill but no Community Pi-package entry. This change
|
|
102
|
+
does not publish or invent a package; the Community plugin list stays empty until a publisher adds
|
|
103
|
+
a valid entry.
|
|
104
|
+
|
|
105
|
+
## Migration
|
|
106
|
+
|
|
107
|
+
No data migration. Existing receipts from all channels remain in storage and appear in Installed with
|
|
108
|
+
their channel label. Existing plugin trust, attachment, settings and package data remain unchanged.
|
|
109
|
+
The command names and protected service routes remain stable; only the direct-page routing and
|
|
110
|
+
receipt-aware removal behavior change. `/harness` retains its broad browser.
|
|
111
|
+
|
|
112
|
+
## Checks
|
|
113
|
+
|
|
114
|
+
- Harness route and page tests: distinct command destinations; Community-only catalog results;
|
|
115
|
+
all-channel Installed receipts; cache-first refresh and visible fallback status; bounded
|
|
116
|
+
registry/document Preview with no Pi-package Preview; and receipt-aware removal/update behavior.
|
|
117
|
+
- Harness: `npm run typecheck`, `npm test`, and `npm run prove` after changing the server method.
|
|
118
|
+
- Host/App tests: matching route, filtering, refresh and receipt behavior; then App
|
|
119
|
+
`npm run typecheck`, `npm test`, `npm run check:layers`, `npm run check:ui`, and
|
|
120
|
+
`cd src-tauri && cargo test`.
|
|
121
|
+
- Inspect isolated terminal and host screens at compact and wide sizes. Tests use fixtures; do not
|
|
122
|
+
install a real package or make a model request for verification.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: PROP-0048
|
|
3
|
+
title: One annotate page, two actions, and easy app attach
|
|
4
|
+
status: Implemented
|
|
5
|
+
created: 2026-10-27
|
|
6
|
+
updated: 2026-10-27
|
|
7
|
+
affects: [PROP-0018, 07-tools-and-gate.md, 10-server-protocol.md, 11-terminal.md, 13-world-tools.md, terminal-tui.md, parity.md]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PROP-0048: One annotate page, two actions, and easy app attach
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
People testing `/annotate:` found it hard to use:
|
|
15
|
+
|
|
16
|
+
- `/annotate:annotate` duplicated `/annotate:` in every command list.
|
|
17
|
+
- With no address, the page asked for one in a dialog that opened *behind* the full-screen page.
|
|
18
|
+
`PageOverlay` started its page in its constructor, before `dialogs.custom` mounted the overlay,
|
|
19
|
+
so any dialog the page opened as it started was stacked below it.
|
|
20
|
+
- While that hidden dialog waited, the page's single-action guard dropped every key (`s`, `i`)
|
|
21
|
+
without a word: "send queue sometimes doesn't work".
|
|
22
|
+
- A send held back while the agent was busy was tried once, 250 ms after the run ended. If the
|
|
23
|
+
terminal still reported its turn as active, the notes waited forever.
|
|
24
|
+
- `/annotate:notes` was a separate centred dialog with its own capture flow.
|
|
25
|
+
- The popover had three choices (save, ask the agent to fix, proceed now), the page had a queue, a
|
|
26
|
+
confirm step, an unqueue key and a "fixed" status reported by the agent's `page_notes_mark_fixed`.
|
|
27
|
+
- Attaching an Electron app needed its DevTools address typed by hand.
|
|
28
|
+
|
|
29
|
+
## Design
|
|
30
|
+
|
|
31
|
+
**Delivery.** A note is either **pending** (shared with the session, unsent) or **sent**.
|
|
32
|
+
`NoteDelivery.state` is `pending | sent`; records written before this read `queued` as `pending`
|
|
33
|
+
and `fixed` as `sent`, without a migration write. Every annotation made in the inspector with a
|
|
34
|
+
session is shared with it at once. The popover has two buttons: **Annotate** (`save`) and
|
|
35
|
+
**Annotate & send** (`send`, also Cmd/Ctrl+Enter); `send` sends *all* the session's pending notes
|
|
36
|
+
as one message. Any other action the page reports is a save. Page-origin notes (DevTools or
|
|
37
|
+
bridge, untrusted) still wait for the person's confirmation; the terminal asks once for all of
|
|
38
|
+
them, and an `empty` send reports how many still wait.
|
|
39
|
+
|
|
40
|
+
`NoteDeliveries.runEnded` now tries a held-back send again (250 ms, 1 s, 3 s, 8 s) while the
|
|
41
|
+
session answers `busy`, and starts over if another run ends meanwhile.
|
|
42
|
+
|
|
43
|
+
`/annotate:submit <request>` sends the pending notes with the person's request after them
|
|
44
|
+
(`compose(notes, prompt)`). With no pending notes it sends nothing. A request is not kept while
|
|
45
|
+
the agent is busy; the notes stay pending and the person submits again. `/annotate:clear` resolves
|
|
46
|
+
the session's pending notes and withdraws their grant to it; they can be reopened from
|
|
47
|
+
`/annotate:notes`.
|
|
48
|
+
|
|
49
|
+
`page_notes_mark_fixed` is removed; the agent's page-note tools are read-only again. Only the
|
|
50
|
+
person resolves a note.
|
|
51
|
+
|
|
52
|
+
**Commands.** A built-in command may be `rootOnly`: it is the namespace root (`/annotate:`) and has
|
|
53
|
+
no named route, is not listed, and is not reachable as `/plugin:<name>`. The annotations plugin has
|
|
54
|
+
`/annotate: [url | --app [port] | --bridge]`, `/annotate:notes`, `/annotate:submit` and
|
|
55
|
+
`/annotate:clear`.
|
|
56
|
+
|
|
57
|
+
**One page.** `AnnotatePage` is one full-screen page with an **Annotate** tab and an **All
|
|
58
|
+
annotations** tab (`/annotate:notes` opens on the second). The Annotate tab takes the page address,
|
|
59
|
+
a DevTools port or an app path in an inline field, never a dialog. `a` opens a list of the apps
|
|
60
|
+
answering on a DevTools port on this computer, with *Start an app with a DevTools port*, *Type a
|
|
61
|
+
DevTools port*, *Use the page bridge* and *Annotate a web page instead*. The notes are grouped
|
|
62
|
+
**Unsent (n)** and **Sent**. A key pressed while the page is busy is answered with a notice.
|
|
63
|
+
|
|
64
|
+
`PageOverlay` starts its page when the host reports it mounted (`mounted()`, called by
|
|
65
|
+
`dialogs.custom` after `showOverlay`), or on the next turn for a host that does not. Dialogs a page
|
|
66
|
+
opens as it starts now stack above it, on every page.
|
|
67
|
+
|
|
68
|
+
**DevTools apps.** `AnnotationCapture.discover()` probes `127.0.0.1` on ports 9222–9230 and any port
|
|
69
|
+
used before, reading `/json/version` and `/json/list` with a short timeout. A Node inspector
|
|
70
|
+
(`node.js/…`) is skipped. `launchApp(key, path, args)` starts the program (the one inside a macOS
|
|
71
|
+
`.app` bundle) with `--remote-debugging-port=<free loopback port>`, waits for its DevTools port, and
|
|
72
|
+
attaches. The app keeps running after the capture ends. The loopback-only rule for `cdp` targets
|
|
73
|
+
is unchanged.
|
|
74
|
+
|
|
75
|
+
**Protocol.** Removed: `annotations.queue`, `annotations.dequeue`, `annotations.queued`. Added:
|
|
76
|
+
`annotations.pending`, `annotations.markPending`, `annotations.confirmAll`, `annotations.clear`,
|
|
77
|
+
`annotations.capture.discover`, `annotations.capture.launch`. `annotations.createAndAct` takes
|
|
78
|
+
`save | send`; `annotations.compose` and `annotations.send` take an optional `prompt`. Terminal
|
|
79
|
+
routes: `terminal.annotations.confirmAll|clear|discover|launch`; `queue` and `dequeue` are gone.
|
|
80
|
+
|
|
81
|
+
## Consequences
|
|
82
|
+
|
|
83
|
+
The App's Annotate panel used `queue`, `fixed` and `createAndAct('queue')` and follows in its own
|
|
84
|
+
change. The prompt's Annotations group no longer names `page_notes_mark_fixed`, which changes the
|
|
85
|
+
stable prefix once.
|