@crouton-kit/crouter 0.3.66 → 0.3.68

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 (86) hide show
  1. package/dist/build-root.js +1 -0
  2. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
  3. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +2 -0
  4. package/dist/clients/attach/__tests__/attach-chrome-remote.test.d.ts +1 -0
  5. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +371 -0
  6. package/dist/clients/attach/__tests__/attach-remote-readonly.test.d.ts +1 -0
  7. package/dist/clients/attach/__tests__/attach-remote-readonly.test.js +191 -0
  8. package/dist/clients/attach/__tests__/transport-relay.test.js +38 -1
  9. package/dist/clients/attach/attach-cmd.d.ts +30 -2
  10. package/dist/clients/attach/attach-cmd.js +624 -624
  11. package/dist/clients/attach/canvas-panels.js +9 -3
  12. package/dist/clients/attach/graph-overlay.d.ts +5 -0
  13. package/dist/clients/attach/graph-overlay.js +40 -7
  14. package/dist/clients/attach/input-controller.d.ts +9 -0
  15. package/dist/clients/attach/input-controller.js +47 -8
  16. package/dist/clients/attach/slash-commands.d.ts +11 -4
  17. package/dist/clients/attach/slash-commands.js +44 -9
  18. package/dist/clients/attach/transport-relay.d.ts +5 -5
  19. package/dist/clients/attach/transport-relay.js +3 -30
  20. package/dist/commands/__tests__/canvas-config.test.d.ts +1 -0
  21. package/dist/commands/__tests__/canvas-config.test.js +107 -0
  22. package/dist/commands/canvas-browse.js +26 -1
  23. package/dist/commands/canvas-config.d.ts +2 -0
  24. package/dist/commands/canvas-config.js +210 -0
  25. package/dist/commands/canvas-use.d.ts +1 -0
  26. package/dist/commands/canvas-use.js +63 -0
  27. package/dist/commands/canvas.js +4 -2
  28. package/dist/commands/capture.d.ts +2 -0
  29. package/dist/commands/capture.js +28 -0
  30. package/dist/commands/node.js +41 -11
  31. package/dist/core/__tests__/remote-canvas-target.test.d.ts +1 -0
  32. package/dist/core/__tests__/remote-canvas-target.test.js +87 -0
  33. package/dist/core/__tests__/revive.test.js +70 -1
  34. package/dist/core/__tests__/secrets.test.d.ts +1 -0
  35. package/dist/core/__tests__/secrets.test.js +55 -0
  36. package/dist/core/canvas/__tests__/remote-canvas-source.test.d.ts +1 -0
  37. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +371 -0
  38. package/dist/core/canvas/__tests__/remote-event-stream.test.d.ts +1 -0
  39. package/dist/core/canvas/__tests__/remote-event-stream.test.js +144 -0
  40. package/dist/core/canvas/__tests__/render-remote.test.d.ts +1 -0
  41. package/dist/core/canvas/__tests__/render-remote.test.js +221 -0
  42. package/dist/core/canvas/__tests__/source-resolve.test.d.ts +1 -0
  43. package/dist/core/canvas/__tests__/source-resolve.test.js +77 -0
  44. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.d.ts +1 -0
  45. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +117 -0
  46. package/dist/core/canvas/browse/app.d.ts +14 -0
  47. package/dist/core/canvas/browse/app.js +97 -15
  48. package/dist/core/canvas/browse/rebuild-coalescer.d.ts +7 -0
  49. package/dist/core/canvas/browse/rebuild-coalescer.js +61 -0
  50. package/dist/core/canvas/browse/render.d.ts +4 -0
  51. package/dist/core/canvas/browse/render.js +3 -1
  52. package/dist/core/canvas/nav-model.d.ts +19 -10
  53. package/dist/core/canvas/nav-model.js +30 -12
  54. package/dist/core/canvas/remote-canvas-source.d.ts +62 -0
  55. package/dist/core/canvas/remote-canvas-source.js +222 -0
  56. package/dist/core/canvas/remote-event-stream.d.ts +24 -0
  57. package/dist/core/canvas/remote-event-stream.js +94 -0
  58. package/dist/core/canvas/render.d.ts +13 -1
  59. package/dist/core/canvas/render.js +56 -37
  60. package/dist/core/canvas/source.d.ts +9 -0
  61. package/dist/core/canvas/source.js +15 -0
  62. package/dist/core/command.d.ts +15 -0
  63. package/dist/core/command.js +72 -0
  64. package/dist/core/config.js +4 -3
  65. package/dist/core/profiles/select.d.ts +4 -1
  66. package/dist/core/profiles/select.js +356 -81
  67. package/dist/core/runtime/__tests__/node-env.test.d.ts +1 -0
  68. package/dist/core/runtime/__tests__/node-env.test.js +91 -0
  69. package/dist/core/runtime/nodes.js +10 -0
  70. package/dist/core/runtime/revive.js +176 -139
  71. package/dist/core/runtime/tmux.js +4 -1
  72. package/dist/core/secrets.d.ts +25 -0
  73. package/dist/core/secrets.js +55 -0
  74. package/dist/core/view/__tests__/transport-remote.test.d.ts +1 -0
  75. package/dist/core/view/__tests__/transport-remote.test.js +95 -0
  76. package/dist/core/view/remote-canvas-target.d.ts +2 -1
  77. package/dist/core/view/remote-canvas-target.js +12 -7
  78. package/dist/core/view/transport-local.js +12 -3
  79. package/dist/core/view/transport-remote.d.ts +2 -0
  80. package/dist/core/view/transport-remote.js +53 -0
  81. package/dist/types.d.ts +19 -11
  82. package/dist/types.js +1 -1
  83. package/dist/web-client/assets/{index-BvzxXXGU.js → index-CnF5r8ky.js} +18 -18
  84. package/dist/web-client/index.html +1 -1
  85. package/dist/web-client/sw.js +1 -1
  86. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
- import type { Scope } from '../../types.js';
1
+ import type { Scope, RemoteCanvasTarget } from '../../types.js';
2
2
  import type { RelayTarget } from '../../clients/attach/transport-relay.js';
3
+ export declare function getRemoteCanvasTarget(name: string, scope?: Scope): RemoteCanvasTarget | undefined;
3
4
  export declare function resolveRemoteCanvasTarget(name: string, scope?: Scope): RelayTarget;
@@ -2,12 +2,17 @@
2
2
  // config entry (see `RemoteCanvasTarget`, `src/types.ts`) into a `RelayTarget`
3
3
  // ready for `RelayTransport` (`src/clients/attach/transport-relay.ts`).
4
4
  //
5
- // The raw bearer token NEVER lives in config or argv — only the name of an
6
- // environment variable holding it (`relayTokenEnv`), read here at connect
7
- // time. This is the Phase 1 interim contract; Phase 3 owns the real
8
- // secret-store-backed `crtr canvas config`/`crtr canvas use` CLI.
5
+ // The raw bearer token NEVER lives in config.json — only a ref
6
+ // (`relayTokenRef`) into the 0600 secrets store (`src/core/secrets.ts`),
7
+ // resolved here at connect time via `getRelayToken`. Targets are registered
8
+ // and the token stored via `crtr canvas config add` (`--relay-token -` reads
9
+ // it from stdin, the preferred form to keep it out of shell history).
9
10
  import { usage } from '../errors.js';
10
11
  import { readConfig } from '../config.js';
12
+ import { getRelayToken } from '../secrets.js';
13
+ export function getRemoteCanvasTarget(name, scope = 'user') {
14
+ return readConfig(scope).remoteCanvas.targets[name];
15
+ }
11
16
  export function resolveRemoteCanvasTarget(name, scope = 'user') {
12
17
  const cfg = readConfig(scope);
13
18
  const target = cfg.remoteCanvas.targets[name];
@@ -15,11 +20,11 @@ export function resolveRemoteCanvasTarget(name, scope = 'user') {
15
20
  const known = Object.keys(cfg.remoteCanvas.targets);
16
21
  throw usage(`no remote canvas target named '${name}'` +
17
22
  (known.length > 0 ? ` — configured: ${known.join(', ')}` : ' — none configured yet') +
18
- `. Add remoteCanvas.targets.${name} to config.json (run \`crtr sys config path\`): {"previewEndpoint": "https://<hash>.preview.bl.run", "relayTokenEnv": "<ENV_VAR_NAME>"}.`);
23
+ `. Add one with \`crtr canvas config add ${name} --preview <url> --relay-token -\`.`);
19
24
  }
20
- const relayToken = process.env[target.relayTokenEnv];
25
+ const relayToken = getRelayToken(target.relayTokenRef, scope);
21
26
  if (relayToken === undefined || relayToken === '') {
22
- throw usage(`remote canvas target '${name}' needs its relay token in $${target.relayTokenEnv} that environment variable is unset. Export it before running this command; the token is never read from config or argv.`);
27
+ throw usage(`target '${name}' has no stored relay token — add it with \`crtr canvas config add ${name} --relay-token -\`.`);
23
28
  }
24
29
  return { previewEndpoint: target.previewEndpoint, relayToken };
25
30
  }
@@ -38,9 +38,18 @@ function sendExec(req, baseCwd) {
38
38
  resolve({ ok: true, exitCode: code, stdout: stdout ?? '', stderr: stderr ?? '' });
39
39
  return;
40
40
  }
41
- if (err.signal) {
42
- // Killed by signal: it ran; surface as a non-zero exit.
43
- resolve({ ok: true, exitCode: 1, stdout: stdout ?? '', stderr: stderr ?? '' });
41
+ const signal = err.signal;
42
+ if (signal) {
43
+ // Killed by signal: it ran; surface as a non-zero exit. A SIGKILL with
44
+ // no stderr at all (the live-incident shape: a guest OOM killer takes
45
+ // out the child before it ever writes anything) used to come back as
46
+ // a bare `failed (1)` with nothing to explain it — the signal itself
47
+ // IS the useful diagnostic here, so surface it when stderr is empty
48
+ // rather than discarding it.
49
+ const detail = stderr && stderr.trim() !== ''
50
+ ? stderr
51
+ : `killed by signal ${signal}${signal === 'SIGKILL' ? ' (often out-of-memory)' : ''}`;
52
+ resolve({ ok: true, exitCode: 1, stdout: stdout ?? '', stderr: detail });
44
53
  return;
45
54
  }
46
55
  // Spawn-level failure (ENOENT/EACCES/maxBuffer): transport failure.
@@ -0,0 +1,2 @@
1
+ import type { RawResponse } from './contract.js';
2
+ export declare function createRemoteExec(previewEndpoint: string, relayToken: string, timeoutMs?: number): (bin: string, args: string[]) => Promise<RawResponse>;
@@ -0,0 +1,53 @@
1
+ // transport-remote.ts — the Node-side remote exec transport for a
2
+ // RemoteCanvasSource. POSTs a SourceRequest to a Blaxel preview endpoint's
3
+ // `/__crtr/source` route (the SAME in-guest source-fulfillment endpoint the
4
+ // browser/web transport already speaks), bearer-authed with the relay token.
5
+ //
6
+ // This is the ONLY way RemoteCanvasSource reaches the remote canvas: it never
7
+ // reads a remote SQLite file, and it never invokes an in-guest command that
8
+ // doesn't already exist. Every argv it sends is `crtr --json <existing
9
+ // subcommand>` — read-only.
10
+ /** The remote read plane crosses a network boundary — a stalled TCP connection
11
+ * or a hung `/__crtr/source` handler must fail closed, not wedge `node
12
+ * inspect`/`canvas browse`/attach forever. Low enough that a genuinely hung
13
+ * endpoint surfaces as a failed read within one interactive frame, not a
14
+ * silent hang. */
15
+ const DEFAULT_TIMEOUT_MS = 5_000;
16
+ export function createRemoteExec(previewEndpoint, relayToken, timeoutMs = DEFAULT_TIMEOUT_MS) {
17
+ // A malformed stored token (control chars / non-Latin1 bytes) would throw
18
+ // from the Headers constructor with the invalid value IN the thrown
19
+ // message — validate up front so that never happens, and fail with a
20
+ // GENERIC message instead (Phase 3 review Minor 1: no token bytes may ever
21
+ // reach returned stderr). HTTP header values are ISO-8859-1; reject
22
+ // anything outside `/^[\x20-\x7e]+$/` (printable ASCII, no CR/LF/control).
23
+ const tokenValid = /^[\x20-\x7e]+$/.test(relayToken);
24
+ return async function exec(bin, args) {
25
+ if (!tokenValid) {
26
+ return { ok: false, stdout: '', stderr: 'remote source: invalid stored relay token' };
27
+ }
28
+ const req = { kind: 'exec', bin, args };
29
+ const controller = new AbortController();
30
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
31
+ let res;
32
+ try {
33
+ res = await fetch(new URL('/__crtr/source', previewEndpoint), {
34
+ method: 'POST',
35
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${relayToken}` },
36
+ body: JSON.stringify(req),
37
+ signal: controller.signal,
38
+ });
39
+ }
40
+ catch (e) {
41
+ if (controller.signal.aborted) {
42
+ return { ok: false, stdout: '', stderr: `remote source: timeout after ${timeoutMs}ms` };
43
+ }
44
+ return { ok: false, stdout: '', stderr: 'remote source: network error' };
45
+ }
46
+ finally {
47
+ clearTimeout(timer);
48
+ }
49
+ if (!res.ok)
50
+ return { ok: false, stdout: '', stderr: `remote source: HTTP ${res.status} ${res.statusText}` };
51
+ return (await res.json());
52
+ };
53
+ }
package/dist/types.d.ts CHANGED
@@ -138,10 +138,10 @@ export interface ScopeConfig {
138
138
  * entries at the same scope precedence as the rest of `ScopeConfig`. */
139
139
  kinds: Record<string, KindConfig>;
140
140
  /** Named remote-canvas targets for `crtr surface attach to <id> --canvas
141
- * <name>` (Phase 1 interim contract hand-edited in config.json, no CLI
142
- * verbs yet; Phase 3 owns the real secret-store-backed `crtr canvas
143
- * config`/`crtr canvas use`). Unset via `sys config set` — not in
144
- * `TOP_LEVEL_KEYS`. */
141
+ * <name>`, `crtr node inspect list/show --canvas <name>`, and `crtr canvas
142
+ * browse --canvas <name>` registered/managed via `crtr canvas config
143
+ * add/list/show/remove` and selected durably via `crtr canvas use`. Unset
144
+ * via `sys config set` — not in `TOP_LEVEL_KEYS`. */
145
145
  remoteCanvas: RemoteCanvasConfig;
146
146
  /** Extra env-var names/globs a scope explicitly admits across the broker
147
147
  * spawn-env boundary (`buildBrokerEnv`, `core/runtime/spawn-env.ts`) — the
@@ -154,14 +154,17 @@ export interface ScopeConfig {
154
154
  };
155
155
  }
156
156
  /** One remote canvas target: where to relay-attach and how to find its
157
- * bearer token. The token itself is NEVER stored here — only the name of an
158
- * environment variable holding it, resolved at connect time by
159
- * `resolveRemoteCanvasTarget` (`src/core/view/remote-canvas-target.ts`). */
157
+ * bearer token. The token itself is NEVER stored here — only a ref into the
158
+ * 0600 secrets store, resolved at connect time by `resolveRemoteCanvasTarget`
159
+ * (`src/core/view/remote-canvas-target.ts`) via `getRelayToken`
160
+ * (`src/core/secrets.ts`). */
160
161
  export interface RemoteCanvasTarget {
161
162
  previewEndpoint: string;
162
- /** Name of an environment variable holding the raw relay/bearer token
163
- * NEVER the token itself. Resolved from process.env at connect time. */
164
- relayTokenEnv: string;
163
+ /** Name/ref under which the raw token is stored in secrets.json NEVER the
164
+ * token itself. Resolved via `getRelayToken` (`core/secrets.ts`) at connect
165
+ * time. Defaults to the target name at creation but is a distinct field so
166
+ * a future rename doesn't orphan the secret. */
167
+ relayTokenRef: string;
165
168
  cpOrigin?: string;
166
169
  }
167
170
  export interface RemoteCanvasConfig {
@@ -176,6 +179,11 @@ export interface ScopeState {
176
179
  }>;
177
180
  last_self_check?: string;
178
181
  bootstrap_done?: boolean;
182
+ /** The name of the remote canvas target `crtr canvas use` last selected
183
+ * (see `RemoteCanvasConfig`), or `null`/omitted for local. Read by
184
+ * `resolveCanvasSource` (`core/canvas/source.ts`) as the durable fallback
185
+ * when a command's own `--canvas` flag is absent. */
186
+ activeCanvas?: string | null;
179
187
  }
180
188
  export interface SubagentFrontmatter {
181
189
  name: string;
@@ -244,7 +252,7 @@ export declare const PROFILE_DIR = "profiles";
244
252
  export declare const DEFAULT_MAX_PANES_PER_WINDOW = 3;
245
253
  export declare function defaultScopeConfig(): ScopeConfig;
246
254
  /** No remote canvas targets are configured out of the box — every one is
247
- * hand-added to config.json (Phase 1 interim contract, see `RemoteCanvasConfig`). */
255
+ * registered via `crtr canvas config add` (see `RemoteCanvasConfig`). */
248
256
  export declare function defaultRemoteCanvasConfig(): RemoteCanvasConfig;
249
257
  /** The builtin kind registry (spec §1.5): the built-in defaults for every
250
258
  * top-level kind and its sub-persona kinds. `whenToUse`/`model` are the
package/dist/types.js CHANGED
@@ -36,7 +36,7 @@ export function defaultScopeConfig() {
36
36
  };
37
37
  }
38
38
  /** No remote canvas targets are configured out of the box — every one is
39
- * hand-added to config.json (Phase 1 interim contract, see `RemoteCanvasConfig`). */
39
+ * registered via `crtr canvas config add` (see `RemoteCanvasConfig`). */
40
40
  export function defaultRemoteCanvasConfig() {
41
41
  return { targets: {} };
42
42
  }