@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
package/docs/terminal-tui.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Harness terminal frontend
|
|
2
2
|
|
|
3
|
-
Status: current terminal behavior, checked against `@xingular/harness` 1.
|
|
3
|
+
Status: current terminal behavior, checked against `@xingular/harness` 1.3.0. Last updated: 2026-11-19.
|
|
4
4
|
Decision: [ADR-0001](decisions/ADR-0001-owned-terminal.md),
|
|
5
5
|
[ADR-0006](decisions/ADR-0006-opentui-only-terminal.md),
|
|
6
6
|
[ADR-0009](decisions/ADR-0009-xharness-command.md),
|
|
@@ -93,9 +93,9 @@ The frontend is verified with a real isolated PTY and a loopback provider. Run
|
|
|
93
93
|
`python3 scripts/verify-terminal.py --welcome-only --sizes 40x20,80x24,120x40` to check the empty
|
|
94
94
|
welcome, product label, accent colors and `/help` transition. Run
|
|
95
95
|
`python3 scripts/verify-terminal.py --composer-only` for recognized slash-command colors in the composer
|
|
96
|
-
and a user bubble,
|
|
97
|
-
prompt gutters, and normal/plan/Bash mode exclusivity.
|
|
98
|
-
compact through wide layouts. Use `--dialog-paste-only` to verify bracketed paste into a centered
|
|
96
|
+
and a user bubble, enabled-skill colors in the composer, unknown-token and argument colors,
|
|
97
|
+
explicit-newline and soft-wrap checks of both prompt gutters, and normal/plan/Bash mode exclusivity.
|
|
98
|
+
Run it with `--sizes 40x20,80x24,120x40` for compact through wide layouts. Use `--dialog-paste-only` to verify bracketed paste into a centered
|
|
99
99
|
input dialog, `--file-completion-only` for filesystem completion and insertion,
|
|
100
100
|
`--history-only` for active-session history across `/new` and `/session`, `--resume-only` for the full-screen searchable, unnumbered two-line saved-session picker, `--help-only` for `/help` replacing the welcome screen with grouped two-column output that wraps without per-command gaps, `--questions-only` for multi-select marker glyphs, recommended choices,
|
|
101
101
|
selected-row and Continue/Submit colors, `--jump-latest-only` for scroll-away badge visibility and click-to-latest (screen-level click assertions use optional `pyte`), and choice-backed “Something else” answers, or `--thinking-only` for `/thinking` visibility toggles. The full suite covers a complete turn, `read`, `bash` approval, `ask_user_question` approval and picker, plugin overlay/widget/status
|
|
@@ -124,16 +124,24 @@ and a searchable `/subagents` page. The rows poll a private monitor route once p
|
|
|
124
124
|
during a turn and make a final read at settlement. They sit one blank row below the status line, with
|
|
125
125
|
no heading, and each reads: the status mark, the agent profile name in its colour (`subagent` for a
|
|
126
126
|
copy of the parent), the title the parent gave the child (PROP-0030), and `n of m tasks` from the
|
|
127
|
-
child's own
|
|
127
|
+
child's own todo list. At most three show, active first, then `+N more · /subagents`. The
|
|
128
128
|
`/subagents` page uses a colored profile and normal-color title on the first line, then muted account,
|
|
129
129
|
effective model, effort and cumulative usage metadata on the second. One blank row separates each
|
|
130
130
|
two-line entry. The page also shows status, elapsed time and the latest tool name. Runtime metadata
|
|
131
131
|
stays in the private terminal projection.
|
|
132
132
|
Usage contains safe token/cache/cost/context totals, not per-request payloads or reasoning summaries.
|
|
133
133
|
The projection is read-only, flat across nested descendants, and scoped to the latest parent run in
|
|
134
|
-
this terminal session; finished rows remain visible until the next parent run starts.
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
this terminal session; finished rows remain visible until the next parent run starts. The page also
|
|
135
|
+
pins a `main` row for the parent run itself, with the same details; the rows under the status line
|
|
136
|
+
leave it out. Reopening a conversation (a new launch, `/resume`, or a switch) rebuilds the rows from
|
|
137
|
+
the branch's latest parent run and its saved child runs, with their final status, until the next run
|
|
138
|
+
starts. A switch to a conversation without one clears them, as does disposal. It never includes tool
|
|
139
|
+
arguments (beyond the title), output or todo item text.
|
|
140
|
+
|
|
141
|
+
An interrupted or failed child keeps its saved conversation. The next reply is told which children
|
|
142
|
+
stopped before it answers, and the parent continues one with `spawn_subagent { continue: <runId> }`,
|
|
143
|
+
which reopens that child's own history with its profile and tools (ADR-0043). Esc therefore does
|
|
144
|
+
not lose a child's progress.
|
|
137
145
|
|
|
138
146
|
`/agents` opens the Agents page (PROP-0029): built-in, global, project and variant profiles with
|
|
139
147
|
their tools, plugins, variant, model and instructions. Enter on a row edits a person's own profile
|
|
@@ -215,7 +223,7 @@ rule; then the work that followed. The summary is shown by default. Clicking eit
|
|
|
215
223
|
shows it, and Ctrl+O shows every summary again. On a narrow screen the rule drops the click hint, then
|
|
216
224
|
the token count. Earlier compactions in the same session keep their own rules and summary in place.
|
|
217
225
|
Notices stay after the message they followed. The model sees the summary and recent messages plus a
|
|
218
|
-
bounded, hidden checkpoint of the active request,
|
|
226
|
+
bounded, hidden checkpoint of the active request, todo list and plan instructions when available;
|
|
219
227
|
the checkpoint is regenerated for each post-compaction request until the run settles. The visible
|
|
220
228
|
transcript remains a presentation of the full history, not the model context.
|
|
221
229
|
Transcript entry ids follow positions in the displayed message list, so when a rebuilt list moves a
|
|
@@ -260,23 +268,36 @@ restores the terminal's alternate-screen state when the application exits.
|
|
|
260
268
|
|
|
261
269
|
Assistant replies, plan-card bodies and Markdown image-result text share one style map. Heading
|
|
262
270
|
levels use the Harness palette; links are blue and underlined, and only their labels appear in the
|
|
263
|
-
transcript. Hovering a
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
OSC 8
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
271
|
+
transcript. Hovering a link changes the terminal pointer to a hand and recolours the link's own
|
|
272
|
+
text (`theme.linkHover`); the status line says nothing about it. The gesture that opens a link is
|
|
273
|
+
the one the platform uses: **Ctrl+click** where the terminal reports the modifier, and on macOS the
|
|
274
|
+
**primary click**, because ⌘ is not part of the terminal mouse protocol (a macOS terminal opens an
|
|
275
|
+
OSC 8 link itself on ⌘+click). Either way the link opens with the operating system's handler for
|
|
276
|
+
its kind: a web address in the browser, `mailto:` in the mail client, a file in its default
|
|
277
|
+
application, a folder in Finder. A click that opens a link leaves the composer focused. `core/links.ts` decides what
|
|
278
|
+
may open (ADR-0047): a relative path resolves against the session's folder, and an application
|
|
279
|
+
bundle, an installer, a launchable script or an executable file is refused with a notice instead of
|
|
280
|
+
being run. The launcher receives the address as one argument without a shell. OSC 8 metadata is
|
|
281
|
+
emitted where available, but link activation does not depend on terminal OSC 8 support; a terminal
|
|
282
|
+
that opens OSC 8 links itself acts on its own modifier, so the Harness keeps the primary click.
|
|
283
|
+
Inline and fenced code use a subtle panel fill with syntax colors. Emphasis, quotes, list markers,
|
|
284
|
+
tables, dividers and task-list markers use the existing titanium palette. Images display their alt
|
|
285
|
+
text and are not fetched or rendered as image files.
|
|
286
|
+
|
|
287
|
+
## Todo block
|
|
288
|
+
|
|
289
|
+
`todo_write` is registered in terminal sessions (PAR-001). Each call renders in the transcript as
|
|
290
|
+
a todo block: a status mark, `Todo · n of m done`, then one line per item with `✓` (done, success
|
|
291
|
+
colour), `●` (in progress, warning yellow, bold) or `○` (pending, dim). Each row reserves a one-cell
|
|
292
|
+
status column and one-cell gap; item text and wrapped lines share the same starting column. A call
|
|
293
|
+
whose arguments are not a todo list, or that failed, stays an ordinary tool row. The prompt's
|
|
294
|
+
Progress group asks the model to keep the list current and write a final update before replying;
|
|
295
|
+
unfinished work remains unfinished rather than being marked complete.
|
|
296
|
+
|
|
297
|
+
`/todo` (alias `/checklist`) appends a snapshot of the current list: the same header and rows, with
|
|
298
|
+
no status mark on the header, because it is not a tool call. It reads the latest non-side-question
|
|
299
|
+
run of this terminal's native session and makes no model request; an empty list is a one-line
|
|
300
|
+
notice.
|
|
280
301
|
|
|
281
302
|
## Blocks and pages
|
|
282
303
|
|
|
@@ -301,20 +322,36 @@ frontends draw that field from the same muted-blue selection palette (`selection
|
|
|
301
322
|
explicit high-contrast text on it instead of the accent colour, so a choice reads the same in every
|
|
302
323
|
list. Rules use the theme's `warning` and `dim` colors, so a custom theme restyles them.
|
|
303
324
|
|
|
304
|
-
The Harness resource browser (PROP-0013) unifies Overview, Foundation, Variant, Skills,
|
|
305
|
-
Connections, Tools and Library. `/harness` opens Overview; `/skills`, `/
|
|
306
|
-
(`/mcp`) and `/
|
|
307
|
-
|
|
325
|
+
The broad Harness resource browser (PROP-0013) unifies Overview, Foundation, Variant, Skills,
|
|
326
|
+
Plugins, Connections, Tools and Library. `/harness` opens Overview; `/skills`, `/connections`
|
|
327
|
+
(`/mcp`), `/tools` and `/components` open sections. `/plugins` is a separate
|
|
328
|
+
full-screen local manager with Plugins, Trust and Packages tabs; `/hub` is a separate
|
|
329
|
+
full-screen Community catalog with Catalog and Installed tabs. Both keep a searchable
|
|
330
|
+
inventory beside selected-item details on wide terminals, stacking details below the list
|
|
331
|
+
on compact terminals. The existing Accounts, Permissions, Settings, Trajectory and Log
|
|
332
|
+
pages retain their own tabs.
|
|
308
333
|
|
|
309
334
|
`/settings` includes a Browser tab with the device-local **Private address access** setting. It is
|
|
310
335
|
off by default. Enabling it asks for confirmation and allows agent browsing and annotation capture
|
|
311
336
|
to reach localhost and private networks.
|
|
312
337
|
|
|
313
|
-
|
|
314
|
-
resources; current-session availability comes only from the runtime
|
|
315
|
-
Discover uses the
|
|
316
|
-
No matching
|
|
317
|
-
The view preserves search across source switches and restores section selection
|
|
338
|
+
Within the broad `/harness` browser, resource sections share Installed/Discover and source filters.
|
|
339
|
+
Installed includes locally present resources; current-session availability comes only from the runtime
|
|
340
|
+
loader and active tool registry. Discover uses the unfiltered Hub service with All/Community/Official
|
|
341
|
+
filters and an explicit refresh. No matching Community entries is an empty result, never replaced with
|
|
342
|
+
built-in resources. The view preserves search across source switches and restores section selection.
|
|
343
|
+
|
|
344
|
+
The dedicated `/hub` Catalog shows Community entries across supported types only. Its Installed tab
|
|
345
|
+
shows receipts from every channel with the channel labeled. On each page entry, cached/bundled entries
|
|
346
|
+
appear first, then the remote catalog refreshes; the status keeps the origin, last-refresh time and any
|
|
347
|
+
stale/error feedback visible. Manual refresh remains available. Catalog installs are pinned to the
|
|
348
|
+
selected version, and Hub uninstalls remove only receipt-owned resources. Registry/document entries
|
|
349
|
+
offer a bounded payload Preview; Pi packages have no JSON payload Preview.
|
|
350
|
+
|
|
351
|
+
The `/plugins` manager keeps local switching, code trust and settings separate from public discovery.
|
|
352
|
+
Its Packages tab adds local package installation, update and removal. Hub-owned packages remain pinned
|
|
353
|
+
to exact catalog versions; removal goes through Hub receipt cleanup, and updating requires an explicit
|
|
354
|
+
Hub version replacement.
|
|
318
355
|
|
|
319
356
|
The browser fills the terminal (PROP-0014), with Overview, Foundation, Variant, Skills, Plugins,
|
|
320
357
|
Connections, Tools and Library as persistent top tabs. The section dropdown and sidebar are removed.
|
|
@@ -329,8 +366,8 @@ Left/Right changes the focused tab or control; Enter on the tab strip returns to
|
|
|
329
366
|
Ctrl+F focuses search. Escape returns from content to actions, returns to the list, clears search,
|
|
330
367
|
then closes. Mouse clicks select tabs directly, activate resource actions and focus filters;
|
|
331
368
|
wheel scrolling targets the list or inspector under the pointer. Other command pages keep their
|
|
332
|
-
centered presentation; `/settings` and `/
|
|
333
|
-
the composer draft and attachments.
|
|
369
|
+
centered presentation; `/settings`, `/accounts`, `/plugins` and `/hub` use full-screen page layouts.
|
|
370
|
+
Closing the browser preserves the composer draft and attachments.
|
|
334
371
|
|
|
335
372
|
Foundation explains fixed runtime ownership; it is read-only. Variant shows c1–c8 with the
|
|
336
373
|
prepared version and current head separately. It previews pinned files from the preparation
|
|
@@ -359,24 +396,34 @@ skill import rejects symbolic links and limits bytes, files and traversal. See
|
|
|
359
396
|
[PROP-0013](architecture/proposals/PROP-0013-resource-browser.md) and
|
|
360
397
|
[ADR-0015](decisions/ADR-0015-resource-browser.md).
|
|
361
398
|
|
|
362
|
-
## Annotate
|
|
399
|
+
## Annotate page (PROP-0018, PROP-0048)
|
|
363
400
|
|
|
364
|
-
`/annotate:` opens the full-screen
|
|
401
|
+
`/annotate:` opens the full-screen annotate page beside the window being inspected. It has two tabs:
|
|
402
|
+
**Annotate** and **All annotations** (`/annotate:notes` opens on the second). Add a page address with
|
|
403
|
+
`/annotate: [url]`; without one, the page returns to the window that is still open, with its URL and
|
|
404
|
+
the inspector on, and asks for an address only when no window is open. The target window is one of:
|
|
365
405
|
- the visible capture browser
|
|
366
|
-
- an app's own windows
|
|
406
|
+
- an app's own windows over its DevTools port (`--app [port]`, or `a` in the page)
|
|
367
407
|
- app windows that loaded the page bridge script (`--bridge`)
|
|
368
408
|
|
|
369
|
-
The header shows the target and window and whether the inspector is on.
|
|
409
|
+
The header shows the target and window and whether the inspector is on. Click a component in the
|
|
410
|
+
window and choose **Annotate** or **Annotate & send** (Cmd/Ctrl+Enter). Every annotation is shared
|
|
411
|
+
with this session; the list groups them as Unsent and Sent. While the inspector is on, the page polls
|
|
412
|
+
for the next popover comment every 400 ms, shows the result as a notice, and refreshes the list.
|
|
370
413
|
|
|
371
414
|
| Key | Action |
|
|
372
415
|
|---|---|
|
|
373
416
|
| `i` | inspector on/off |
|
|
374
|
-
| `s` | send
|
|
375
|
-
| `
|
|
417
|
+
| `s` | send every unsent annotation (page-origin ones are confirmed once first) |
|
|
418
|
+
| `o` | type a page address |
|
|
419
|
+
| `a` | apps with a DevTools port: pick one, type a port, start an app with one, or use the bridge |
|
|
376
420
|
| `t` | choose a window |
|
|
377
|
-
| `Enter` | the
|
|
421
|
+
| `Enter` | the annotation menu |
|
|
422
|
+
| `Tab` | switch tab |
|
|
378
423
|
|
|
379
|
-
The
|
|
424
|
+
The Annotate tab has no search row, so these letters are free for actions. `/annotate:submit <request>`
|
|
425
|
+
sends the unsent annotations with your request after them; `/annotate:clear` resolves the unsent ones
|
|
426
|
+
and stops sharing them.
|
|
380
427
|
|
|
381
428
|
## Plan mode and thinking keys
|
|
382
429
|
|
|
@@ -384,16 +431,21 @@ Use `/plan <brief>` for one read-only planning request. A plan waits outside Pi'
|
|
|
384
431
|
queue until the active response settles, then runs by itself. Later messages remain behind it, even
|
|
385
432
|
when Pi's follow-up mode is `all`. During that run the session narrows to read-only inspection
|
|
386
433
|
(`read`, `grep`, `find`, `ls`), web search/page reading, questions (`ask_user`, `ask_user_question`)
|
|
387
|
-
and recall (history and Wiki reads, `memory_facts`).
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
434
|
+
and recall (history and Wiki reads, `memory_facts`). The parent may also run Bash in the
|
|
435
|
+
OS-enforced read-only sandbox: no network and no writes except a discarded per-command temporary
|
|
436
|
+
directory (PROP-0043). It may delegate bounded research to a named profile whose effective tool and
|
|
437
|
+
plugin allowlists qualify for research; the child inherits plan mode and receives only the
|
|
438
|
+
intersection of the parent's frozen capabilities, profile and plan-research set. Children cannot
|
|
439
|
+
write, run commands, ask the user, use connectors or spawn more children; they remain bounded by the
|
|
440
|
+
configured work-slice policy without gaining `checkpoint_write`, and the Harness records an
|
|
441
|
+
evidence-derived checkpoint if the child stops at a boundary. Normal mode omits both question tools
|
|
442
|
+
from the active set; the plan request enables registered questions and research delegation
|
|
443
|
+
temporarily and restores the normal set when it settles, including on failure or interruption.
|
|
444
|
+
Providers may mark individual calls as safe for research; every other call is blocked before
|
|
445
|
+
approval. Edits, writes, memory writes and connected-app tools remain unavailable to parent and
|
|
446
|
+
child; generic browser controls are also blocked. Sandboxed read-only Bash is the parent's only
|
|
447
|
+
plan-mode shell exception; children cannot run commands. The plan instructions arrive as a
|
|
448
|
+
request-scoped prompt section, which the next ordinary request withdraws.
|
|
397
449
|
|
|
398
450
|
Each mode keeps its own model and effort for the account. Every selection the person makes (the model
|
|
399
451
|
picker, `/effort`, Shift+Up/Down, Ctrl+P) is saved against the mode it was made in, so Shift+Tab switches to that
|
|
@@ -699,12 +751,16 @@ normal-color title and a muted second line with relative activity time, `<projec
|
|
|
699
751
|
file size separated by ` · `. One blank line separates each session. Enter resumes the selected
|
|
700
752
|
session; account and folder scope checks
|
|
701
753
|
remain enforced. Supplying an explicit path continues directly without opening the picker.
|
|
702
|
-
The
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
754
|
+
The `$` palette completes enabled skill invocations using the same two-column palette as slash
|
|
755
|
+
commands; `/skills` always browses skills. Choosing a skill inserts `$name ` without submitting.
|
|
756
|
+
A recognized leading `$name` uses the blue accent in the composer, while its arguments, unavailable
|
|
757
|
+
names and ordinary currency text keep the normal color. `/help` renders the command list as one
|
|
758
|
+
transcript entry, grouped under Core, Run, Model, Session, Inspect, Harness, Plugins and Prompts;
|
|
759
|
+
command names and descriptions wrap in aligned columns, with no blank rows between choices. `/plugins`
|
|
760
|
+
opens the focused local manager; its Packages tab installs, updates and removes packages with protected
|
|
761
|
+
Harness operations. Settings use `plugins.configure`; on/off settings and bounded whole-number settings
|
|
762
|
+
keep their existing ranges. Saved settings are read when the plugin next uses them and do not require a
|
|
763
|
+
restart. The standalone
|
|
708
764
|
terminal no longer has separate `/login`, `/trust`, `/bug`, `/changelog`, `/share`, `/scoped-mode` or
|
|
709
765
|
`/import` commands. `/btw <question>` (or `/side <question>`) starts a separate Harness run with the
|
|
710
766
|
main run's effective instructions, visible conversation and redacted public tool inputs/results.
|
|
@@ -738,8 +794,8 @@ of feature-plugin command metadata: `/doctor`, `/worktree`, `/trajectory`, `/sub
|
|
|
738
794
|
`/history` (also `/tree`) continues to navigate session branches. `/mcp` and `/connections` open the
|
|
739
795
|
Connections browser. Feature descriptors and their services remain registered; only these terminal
|
|
740
796
|
routes move out of the plugin command registry. Other plugin-owned commands continue to use
|
|
741
|
-
`/<owner-prefix>:<command>`. The annotations plugin uses `/annotate:annotate` and
|
|
742
|
-
`/annotate:` opens its
|
|
797
|
+
`/<owner-prefix>:<command>`. The annotations plugin uses `/annotate:notes`, `/annotate:submit` and
|
|
798
|
+
`/annotate:clear`; `/annotate:` opens its annotate page (a root-only command with no named route). Pi package extensions use their normalized package name
|
|
743
799
|
as owner prefix unless `harness.commandPrefix` overrides it; loose extensions use their normalized
|
|
744
800
|
extension name. A plugin prefix collision or a duplicate command within one owner is rejected with
|
|
745
801
|
owner paths in the diagnostic. The former owner-qualified and `/plugin:<command>` routes of promoted
|
|
@@ -894,12 +950,18 @@ inherit that retained ledger.
|
|
|
894
950
|
|
|
895
951
|
## Agent-managed session names
|
|
896
952
|
|
|
897
|
-
Agents can use `session_name({ name: string })` to name
|
|
898
|
-
|
|
953
|
+
Agents can use `session_name({ name: string })` to name work before their first other tool call
|
|
954
|
+
when a request needs tools or changes state, and revise the name only when the objective changes.
|
|
955
|
+
Names submitted by agents are short imperative
|
|
899
956
|
sentences with at most six words. The agent may revise a manual name; `/name` remains
|
|
900
957
|
available and manual names have no new word limit. Pi stores the name in native history,
|
|
901
958
|
so resuming the same conversation restores it without another model request.
|
|
902
959
|
|
|
960
|
+
A substantive first turn also gets a provisional name through the terminal policy when the
|
|
961
|
+
session is unnamed; a refused or failed name leaves it unnamed. Each turn appends a hidden
|
|
962
|
+
`xingular-session-state` message with the current name and this run's empty todo, with the
|
|
963
|
+
previous run's list as context; the message is request-only and does not enter the stable pack.
|
|
964
|
+
|
|
903
965
|
The working line shows `Working (2m, 50 tok/s) – Add web browser integrations`; the name
|
|
904
966
|
also stays on the completion line. Unnamed sessions have no separator, and narrow terminals
|
|
905
967
|
truncate trailing text. Renaming refreshes the line through Pi's existing metadata event.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xingular/harness",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1-unstable.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Xingular Harness — a Pi agent harness built on recursive harnessing (Harness²): versioned eight-component variants, refinement from evidence, multi-account sessions, a compiled prompt, project notes, tools, and MCP",
|
|
6
6
|
"repository": {
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Web annotations page (`/annotate:notes`, `/annotate:annotate [url]`): comments a person keeps about web pages. A new annotation
|
|
3
|
-
* is captured in a visible browser window: the whole page, text the person selects, or an element
|
|
4
|
-
* they click. An annotation is private until it is shared with this session, whose agent can then read it
|
|
5
|
-
* with `page_notes_read` (PROP-0017).
|
|
6
|
-
*/
|
|
7
|
-
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
8
|
-
import type { MenuCall, MenuUi } from "../../pluginMenu.js";
|
|
9
|
-
import type { TabInfo } from "../chrome.js";
|
|
10
|
-
import { type ListRow } from "../list.js";
|
|
11
|
-
import type { TerminalMouseInput } from "../mouse.js";
|
|
12
|
-
import type { TerminalPage } from "../page.js";
|
|
13
|
-
import type { Note } from "../../../annotations/store.js";
|
|
14
|
-
export interface NotesPageOptions {
|
|
15
|
-
theme(): Theme;
|
|
16
|
-
call: MenuCall;
|
|
17
|
-
ui: MenuUi & {
|
|
18
|
-
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
19
|
-
};
|
|
20
|
-
changed(): void;
|
|
21
|
-
/** Start a new annotation as soon as the page opens (`/annotate:annotate [url]`), on this address when given. */
|
|
22
|
-
start?: {
|
|
23
|
-
url?: string;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
type Row = {
|
|
27
|
-
kind: 'new';
|
|
28
|
-
} | {
|
|
29
|
-
kind: 'note';
|
|
30
|
-
note: Note;
|
|
31
|
-
};
|
|
32
|
-
export declare const NOTE_KINDS: {
|
|
33
|
-
readonly page: "The whole page";
|
|
34
|
-
readonly text: "Text I select in the window";
|
|
35
|
-
readonly element: "An element I click in the window";
|
|
36
|
-
};
|
|
37
|
-
export declare const NOTE_ACTIONS: {
|
|
38
|
-
readonly reveal: "Show it in the browser window";
|
|
39
|
-
readonly edit: "Edit the annotation";
|
|
40
|
-
readonly resolve: "Mark resolved";
|
|
41
|
-
readonly reopen: "Reopen";
|
|
42
|
-
readonly share: "Let this session's agent read it";
|
|
43
|
-
readonly unshare: "Stop sharing it with this session";
|
|
44
|
-
readonly delete: "Delete";
|
|
45
|
-
};
|
|
46
|
-
export declare class NotesPage implements TerminalPage {
|
|
47
|
-
private readonly options;
|
|
48
|
-
presentation: "centered";
|
|
49
|
-
private notes;
|
|
50
|
-
private sessionId;
|
|
51
|
-
private error;
|
|
52
|
-
private busy;
|
|
53
|
-
private disposed;
|
|
54
|
-
private readonly list;
|
|
55
|
-
constructor(options: NotesPageOptions);
|
|
56
|
-
get focused(): boolean;
|
|
57
|
-
set focused(value: boolean);
|
|
58
|
-
activate(): void;
|
|
59
|
-
dispose(): void;
|
|
60
|
-
tabs(): readonly TabInfo[];
|
|
61
|
-
activeTab(): string;
|
|
62
|
-
hint(): string;
|
|
63
|
-
reload(): Promise<void>;
|
|
64
|
-
private shared;
|
|
65
|
-
rows(): ListRow<Row>[];
|
|
66
|
-
private attempt;
|
|
67
|
-
activateRow(row: Row): Promise<void>;
|
|
68
|
-
/** Opens the capture window, takes what the person points at, and saves their annotation. */
|
|
69
|
-
newNote(startUrl?: string): Promise<void>;
|
|
70
|
-
private noteMenu;
|
|
71
|
-
handleMouse(event: TerminalMouseInput): import("@earendil-works/pi-tui").TuiMouseEventResult | undefined;
|
|
72
|
-
handleInput(data: string): boolean;
|
|
73
|
-
render(width: number, rows: number): string[];
|
|
74
|
-
}
|
|
75
|
-
export {};
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { truncateToWidth } from '@earendil-works/pi-tui';
|
|
2
|
-
import { FilterList } from "../list.js";
|
|
3
|
-
const TABS = [{ id: 'notes', title: 'Web annotations' }];
|
|
4
|
-
export const NOTE_KINDS = { page: 'The whole page', text: 'Text I select in the window', element: 'An element I click in the window' };
|
|
5
|
-
export const NOTE_ACTIONS = {
|
|
6
|
-
reveal: 'Show it in the browser window',
|
|
7
|
-
edit: 'Edit the annotation',
|
|
8
|
-
resolve: 'Mark resolved',
|
|
9
|
-
reopen: 'Reopen',
|
|
10
|
-
share: 'Let this session\'s agent read it',
|
|
11
|
-
unshare: 'Stop sharing it with this session',
|
|
12
|
-
delete: 'Delete'
|
|
13
|
-
};
|
|
14
|
-
const clip = (text, size) => (text.length > size ? `${text.slice(0, size - 1)}…` : text);
|
|
15
|
-
function describeTarget(target) {
|
|
16
|
-
if (target.kind === 'text')
|
|
17
|
-
return `“${clip(target.exact.replace(/\s+/g, ' '), 60)}”`;
|
|
18
|
-
if (target.kind === 'element')
|
|
19
|
-
return `<${target.tag}> ${clip(target.name || target.text, 50)}`;
|
|
20
|
-
return 'whole page';
|
|
21
|
-
}
|
|
22
|
-
export class NotesPage {
|
|
23
|
-
options;
|
|
24
|
-
presentation = 'centered';
|
|
25
|
-
notes;
|
|
26
|
-
sessionId = null;
|
|
27
|
-
error;
|
|
28
|
-
busy = false;
|
|
29
|
-
disposed = false;
|
|
30
|
-
list;
|
|
31
|
-
constructor(options) {
|
|
32
|
-
this.options = options;
|
|
33
|
-
this.list = new FilterList({
|
|
34
|
-
theme: options.theme, search: 'always', noun: ['annotation', 'annotations'], empty: 'No web annotations yet',
|
|
35
|
-
onActivate: row => { if (row.data)
|
|
36
|
-
void this.activateRow(row.data); }
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
get focused() { return this.list.focused; }
|
|
40
|
-
set focused(value) { this.list.focused = value; }
|
|
41
|
-
activate() {
|
|
42
|
-
void this.reload().then(() => {
|
|
43
|
-
if (this.options.start)
|
|
44
|
-
void this.newNote(this.options.start.url);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
dispose() { this.disposed = true; }
|
|
48
|
-
tabs() { return TABS; }
|
|
49
|
-
activeTab() { return 'notes'; }
|
|
50
|
-
hint() { return 'Enter choose · type to search · Esc close'; }
|
|
51
|
-
async reload() {
|
|
52
|
-
try {
|
|
53
|
-
const result = await this.options.call('terminal.annotations.list');
|
|
54
|
-
this.notes = result.notes;
|
|
55
|
-
this.sessionId = result.sessionId;
|
|
56
|
-
this.error = undefined;
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
this.error = error instanceof Error ? error.message : String(error);
|
|
60
|
-
}
|
|
61
|
-
if (this.disposed)
|
|
62
|
-
return;
|
|
63
|
-
this.list.setRows(this.rows());
|
|
64
|
-
this.options.changed();
|
|
65
|
-
}
|
|
66
|
-
shared(note) {
|
|
67
|
-
return note.grants.some(grant => grant.principal.sessionId && grant.principal.sessionId === this.sessionId);
|
|
68
|
-
}
|
|
69
|
-
rows() {
|
|
70
|
-
const rows = [{ id: 'new', label: 'New web annotation…', group: 'Actions', detail: 'opens a browser window', tone: 'accent', data: { kind: 'new' } }];
|
|
71
|
-
for (const note of this.notes ?? []) {
|
|
72
|
-
rows.push({
|
|
73
|
-
id: `note:${note.id}`, label: clip(note.body.replace(/\s+/g, ' '), 60), group: 'Annotations',
|
|
74
|
-
detail: `${describeTarget(note.target)} · ${note.status}${this.shared(note) ? ' · shared here' : ''}`,
|
|
75
|
-
tone: note.status === 'resolved' ? 'dim' : this.shared(note) ? 'success' : 'muted',
|
|
76
|
-
searchText: `${note.body} ${note.source.url} ${note.source.title} ${note.tags.join(' ')}`,
|
|
77
|
-
data: { kind: 'note', note }
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
return rows;
|
|
81
|
-
}
|
|
82
|
-
async attempt(work) {
|
|
83
|
-
if (this.busy)
|
|
84
|
-
return;
|
|
85
|
-
this.busy = true;
|
|
86
|
-
try {
|
|
87
|
-
const message = await work();
|
|
88
|
-
if (message)
|
|
89
|
-
this.options.ui.notify(message, 'info');
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
this.options.ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
93
|
-
}
|
|
94
|
-
finally {
|
|
95
|
-
this.busy = false;
|
|
96
|
-
}
|
|
97
|
-
await this.reload();
|
|
98
|
-
}
|
|
99
|
-
async activateRow(row) {
|
|
100
|
-
if (row.kind === 'new')
|
|
101
|
-
return this.newNote();
|
|
102
|
-
return this.noteMenu(row.note);
|
|
103
|
-
}
|
|
104
|
-
/** Opens the capture window, takes what the person points at, and saves their annotation. */
|
|
105
|
-
newNote(startUrl) {
|
|
106
|
-
const { call, ui } = this.options;
|
|
107
|
-
return this.attempt(async () => {
|
|
108
|
-
const url = startUrl ?? await ui.input('Page address', 'https://');
|
|
109
|
-
if (!url)
|
|
110
|
-
return;
|
|
111
|
-
await call('terminal.annotations.open', { url });
|
|
112
|
-
const kind = await ui.select('What does the annotation point at?', Object.values(NOTE_KINDS));
|
|
113
|
-
if (!kind)
|
|
114
|
-
return;
|
|
115
|
-
let envelope;
|
|
116
|
-
if (kind === NOTE_KINDS.page) {
|
|
117
|
-
const identity = await call('terminal.annotations.identity');
|
|
118
|
-
envelope = { ...identity, target: { kind: 'page' } };
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
const element = kind === NOTE_KINDS.element;
|
|
122
|
-
const { captureId } = await call('terminal.annotations.begin', { kind: element ? 'element' : 'text' });
|
|
123
|
-
const ready = await ui.confirm(element ? 'Click the element in the browser window' : 'Select the text in the browser window', 'When it is selected, choose Yes to capture it. Choose No to cancel.');
|
|
124
|
-
if (!ready) {
|
|
125
|
-
await call('terminal.annotations.cancel', { captureId });
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
envelope = await call('terminal.annotations.capture', { captureId });
|
|
129
|
-
if (!envelope)
|
|
130
|
-
return 'Nothing was selected in the browser window, so no annotation was made.';
|
|
131
|
-
}
|
|
132
|
-
const body = await ui.input('Comment', 'What should change or be remembered?');
|
|
133
|
-
if (!body?.trim())
|
|
134
|
-
return 'An annotation needs a comment; nothing was saved.';
|
|
135
|
-
const tags = (await ui.input('Tags (optional, comma separated)', '') ?? '').split(',').map(tag => tag.trim()).filter(Boolean);
|
|
136
|
-
const share = await ui.confirm('Share it with this session?', 'This session\'s agent can then read the annotation with page_notes_read. You can stop sharing it later.');
|
|
137
|
-
await call('terminal.annotations.create', {
|
|
138
|
-
source: { url: envelope.url, title: envelope.title, capturedAt: new Date().toISOString(), surface: 'terminal', representationHint: envelope.documentId },
|
|
139
|
-
target: envelope.target, body, tags, share
|
|
140
|
-
});
|
|
141
|
-
return share ? 'Annotation saved and shared with this session.' : 'Annotation saved. It stays private until you share it.';
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
async noteMenu(note) {
|
|
145
|
-
const { call, ui } = this.options;
|
|
146
|
-
const choices = [
|
|
147
|
-
NOTE_ACTIONS.reveal,
|
|
148
|
-
NOTE_ACTIONS.edit,
|
|
149
|
-
note.status === 'open' ? NOTE_ACTIONS.resolve : NOTE_ACTIONS.reopen,
|
|
150
|
-
this.shared(note) ? NOTE_ACTIONS.unshare : NOTE_ACTIONS.share,
|
|
151
|
-
NOTE_ACTIONS.delete
|
|
152
|
-
];
|
|
153
|
-
const choice = await ui.select(`${clip(note.source.title || note.source.url, 60)} · ${describeTarget(note.target)}`, choices);
|
|
154
|
-
const id = note.id;
|
|
155
|
-
if (choice === NOTE_ACTIONS.reveal)
|
|
156
|
-
return this.attempt(async () => {
|
|
157
|
-
const result = await call('terminal.annotations.reveal', { id });
|
|
158
|
-
return result.state === 'matched' ? 'Marked in the browser window.' : `The target is ${result.state}${result.reason ? `: ${result.reason}` : ''}.`;
|
|
159
|
-
});
|
|
160
|
-
if (choice === NOTE_ACTIONS.edit)
|
|
161
|
-
return this.attempt(async () => {
|
|
162
|
-
const body = await ui.input('Note', note.body);
|
|
163
|
-
if (!body?.trim() || body === note.body)
|
|
164
|
-
return;
|
|
165
|
-
await call('terminal.annotations.update', { id, expectedVersion: note.version, patch: { body } });
|
|
166
|
-
return 'Annotation saved.';
|
|
167
|
-
});
|
|
168
|
-
if (choice === NOTE_ACTIONS.resolve || choice === NOTE_ACTIONS.reopen)
|
|
169
|
-
return this.attempt(async () => {
|
|
170
|
-
await call('terminal.annotations.update', { id, expectedVersion: note.version, patch: { status: choice === NOTE_ACTIONS.resolve ? 'resolved' : 'open' } });
|
|
171
|
-
});
|
|
172
|
-
if (choice === NOTE_ACTIONS.share || choice === NOTE_ACTIONS.unshare)
|
|
173
|
-
return this.attempt(async () => {
|
|
174
|
-
await call(choice === NOTE_ACTIONS.share ? 'terminal.annotations.share' : 'terminal.annotations.unshare', { id });
|
|
175
|
-
return choice === NOTE_ACTIONS.share ? 'This session\'s agent can read the annotation.' : 'The annotation is no longer shared with this session.';
|
|
176
|
-
});
|
|
177
|
-
if (choice === NOTE_ACTIONS.delete)
|
|
178
|
-
return this.attempt(async () => {
|
|
179
|
-
if (!await ui.confirm('Delete this annotation?', 'It cannot be restored.'))
|
|
180
|
-
return;
|
|
181
|
-
await call('terminal.annotations.delete', { id, expectedVersion: note.version });
|
|
182
|
-
return 'Annotation deleted.';
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
handleMouse(event) {
|
|
186
|
-
return this.list.handleMouse(event);
|
|
187
|
-
}
|
|
188
|
-
handleInput(data) {
|
|
189
|
-
return this.list.handleInput(data);
|
|
190
|
-
}
|
|
191
|
-
render(width, rows) {
|
|
192
|
-
const theme = this.options.theme();
|
|
193
|
-
if (width < 1 || rows < 1)
|
|
194
|
-
return [];
|
|
195
|
-
if (this.error)
|
|
196
|
-
return [theme.fg('error', `Could not read web annotations: ${this.error}`)];
|
|
197
|
-
if (!this.notes)
|
|
198
|
-
return [theme.fg('dim', 'Reading web annotations…')];
|
|
199
|
-
return this.list.render(width, rows).slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type ChecklistItem, type RunEvent } from "../sessions/contracts.js";
|
|
2
|
-
import type { ActiveRun } from "../sessions/registry.js";
|
|
3
|
-
import type { ToolSpec } from "./types.js";
|
|
4
|
-
export declare const CHECKLIST_WRITE = "checklist_write";
|
|
5
|
-
/** The checklist as the model reads it back. */
|
|
6
|
-
export declare function describeChecklist(items: readonly ChecklistItem[]): string;
|
|
7
|
-
/** The latest checklist a run wrote, or an empty list. */
|
|
8
|
-
export declare function checklistOf(events: readonly RunEvent[]): ChecklistItem[];
|
|
9
|
-
export declare function checklistTool(run: Pick<ActiveRun, 'emit'>): ToolSpec;
|