@north-light/crouter 0.3.154 → 0.3.157

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +2 -1
  2. package/dist/api/client.d.ts +1 -4
  3. package/dist/api/client.js +0 -5
  4. package/dist/api/dto/broker.d.ts +1 -1
  5. package/dist/api/dto/nodes.d.ts +0 -15
  6. package/dist/api/routes.d.ts +0 -1
  7. package/dist/api/routes.js +0 -1
  8. package/dist/builtin-views/chat/core.mjs +51 -6
  9. package/dist/builtin-views/chat/tui.mjs +14 -6
  10. package/dist/builtin-views/chat/web.jsx +7 -2
  11. package/dist/clients/attach/__tests__/oauth-dialog-lifecycle.test.js +1 -1
  12. package/dist/clients/attach/chrome/roster.d.ts +1 -1
  13. package/dist/clients/attach/chrome/roster.js +1 -9
  14. package/dist/clients/attach/command.js +5 -5
  15. package/dist/clients/attach/input/controller.d.ts +8 -23
  16. package/dist/clients/attach/input/controller.js +29 -59
  17. package/dist/clients/attach/overlays/dialogs.d.ts +2 -1
  18. package/dist/clients/attach/overlays/graph.d.ts +1 -4
  19. package/dist/clients/attach/overlays/graph.js +7 -25
  20. package/dist/clients/attach/session/context.d.ts +0 -7
  21. package/dist/clients/attach/session/frames.js +8 -1
  22. package/dist/clients/attach/session/input-wiring.d.ts +1 -1
  23. package/dist/clients/attach/session/input-wiring.js +11 -21
  24. package/dist/clients/attach/session/mode.d.ts +3 -4
  25. package/dist/clients/attach/session/mode.js +1 -6
  26. package/dist/clients/attach/session/reconnect.d.ts +3 -3
  27. package/dist/clients/attach/session/reconnect.js +7 -6
  28. package/dist/clients/attach/session/state-sync.d.ts +1 -1
  29. package/dist/clients/attach/session/state-sync.js +2 -2
  30. package/dist/clients/attach/slash/dispatch.d.ts +1 -13
  31. package/dist/clients/attach/slash/dispatch.js +17 -65
  32. package/dist/clients/attach/viewer.js +523 -523
  33. package/dist/clients/web/web-client/shared/protocol.d.ts +3 -5
  34. package/dist/core/__tests__/broker-sdk-wiring.test.js +18 -18
  35. package/dist/core/__tests__/chat-view-reconnect.test.js +23 -44
  36. package/dist/core/__tests__/full/broker-attach-limits.test.js +36 -60
  37. package/dist/core/__tests__/full/broker-attach-stream.test.js +4 -4
  38. package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
  39. package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
  40. package/dist/core/__tests__/full/broker-dialogs.test.js +62 -121
  41. package/dist/core/__tests__/helpers/broker-clients.js +2 -2
  42. package/dist/core/__tests__/session-model.test.js +26 -15
  43. package/dist/core/keybindings/__tests__/resolve.test.js +1 -1
  44. package/dist/core/keybindings/catalog.d.ts +2 -2
  45. package/dist/core/keybindings/catalog.js +2 -0
  46. package/dist/core/runtime/auth-reload.d.ts +4 -4
  47. package/dist/core/runtime/auth-reload.js +13 -9
  48. package/dist/core/runtime/boot-root.d.ts +2 -2
  49. package/dist/core/runtime/boot-root.js +7 -7
  50. package/dist/core/runtime/broker-protocol.d.ts +27 -23
  51. package/dist/core/runtime/broker-protocol.js +1 -1
  52. package/dist/core/runtime/broker-request.js +11 -5
  53. package/dist/core/runtime/broker.d.ts +13 -21
  54. package/dist/core/runtime/broker.js +186 -151
  55. package/dist/core/runtime/interactive-deliver.js +5 -4
  56. package/dist/core/runtime/model-swap.d.ts +3 -2
  57. package/dist/core/runtime/model-swap.js +4 -3
  58. package/dist/core/runtime/node-read.d.ts +0 -20
  59. package/dist/core/runtime/node-read.js +1 -34
  60. package/dist/core/runtime/resume-root.d.ts +1 -1
  61. package/dist/core/runtime/resume-root.js +6 -6
  62. package/dist/core/runtime/spawn.js +3 -3
  63. package/dist/core/session-model/session-state.d.ts +6 -8
  64. package/dist/core/session-model/session-state.js +16 -6
  65. package/dist/daemon/api/handlers/nodes.js +1 -18
  66. package/dist/daemon/manage.js +2 -2
  67. package/dist/index.d.ts +1 -1
  68. package/dist/web-client/assets/index--SsQYcKu.js +79 -0
  69. package/dist/web-client/assets/{index-CpEl9LTS.css → index-DJhQZoAj.css} +1 -1
  70. package/dist/web-client/index.html +2 -2
  71. package/dist/web-client/sw.js +1 -1
  72. package/docs/compat/hearth-crtr-v1.md +1 -1
  73. package/docs/compat/hearth-crtr-v2.md +1 -1
  74. package/docs/compat/hearth-crtr-v3.md +1 -1
  75. package/docs/compat/hearth-crtr-v4.md +3 -1
  76. package/docs/public-api.md +2 -2
  77. package/package.json +4 -4
  78. package/runtime.lock.json +2 -2
  79. package/dist/web-client/assets/index-BpyZGBhI.js +0 -79
  80. package/docs/compat/hearth-crtr-v5.md +0 -175
@@ -52,17 +52,6 @@ const CANVAS_NAMES = new Set(CANVAS_SLASH_COMMANDS.map((c) => c.name));
52
52
  * (the in-process GRAPH overlay, already remote-safe — see overlays/graph.ts)
53
53
  * and `/view` (a self-contained popup unrelated to `nodeId`) stay available. */
54
54
  const REMOTE_UNSAFE_CANVAS_NAMES = new Set(['promote', 'resume-node', 'context', 'node-metadata', 'rename', 'clear', 'mcp']);
55
- /** Native canvas commands an OBSERVER may not run — the ones that drive the
56
- * engine or mutate the node, whether by frame or by shelling the crtr CLI:
57
- * `/clear` sends `new_session`; `/promote` shells `crtr node promote` and then
58
- * triggers a turn; `/rename` sends `set_session_name` and shells `crtr node
59
- * config --name`; `/resume-node` opens the navigator whose Enter path focuses
60
- * (and so revives) a node; `/mcp`'s panel actions ride a `prompt` frame into
61
- * the engine. Deliberately NOT here — genuinely read-only or viewer-local:
62
- * `/graph` (in-process overlay), `/context` and `/node-metadata` (read-only
63
- * inspection popups), `/color` (this pane's tmux border + this viewer's name
64
- * chip). */
65
- const OBSERVER_UNSAFE_CANVAS_NAMES = new Set(['clear', 'promote', 'rename', 'resume-node', 'view', 'mcp']);
66
55
  /** tmux named colours accepted by `/color` (plus `colourN`/`#rrggbb`, validated
67
56
  * by pattern). Mirrors tmux's colour-name table so a typo is rejected with the
68
57
  * options rather than silently ignored by tmux. */
@@ -89,53 +78,17 @@ const THINKING_LEVELS = new Set(Object.keys({
89
78
  max: true,
90
79
  }));
91
80
  const BUILTIN_NAMES = new Set(BUILTIN_SLASH_COMMANDS.map((c) => c.name));
92
- /** Builtin slash commands safe to run from a READ-ONLY viewer — a REMOTE
93
- * attach (`--canvas`) or an `--observer` one —
81
+ /** Builtin slash commands safe to run against a REMOTE attach (`--canvas`) —
94
82
  * everything else in `BUILTIN_SLASH_COMMANDS` either drives the engine
95
83
  * (`/model`, `/new`, `/compact`, `/name`, `/resume`, `/fork`, `/tree`,
96
84
  * `/settings`, `/share`, `/clone`, `/import`, `/reload`, `/scoped-models`
97
85
  * selection) or is viewer-local but operates on the WRONG host for a remote
98
86
  * node (`/login`, `/logout` — LOCAL `auth.json` via `defaultAgentDir()`, not
99
- * the remote broker's; for an observer, credentials it may not swap under a
100
- * running engine). Blocked BEFORE the switch so a read-only viewer never even
101
- * opens the picker only to have the eventual selection frame swallowed by
102
- * InputController's `emitCommand` gate (defense-in-depth #2, not the only
103
- * defense — see input/controller.ts DRIVE_FRAME_TYPES). */
104
- const READ_ONLY_SAFE_BUILTIN_NAMES = new Set(['copy', 'session', 'changelog', 'hotkeys', 'quit']);
105
- /** THE capability gate for a read-only viewer, keyed on the two fixed facts a
106
- * session resolves once (`remote`, `role`) — so the answer for a given command
107
- * cannot change mid-session. Returns the refusal notice, or `undefined` when
108
- * this viewer may run the command. Both `dispatchSlashCommand` (so a direct
109
- * caller is safe) and the InputController's submit path (so a refusal is
110
- * reported before command dispatch) consult this one function; there is no
111
- * second policy anywhere. */
112
- function readOnlyRefusal(name, ctx) {
113
- const canvas = CANVAS_NAMES.has(name);
114
- const builtinUnsafe = BUILTIN_NAMES.has(name) && !READ_ONLY_SAFE_BUILTIN_NAMES.has(name);
115
- if (ctx.remote === true) {
116
- if (canvas && REMOTE_UNSAFE_CANVAS_NAMES.has(name)) {
117
- return `/${name} is not available for a remote attach (--canvas) — it acts on this machine's local canvas`;
118
- }
119
- if (builtinUnsafe)
120
- return `/${name} is not available for a remote attach (--canvas) — view-only`;
121
- }
122
- if (ctx.remote !== true && (ctx.role ?? 'controller') !== 'controller') {
123
- if ((canvas && OBSERVER_UNSAFE_CANVAS_NAMES.has(name)) || builtinUnsafe) {
124
- return `/${name} is not available to a read-only observer attach (--observer) — it would drive this node`;
125
- }
126
- }
127
- return undefined;
128
- }
129
- /** The same gate, entered from raw editor text: the InputController asks BEFORE
130
- * dispatching so a refused command is reported without reaching command
131
- * dispatch. Unrecognized (extension) commands answer `undefined` here — they
132
- * ride the normal `prompt` path, which the controller's own drive gate covers. */
133
- export function readOnlySlashRefusal(text, ctx) {
134
- const m = /^\/(\S+)\s*([\s\S]*)$/.exec(text.trim());
135
- if (!m)
136
- return undefined;
137
- return readOnlyRefusal(m[1], ctx);
138
- }
87
+ * the remote broker's). Blocked here BEFORE the switch so a remote attach
88
+ * never even opens the picker only to have the eventual selection frame
89
+ * swallowed by InputController's `emitCommand` gate (defense-in-depth #2,
90
+ * not the only defense — see input/controller.ts DRIVE_FRAME_TYPES). */
91
+ const REMOTE_SAFE_BUILTIN_NAMES = new Set(['copy', 'session', 'changelog', 'hotkeys', 'quit']);
139
92
  /** Every leading-command name this viewer consumes ENTIRELY locally — the
140
93
  * message never reaches the engine as prose, whether dispatched or blocked
141
94
  * with a notice (a remote-unsafe canvas/builtin command still returns
@@ -172,20 +125,13 @@ export function dispatchSlashCommand(text, ctx) {
172
125
  }
173
126
  // Canvas commands (reimplemented native in the viewer) — handled before the
174
127
  // builtin gate since they are neither pi builtins nor engine-extension commands.
175
- if (CANVAS_NAMES.has(name)) {
176
- const refusal = readOnlyRefusal(name, ctx);
177
- if (refusal !== undefined) {
178
- ctx.notify(refusal);
179
- return true;
180
- }
128
+ if (CANVAS_NAMES.has(name))
181
129
  return dispatchCanvasCommand(name, arg, ctx);
182
- }
183
130
  // Unknown to us AND not a builtin → let the engine's extension runner have it.
184
131
  if (!BUILTIN_NAMES.has(name))
185
132
  return false;
186
- const refusal = readOnlyRefusal(name, ctx);
187
- if (refusal !== undefined) {
188
- ctx.notify(refusal);
133
+ if (ctx.remote === true && !REMOTE_SAFE_BUILTIN_NAMES.has(name)) {
134
+ ctx.notify(`/${name} is not available for a remote attach (--canvas) — view-only`);
189
135
  return true;
190
136
  }
191
137
  switch (name) {
@@ -340,8 +286,14 @@ export function commandAutocompleteItems(commands = BUILTIN_SLASH_COMMANDS, remo
340
286
  /** Dispatch one of the native canvas commands. Always returns `true` (the
341
287
  * command is viewer-owned — never forwarded to the engine as a prompt). */
342
288
  function dispatchCanvasCommand(name, arg, ctx) {
343
- // The capability gate (`readOnlyRefusal`) already ran in dispatchSlashCommand,
344
- // so everything reaching here is a command this viewer may run.
289
+ // Structural omission (withCanvasCommands) keeps these out of remote-mode
290
+ // autocomplete; this gate is the belt-and-suspenders that also makes them
291
+ // NOT EXECUTABLE if typed by hand — a remote node id has no relationship to
292
+ // this machine's local canvas.db (or, worse, collides with one that does).
293
+ if (ctx.remote && REMOTE_UNSAFE_CANVAS_NAMES.has(name)) {
294
+ ctx.notify(`/${name} is not available for a remote attach (--canvas) — it acts on this machine's local canvas`);
295
+ return true;
296
+ }
345
297
  switch (name) {
346
298
  case 'clear':
347
299
  // Claude-Code ergonomics: `/clear` == `/new` — drop the conversation and