@north-light/crouter 0.3.197 → 0.3.199
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +19 -19
- package/dist/api/client.js +29 -37
- package/dist/api/dto/broker-ops.d.ts +3 -1
- package/dist/api/dto/broker.d.ts +13 -2
- package/dist/api/dto/broker.js +4 -4
- package/dist/api/dto/human.d.ts +6 -5
- package/dist/api/dto/inbox.d.ts +126 -33
- package/dist/api/dto/nodes.d.ts +8 -2
- package/dist/api/dto/profiles.d.ts +23 -0
- package/dist/api/dto/profiles.js +2 -2
- package/dist/api/dto/worktree.d.ts +3 -5
- package/dist/api/routes.d.ts +3 -5
- package/dist/api/routes.js +4 -6
- package/dist/builtin-memory/00-runtime-base.md +8 -8
- package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
- package/dist/builtin-memory/02-lifecycle/00-terminal.md +3 -3
- package/dist/builtin-memory/04-orchestration-kernel.md +6 -6
- package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +2 -2
- package/dist/builtin-memory/05-kinds/review/00-base.md +2 -2
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +1 -1
- package/dist/builtin-memory/insights/capture.md +2 -2
- package/dist/builtin-memory/insights/init.md +3 -3
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/memory-loading.md +1 -1
- package/dist/builtin-memory/internal/nodes-and-canvas.md +3 -3
- package/dist/builtin-memory/internal/plugins.md +59 -2
- package/dist/builtin-memory/internal/storage-tiers.md +3 -1
- package/dist/builtin-memory/spec/roadmap.md +2 -2
- package/dist/builtin-memory/testing.md +1 -1
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +1 -1
- package/dist/clients/attach/chrome/bash-jobs.js +3 -3
- package/dist/clients/attach/render/chat-view.d.ts +29 -9
- package/dist/clients/attach/render/chat-view.js +64 -35
- package/dist/clients/attach/render/markdown-source.js +0 -6
- package/dist/clients/attach/render/page-block.d.ts +34 -0
- package/dist/clients/attach/render/page-block.js +226 -0
- package/dist/clients/attach/render/tool-calls.js +16 -2
- package/dist/clients/attach/session/whip.d.ts +2 -0
- package/dist/clients/attach/session/whip.js +2 -0
- package/dist/clients/attach/viewer.js +1419 -982
- package/dist/clients/conversation/projection.js +18 -3
- package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +9 -6
- package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +13 -14
- package/dist/clients/inbox/controller.js +10 -16
- package/dist/clients/inbox/page-adapter.d.ts +3 -4
- package/dist/clients/inbox/page-adapter.js +3 -4
- package/dist/clients/inbox/resolve.d.ts +1 -1
- package/dist/clients/inbox/resolve.js +3 -3
- package/dist/clients/inbox/review/document-surface.js +3 -1
- package/dist/clients/inbox/review/state.d.ts +2 -1
- package/dist/clients/inbox/review/state.js +5 -16
- package/dist/clients/inbox/tui/input.js +37 -19
- package/dist/clients/inbox/tui/panel.js +5 -31
- package/dist/clients/inbox/tui/render.d.ts +11 -0
- package/dist/clients/inbox/tui/render.js +101 -36
- package/dist/clients/inbox/tui/slots.d.ts +4 -4
- package/dist/clients/inbox/tui/slots.js +19 -44
- package/dist/clients/inbox/tui/types.d.ts +6 -10
- package/dist/clients/inbox/tui.js +2 -2
- package/dist/commands/__tests__/human.test.js +118 -24
- package/dist/commands/__tests__/node-message.test.js +14 -0
- package/dist/commands/attention.js +4 -4
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/canvas-snapshot.js +1 -1
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/human/{doc.d.ts → components.d.ts} +1 -1
- package/dist/commands/human/components.js +77 -0
- package/dist/commands/human/feedback.d.ts +2 -0
- package/dist/commands/human/feedback.js +108 -0
- package/dist/commands/human/prompts.d.ts +17 -8
- package/dist/commands/human/prompts.js +217 -226
- package/dist/commands/human/queue.js +57 -88
- package/dist/commands/human/shared.d.ts +4 -15
- package/dist/commands/human/shared.js +19 -61
- package/dist/commands/human.js +32 -19
- package/dist/commands/memory/origin.js +2 -2
- package/dist/commands/node/bash.js +4 -4
- package/dist/commands/node/inspect.js +3 -3
- package/dist/commands/node/lifecycle.js +1 -1
- package/dist/commands/node/message.js +2 -2
- package/dist/commands/node-worktree.js +8 -8
- package/dist/commands/pkg/browse.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +129 -10
- package/dist/commands/profile/delete.js +41 -15
- package/dist/commands/profile.js +1 -1
- package/dist/commands/push.js +1 -1
- package/dist/commands/surface/node/focus.js +29 -14
- package/dist/commands/surface-edit.js +3 -3
- package/dist/commands/surface-inbox.d.ts +2 -0
- package/dist/commands/{human/inbox.js → surface-inbox.js} +14 -18
- package/dist/commands/surface.js +2 -1
- package/dist/commands/sys/doctor.js +60 -3
- package/dist/commands/sys/feedback.js +79 -25
- package/dist/commands/sys/settings.js +1 -1
- package/dist/core/__tests__/cron-broker-capacity.test.js +1 -1
- package/dist/core/__tests__/daemon-boot.test.js +7 -4
- package/dist/core/__tests__/dead-node-policy-table.test.js +20 -36
- package/dist/core/__tests__/extension-abort.test.js +5 -2
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +13 -2
- package/dist/core/__tests__/fixtures/fake-engine.js +47 -3
- package/dist/core/__tests__/human-cancel-guard.test.js +31 -10
- package/dist/core/__tests__/human-deliver.test.js +41 -45
- package/dist/core/__tests__/human-node-not-supervised.test.js +1 -1
- package/dist/core/__tests__/plugin-page-components.test.js +157 -0
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +13 -11
- package/dist/core/__tests__/seam/dormancy-release.test.js +103 -4
- package/dist/core/__tests__/serial/flagship-lifecycle.test.js +2 -2
- package/dist/core/__tests__/serial/human-deliver-e2e.test.js +12 -16
- package/dist/core/__tests__/serial/live-mutation.test.js +1 -1
- package/dist/core/__tests__/serial/tmux-surface.test.js +4 -2
- package/dist/core/__tests__/serial/worktree.test.js +24 -198
- package/dist/core/__tests__/session-cycles.test.js +22 -0
- package/dist/core/__tests__/stop-guard.test.js +4 -4
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +19 -4
- package/dist/core/bash-jobs.d.ts +6 -0
- package/dist/core/bash-jobs.js +10 -0
- package/dist/core/canvas/__tests__/attention.test.js +8 -5
- package/dist/core/canvas/__tests__/render-remote.test.js +5 -5
- package/dist/core/canvas/attention.js +8 -6
- package/dist/core/canvas/browse/app.d.ts +1 -1
- package/dist/core/canvas/browse/app.js +21 -3
- package/dist/core/canvas/browse/model.d.ts +8 -2
- package/dist/core/canvas/browse/model.js +11 -4
- package/dist/core/canvas/browse/render.d.ts +4 -0
- package/dist/core/canvas/browse/render.js +5 -1
- package/dist/core/canvas/canvas.d.ts +33 -0
- package/dist/core/canvas/canvas.js +92 -0
- package/dist/core/canvas/crons.d.ts +9 -0
- package/dist/core/canvas/crons.js +51 -0
- package/dist/core/canvas/node-order.d.ts +22 -1
- package/dist/core/canvas/node-order.js +26 -1
- package/dist/core/canvas/render-source.d.ts +5 -0
- package/dist/core/canvas/render-source.js +1 -0
- package/dist/core/canvas/types.d.ts +9 -3
- package/dist/core/command-plugins/bundle.d.ts +6 -1
- package/dist/core/command-plugins/bundle.js +26 -13
- package/dist/core/command.js +8 -12
- package/dist/core/config.d.ts +47 -1
- package/dist/core/config.js +138 -4
- package/dist/core/help.d.ts +3 -0
- package/dist/core/help.js +1 -1
- package/dist/core/human/__tests__/page-catalog.test.d.ts +1 -0
- package/dist/core/human/__tests__/page-catalog.test.js +20 -0
- package/dist/core/human/__tests__/page-tickets.test.js +68 -34
- package/dist/core/human/__tests__/page.test.js +60 -119
- package/dist/core/human/__tests__/serial/inbox-core.test.js +6 -16
- package/dist/core/human/answer-text.d.ts +3 -0
- package/dist/core/human/answer-text.js +98 -0
- package/dist/core/human/answer.d.ts +53 -0
- package/dist/core/human/answer.js +119 -0
- package/dist/core/human/component-docs.d.ts +18 -0
- package/dist/core/human/component-docs.js +434 -0
- package/dist/core/human/convention.d.ts +17 -3
- package/dist/core/human/convention.js +36 -5
- package/dist/core/human/feedback-companion.d.ts +20 -0
- package/dist/core/human/feedback-companion.js +98 -0
- package/dist/core/human/feedback.d.ts +65 -0
- package/dist/core/human/feedback.js +116 -0
- package/dist/core/human/page-catalog.d.ts +56 -5
- package/dist/core/human/page-catalog.js +151 -22
- package/dist/core/human/page-errors.d.ts +4 -0
- package/dist/core/human/page-errors.js +7 -0
- package/dist/core/human/page-eval.d.ts +20 -0
- package/dist/core/human/page-eval.js +123 -0
- package/dist/core/human/page-schema.d.ts +48 -116
- package/dist/core/human/page-schema.js +100 -72
- package/dist/core/human/page-synth.d.ts +2 -4
- package/dist/core/human/page-synth.js +20 -7
- package/dist/core/human/page.d.ts +13 -21
- package/dist/core/human/page.js +147 -391
- package/dist/core/human/review-schema.d.ts +1 -0
- package/dist/core/human/review-schema.js +1 -1
- package/dist/core/human/root.d.ts +6 -2
- package/dist/core/human/root.js +12 -4
- package/dist/core/human/scan.d.ts +3 -3
- package/dist/core/human/scan.js +21 -21
- package/dist/core/human/summary.d.ts +2 -6
- package/dist/core/human/summary.js +3 -59
- package/dist/core/human/tickets.d.ts +22 -15
- package/dist/core/human/tickets.js +90 -28
- package/dist/core/human/types.d.ts +14 -2
- package/dist/core/keybindings/catalog.d.ts +2 -2
- package/dist/core/keybindings/catalog.js +1 -0
- package/dist/core/preview-registry.js +8 -10
- package/dist/core/profiles/default-binding.d.ts +4 -0
- package/dist/core/profiles/default-binding.js +24 -0
- package/dist/core/profiles/deletion-reservation.d.ts +8 -0
- package/dist/core/profiles/deletion-reservation.js +38 -0
- package/dist/core/profiles/manifest.d.ts +3 -0
- package/dist/core/profiles/manifest.js +12 -0
- package/dist/core/profiles/select.js +2 -2
- package/dist/core/review/realize.js +12 -4
- package/dist/core/review/store.d.ts +6 -0
- package/dist/core/review/store.js +31 -0
- package/dist/core/runtime/bearings.d.ts +0 -4
- package/dist/core/runtime/bearings.js +4 -62
- package/dist/core/runtime/bin-contributions.d.ts +44 -0
- package/dist/core/runtime/bin-contributions.js +186 -0
- package/dist/core/runtime/boot-root.js +6 -1
- package/dist/core/runtime/broker/client-registry.d.ts +4 -0
- package/dist/core/runtime/broker/client-registry.js +13 -1
- package/dist/core/runtime/broker/extension-abort.d.ts +1 -1
- package/dist/core/runtime/broker/extension-abort.js +4 -2
- package/dist/core/runtime/broker/fault-retry.js +4 -0
- package/dist/core/runtime/broker/frame-dispatch.d.ts +3 -1
- package/dist/core/runtime/broker/frame-dispatch.js +5 -6
- package/dist/core/runtime/broker/read-ops.d.ts +1 -1
- package/dist/core/runtime/broker/read-ops.js +2 -2
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +6 -1
- package/dist/core/runtime/broker-extension-render.js +19 -0
- package/dist/core/runtime/broker-protocol.d.ts +14 -0
- package/dist/core/runtime/broker.d.ts +1 -1
- package/dist/core/runtime/broker.js +25 -12
- package/dist/core/runtime/busy.d.ts +4 -3
- package/dist/core/runtime/busy.js +4 -3
- package/dist/core/runtime/front-door-env.d.ts +5 -0
- package/dist/core/runtime/front-door-env.js +16 -0
- package/dist/core/runtime/front-door.d.ts +1 -5
- package/dist/core/runtime/front-door.js +2 -5
- package/dist/core/runtime/host.d.ts +1 -1
- package/dist/core/runtime/invocation.d.ts +6 -0
- package/dist/core/runtime/invocation.js +10 -0
- package/dist/core/runtime/kickoff.js +34 -0
- package/dist/core/runtime/launch.d.ts +2 -6
- package/dist/core/runtime/node-read.js +4 -1
- package/dist/core/runtime/nodes.js +2 -0
- package/dist/core/runtime/promote.d.ts +1 -0
- package/dist/core/runtime/promote.js +3 -1
- package/dist/core/runtime/session-cycles.d.ts +6 -0
- package/dist/core/runtime/session-cycles.js +15 -1
- package/dist/core/runtime/session-visibility.d.ts +17 -8
- package/dist/core/runtime/session-visibility.js +19 -10
- package/dist/core/runtime/spawn-env.d.ts +9 -1
- package/dist/core/runtime/spawn-env.js +62 -2
- package/dist/core/runtime/spawn.js +4 -4
- package/dist/core/runtime/stop-guard.d.ts +2 -2
- package/dist/core/runtime/stop-guard.js +2 -2
- package/dist/core/runtime/stop-signals.d.ts +1 -1
- package/dist/core/runtime/stop-signals.js +2 -2
- package/dist/core/runtime/tmux-bindings.js +1 -1
- package/dist/core/session-model/session-state.d.ts +4 -3
- package/dist/core/session-model/session-state.js +14 -1
- package/dist/core/user-settings.d.ts +36 -2
- package/dist/core/user-settings.js +56 -14
- package/dist/core/worktree.d.ts +15 -45
- package/dist/core/worktree.js +59 -261
- package/dist/daemon/api/__tests__/seam/profile-delete.test.d.ts +1 -0
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +386 -0
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +9 -5
- package/dist/daemon/api/handlers/feedback-comments.d.ts +2 -0
- package/dist/daemon/api/handlers/feedback-comments.js +207 -0
- package/dist/daemon/api/handlers/human.js +24 -20
- package/dist/daemon/api/handlers/inbox.d.ts +10 -0
- package/dist/daemon/api/handlers/inbox.js +48 -109
- package/dist/daemon/api/handlers/profiles.js +11 -29
- package/dist/daemon/api/map.d.ts +6 -1
- package/dist/daemon/api/map.js +23 -0
- package/dist/daemon/api/server.js +3 -1
- package/dist/daemon/companion-retire.d.ts +2 -0
- package/dist/daemon/companion-retire.js +33 -0
- package/dist/daemon/cron-run.js +29 -17
- package/dist/daemon/crtrd.js +1 -1
- package/dist/daemon/fleet.d.ts +22 -10
- package/dist/daemon/fleet.js +43 -24
- package/dist/daemon/human/finish.d.ts +12 -6
- package/dist/daemon/human/finish.js +134 -54
- package/dist/daemon/human/sweep.js +9 -3
- package/dist/daemon/profile-delete.d.ts +7 -0
- package/dist/daemon/profile-delete.js +306 -0
- package/dist/daemon/reconcilers/broker-supervision.js +14 -9
- package/dist/daemon/reconcilers/dormant-inbox.js +11 -6
- package/dist/daemon/reconcilers/live-obligation.d.ts +21 -1
- package/dist/daemon/reconcilers/live-obligation.js +30 -2
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -0
- package/dist/daemon/reconcilers/storage-maintenance.js +28 -1
- package/dist/daemon/review/deliver.js +3 -3
- package/dist/daemon/review/finish.d.ts +0 -2
- package/dist/daemon/review/finish.js +1 -29
- package/dist/daemon/review/sweep.js +12 -1
- package/dist/pi-extensions/__tests__/canvas-bash-valve.test.js +56 -1
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +4 -4
- package/dist/pi-extensions/canvas-bash-valve.d.ts +9 -1
- package/dist/pi-extensions/canvas-bash-valve.js +31 -13
- package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
- package/dist/pi-extensions/canvas-review-boundary.d.ts +4 -0
- package/dist/pi-extensions/canvas-review-boundary.js +18 -9
- package/dist/pi-extensions/canvas-stophook.js +4 -4
- package/dist/shared/generated-context.js +2 -2
- package/dist/types.d.ts +61 -5
- package/dist/types.js +8 -2
- package/package.json +4 -4
- package/runtime.lock.json +5 -33
- package/scripts/install-runtime.mjs +19 -24
- package/dist/builtin-memory/init.md +0 -38
- package/dist/builtin-memory/plan.md +0 -19
- package/dist/builtin-memory/spec.md +0 -19
- package/dist/clients/attach/render/html-markdown.d.ts +0 -13
- package/dist/clients/attach/render/html-markdown.js +0 -206
- package/dist/commands/human/doc.js +0 -144
- package/dist/commands/human/inbox.d.ts +0 -2
- package/dist/core/human/__tests__/page-render.test.js +0 -49
- package/dist/core/human/markdown-html.d.ts +0 -8
- package/dist/core/human/markdown-html.js +0 -581
- package/dist/core/human/page-render.d.ts +0 -3
- package/dist/core/human/page-render.js +0 -131
- package/dist/pages/bundle.css +0 -1
- package/dist/pages/bundle.js +0 -1347
- package/dist/pages/comments.d.ts +0 -43
- package/dist/pages/comments.js +0 -125
- package/dist/pages/elements/cards.d.ts +0 -17
- package/dist/pages/elements/cards.js +0 -802
- package/dist/pages/elements/chart.js +0 -648
- package/dist/pages/elements/options.d.ts +0 -21
- package/dist/pages/elements/options.js +0 -629
- package/dist/pages/elements/pages.d.ts +0 -24
- package/dist/pages/elements/pages.js +0 -355
- package/dist/pages/elements/slot.d.ts +0 -21
- package/dist/pages/elements/slot.js +0 -105
- package/dist/pages/elements/table.d.ts +0 -19
- package/dist/pages/elements/table.js +0 -935
- package/dist/pages/elements/text.d.ts +0 -25
- package/dist/pages/elements/text.js +0 -968
- package/dist/pages/entry.d.ts +0 -8
- package/dist/pages/entry.js +0 -8
- package/dist/pages/host.d.ts +0 -158
- package/dist/pages/host.js +0 -182
- package/dist/pages/register.d.ts +0 -2
- package/dist/pages/register.js +0 -3
- package/dist/pages/slot-config.d.ts +0 -36
- package/dist/pages/slot-config.js +0 -50
- package/dist/pages/types.d.ts +0 -98
- package/dist/pages/types.js +0 -23
- /package/dist/{core/human/__tests__/page-render.test.d.ts → commands/__tests__/node-message.test.d.ts} +0 -0
- /package/dist/{pages/elements/chart.d.ts → core/__tests__/plugin-page-components.test.d.ts} +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { PageTicketSummary, TicketSummary } from './types.js';
|
|
2
2
|
/** Read all unresolved page/review tickets, newest first. Progress never affects visibility. */
|
|
3
|
-
export declare function scanInbox(
|
|
3
|
+
export declare function scanInbox(): TicketSummary[];
|
|
4
4
|
export interface PageHistoryEntry extends PageTicketSummary {
|
|
5
|
-
state: 'pending' | 'resolved' | 'canceled';
|
|
5
|
+
state: 'pending' | 'resolved' | 'canceled' | 'passive';
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Every page ticket raised by one node — pending, resolved or canceled — oldest
|
|
9
9
|
* first. This is the durable discovery seam for transcript placement, so it is a
|
|
10
10
|
* separate walk from the pending-only inbox scan and never filters on a terminal file.
|
|
11
11
|
*/
|
|
12
|
-
export declare function scanPageHistory(nodeId: string
|
|
12
|
+
export declare function scanPageHistory(nodeId: string): PageHistoryEntry[];
|
package/dist/core/human/scan.js
CHANGED
|
@@ -3,8 +3,8 @@ import { basename, join } from 'node:path';
|
|
|
3
3
|
import { claimPath, isResolved, pageManifestPath, reviewPath } from './convention.js';
|
|
4
4
|
import { readJsonOrNull } from '../fs-utils.js';
|
|
5
5
|
import { validateReviewDescriptor } from './review-schema.js';
|
|
6
|
-
import {
|
|
7
|
-
import { pageTicketState } from './tickets.js';
|
|
6
|
+
import { parsePage } from './page.js';
|
|
7
|
+
import { pageTicketState, readTicketResult } from './tickets.js';
|
|
8
8
|
import { ticketsRoot } from './root.js';
|
|
9
9
|
function claimSummary(dir) {
|
|
10
10
|
const claim = readJsonOrNull(claimPath(dir));
|
|
@@ -25,21 +25,18 @@ function reviewSummary(dir, id) {
|
|
|
25
25
|
}
|
|
26
26
|
return { dir, id, kind: 'review', title: review.title, subtitle: review.subtitle, file: review.file, output: review.output, source: review.source, blockedSince: review.blockedSince, claim: claimSummary(dir) };
|
|
27
27
|
}
|
|
28
|
-
function pageSummary(dir, id
|
|
29
|
-
const raw = readJsonOrNull(pageManifestPath(dir));
|
|
30
|
-
if (raw === null)
|
|
31
|
-
return null;
|
|
28
|
+
function pageSummary(dir, id) {
|
|
32
29
|
let manifest;
|
|
33
30
|
try {
|
|
34
|
-
manifest =
|
|
31
|
+
manifest = parsePage(dir);
|
|
35
32
|
}
|
|
36
33
|
catch {
|
|
37
34
|
return null;
|
|
38
35
|
}
|
|
39
|
-
let
|
|
40
|
-
if (
|
|
36
|
+
let emittedAt = manifest.source?.emittedAt;
|
|
37
|
+
if (emittedAt === undefined) {
|
|
41
38
|
try {
|
|
42
|
-
|
|
39
|
+
emittedAt = statSync(pageManifestPath(dir)).mtime.toISOString();
|
|
43
40
|
}
|
|
44
41
|
catch {
|
|
45
42
|
return null;
|
|
@@ -52,17 +49,18 @@ function pageSummary(dir, id, productKinds) {
|
|
|
52
49
|
title: manifest.title,
|
|
53
50
|
subtitle: manifest.subtitle ?? '',
|
|
54
51
|
dialect: manifest.dialect,
|
|
55
|
-
placement: manifest.placement,
|
|
52
|
+
placement: manifest.delivery.placement,
|
|
53
|
+
inbox: manifest.delivery.inbox,
|
|
56
54
|
steps: manifest.steps,
|
|
57
55
|
slotKinds: manifest.slots.map((slot) => slot.kind),
|
|
58
|
-
awaitsResponse: manifest.
|
|
56
|
+
awaitsResponse: manifest.delivery.reply,
|
|
59
57
|
source: manifest.source ?? {},
|
|
60
|
-
|
|
58
|
+
emittedAt,
|
|
61
59
|
claim: claimSummary(dir),
|
|
62
60
|
};
|
|
63
61
|
}
|
|
64
62
|
/** Read all unresolved page/review tickets, newest first. Progress never affects visibility. */
|
|
65
|
-
export function scanInbox(
|
|
63
|
+
export function scanInbox() {
|
|
66
64
|
let entries;
|
|
67
65
|
try {
|
|
68
66
|
entries = readdirSync(ticketsRoot());
|
|
@@ -82,18 +80,18 @@ export function scanInbox(productKinds = []) {
|
|
|
82
80
|
}
|
|
83
81
|
if (isResolved(dir))
|
|
84
82
|
continue;
|
|
85
|
-
const item = reviewSummary(dir, basename(dir)) ?? pageSummary(dir, basename(dir)
|
|
86
|
-
if (item !== null)
|
|
83
|
+
const item = reviewSummary(dir, basename(dir)) ?? pageSummary(dir, basename(dir));
|
|
84
|
+
if (item !== null && (item.kind !== 'page' || item.inbox))
|
|
87
85
|
items.push(item);
|
|
88
86
|
}
|
|
89
|
-
return items.sort((a, b) => b.blockedSince.localeCompare(a.blockedSince) || a.id.localeCompare(b.id));
|
|
87
|
+
return items.sort((a, b) => (b.kind === 'page' ? b.emittedAt : b.blockedSince).localeCompare(a.kind === 'page' ? a.emittedAt : a.blockedSince) || a.id.localeCompare(b.id));
|
|
90
88
|
}
|
|
91
89
|
/**
|
|
92
90
|
* Every page ticket raised by one node — pending, resolved or canceled — oldest
|
|
93
91
|
* first. This is the durable discovery seam for transcript placement, so it is a
|
|
94
92
|
* separate walk from the pending-only inbox scan and never filters on a terminal file.
|
|
95
93
|
*/
|
|
96
|
-
export function scanPageHistory(nodeId
|
|
94
|
+
export function scanPageHistory(nodeId) {
|
|
97
95
|
let entries;
|
|
98
96
|
try {
|
|
99
97
|
entries = readdirSync(ticketsRoot());
|
|
@@ -111,10 +109,12 @@ export function scanPageHistory(nodeId, productKinds = []) {
|
|
|
111
109
|
catch {
|
|
112
110
|
continue;
|
|
113
111
|
}
|
|
114
|
-
const summary = pageSummary(dir, basename(dir)
|
|
112
|
+
const summary = pageSummary(dir, basename(dir));
|
|
115
113
|
if (summary === null || summary.source.nodeId !== nodeId)
|
|
116
114
|
continue;
|
|
117
|
-
|
|
115
|
+
const state = pageTicketState(dir);
|
|
116
|
+
const result = state === 'resolved' ? readTicketResult(dir) : null;
|
|
117
|
+
items.push({ ...summary, state, ...(result?.kind === 'page' ? { answerDigest: result.summary.replace(/\s+/g, ' ').trim() } : {}) });
|
|
118
118
|
}
|
|
119
|
-
return items.sort((a, b) => Date.parse(a.
|
|
119
|
+
return items.sort((a, b) => Date.parse(a.emittedAt) - Date.parse(b.emittedAt) || a.id.localeCompare(b.id));
|
|
120
120
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
* Deterministic, no-LLM page resolution summary — one line per answered slot in
|
|
4
|
-
* document order: `"<slot id>: <answer>"`. An acknowledgement (`responses: {}`)
|
|
5
|
-
* summarizes as the empty string.
|
|
6
|
-
*/
|
|
1
|
+
import type { PageManifest, PageResponses } from './page-schema.js';
|
|
2
|
+
/** The stable one-line digest stored in response.json. */
|
|
7
3
|
export declare function buildPageSummary(manifest: PageManifest, responses: PageResponses): string;
|
|
@@ -1,61 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const byId = new Map((Array.isArray(items) ? items : [])
|
|
4
|
-
.filter((item) => typeof item === 'object' && item !== null)
|
|
5
|
-
.map((item) => [String(item['id']), typeof item[labelKey] === 'string' ? item[labelKey] : String(item['id'])]));
|
|
6
|
-
return (Array.isArray(ids) ? ids : []).map((id) => byId.get(String(id)) ?? String(id));
|
|
7
|
-
}
|
|
8
|
-
function pickedWithFreetext(picked, freetext) {
|
|
9
|
-
const text = typeof freetext === 'string' && freetext !== '' ? freetext : undefined;
|
|
10
|
-
const selection = picked.length > 0 ? picked.join(', ') : undefined;
|
|
11
|
-
if (selection !== undefined && text !== undefined)
|
|
12
|
-
return `${selection} — ${text}`;
|
|
13
|
-
return selection ?? text ?? '(no selection)';
|
|
14
|
-
}
|
|
15
|
-
function commentSuffix(response) {
|
|
16
|
-
const comments = response['comments'];
|
|
17
|
-
const count = Array.isArray(comments) ? comments.length : 0;
|
|
18
|
-
return count === 0 ? '' : ` (${count} comment${count === 1 ? '' : 's'})`;
|
|
19
|
-
}
|
|
20
|
-
function describeSlotResponse(slot, response) {
|
|
21
|
-
const value = response;
|
|
22
|
-
const config = slot.config;
|
|
23
|
-
switch (slot.kind) {
|
|
24
|
-
case 'options':
|
|
25
|
-
return `${pickedWithFreetext(labelsOf(config['options'], value['selectedOptionIds'], 'label'), value['freetext'])}${commentSuffix(value)}`;
|
|
26
|
-
case 'text': {
|
|
27
|
-
const text = typeof value['text'] === 'string' ? value['text'].replace(/\s+/g, ' ').trim() : '';
|
|
28
|
-
return `${text === '' ? '(empty)' : text}${commentSuffix(value)}`;
|
|
29
|
-
}
|
|
30
|
-
case 'table': {
|
|
31
|
-
const rows = (Array.isArray(value['selectedRowIds']) ? value['selectedRowIds'] : []).map(String);
|
|
32
|
-
const columns = labelsOf(config['columns'], value['selectedColumnIds'], 'label');
|
|
33
|
-
const parts = [...(rows.length > 0 ? [`rows ${rows.join(', ')}`] : []), ...(columns.length > 0 ? [`columns ${columns.join(', ')}`] : [])];
|
|
34
|
-
return `${parts.length === 0 ? '(no selection)' : parts.join('; ')}${commentSuffix(value)}`;
|
|
35
|
-
}
|
|
36
|
-
case 'cards': {
|
|
37
|
-
const picked = labelsOf(config['cards'], value['selectedCardIds'], 'title');
|
|
38
|
-
return `${picked.length === 0 ? '(no selection)' : picked.join(', ')}${commentSuffix(value)}`;
|
|
39
|
-
}
|
|
40
|
-
default:
|
|
41
|
-
// A product kind crtr does not render: its opaque response is the summary.
|
|
42
|
-
return JSON.stringify(value);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Deterministic, no-LLM page resolution summary — one line per answered slot in
|
|
47
|
-
* document order: `"<slot id>: <answer>"`. An acknowledgement (`responses: {}`)
|
|
48
|
-
* summarizes as the empty string.
|
|
49
|
-
*/
|
|
1
|
+
import { describePageAnswer } from './answer.js';
|
|
2
|
+
/** The stable one-line digest stored in response.json. */
|
|
50
3
|
export function buildPageSummary(manifest, responses) {
|
|
51
|
-
|
|
52
|
-
for (const slot of manifest.slots) {
|
|
53
|
-
if (!isResponseBearingSlot(slot) || slot.id === undefined)
|
|
54
|
-
continue;
|
|
55
|
-
const response = responses[slot.id];
|
|
56
|
-
if (response === undefined)
|
|
57
|
-
continue;
|
|
58
|
-
lines.push(`${slot.id}: ${describeSlotResponse(slot, response)}`);
|
|
59
|
-
}
|
|
60
|
-
return lines.join('\n');
|
|
4
|
+
return describePageAnswer(manifest, responses, { completedAt: '' }).digest;
|
|
61
5
|
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import type { ReviewDescriptor, TicketResult } from './types.js';
|
|
2
|
-
import {
|
|
3
|
-
import { type PageManifest, type PageResponses, type PageSource } from './page-schema.js';
|
|
2
|
+
import type { ProductPageComponents } from '../../types.js';
|
|
3
|
+
import { type PageDelivery, type PageManifest, type PageResponses, type PageSource } from './page-schema.js';
|
|
4
4
|
/** Strict decoder for the only canonical final marker. */
|
|
5
5
|
export declare function readTicketResult(dir: string): TicketResult | null;
|
|
6
6
|
export interface SubmitPageOptions {
|
|
7
7
|
dir: string;
|
|
8
8
|
/** The authored page source; copied into the ticket directory as its `document`. */
|
|
9
9
|
sourceFile: string;
|
|
10
|
-
dialect: PageDialect;
|
|
11
10
|
source?: PageSource;
|
|
12
|
-
productKinds?:
|
|
11
|
+
productKinds?: ProductPageComponents;
|
|
12
|
+
delivery?: PageDelivery;
|
|
13
13
|
}
|
|
14
14
|
/** One validated page, ready to publish into a ticket directory. */
|
|
15
15
|
export interface PreparedPage {
|
|
16
|
-
dialect: PageDialect;
|
|
17
16
|
/** The authored source, verbatim, as the ticket's `document`. */
|
|
18
17
|
document: string;
|
|
18
|
+
/** The compiled CommonJS module the Gateway evaluates for JSX pages. */
|
|
19
|
+
module?: string;
|
|
19
20
|
manifest: PageManifest;
|
|
20
21
|
}
|
|
21
22
|
/** Validate one authored page source into publishable form. Reads only: a page
|
|
@@ -24,7 +25,12 @@ export interface PreparedPage {
|
|
|
24
25
|
* The source is read exactly once, so the published document is the same bytes
|
|
25
26
|
* the manifest was derived from even if the file changes underneath. */
|
|
26
27
|
export declare function preparePage(opts: Omit<SubmitPageOptions, 'dir'>): PreparedPage;
|
|
27
|
-
/** Publish one prepared page ticket: the authored source plus its manifest
|
|
28
|
+
/** Publish one prepared page ticket: the authored source plus its manifest.
|
|
29
|
+
* These writes are overwrites. A ticket's REQUEST is whatever page the agent
|
|
30
|
+
* currently wants on screen, and `crtr human send --replace` revises it in
|
|
31
|
+
* place while the human watches; only the ANSWER is write-once, which
|
|
32
|
+
* `publishJsonExclusive` still guarantees for response.json alone. The manifest
|
|
33
|
+
* switches after all new generation files exist, then stale media is removed. */
|
|
28
34
|
export declare function publishPage(dir: string, prepared: PreparedPage): {
|
|
29
35
|
id: string;
|
|
30
36
|
dir: string;
|
|
@@ -53,26 +59,27 @@ export declare function submitReview(opts: SubmitReviewOptions): {
|
|
|
53
59
|
kind: 'review';
|
|
54
60
|
};
|
|
55
61
|
/** Validate a page resolution against its canonical ticket before claim takeover. */
|
|
56
|
-
export declare function validatePageTicketResponses(dir: string, responses: unknown
|
|
62
|
+
export declare function validatePageTicketResponses(dir: string, responses: unknown): PageResponses;
|
|
57
63
|
/** The three terminal states of a page ticket, derived from its published result. */
|
|
58
|
-
export declare function pageTicketState(dir: string): 'pending' | 'resolved' | 'canceled';
|
|
59
|
-
/** Autosave partial page work. Every supplied response is validated; omitted
|
|
60
|
-
export declare function writePageProgress(dir: string, responses: unknown
|
|
64
|
+
export declare function pageTicketState(dir: string): 'pending' | 'resolved' | 'canceled' | 'passive';
|
|
65
|
+
/** Autosave partial page work. Every supplied response is validated; omitted components are permitted. */
|
|
66
|
+
export declare function writePageProgress(dir: string, responses: unknown): PageResponses;
|
|
61
67
|
/** Saved partial work, or null when none exists. Malformed progress is an error, never silently discarded. */
|
|
62
|
-
export declare function readPageProgress(dir: string
|
|
68
|
+
export declare function readPageProgress(dir: string): PageResponses | null;
|
|
63
69
|
export interface PageTicket {
|
|
64
70
|
dir: string;
|
|
65
71
|
id: string;
|
|
66
72
|
manifest: PageManifest;
|
|
67
|
-
/** The authored source document, verbatim. */
|
|
73
|
+
/** The authored TSX source document, verbatim. */
|
|
68
74
|
document: string;
|
|
69
|
-
|
|
75
|
+
/** The compiled module the Gateway evaluates, for JSX pages. */
|
|
76
|
+
module?: string;
|
|
77
|
+
state: 'pending' | 'resolved' | 'canceled' | 'passive';
|
|
70
78
|
progress: PageResponses | null;
|
|
71
79
|
}
|
|
72
80
|
/** Read one addressable page ticket — pending, resolved or canceled alike. */
|
|
73
|
-
export declare function readPageTicket(dir: string
|
|
81
|
+
export declare function readPageTicket(dir: string): PageTicket;
|
|
74
82
|
export interface CompletePageOptions {
|
|
75
|
-
productKinds?: string[];
|
|
76
83
|
completedAt?: string;
|
|
77
84
|
}
|
|
78
85
|
export declare function completePage(dir: string, responses: unknown, claimToken: string, opts?: CompletePageOptions): {
|
|
@@ -3,10 +3,10 @@ import { basename, isAbsolute, resolve } from 'node:path';
|
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { buildPageSummary } from './summary.js';
|
|
6
|
-
import { atomicWriteJson, clearProgress, claimPath, pageManifestPath, pagePath, progressPath, publishJsonExclusive, requireTicket, responsePath, reviewPath } from './convention.js';
|
|
6
|
+
import { atomicWriteJson, atomicWriteText, clearProgress, claimPath, pageManifestPath, pageModulePath, pagePath, progressPath, publishJsonExclusive, requireTicket, responsePath, reviewPath } from './convention.js';
|
|
7
7
|
import { validateReviewDescriptor, validateReviewProjection } from './review-schema.js';
|
|
8
|
-
import { derivePageManifestFromDocument, parsePage, PageAuthoringError } from './page.js';
|
|
9
|
-
import { validatePageResponses, validatePartialPageResponses } from './page-schema.js';
|
|
8
|
+
import { compilePage, deriveHtmlPageManifest, derivePageManifestFromDocument, parsePage, PageAuthoringError } from './page.js';
|
|
9
|
+
import { isResponseBearingSlot, validatePageResponses, validatePartialPageResponses } from './page-schema.js';
|
|
10
10
|
import { signalInboxActivity } from './root.js';
|
|
11
11
|
import { readTicketClaim, releaseClaimLocked, withTicketLock } from './claim.js';
|
|
12
12
|
import { checkReviewableFile } from './visible-paths.js';
|
|
@@ -46,7 +46,7 @@ export function readTicketResult(dir) {
|
|
|
46
46
|
return canceled.success ? canceled.data : null;
|
|
47
47
|
}
|
|
48
48
|
function hasTicketProtocolState(dir) {
|
|
49
|
-
return [pageManifestPath(dir), pagePath(dir
|
|
49
|
+
return [pageManifestPath(dir), pagePath(dir), pageModulePath(dir), reviewPath(dir), responsePath(dir), progressPath(dir), claimPath(dir)].some(existsSync);
|
|
50
50
|
}
|
|
51
51
|
function publishRequest(path, value) {
|
|
52
52
|
if (!publishJsonExclusive(path, value))
|
|
@@ -58,26 +58,58 @@ function publishRequest(path, value) {
|
|
|
58
58
|
* The source is read exactly once, so the published document is the same bytes
|
|
59
59
|
* the manifest was derived from even if the file changes underneath. */
|
|
60
60
|
export function preparePage(opts) {
|
|
61
|
+
const html = /\.html?$/i.test(opts.sourceFile);
|
|
62
|
+
if (!html && !opts.sourceFile.endsWith('.tsx'))
|
|
63
|
+
throw new PageAuthoringError(`page source file must be .tsx, .html, or .htm: ${opts.sourceFile}`);
|
|
61
64
|
if (!existsSync(opts.sourceFile))
|
|
62
65
|
throw new PageAuthoringError(`page source file does not exist: ${opts.sourceFile}`);
|
|
63
66
|
const document = readFileSync(opts.sourceFile, 'utf8');
|
|
64
|
-
const stamped = { ...(opts.source ?? {}),
|
|
65
|
-
|
|
67
|
+
const stamped = { ...(opts.source ?? {}), emittedAt: opts.source?.emittedAt ?? new Date().toISOString() };
|
|
68
|
+
const delivery = opts.delivery ?? { placement: 'inline', inbox: false, reply: false };
|
|
69
|
+
if (html)
|
|
70
|
+
return { document, manifest: deriveHtmlPageManifest(document, stamped, delivery) };
|
|
71
|
+
return { document, module: compilePage(document), manifest: derivePageManifestFromDocument(document, opts.productKinds ?? [], stamped, delivery) };
|
|
66
72
|
}
|
|
67
|
-
/**
|
|
73
|
+
/** Remove a stale generation file. The manifest always switches first, so a
|
|
74
|
+
* failed cleanup leaves one valid current record plus harmless old source. */
|
|
75
|
+
function unlinkIfPresent(path) {
|
|
76
|
+
try {
|
|
77
|
+
unlinkSync(path);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error.code !== 'ENOENT')
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Publish one prepared page ticket: the authored source plus its manifest.
|
|
85
|
+
* These writes are overwrites. A ticket's REQUEST is whatever page the agent
|
|
86
|
+
* currently wants on screen, and `crtr human send --replace` revises it in
|
|
87
|
+
* place while the human watches; only the ANSWER is write-once, which
|
|
88
|
+
* `publishJsonExclusive` still guarantees for response.json alone. The manifest
|
|
89
|
+
* switches after all new generation files exist, then stale media is removed. */
|
|
68
90
|
export function publishPage(dir, prepared) {
|
|
69
91
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
70
92
|
const ticket = realpathSync(dir);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
93
|
+
atomicWriteText(pagePath(ticket, prepared.manifest.dialect), prepared.document);
|
|
94
|
+
if (prepared.manifest.dialect === 'jsx')
|
|
95
|
+
atomicWriteText(pageModulePath(ticket), prepared.module);
|
|
96
|
+
atomicWriteJson(pageManifestPath(ticket), prepared.manifest);
|
|
97
|
+
if (prepared.manifest.dialect === 'jsx')
|
|
98
|
+
unlinkIfPresent(pagePath(ticket, 'html'));
|
|
99
|
+
else {
|
|
100
|
+
unlinkIfPresent(pagePath(ticket, 'jsx'));
|
|
101
|
+
unlinkIfPresent(pageModulePath(ticket));
|
|
102
|
+
}
|
|
103
|
+
// Unconditional: a no-inbox page still lives in an attached viewer's transcript, and
|
|
104
|
+
// --replace promises every open surface reloads it.
|
|
75
105
|
signalInboxActivity();
|
|
76
106
|
return { id: basename(ticket), dir: ticket, kind: 'page', manifest: prepared.manifest };
|
|
77
107
|
}
|
|
78
108
|
/** Validate and publish one page ticket in a single step, for callers that own
|
|
79
109
|
* the ticket directory before they have a page. */
|
|
80
110
|
export function submitPage(opts) {
|
|
111
|
+
if (existsSync(opts.dir) && hasTicketProtocolState(opts.dir) && !existsSync(pageManifestPath(opts.dir)))
|
|
112
|
+
throw new Error(`ticket protocol state already exists: ${opts.dir}`);
|
|
81
113
|
return publishPage(opts.dir, preparePage(opts));
|
|
82
114
|
}
|
|
83
115
|
export function submitReview(opts) {
|
|
@@ -102,17 +134,40 @@ function exclusiveResult(dir, result) {
|
|
|
102
134
|
return publishJsonExclusive(responsePath(dir), result);
|
|
103
135
|
}
|
|
104
136
|
function requireReview(dir) { return validateReviewDescriptor(JSON.parse(readFileSync(reviewPath(dir), 'utf8'))); }
|
|
105
|
-
function requirePage(dir
|
|
137
|
+
function requirePage(dir) {
|
|
106
138
|
if (!existsSync(pageManifestPath(dir)))
|
|
107
139
|
throw new Error(`not a page ticket: ${dir}`);
|
|
108
|
-
return parsePage(dir
|
|
140
|
+
return parsePage(dir);
|
|
141
|
+
}
|
|
142
|
+
function requireSettleablePage(dir) {
|
|
143
|
+
const manifest = requirePage(dir);
|
|
144
|
+
if (!manifest.delivery.inbox && !manifest.delivery.reply)
|
|
145
|
+
throw new Error('page_has_no_response_lifecycle');
|
|
146
|
+
return manifest;
|
|
147
|
+
}
|
|
148
|
+
function isEmptyResponseMap(responses) {
|
|
149
|
+
return typeof responses === 'object' && responses !== null && !Array.isArray(responses) && Object.keys(responses).length === 0;
|
|
150
|
+
}
|
|
151
|
+
/** Validate a final page response against its ticket's reply contract. */
|
|
152
|
+
function validateFinalPageTicketResponses(dir, responses) {
|
|
153
|
+
const manifest = requireSettleablePage(dir);
|
|
154
|
+
// An inbox-only page accepts an empty acknowledgement without requiring an answer
|
|
155
|
+
// from every response-bearing component.
|
|
156
|
+
if (!manifest.delivery.reply && isEmptyResponseMap(responses)) {
|
|
157
|
+
return validatePartialPageResponses(manifest, responses);
|
|
158
|
+
}
|
|
159
|
+
return validatePageResponses(manifest, responses);
|
|
109
160
|
}
|
|
110
161
|
/** Validate a page resolution against its canonical ticket before claim takeover. */
|
|
111
|
-
export function validatePageTicketResponses(dir, responses
|
|
112
|
-
|
|
162
|
+
export function validatePageTicketResponses(dir, responses) {
|
|
163
|
+
const ticket = requireTicket(dir);
|
|
164
|
+
return validateFinalPageTicketResponses(ticket, responses);
|
|
113
165
|
}
|
|
114
166
|
/** The three terminal states of a page ticket, derived from its published result. */
|
|
115
167
|
export function pageTicketState(dir) {
|
|
168
|
+
const manifest = requirePage(dir);
|
|
169
|
+
if (!manifest.delivery.inbox && !manifest.delivery.reply)
|
|
170
|
+
return 'passive';
|
|
116
171
|
const result = readTicketResult(dir);
|
|
117
172
|
if (result === null)
|
|
118
173
|
return 'pending';
|
|
@@ -131,33 +186,38 @@ function readPageProgressFor(dir, manifest) {
|
|
|
131
186
|
const parsed = pageProgressSchema.safeParse(raw);
|
|
132
187
|
if (!parsed.success)
|
|
133
188
|
throw new Error(`page progress is malformed: ${progressPath(dir)}`);
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
189
|
+
// A pending page's request can be replaced under saved work, so progress may
|
|
190
|
+
// name a component the current page no longer declares. Those entries are dropped
|
|
191
|
+
// and everything still declared hydrates; what remains is validated, so a
|
|
192
|
+
// saved answer that no longer fits its own component is still an error.
|
|
193
|
+
const declared = new Set(manifest.slots.filter(isResponseBearingSlot).map((slot) => slot.id));
|
|
194
|
+
const current = Object.fromEntries(Object.entries(parsed.data.responses).filter(([id]) => declared.has(id)));
|
|
195
|
+
return validatePartialPageResponses(manifest, current);
|
|
137
196
|
}
|
|
138
|
-
/** Autosave partial page work. Every supplied response is validated; omitted
|
|
139
|
-
export function writePageProgress(dir, responses
|
|
197
|
+
/** Autosave partial page work. Every supplied response is validated; omitted components are permitted. */
|
|
198
|
+
export function writePageProgress(dir, responses) {
|
|
140
199
|
const ticket = requireTicket(dir);
|
|
141
|
-
const validated = validatePartialPageResponses(
|
|
200
|
+
const validated = validatePartialPageResponses(requireSettleablePage(ticket), responses);
|
|
142
201
|
atomicWriteJson(progressPath(ticket), { kind: 'page', responses: validated, savedAt: new Date().toISOString() });
|
|
143
202
|
return validated;
|
|
144
203
|
}
|
|
145
204
|
/** Saved partial work, or null when none exists. Malformed progress is an error, never silently discarded. */
|
|
146
|
-
export function readPageProgress(dir
|
|
205
|
+
export function readPageProgress(dir) {
|
|
147
206
|
const ticket = requireTicket(dir);
|
|
148
|
-
return readPageProgressFor(ticket,
|
|
207
|
+
return readPageProgressFor(ticket, requireSettleablePage(ticket));
|
|
149
208
|
}
|
|
150
209
|
/** Read one addressable page ticket — pending, resolved or canceled alike. */
|
|
151
|
-
export function readPageTicket(dir
|
|
210
|
+
export function readPageTicket(dir) {
|
|
152
211
|
const ticket = requireTicket(dir);
|
|
153
|
-
const manifest = requirePage(ticket
|
|
212
|
+
const manifest = requirePage(ticket);
|
|
154
213
|
return {
|
|
155
214
|
dir: ticket,
|
|
156
215
|
id: basename(ticket),
|
|
157
216
|
manifest,
|
|
158
217
|
document: readFileSync(pagePath(ticket, manifest.dialect), 'utf8'),
|
|
218
|
+
...(manifest.dialect === 'jsx' ? { module: readFileSync(pageModulePath(ticket), 'utf8') } : { module: undefined }),
|
|
159
219
|
state: pageTicketState(ticket),
|
|
160
|
-
progress: readPageProgressFor(ticket, manifest),
|
|
220
|
+
progress: manifest.delivery.inbox || manifest.delivery.reply ? readPageProgressFor(ticket, manifest) : null,
|
|
161
221
|
};
|
|
162
222
|
}
|
|
163
223
|
function requireClaimOwnership(dir, token) {
|
|
@@ -168,8 +228,8 @@ function clearOwnedWork(dir, claimToken) { clearProgress(dir); releaseClaimLocke
|
|
|
168
228
|
/** Caller holds `.ticket-lock`. */
|
|
169
229
|
function completePageLocked(dir, responses, claimToken, opts) {
|
|
170
230
|
requireClaimOwnership(dir, claimToken);
|
|
171
|
-
const manifest = requirePage(dir
|
|
172
|
-
const parsedResponses =
|
|
231
|
+
const manifest = requirePage(dir);
|
|
232
|
+
const parsedResponses = validateFinalPageTicketResponses(dir, responses);
|
|
173
233
|
const result = { schema: 'crtr.page-response/v1', kind: 'page', responses: parsedResponses, summary: buildPageSummary(manifest, parsedResponses), completedAt: opts.completedAt ?? new Date().toISOString() };
|
|
174
234
|
const won = exclusiveResult(dir, result);
|
|
175
235
|
clearOwnedWork(dir, claimToken);
|
|
@@ -211,6 +271,8 @@ export function takeoverAndCompletePage(dir, responses, owner, opts = {}) {
|
|
|
211
271
|
export function cancelTicket(dir, opts = {}) {
|
|
212
272
|
const ticket = requireTicket(dir);
|
|
213
273
|
const canceled = withTicketLock(ticket, () => {
|
|
274
|
+
if (existsSync(pageManifestPath(ticket)))
|
|
275
|
+
requireSettleablePage(ticket);
|
|
214
276
|
const result = { schema: 'humanloop.cancel/v1', kind: 'canceled', canceledAt: new Date().toISOString(), ...(opts.reason === undefined ? {} : { reason: opts.reason }), ...(opts.actor === undefined ? {} : { actor: opts.actor }) };
|
|
215
277
|
const won = exclusiveResult(ticket, result);
|
|
216
278
|
return { status: won ? 'canceled' : 'already_resolved', result: won ? result : readTicketResult(ticket) ?? result };
|
|
@@ -4,6 +4,8 @@ export interface TicketSource {
|
|
|
4
4
|
sessionName?: string;
|
|
5
5
|
askedBy?: string;
|
|
6
6
|
blockedSince?: string;
|
|
7
|
+
/** Profile name the originating node runs under. Product consumers use this stable name to resolve the applet or worker identity behind the ticket. */
|
|
8
|
+
profileName?: string;
|
|
7
9
|
/** Originating canvas node id (CRTR_NODE_ID) when the ask was raised inside a crouter canvas node. */
|
|
8
10
|
nodeId?: string;
|
|
9
11
|
}
|
|
@@ -46,10 +48,20 @@ export interface ReviewTicketSummary extends TicketSummaryBase {
|
|
|
46
48
|
output: string;
|
|
47
49
|
}
|
|
48
50
|
/** Page triage fields: a client picks a transcript rendering without a second fetch. */
|
|
49
|
-
export interface PageTicketSummary
|
|
51
|
+
export interface PageTicketSummary {
|
|
52
|
+
dir: string;
|
|
53
|
+
id: string;
|
|
50
54
|
kind: 'page';
|
|
51
|
-
|
|
55
|
+
title: string;
|
|
56
|
+
subtitle: string;
|
|
57
|
+
source: import('./page-schema.js').PageSource;
|
|
58
|
+
emittedAt: string;
|
|
59
|
+
claim?: ClaimSummary;
|
|
60
|
+
/** Present on resolved history entries; the stored one-line response digest. */
|
|
61
|
+
answerDigest?: string;
|
|
62
|
+
dialect: 'jsx' | 'html';
|
|
52
63
|
placement: 'inline' | 'panel';
|
|
64
|
+
inbox: boolean;
|
|
53
65
|
steps: number;
|
|
54
66
|
slotKinds: string[];
|
|
55
67
|
awaitsResponse: boolean;
|
|
@@ -3,13 +3,13 @@ import type { AttachBindingId, AttachMenuBindingId } from './attach-control.js';
|
|
|
3
3
|
type TmuxMenuAction = 'open' | 'attach' | 'show' | 'view-settings' | 'fold-tools' | 'metadata' | 'promote' | 'demote-mode' | 'resume' | 'fork' | 'demote' | 'make-resident' | 'detach' | 'close-subtree' | 'background-bash' | 'file-review' | 'pin' | 'reload-viewer' | 'recap' | 'context' | 'providers' | 'plugins' | 'graph' | 'focus-manager' | 'copy-id' | 'issues';
|
|
4
4
|
type TmuxMenuEntryAction = Exclude<TmuxMenuAction, 'open' | 'attach'> | `issue.${'idea' | 'bug'}`;
|
|
5
5
|
type GraphAction = 'down' | 'up' | 'first' | 'last' | 'collapse-or-manager' | 'expand-or-child' | 'focus' | 'revive' | 'focus-manager' | 'close-subtree' | 'dismiss';
|
|
6
|
-
type BrowseAction = 'quit' | 'down' | 'up' | 'first' | 'last' | 'expand-or-child' | 'collapse-or-parent' | 'toggle-fold' | 'tab-next' | 'tab-previous' | `tab.${1 | 2 | 3 | 4 | 5}` | 'close-subtree' | 'confirm-close' | 'sort' | 'scope' | 'profile' | 'residents' | 'preview' | 'search' | 'revive-now' | 'focus' | 'focus-background';
|
|
6
|
+
type BrowseAction = 'quit' | 'down' | 'up' | 'first' | 'last' | 'expand-or-child' | 'collapse-or-parent' | 'toggle-fold' | 'tab-next' | 'tab-previous' | `tab.${1 | 2 | 3 | 4 | 5}` | 'close-subtree' | 'confirm-close' | 'sort' | 'scope' | 'profile' | 'residents' | 'preview' | 'search' | 'revive-now' | 'focus' | 'focus-background' | 'yank-id';
|
|
7
7
|
type ProfileMenuAction = 'up' | 'down' | 'select' | 'accept-default' | 'abort' | `slot.${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}` | 'create' | 'search-existing' | 'use-root' | 'set-default' | 'add-directory' | 'unpin';
|
|
8
8
|
type SetupAction = 'cancel' | 'tab-next' | 'tab-previous' | 'open' | 'list-down' | 'list-up' | 'toggle' | 'details' | 'advance' | 'cell-previous' | 'cell-next';
|
|
9
9
|
type SetupKeybindingAction = 'edit' | 'commit-edit' | 'cancel-edit' | 'unbind' | 'reset-row' | 'reset-all' | 'save' | 'discard' | 'page-up' | 'page-down' | 'filter' | 'filter-delete' | 'filter-clear';
|
|
10
10
|
type SetupModelsAction = 'open' | 'commit' | 'cancel' | 'scope-next';
|
|
11
11
|
export type BindingId = `crtr.tmux.menu.${TmuxMenuAction}` | `crtr.tmux.menu.issue.${'idea' | 'bug'}` | AttachMenuBindingId | `crtr.tmux.menu-global.${TmuxMenuEntryAction}` | `crtr.tmux.node.${'next' | 'previous'}` | 'crtr.tmux.inbox.toggle' | `crtr.attach.scroll.${'up' | 'down' | 'page-up' | 'page-down' | 'live'}` | 'crtr.attach.mouse.toggle' | 'crtr.attach.copy.message' | 'crtr.attach.help.toggle' | AttachBindingId | `crtr.graph.${GraphAction}` | `crtr.graph.confirm.${'accept' | 'cancel'}` | `crtr.inspector.${'force-quit' | 'down' | 'up' | 'section-next' | 'section-prev' | 'page-down' | 'page-up' | 'toggle-detail' | 'cancel-item' | 'open-log' | 'confirm' | 'dismiss' | 'retarget' | 'refresh' | 'quit'}` | `crtr.browse.${BrowseAction}` | `crtr.browse.search.${'cancel' | 'commit' | 'delete' | 'quit'}` | `crtr.profile.menu.${ProfileMenuAction}` | `crtr.profile.search.${'up' | 'down' | 'pick' | 'back' | 'delete' | 'abort'}` | `crtr.setup.${SetupAction}` | `crtr.setup.confirm.${'accept' | 'back'}` | `crtr.setup.keybindings.${SetupKeybindingAction}` | `crtr.setup.models.${SetupModelsAction}`;
|
|
12
|
-
export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, BindingDefinition<"crtr.tmux.menu.attach">, ...(BindingDefinition<BindingId> | BindingDefinition<"crtr.tmux.node.next"> | BindingDefinition<"crtr.tmux.node.previous"> | BindingDefinition<"crtr.tmux.inbox.toggle"> | BindingDefinition<"crtr.attach.scroll.up"> | BindingDefinition<"crtr.attach.scroll.down"> | BindingDefinition<"crtr.attach.scroll.page-up"> | BindingDefinition<"crtr.attach.scroll.page-down"> | BindingDefinition<"crtr.attach.scroll.live"> | BindingDefinition<"crtr.attach.mouse.toggle"> | BindingDefinition<"crtr.attach.copy.message"> | BindingDefinition<"crtr.graph.down"> | BindingDefinition<"crtr.graph.up"> | BindingDefinition<"crtr.graph.first"> | BindingDefinition<"crtr.graph.last"> | BindingDefinition<"crtr.graph.collapse-or-manager"> | BindingDefinition<"crtr.graph.expand-or-child"> | BindingDefinition<"crtr.graph.focus"> | BindingDefinition<"crtr.graph.revive"> | BindingDefinition<"crtr.graph.focus-manager"> | BindingDefinition<"crtr.graph.close-subtree"> | BindingDefinition<"crtr.graph.dismiss"> | BindingDefinition<"crtr.graph.confirm.accept"> | BindingDefinition<"crtr.graph.confirm.cancel"> | BindingDefinition<"crtr.inspector.force-quit"> | BindingDefinition<"crtr.inspector.down"> | BindingDefinition<"crtr.inspector.up"> | BindingDefinition<"crtr.inspector.section-next"> | BindingDefinition<"crtr.inspector.section-prev"> | BindingDefinition<"crtr.inspector.page-down"> | BindingDefinition<"crtr.inspector.page-up"> | BindingDefinition<"crtr.inspector.toggle-detail"> | BindingDefinition<"crtr.inspector.cancel-item"> | BindingDefinition<"crtr.inspector.open-log"> | BindingDefinition<"crtr.inspector.confirm"> | BindingDefinition<"crtr.inspector.dismiss"> | BindingDefinition<"crtr.inspector.retarget"> | BindingDefinition<"crtr.inspector.refresh"> | BindingDefinition<"crtr.inspector.quit"> | BindingDefinition<"crtr.browse.quit"> | BindingDefinition<"crtr.browse.down"> | BindingDefinition<"crtr.browse.up"> | BindingDefinition<"crtr.browse.first"> | BindingDefinition<"crtr.browse.last"> | BindingDefinition<"crtr.browse.expand-or-child"> | BindingDefinition<"crtr.browse.collapse-or-parent"> | BindingDefinition<"crtr.browse.toggle-fold"> | BindingDefinition<"crtr.browse.tab-next"> | BindingDefinition<"crtr.browse.tab-previous"> | BindingDefinition<"crtr.browse.tab.2" | "crtr.browse.tab.1" | "crtr.browse.tab.3" | "crtr.browse.tab.4" | "crtr.browse.tab.5"> | BindingDefinition<"crtr.browse.close-subtree"> | BindingDefinition<"crtr.browse.confirm-close"> | BindingDefinition<"crtr.browse.sort"> | BindingDefinition<"crtr.browse.scope"> | BindingDefinition<"crtr.browse.profile"> | BindingDefinition<"crtr.browse.residents"> | BindingDefinition<"crtr.browse.preview"> | BindingDefinition<"crtr.browse.search"> | BindingDefinition<"crtr.browse.revive-now"> | BindingDefinition<"crtr.browse.focus"> | BindingDefinition<"crtr.browse.focus-background"> | BindingDefinition<"crtr.browse.search.cancel"> | BindingDefinition<"crtr.browse.search.commit"> | BindingDefinition<"crtr.browse.search.delete"> | BindingDefinition<"crtr.browse.search.quit"> | BindingDefinition<"crtr.profile.menu.up"> | BindingDefinition<"crtr.profile.menu.down"> | BindingDefinition<"crtr.profile.menu.select"> | BindingDefinition<"crtr.profile.menu.accept-default"> | BindingDefinition<"crtr.profile.menu.abort"> | BindingDefinition<"crtr.profile.menu.slot.2" | "crtr.profile.menu.slot.1" | "crtr.profile.menu.slot.3" | "crtr.profile.menu.slot.4" | "crtr.profile.menu.slot.5" | "crtr.profile.menu.slot.6" | "crtr.profile.menu.slot.7" | "crtr.profile.menu.slot.8" | "crtr.profile.menu.slot.9">)[], BindingDefinition<"crtr.profile.menu.create">, BindingDefinition<"crtr.profile.menu.search-existing">, BindingDefinition<"crtr.profile.menu.use-root">, BindingDefinition<"crtr.profile.menu.set-default">, BindingDefinition<"crtr.profile.menu.add-directory">, BindingDefinition<"crtr.profile.menu.unpin">, BindingDefinition<"crtr.profile.search.up">, BindingDefinition<"crtr.profile.search.down">, BindingDefinition<"crtr.profile.search.pick">, BindingDefinition<"crtr.profile.search.back">, BindingDefinition<"crtr.profile.search.delete">, BindingDefinition<"crtr.profile.search.abort">, BindingDefinition<"crtr.setup.cancel">, BindingDefinition<"crtr.setup.tab-next">, BindingDefinition<"crtr.setup.tab-previous">, BindingDefinition<"crtr.setup.open">, BindingDefinition<"crtr.setup.list-down">, BindingDefinition<"crtr.setup.list-up">, BindingDefinition<"crtr.setup.toggle">, BindingDefinition<"crtr.setup.details">, BindingDefinition<"crtr.setup.advance">, BindingDefinition<"crtr.setup.confirm.accept">, BindingDefinition<"crtr.setup.confirm.back">, BindingDefinition<"crtr.setup.keybindings.edit">, BindingDefinition<"crtr.setup.keybindings.commit-edit">, BindingDefinition<"crtr.setup.keybindings.cancel-edit">, BindingDefinition<"crtr.setup.keybindings.unbind">, BindingDefinition<"crtr.setup.keybindings.reset-row">, BindingDefinition<"crtr.setup.keybindings.reset-all">, BindingDefinition<"crtr.setup.keybindings.save">, BindingDefinition<"crtr.setup.keybindings.discard">, BindingDefinition<"crtr.setup.keybindings.page-up">, BindingDefinition<"crtr.setup.keybindings.page-down">, BindingDefinition<"crtr.setup.keybindings.filter">, BindingDefinition<"crtr.setup.keybindings.filter-delete">, BindingDefinition<"crtr.setup.keybindings.filter-clear">, BindingDefinition<"crtr.setup.cell-previous">, BindingDefinition<"crtr.setup.cell-next">, BindingDefinition<"crtr.setup.models.open">, BindingDefinition<"crtr.setup.models.scope-next">, BindingDefinition<"crtr.setup.models.commit">, BindingDefinition<"crtr.setup.models.cancel">];
|
|
12
|
+
export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, BindingDefinition<"crtr.tmux.menu.attach">, ...(BindingDefinition<BindingId> | BindingDefinition<"crtr.tmux.node.next"> | BindingDefinition<"crtr.tmux.node.previous"> | BindingDefinition<"crtr.tmux.inbox.toggle"> | BindingDefinition<"crtr.attach.scroll.up"> | BindingDefinition<"crtr.attach.scroll.down"> | BindingDefinition<"crtr.attach.scroll.page-up"> | BindingDefinition<"crtr.attach.scroll.page-down"> | BindingDefinition<"crtr.attach.scroll.live"> | BindingDefinition<"crtr.attach.mouse.toggle"> | BindingDefinition<"crtr.attach.copy.message"> | BindingDefinition<"crtr.graph.down"> | BindingDefinition<"crtr.graph.up"> | BindingDefinition<"crtr.graph.first"> | BindingDefinition<"crtr.graph.last"> | BindingDefinition<"crtr.graph.collapse-or-manager"> | BindingDefinition<"crtr.graph.expand-or-child"> | BindingDefinition<"crtr.graph.focus"> | BindingDefinition<"crtr.graph.revive"> | BindingDefinition<"crtr.graph.focus-manager"> | BindingDefinition<"crtr.graph.close-subtree"> | BindingDefinition<"crtr.graph.dismiss"> | BindingDefinition<"crtr.graph.confirm.accept"> | BindingDefinition<"crtr.graph.confirm.cancel"> | BindingDefinition<"crtr.inspector.force-quit"> | BindingDefinition<"crtr.inspector.down"> | BindingDefinition<"crtr.inspector.up"> | BindingDefinition<"crtr.inspector.section-next"> | BindingDefinition<"crtr.inspector.section-prev"> | BindingDefinition<"crtr.inspector.page-down"> | BindingDefinition<"crtr.inspector.page-up"> | BindingDefinition<"crtr.inspector.toggle-detail"> | BindingDefinition<"crtr.inspector.cancel-item"> | BindingDefinition<"crtr.inspector.open-log"> | BindingDefinition<"crtr.inspector.confirm"> | BindingDefinition<"crtr.inspector.dismiss"> | BindingDefinition<"crtr.inspector.retarget"> | BindingDefinition<"crtr.inspector.refresh"> | BindingDefinition<"crtr.inspector.quit"> | BindingDefinition<"crtr.browse.quit"> | BindingDefinition<"crtr.browse.down"> | BindingDefinition<"crtr.browse.up"> | BindingDefinition<"crtr.browse.first"> | BindingDefinition<"crtr.browse.last"> | BindingDefinition<"crtr.browse.expand-or-child"> | BindingDefinition<"crtr.browse.collapse-or-parent"> | BindingDefinition<"crtr.browse.toggle-fold"> | BindingDefinition<"crtr.browse.tab-next"> | BindingDefinition<"crtr.browse.tab-previous"> | BindingDefinition<"crtr.browse.tab.2" | "crtr.browse.tab.1" | "crtr.browse.tab.3" | "crtr.browse.tab.4" | "crtr.browse.tab.5"> | BindingDefinition<"crtr.browse.close-subtree"> | BindingDefinition<"crtr.browse.confirm-close"> | BindingDefinition<"crtr.browse.sort"> | BindingDefinition<"crtr.browse.scope"> | BindingDefinition<"crtr.browse.profile"> | BindingDefinition<"crtr.browse.residents"> | BindingDefinition<"crtr.browse.preview"> | BindingDefinition<"crtr.browse.search"> | BindingDefinition<"crtr.browse.revive-now"> | BindingDefinition<"crtr.browse.focus"> | BindingDefinition<"crtr.browse.focus-background"> | BindingDefinition<"crtr.browse.yank-id"> | BindingDefinition<"crtr.browse.search.cancel"> | BindingDefinition<"crtr.browse.search.commit"> | BindingDefinition<"crtr.browse.search.delete"> | BindingDefinition<"crtr.browse.search.quit"> | BindingDefinition<"crtr.profile.menu.up"> | BindingDefinition<"crtr.profile.menu.down"> | BindingDefinition<"crtr.profile.menu.select"> | BindingDefinition<"crtr.profile.menu.accept-default"> | BindingDefinition<"crtr.profile.menu.abort"> | BindingDefinition<"crtr.profile.menu.slot.2" | "crtr.profile.menu.slot.1" | "crtr.profile.menu.slot.3" | "crtr.profile.menu.slot.4" | "crtr.profile.menu.slot.5" | "crtr.profile.menu.slot.6" | "crtr.profile.menu.slot.7" | "crtr.profile.menu.slot.8" | "crtr.profile.menu.slot.9">)[], BindingDefinition<"crtr.profile.menu.create">, BindingDefinition<"crtr.profile.menu.search-existing">, BindingDefinition<"crtr.profile.menu.use-root">, BindingDefinition<"crtr.profile.menu.set-default">, BindingDefinition<"crtr.profile.menu.add-directory">, BindingDefinition<"crtr.profile.menu.unpin">, BindingDefinition<"crtr.profile.search.up">, BindingDefinition<"crtr.profile.search.down">, BindingDefinition<"crtr.profile.search.pick">, BindingDefinition<"crtr.profile.search.back">, BindingDefinition<"crtr.profile.search.delete">, BindingDefinition<"crtr.profile.search.abort">, BindingDefinition<"crtr.setup.cancel">, BindingDefinition<"crtr.setup.tab-next">, BindingDefinition<"crtr.setup.tab-previous">, BindingDefinition<"crtr.setup.open">, BindingDefinition<"crtr.setup.list-down">, BindingDefinition<"crtr.setup.list-up">, BindingDefinition<"crtr.setup.toggle">, BindingDefinition<"crtr.setup.details">, BindingDefinition<"crtr.setup.advance">, BindingDefinition<"crtr.setup.confirm.accept">, BindingDefinition<"crtr.setup.confirm.back">, BindingDefinition<"crtr.setup.keybindings.edit">, BindingDefinition<"crtr.setup.keybindings.commit-edit">, BindingDefinition<"crtr.setup.keybindings.cancel-edit">, BindingDefinition<"crtr.setup.keybindings.unbind">, BindingDefinition<"crtr.setup.keybindings.reset-row">, BindingDefinition<"crtr.setup.keybindings.reset-all">, BindingDefinition<"crtr.setup.keybindings.save">, BindingDefinition<"crtr.setup.keybindings.discard">, BindingDefinition<"crtr.setup.keybindings.page-up">, BindingDefinition<"crtr.setup.keybindings.page-down">, BindingDefinition<"crtr.setup.keybindings.filter">, BindingDefinition<"crtr.setup.keybindings.filter-delete">, BindingDefinition<"crtr.setup.keybindings.filter-clear">, BindingDefinition<"crtr.setup.cell-previous">, BindingDefinition<"crtr.setup.cell-next">, BindingDefinition<"crtr.setup.models.open">, BindingDefinition<"crtr.setup.models.scope-next">, BindingDefinition<"crtr.setup.models.commit">, BindingDefinition<"crtr.setup.models.cancel">];
|
|
13
13
|
export declare const BINDING_IDS: ReadonlySet<string>;
|
|
14
14
|
/** True for an action whose direct gesture is handled inside an attach viewer.
|
|
15
15
|
* Tmux menu selectors and root shortcuts are chrome, not pane input. */
|
|
@@ -142,6 +142,7 @@ function browseBindings() {
|
|
|
142
142
|
b('crtr.browse.revive-now', 'Browse and pickers', 'Revive now', 'Revive the selected node now.', ['shift+k'], 'terminal', [nav]),
|
|
143
143
|
b('crtr.browse.focus', 'Browse and pickers', 'Focus node', 'Focus the selected node.', ['enter', 'o'], 'terminal', [nav]),
|
|
144
144
|
b('crtr.browse.focus-background', 'Browse and pickers', 'Focus node (keep browsing)', 'Focus the selected node without leaving the navigator.', ['shift+o'], 'terminal', [nav]),
|
|
145
|
+
b('crtr.browse.yank-id', 'Browse and pickers', 'Yank node id', 'Copy the selected node id to the system clipboard.', ['y'], 'terminal', [nav]),
|
|
145
146
|
b('crtr.browse.search.cancel', 'Browse and pickers', 'Cancel search', 'Cancel browse search.', ['escape'], 'terminal', ['browse.search'], 'dismiss-modal'),
|
|
146
147
|
b('crtr.browse.search.commit', 'Browse and pickers', 'Commit search', 'Apply browse search.', ['enter'], 'terminal', ['browse.search']),
|
|
147
148
|
b('crtr.browse.search.delete', 'Browse and pickers', 'Delete search text', 'Delete the previous search character.', ['backspace'], 'terminal', ['browse.search']),
|
|
@@ -104,9 +104,8 @@ const LEAF_ICON_CP = {
|
|
|
104
104
|
'canvas issue new': 0xf188,
|
|
105
105
|
'canvas prune': 0xf0c4,
|
|
106
106
|
'canvas rebuild-index': 0xf0ad,
|
|
107
|
-
'human
|
|
107
|
+
'human send': 0xf059,
|
|
108
108
|
'human review': 0xf044,
|
|
109
|
-
'human notify': 0xf0f3,
|
|
110
109
|
'human show': 0xf108,
|
|
111
110
|
'human cancel': 0xf00d,
|
|
112
111
|
'human list': 0xf03a,
|
|
@@ -304,15 +303,14 @@ function summarizeDaemon(field, active, inactive) {
|
|
|
304
303
|
return [{ text: state ? `${active}${pid === undefined ? '' : ` · pid ${pid}`}` : inactive, tone: state ? 'success' : 'muted' }];
|
|
305
304
|
};
|
|
306
305
|
}
|
|
307
|
-
function
|
|
306
|
+
function summarizeHumanSend(input) {
|
|
308
307
|
const value = record(input);
|
|
309
|
-
if (value === undefined || stringField(value, '
|
|
308
|
+
if (value === undefined || stringField(value, 'page_id') === undefined)
|
|
310
309
|
return null;
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
];
|
|
310
|
+
const reply = booleanField(value, 'reply');
|
|
311
|
+
if (reply === undefined)
|
|
312
|
+
return null;
|
|
313
|
+
return [{ text: reply ? 'page sent → waiting on human' : 'announcement sent', tone: reply ? 'accent' : 'success' }];
|
|
316
314
|
}
|
|
317
315
|
function summarizeHumanResolve(input) {
|
|
318
316
|
const value = record(input);
|
|
@@ -352,7 +350,7 @@ const SUMMARIZERS = [
|
|
|
352
350
|
{ path: 'canvas attention count', run: summarizeCount('pending asks', true) },
|
|
353
351
|
{ path: 'canvas attention list', run: summarizeArray('pending asks') },
|
|
354
352
|
{ path: 'canvas attention map', run: summarizeAttentionMap },
|
|
355
|
-
{ path: 'human
|
|
353
|
+
{ path: 'human send', run: summarizeHumanSend },
|
|
356
354
|
{ path: 'human list', run: summarizeArray('pending') },
|
|
357
355
|
{ path: 'human resolve', run: summarizeHumanResolve },
|
|
358
356
|
{ path: 'pkg plugin list', run: summarizeArray('plugins') },
|
|
@@ -4,3 +4,7 @@ export declare function resolveBindingCwd(cwd: string): string;
|
|
|
4
4
|
export declare function getDefaultProfileId(cwd: string): string | null;
|
|
5
5
|
export declare function setDefaultProfileId(cwd: string, profileId: string): void;
|
|
6
6
|
export declare function clearDefaultProfile(cwd: string): void;
|
|
7
|
+
/** Every directory currently pinned to `profileId`, in deterministic order. */
|
|
8
|
+
export declare function defaultProfileDirs(profileId: string): string[];
|
|
9
|
+
/** Clear every per-directory default that names `profileId`. */
|
|
10
|
+
export declare function clearDefaultProfileId(profileId: string): string[];
|