@north-light/crouter 0.3.249 → 0.3.250
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/README.md +1 -1
- package/dist/api/__tests__/integration/client.test.js +28 -7
- package/dist/api/client.d.ts +1 -1
- package/dist/api/client.js +2 -2
- package/dist/api/dto/lifecycle.d.ts +3 -0
- package/dist/api/dto/messages.d.ts +4 -0
- package/dist/api/dto/nodes.d.ts +4 -0
- package/dist/api/dto/reports.d.ts +7 -2
- package/dist/builtin-memory/00-runtime-base/01-escalation.md +1 -1
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +3 -0
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +0 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +4 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +4 -3
- package/dist/clients/attach/session/chrome-refresh.d.ts +3 -0
- package/dist/clients/attach/session/chrome-refresh.js +1 -0
- package/dist/clients/attach/viewer.js +532 -532
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.d.ts +1 -0
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +53 -0
- package/dist/clients/inbox/controller.js +32 -5
- package/dist/clients/inbox/tui/ansi.d.ts +3 -1
- package/dist/clients/inbox/tui/ansi.js +14 -10
- package/dist/commands/__tests__/api-client-cold-start-diagnostic.test.js +7 -7
- package/dist/commands/api-client.d.ts +2 -2
- package/dist/commands/api-client.js +5 -5
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/node/create.js +3 -1
- package/dist/commands/node/inspect.js +1 -0
- package/dist/commands/node/lifecycle.js +1 -1
- package/dist/commands/node/message.js +6 -4
- package/dist/commands/node/wait.js +1 -1
- package/dist/commands/push.js +36 -37
- package/dist/commands/sys/daemon.js +21 -8
- package/dist/commands/sys/setup-core.js +2 -2
- package/dist/core/__tests__/broker-stream-watchdog-floor.test.d.ts +1 -0
- package/dist/core/__tests__/broker-stream-watchdog-floor.test.js +84 -0
- package/dist/core/__tests__/broker-turn-admission.test.d.ts +1 -0
- package/dist/core/__tests__/broker-turn-admission.test.js +44 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +5 -1
- package/dist/core/__tests__/child-death-wake.test.js +11 -7
- package/dist/core/__tests__/collectible.test.d.ts +1 -0
- package/dist/core/__tests__/collectible.test.js +88 -0
- package/dist/core/__tests__/context-intro.test.js +4 -41
- package/dist/core/__tests__/daemon-boot.test.js +30 -14
- package/dist/core/__tests__/daemon-wedge.test.js +25 -19
- package/dist/core/__tests__/fixtures/fake-engine.js +11 -0
- package/dist/core/__tests__/human-deliver.test.js +5 -5
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +65 -4
- package/dist/core/__tests__/integration/human-deliver-e2e.test.js +3 -3
- package/dist/core/__tests__/integration/revive.test.js +48 -0
- package/dist/core/__tests__/integration/spawn-root.test.js +36 -1
- package/dist/core/__tests__/integration/worktree-land.test.js +82 -3
- package/dist/core/__tests__/integration/worktree-reap.test.js +44 -6
- package/dist/core/__tests__/migration.test.js +30 -0
- package/dist/core/__tests__/passive-subscription.test.js +39 -1
- package/dist/core/__tests__/prune.test.js +12 -3
- package/dist/core/__tests__/relaunch-root.test.js +1 -1
- package/dist/core/__tests__/respawn-throttle.test.js +16 -146
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +23 -11
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +81 -2
- package/dist/core/__tests__/seam/dormancy-release.test.js +1 -1
- package/dist/core/__tests__/seam/self-close-teardown.test.d.ts +1 -0
- package/dist/core/__tests__/seam/self-close-teardown.test.js +49 -0
- package/dist/core/__tests__/seam/yield-refresh-transaction.test.js +18 -10
- package/dist/core/canvas/canvas.d.ts +9 -15
- package/dist/core/canvas/canvas.js +41 -47
- package/dist/core/canvas/crons.d.ts +5 -8
- package/dist/core/canvas/crons.js +5 -8
- package/dist/core/canvas/history.d.ts +5 -0
- package/dist/core/canvas/history.js +12 -1
- package/dist/core/canvas/migrations.js +58 -1
- package/dist/core/canvas/pid.d.ts +1 -1
- package/dist/core/canvas/pid.js +5 -2
- package/dist/core/canvas/types.d.ts +4 -0
- package/dist/core/feed/feed.d.ts +4 -0
- package/dist/core/feed/feed.js +13 -8
- package/dist/core/feed/inbox.d.ts +2 -1
- package/dist/core/feed/inbox.js +22 -3
- package/dist/core/git.d.ts +3 -0
- package/dist/core/git.js +3 -1
- package/dist/core/human/feedback-companion.js +1 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/review/companion.js +1 -0
- package/dist/core/review/realize.js +1 -0
- package/dist/core/runtime/broker/auth-reload.d.ts +2 -0
- package/dist/core/runtime/broker/auth-reload.js +9 -3
- package/dist/core/runtime/broker/engine-drive.d.ts +2 -0
- package/dist/core/runtime/broker/engine-drive.js +28 -23
- package/dist/core/runtime/broker/event-projection.d.ts +4 -0
- package/dist/core/runtime/broker/event-projection.js +43 -23
- package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
- package/dist/core/runtime/broker/fault-retry.js +94 -8
- package/dist/core/runtime/broker/frame-dispatch.d.ts +2 -0
- package/dist/core/runtime/broker/frame-dispatch.js +4 -1
- package/dist/core/runtime/broker/inbox.js +4 -0
- package/dist/core/runtime/broker/rebind.js +18 -0
- package/dist/core/runtime/broker/turn-admission.d.ts +11 -0
- package/dist/core/runtime/broker/turn-admission.js +31 -0
- package/dist/core/runtime/broker/turn-ignition.d.ts +2 -0
- package/dist/core/runtime/broker/turn-ignition.js +25 -15
- package/dist/core/runtime/broker.js +21 -2
- package/dist/core/runtime/close.d.ts +11 -9
- package/dist/core/runtime/close.js +23 -19
- package/dist/core/runtime/fault.d.ts +21 -0
- package/dist/core/runtime/fault.js +129 -19
- package/dist/core/runtime/fleet.d.ts +0 -6
- package/dist/core/runtime/host.d.ts +7 -1
- package/dist/core/runtime/host.js +20 -2
- package/dist/core/runtime/nodes.d.ts +5 -1
- package/dist/core/runtime/nodes.js +24 -1
- package/dist/core/runtime/placement.d.ts +6 -6
- package/dist/core/runtime/placement.js +15 -8
- package/dist/core/runtime/reset.js +2 -2
- package/dist/core/runtime/revive.js +40 -4
- package/dist/core/runtime/spawn.d.ts +3 -0
- package/dist/core/runtime/spawn.js +1 -0
- package/dist/core/runtime/warm-pool.d.ts +4 -0
- package/dist/core/runtime/warm-pool.js +2 -0
- package/dist/core/worktree.d.ts +4 -3
- package/dist/core/worktree.js +73 -27
- package/dist/daemon/__tests__/integration/api-startup-readiness.test.d.ts +1 -0
- package/dist/daemon/__tests__/integration/api-startup-readiness.test.js +81 -0
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +38 -0
- package/dist/daemon/api/__tests__/seam/api-server.test.js +1 -0
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +13 -2
- package/dist/daemon/api/handlers/bash-jobs.js +2 -0
- package/dist/daemon/api/handlers/broker-ops.js +23 -2
- package/dist/daemon/api/handlers/human.js +1 -1
- package/dist/daemon/api/handlers/messages.js +11 -2
- package/dist/daemon/api/handlers/nodes.js +13 -1
- package/dist/daemon/api/handlers/reports.js +14 -6
- package/dist/daemon/api/map.js +1 -0
- package/dist/daemon/api/server.d.ts +9 -12
- package/dist/daemon/api/server.js +30 -19
- package/dist/daemon/companion-retire.js +3 -9
- package/dist/daemon/cron/sinks.js +7 -2
- package/dist/daemon/crtrd.js +4 -1
- package/dist/daemon/fleet.d.ts +2 -16
- package/dist/daemon/fleet.js +63 -150
- package/dist/daemon/human/finish.js +2 -0
- package/dist/daemon/manage.d.ts +11 -0
- package/dist/daemon/manage.js +32 -3
- package/dist/daemon/messaging/node-message.js +7 -1
- package/dist/daemon/reconcilers/bash-deadline.js +2 -0
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -0
- package/dist/daemon/reconcilers/broker-supervision.js +22 -9
- package/dist/daemon/reconcilers/live-obligation.d.ts +16 -6
- package/dist/daemon/reconcilers/live-obligation.js +18 -6
- package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +15 -4
- package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +34 -3
- package/dist/daemon/reconcilers/node-lifecycle/terminating.d.ts +4 -1
- package/dist/daemon/reconcilers/node-lifecycle/terminating.js +11 -2
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +14 -7
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -2
- package/dist/daemon/reconcilers/storage-maintenance.js +3 -3
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +4 -4
- package/dist/pi-extensions/canvas-context-intro.d.ts +3 -34
- package/dist/pi-extensions/canvas-context-intro.js +4 -76
- package/dist/pi-extensions/canvas-review-boundary.d.ts +3 -24
- package/dist/pi-extensions/canvas-review-boundary.js +4 -29
- package/dist/pi-extensions/canvas-stophook.js +1 -6
- package/dist/shared/birth-announcement.d.ts +12 -0
- package/dist/shared/birth-announcement.js +25 -0
- package/dist/shared/generated-context.d.ts +8 -4
- package/dist/shared/generated-context.js +15 -9
- package/package.json +4 -4
- package/runtime.lock.json +2 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +0 -254
- package/dist/pi-extensions/truncate.d.ts +0 -5
- package/dist/pi-extensions/truncate.js +0 -14
package/README.md
CHANGED
|
@@ -45,5 +45,5 @@ To opt out of the bootstrap (e.g. in CI), set `CRTR_NO_BOOTSTRAP=1`.
|
|
|
45
45
|
The node runtime hosts the [pi coding agent](https://pi.dev) in each broker. To set your pi install up the way crouter's author runs it, add these to the `packages` array in `~/.pi/agent/settings.json` (neither ships with pi — you add them yourself):
|
|
46
46
|
|
|
47
47
|
- **[pi-claude-oauth-adapter](https://github.com/minzique/dotfiles-agents/tree/main/packages/pi-claude-oauth-adapter)** — third-party npm package; Anthropic OAuth / Claude Code compatibility adapter for pi. Install with `"npm:pi-claude-oauth-adapter"`.
|
|
48
|
-
- **pi-crtr-extensions** — crtr's engine-side pi extensions (crtr help-gate, slash-command surfacing, provider rotation, frontmatter rules
|
|
48
|
+
- **pi-crtr-extensions** — crtr's engine-side pi extensions (crtr help-gate, slash-command surfacing, provider rotation, frontmatter rules). Bundled in this repo at `src/builtin-pi-packages/pi-crtr-extensions` and wired into `~/.pi/agent/settings.json` automatically by `crtr sys setup` — nothing to install separately.
|
|
49
49
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// client.test.ts — regression for issue #516: a cold-start `/healthz` timeout
|
|
2
2
|
// used to throw a bare `daemon_unavailable` message that discarded the actual
|
|
3
|
-
// startup failure (the tail of crtrd.
|
|
3
|
+
// startup failure (the tail of crtrd.log). `coldStartTimeoutMessage` is the
|
|
4
4
|
// pure composition `handleColdSocket` uses on timeout; this proves an injected
|
|
5
5
|
// diagnostic is appended (not dropped) and that a missing/empty diagnostic
|
|
6
6
|
// still falls back to the original bare message unchanged. `safeColdStartDiagnostic`
|
|
@@ -11,19 +11,19 @@
|
|
|
11
11
|
import { test } from 'node:test';
|
|
12
12
|
import assert from 'node:assert/strict';
|
|
13
13
|
import { createServer } from 'node:http';
|
|
14
|
-
import { mkdtempSync, rmSync } from 'node:fs';
|
|
14
|
+
import { mkdirSync, mkdtempSync, rmSync } from 'node:fs';
|
|
15
15
|
import { tmpdir } from 'node:os';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { coldStartTimeoutMessage, CrtrClient, safeColdStartDiagnostic } from '../../client.js';
|
|
18
18
|
import { ApiError } from '../../errors.js';
|
|
19
19
|
test('coldStartTimeoutMessage appends a present diagnostic to the base message', () => {
|
|
20
|
-
const msg = coldStartTimeoutMessage('crtrd.
|
|
20
|
+
const msg = coldStartTimeoutMessage('crtrd.log (tail):\nError: bind EADDRINUSE');
|
|
21
21
|
assert.match(msg, /crtrd did not start/);
|
|
22
|
-
assert.match(msg, /crtrd\.
|
|
22
|
+
assert.match(msg, /crtrd\.log \(tail\):\nError: bind EADDRINUSE/);
|
|
23
23
|
});
|
|
24
24
|
test('coldStartTimeoutMessage falls back to the bare message when no diagnostic is available', () => {
|
|
25
|
-
assert.equal(coldStartTimeoutMessage(undefined), 'crtrd did not start; run `crtr sys daemon start` and check crtrd.
|
|
26
|
-
assert.equal(coldStartTimeoutMessage(''), 'crtrd did not start; run `crtr sys daemon start` and check crtrd.
|
|
25
|
+
assert.equal(coldStartTimeoutMessage(undefined), 'crtrd did not start; run `crtr sys daemon start` and check crtrd.log.');
|
|
26
|
+
assert.equal(coldStartTimeoutMessage(''), 'crtrd did not start; run `crtr sys daemon start` and check crtrd.log.');
|
|
27
27
|
});
|
|
28
28
|
function startDelayedHealthzServer(socketPath, delayMs) {
|
|
29
29
|
const server = createServer((_req, res) => {
|
|
@@ -85,6 +85,27 @@ test('a hang-up mid-mutation reports daemon_restarting, not daemon_unavailable',
|
|
|
85
85
|
rmSync(dir, { recursive: true, force: true });
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
+
test('a non-socket cold-start path surfaces its diagnostic after autostart times out', async () => {
|
|
89
|
+
const dir = mkdtempSync(join(tmpdir(), 'crtr-client-nonsocket-'));
|
|
90
|
+
const socketPath = join(dir, 'crtrd.sock');
|
|
91
|
+
mkdirSync(socketPath);
|
|
92
|
+
const diagnostic = 'crtrd.log (tail):\napi.server.failed: EADDRINUSE';
|
|
93
|
+
const client = new CrtrClient({
|
|
94
|
+
socketPath,
|
|
95
|
+
autostart: true,
|
|
96
|
+
onColdSocket: async () => { },
|
|
97
|
+
coldStartPollWindowMs: 50,
|
|
98
|
+
coldStartDiagnostic: () => diagnostic,
|
|
99
|
+
});
|
|
100
|
+
try {
|
|
101
|
+
await assert.rejects(() => client.healthz(), (error) => error instanceof ApiError
|
|
102
|
+
&& error.code === 'daemon_unavailable'
|
|
103
|
+
&& error.message.includes(diagnostic));
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
rmSync(dir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
88
109
|
test('cliClient-style cold start fails loud when the injected poll window is shorter than the (valid) startup delay', async () => {
|
|
89
110
|
const dir = mkdtempSync(join(tmpdir(), 'crtr-client-coldstart-'));
|
|
90
111
|
const socketPath = join(dir, 'crtrd.sock');
|
|
@@ -132,7 +153,7 @@ test('safeColdStartDiagnostic returns undefined for an absent hook', () => {
|
|
|
132
153
|
assert.equal(safeColdStartDiagnostic(undefined), undefined);
|
|
133
154
|
});
|
|
134
155
|
test('safeColdStartDiagnostic returns the hook result when it succeeds', () => {
|
|
135
|
-
assert.equal(safeColdStartDiagnostic(() => 'crtrd.
|
|
156
|
+
assert.equal(safeColdStartDiagnostic(() => 'crtrd.log (tail):\nboom'), 'crtrd.log (tail):\nboom');
|
|
136
157
|
});
|
|
137
158
|
test('safeColdStartDiagnostic treats a THROWING hook as absent, not a propagated error', () => {
|
|
138
159
|
assert.equal(safeColdStartDiagnostic(() => {
|
package/dist/api/client.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface CrtrClientOptions {
|
|
|
39
39
|
onColdSocket?: () => Promise<void>;
|
|
40
40
|
/** Injected cold-start diagnostic. Called ONLY when the bounded
|
|
41
41
|
* `/healthz` poll times out after `onColdSocket`, so the caller can attach
|
|
42
|
-
* operator-useful context (e.g. a bounded tail of crtrd
|
|
42
|
+
* operator-useful context (e.g. a bounded tail of `crtrd.log`) to the
|
|
43
43
|
* `daemon_unavailable` error instead of it staying a bare message. Must
|
|
44
44
|
* return synchronously and cheaply — it runs on the failure path, not the
|
|
45
45
|
* happy path. A thrown/undefined result is treated as "no diagnostic". */
|
package/dist/api/client.js
CHANGED
|
@@ -668,7 +668,7 @@ export class CrtrClient {
|
|
|
668
668
|
if (this.socketPath === undefined)
|
|
669
669
|
return false;
|
|
670
670
|
const code = err?.code;
|
|
671
|
-
return code === 'ECONNREFUSED' || code === 'ENOENT';
|
|
671
|
+
return code === 'ECONNREFUSED' || code === 'ENOENT' || code === 'ENOTSOCK';
|
|
672
672
|
}
|
|
673
673
|
/** A connection torn down MID-request (Node's "socket hang up" / a broken
|
|
674
674
|
* pipe) — as distinct from a refused connect, which means nothing is
|
|
@@ -817,7 +817,7 @@ function sleep(ms) {
|
|
|
817
817
|
* design) purely so the regression test can assert the composition without
|
|
818
818
|
* waiting out the real poll window. */
|
|
819
819
|
export function coldStartTimeoutMessage(diagnostic) {
|
|
820
|
-
const base = 'crtrd did not start; run `crtr sys daemon start` and check crtrd.
|
|
820
|
+
const base = 'crtrd did not start; run `crtr sys daemon start` and check crtrd.log.';
|
|
821
821
|
return diagnostic !== undefined && diagnostic !== '' ? `${base}\n${diagnostic}` : base;
|
|
822
822
|
}
|
|
823
823
|
/** Invoke the injected `coldStartDiagnostic` hook, treating a THROW the same
|
|
@@ -47,6 +47,9 @@ export interface ReviveAllResultDTO {
|
|
|
47
47
|
* from edges; the flag only opts out of cascading descendants. */
|
|
48
48
|
export interface CloseRequest {
|
|
49
49
|
cascade?: boolean;
|
|
50
|
+
/** PID of the shell that invoked this close. The daemon excludes this process
|
|
51
|
+
* and its descendants from broker teardown so a node can close itself. */
|
|
52
|
+
caller_pid?: number;
|
|
50
53
|
/** Root close disposition: `true` finalizes the root to `done` (the browse `x`
|
|
51
54
|
* "finish" semantics); default/`false` cancels it. The cascade set (computed
|
|
52
55
|
* server-side) is torn down either way. */
|
|
@@ -62,6 +62,10 @@ export interface MessageResultDTO {
|
|
|
62
62
|
* frozen and the daemon relaunches it when one frees. The entry is durably
|
|
63
63
|
* appended either way, and delivery follows that relaunch. */
|
|
64
64
|
not_revived_reason?: 'capacity_frozen';
|
|
65
|
+
/** Present only when the entry was appended ABOVE the requested tier: a
|
|
66
|
+
* terminal target never takes the later cycle `normal`/`deferred` wait for,
|
|
67
|
+
* so its mail is raised to the steering tier. */
|
|
68
|
+
delivered_tier?: InboxTierDTO;
|
|
65
69
|
delivered_at?: IsoTime;
|
|
66
70
|
/** Which channel a `delivery:'interactive'` send actually used: `'engine'`
|
|
67
71
|
* (live broker frame loop, no inbox entry) or `'inbox'` (durable fallback).
|
package/dist/api/dto/nodes.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export interface CreateNodeRequest {
|
|
|
36
36
|
/** Caller-supplied short description, preserved against automatic naming. */
|
|
37
37
|
description?: string;
|
|
38
38
|
parent?: NodeIdDTO | null;
|
|
39
|
+
/** Node that created this request; absent for an external process. */
|
|
40
|
+
creator?: NodeIdDTO;
|
|
39
41
|
root?: boolean;
|
|
40
42
|
/** Lifecycle of the new node. Roots default to `resident`; managed children
|
|
41
43
|
* default to `terminal`. Use `resident` for a child that remains wakeable
|
|
@@ -165,6 +167,8 @@ export interface NodeFaultDTO {
|
|
|
165
167
|
/** The full node view — summary ∪ identity extras ∪ edges ∪ paths. Returned by
|
|
166
168
|
* `GET /v1/nodes/{id}` and by the create/lifecycle actions that yield a node. */
|
|
167
169
|
export interface NodeDetailDTO extends NodeSummaryDTO {
|
|
170
|
+
/** Node that created this node, or null when an external process did. */
|
|
171
|
+
creator: NodeIdDTO | null;
|
|
168
172
|
description?: string;
|
|
169
173
|
/** The namer's prose form of `description` — sentence case, punctuation intact
|
|
170
174
|
* (`NodeMeta.title`). What a surface showing this node to a person reads;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { IsoTime, NodeIdDTO } from './common.js';
|
|
2
|
-
/** Report
|
|
2
|
+
/** Report kind — `crtr push {update,final}`; legacy `urgent` rows remain readable. */
|
|
3
3
|
export type ReportTierDTO = 'update' | 'urgent' | 'final';
|
|
4
|
-
/**
|
|
4
|
+
/** Delivery urgency for an update report's subscriber fan-out. */
|
|
5
|
+
export type ReportDeliveryTierDTO = 'deferred' | 'normal' | 'urgent';
|
|
6
|
+
/** `POST /v1/nodes/{id}/reports` body ({id} = the reporting node).
|
|
7
|
+
* `tier` is the stored report kind; `delivery_tier` is the optional inbox
|
|
8
|
+
* delivery urgency for an update's subscriber fan-out. */
|
|
5
9
|
export interface PushReportRequest {
|
|
6
10
|
tier: ReportTierDTO;
|
|
11
|
+
delivery_tier?: ReportDeliveryTierDTO;
|
|
7
12
|
body: string;
|
|
8
13
|
}
|
|
9
14
|
/** Result of a push. `transitioned` is present only for `final`, which drives a
|
|
@@ -8,7 +8,7 @@ surfaces:
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
## When blocked, want feedback, or need the user
|
|
11
|
-
Ask the user only when the work genuinely requires them: intent that stays ambiguous after you have dug, a tradeoff that is genuinely theirs, a real scope or direction change, a destructive or irreversible action, or sign-off on finished work. Settle everything the code, a tool, or a delegate can settle first — a whole goal costs a handful of asks, not a stream. Ask through the human inbox (`crtr human
|
|
11
|
+
Ask the user only when the work genuinely requires them: intent that stays ambiguous after you have dug, a tradeoff that is genuinely theirs, a real scope or direction change, a destructive or irreversible action, or sign-off on finished work. Settle everything the code, a tool, or a delegate can settle first — a whole goal costs a handful of asks, not a stream. Ask through the human inbox (`crtr human -h`), then end your turn: a question posed as prose in a reply or report pings nobody, while an ask lands on their screen and its answer wakes you.
|
|
12
12
|
|
|
13
13
|
## When crtr itself misbehaves
|
|
14
14
|
A `crtr` command that errors unexpectedly, hangs, churns, double-spawns, or contradicts its own `-h` is a harness bug — don't silently work around it. Run `crtr sys feedback` to report it (`-h` for how), then continue.
|
|
@@ -15,3 +15,6 @@ Choose the one decomposition axis that best covers this surface: **units** (file
|
|
|
15
15
|
Synthesize the child reports yourself into the final review output: one deduplicated, severity-normalized verdict, most important first. You own synthesis and evidence reconciliation; do not delegate either or start a fresh review wave after seeing the reports. The owner disposes findings and validates changed behavior. Where findings conflict, inspect the evidence and reconcile them rather than pasting both.
|
|
16
16
|
|
|
17
17
|
Steer bug findings toward substance in synthesis: weight a traced failing path over a speculative "could break", and prune speculation no child attempted to confirm rather than forwarding it. Code-quality findings are observable facts and carry no such burden. A child's security concern meets the same exploit-path bar — an unknown threat-model assumption it surfaces comes out of your severity-rated verdict and becomes the question you ask.
|
|
18
|
+
|
|
19
|
+
## Avoiding overcomplication
|
|
20
|
+
The nodes beneath you can be nitpicky, but your job is to maintain the greater picture and vision. If a reviewer node raises an issue that is out of scope of the intent of the feature or change that's being reviewed, then it's your responsibility to not get "lost in the sauce" and just flag every issue that could possibly happen, but instead have taste as an engineer and an understanding of the broader vision.
|
|
@@ -29,7 +29,7 @@ Navigate/steer: `surface node focus` (put an attach viewer for a node in your pa
|
|
|
29
29
|
Nothing is reported automatically — the feed contains only what a node **pushes**.
|
|
30
30
|
|
|
31
31
|
- `push update` — routine progress; fans a lightweight pointer to subscribers, no forced wake.
|
|
32
|
-
- `push urgent` — force-wakes every subscriber (you're blocked, scope changed, an error derails the plan).
|
|
32
|
+
- `push update --tier urgent` — force-wakes every subscriber (you're blocked, scope changed, an error derails the plan).
|
|
33
33
|
- `push final` — the ONLY way a terminal node finishes: writes the canonical result, marks the node done, and tears down its broker. Stopping without it is not finishing. Resident/user-facing nodes stay dormant instead of finishing unless explicitly forced.
|
|
34
34
|
|
|
35
35
|
A push fans a ~30-token **pointer** (a ref path), not the content; subscribers dereference lazily. When a subscriber push wakes you, **the wake message already IS the coalesced digest** — dereference the refs that matter rather than trying to re-read it. An empty feed while workers run is normal — a worker that hasn't pushed yet leaves no pointer; the wake it fires when it does push is automatic, so there's nothing to poll or check in the meantime.
|
|
@@ -37,7 +37,6 @@ directory's `node_modules/`.
|
|
|
37
37
|
| `crtr-commands/` | Auto-generates a slash command per `crtr` CLI node. The tree is derived in-process from crtr's own `buildRoot()` (no subprocesses, no cache on disk); `filters.json` controls which nodes are exposed. |
|
|
38
38
|
| `sysprompt-window.ts` | Registers `/sysprompt`, which runs `crtr sys context sysprompt --window` without injecting the prompt into context. |
|
|
39
39
|
| `frontmatter-rules/` | Injects `.pi/rules/*.md` whose `when:` frontmatter matches a read markdown file. `.claude/rules` are migrated into substrate docs with read-glob `surfaces` entries via `crtr sys sync project-guidance`. Needs the `yaml` dep. See the `pi-frontmatter-rules` skill. |
|
|
40
|
-
| `statusline.ts` | Custom status line. |
|
|
41
40
|
|
|
42
41
|
Removing pi's self-referential prompt text (the harness identity sentence and
|
|
43
42
|
the pi documentation block) is NOT done here. It runs as a canvas extension, so
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createAssistantMessageEventStream, } from '@earendil-works/pi-ai';
|
|
3
|
-
import {
|
|
3
|
+
import { streamSimple as streamAnthropicMessages } from '@earendil-works/pi-ai/api/anthropic-messages';
|
|
4
|
+
import { streamSimple as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses';
|
|
4
5
|
import { ANTHROPIC_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID, INVALID_REFRESH_TOKEN_BACKOFF_MS, formatStatusLine, getProviderLabel, isManagedProvider, isInvalidRefreshTokenError, addSubscription, enrichManagedLoginIdentity, markSubscriptionAuthenticationFailed, markSubscriptionRateLimited, markSubscriptionSuccess, parseRetryAfterHeader, promoteSubscription, readRotationConfig, readSubscriptionPool, refreshSubscriptionCredential, removeManagedAccount, resolveProviderCandidates, upsertSubscriptionWithUniqueAccount, } from '../../../core/subscription-state.js';
|
|
5
6
|
import { readMergedLaunchConfig } from '../../../core/config.js';
|
|
6
7
|
import { expandModelCandidates, modelRequestFromConfig, probeRouteAvailability } from '../../../core/model-routes.js';
|
|
@@ -305,9 +306,9 @@ async function reauthenticateCredential(state, providerId, credential) {
|
|
|
305
306
|
}
|
|
306
307
|
function defaultStreamForProvider(model, context, options) {
|
|
307
308
|
if (model.provider === ANTHROPIC_PROVIDER_ID) {
|
|
308
|
-
return
|
|
309
|
+
return streamAnthropicMessages(model, context, options);
|
|
309
310
|
}
|
|
310
|
-
return
|
|
311
|
+
return streamOpenAICodexResponses(model, context, options);
|
|
311
312
|
}
|
|
312
313
|
// Indirection so tests can inject a fake per-provider stream without real network calls.
|
|
313
314
|
let activeStreamForProvider = defaultStreamForProvider;
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
type OAuthAuth,
|
|
13
13
|
type SimpleStreamOptions,
|
|
14
14
|
} from '@earendil-works/pi-ai';
|
|
15
|
-
import {
|
|
15
|
+
import { streamSimple as streamAnthropicMessages } from '@earendil-works/pi-ai/api/anthropic-messages';
|
|
16
|
+
import { streamSimple as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses';
|
|
16
17
|
import {
|
|
17
18
|
ANTHROPIC_PROVIDER_ID,
|
|
18
19
|
OPENAI_CODEX_PROVIDER_ID,
|
|
@@ -441,9 +442,9 @@ async function reauthenticateCredential(state: ProviderRotationState, providerId
|
|
|
441
442
|
|
|
442
443
|
function defaultStreamForProvider(model: Model<any>, context: Context, options: SimpleStreamOptions | undefined): AssistantMessageEventStream {
|
|
443
444
|
if (model.provider === ANTHROPIC_PROVIDER_ID) {
|
|
444
|
-
return
|
|
445
|
+
return streamAnthropicMessages(model as Model<"anthropic-messages">, context, options);
|
|
445
446
|
}
|
|
446
|
-
return
|
|
447
|
+
return streamOpenAICodexResponses(model as Model<"openai-codex-responses">, context, options);
|
|
447
448
|
}
|
|
448
449
|
|
|
449
450
|
// Indirection so tests can inject a fake per-provider stream without real network calls.
|
|
@@ -8,6 +8,9 @@ export interface ChromeRefreshHooks {
|
|
|
8
8
|
refreshRoster: () => Promise<void>;
|
|
9
9
|
/** Repaint the graph overlay if open. */
|
|
10
10
|
refreshGraph: () => void;
|
|
11
|
+
/** Re-read the node's persona/lifecycle/icon from canvas — a runtime
|
|
12
|
+
* promote/reshape changes it with no broker event, so the poll catches it. */
|
|
13
|
+
refreshIdentity: () => void;
|
|
11
14
|
renderFooter: () => void;
|
|
12
15
|
renderExtensionWidgets: () => void;
|
|
13
16
|
/** Re-poll this pane's own git context (owned by the editor chrome). */
|
|
@@ -59,6 +59,7 @@ export function createChromeRefresh(ctx, hooks) {
|
|
|
59
59
|
// source (child status flips emit no broker event) and re-poll the ask map asynchronously.
|
|
60
60
|
const pollChrome = () => {
|
|
61
61
|
refresh();
|
|
62
|
+
hooks.refreshIdentity();
|
|
62
63
|
hooks.renderExtensionWidgets();
|
|
63
64
|
hooks.pollGit();
|
|
64
65
|
// R4: re-evaluate the bash-hint threshold on the existing 5s cadence, so a
|