@crouton-kit/crouter 0.3.36 → 0.3.38
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/build-root.js +3 -6
- package/dist/{builtin-personas/runtime-base.md → builtin-memory/00-runtime-base.md} +8 -1
- package/dist/{builtin-personas/spine/has-manager.md → builtin-memory/01-spine/00-has-manager.md} +8 -0
- package/dist/builtin-memory/01-spine/01-no-manager.md +10 -0
- package/dist/{builtin-personas/lifecycle/terminal.md → builtin-memory/02-lifecycle/00-terminal.md} +8 -0
- package/dist/{builtin-personas/lifecycle/resident.md → builtin-memory/02-lifecycle/01-resident.md} +8 -0
- package/dist/{builtin-personas/waiting.md → builtin-memory/03-waiting.md} +7 -0
- package/dist/{builtin-personas/orchestration-kernel.md → builtin-memory/04-orchestration-kernel.md} +8 -0
- package/dist/{builtin-personas/advisor/PERSONA.md → builtin-memory/05-kinds/advisor/00-base.md} +5 -2
- package/dist/{builtin-personas/design/PERSONA.md → builtin-memory/05-kinds/design/00-base.md} +5 -2
- package/dist/{builtin-personas/design/orchestrator.md → builtin-memory/05-kinds/design/01-orchestrator.md} +5 -4
- package/dist/{builtin-personas/developer/PERSONA.md → builtin-memory/05-kinds/developer/00-base.md} +5 -2
- package/dist/{builtin-personas/developer/orchestrator.md → builtin-memory/05-kinds/developer/01-orchestrator.md} +5 -4
- package/dist/{builtin-personas/explore/PERSONA.md → builtin-memory/05-kinds/explore/00-base.md} +5 -2
- package/dist/{builtin-personas/explore/orchestrator.md → builtin-memory/05-kinds/explore/01-orchestrator.md} +5 -3
- package/dist/{builtin-personas/general/PERSONA.md → builtin-memory/05-kinds/general/00-base.md} +5 -2
- package/dist/{builtin-personas/general/orchestrator.md → builtin-memory/05-kinds/general/01-orchestrator.md} +5 -3
- package/dist/{builtin-personas/plan/PERSONA.md → builtin-memory/05-kinds/plan/00-base.md} +5 -2
- package/dist/{builtin-personas/plan/orchestrator.md → builtin-memory/05-kinds/plan/01-orchestrator.md} +5 -4
- package/dist/{builtin-personas/plan/reviewers/architecture-fit/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/architecture-fit.md} +5 -2
- package/dist/{builtin-personas/plan/reviewers/code-smells/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/code-smells.md} +5 -2
- package/dist/{builtin-personas/plan/reviewers/pattern-consistency/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md} +5 -2
- package/dist/{builtin-personas/plan/reviewers/requirements-coverage/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md} +5 -2
- package/dist/{builtin-personas/plan/reviewers/security/PERSONA.md → builtin-memory/05-kinds/plan/reviewers/security.md} +5 -2
- package/dist/{builtin-personas/product/PERSONA.md → builtin-memory/05-kinds/product/00-base.md} +5 -2
- package/dist/{builtin-personas/product/orchestrator.md → builtin-memory/05-kinds/product/01-orchestrator.md} +5 -4
- package/dist/{builtin-personas/product/teardown/PERSONA.md → builtin-memory/05-kinds/product/teardown.md} +5 -3
- package/dist/{builtin-personas/review/PERSONA.md → builtin-memory/05-kinds/review/00-base.md} +5 -2
- package/dist/{builtin-personas/review/orchestrator.md → builtin-memory/05-kinds/review/01-orchestrator.md} +5 -3
- package/dist/{builtin-personas/spec/PERSONA.md → builtin-memory/05-kinds/spec/00-base.md} +5 -2
- package/dist/{builtin-personas/spec/orchestrator.md → builtin-memory/05-kinds/spec/01-orchestrator.md} +5 -4
- package/dist/{builtin-personas/spec/requirements/PERSONA.md → builtin-memory/05-kinds/spec/requirements.md} +5 -2
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +4 -4
- package/dist/builtin-views/canvas/core.mjs +3 -2
- package/dist/builtin-views/prompt-review/core.mjs +6 -134
- package/dist/builtin-views/settings/core.mjs +26 -94
- package/dist/builtin-views/settings/text.mjs +0 -5
- package/dist/builtin-views/settings/tui.mjs +1 -7
- package/dist/builtin-views/settings/web.jsx +3 -49
- package/dist/clients/attach/__tests__/crtr-output-render.test.js +21 -205
- package/dist/clients/attach/attach-cmd.js +429 -432
- package/dist/clients/web/web-cmd.js +7 -7
- package/dist/commands/__tests__/human.test.js +1 -15
- package/dist/commands/attention.js +9 -6
- package/dist/commands/canvas-history/search.js +2 -2
- package/dist/commands/canvas-history/show.js +3 -3
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas-issue.js +1 -0
- package/dist/commands/canvas-snapshot.js +1 -0
- package/dist/commands/canvas.js +10 -11
- package/dist/commands/chord.js +1 -0
- package/dist/commands/human/prompts.js +0 -1
- package/dist/commands/human/queue.js +1 -0
- package/dist/commands/memory/read.js +3 -3
- package/dist/commands/memory/shared.d.ts +13 -8
- package/dist/commands/memory/shared.js +22 -8
- package/dist/commands/memory/write.js +5 -3
- package/dist/commands/node-snapshot.js +1 -0
- package/dist/commands/node.js +52 -22
- package/dist/commands/profile/add-project.d.ts +1 -0
- package/dist/commands/profile/add-project.js +42 -0
- package/dist/commands/profile/delete.d.ts +1 -0
- package/dist/commands/profile/delete.js +39 -0
- package/dist/commands/profile/list.d.ts +1 -0
- package/dist/commands/profile/list.js +35 -0
- package/dist/commands/profile/new.d.ts +1 -0
- package/dist/commands/profile/new.js +50 -0
- package/dist/commands/profile/remove-project.d.ts +1 -0
- package/dist/commands/profile/remove-project.js +42 -0
- package/dist/commands/profile/rename.d.ts +1 -0
- package/dist/commands/profile/rename.js +42 -0
- package/dist/commands/profile/show.d.ts +1 -0
- package/dist/commands/profile/show.js +50 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +33 -0
- package/dist/commands/push.d.ts +0 -1
- package/dist/commands/push.js +2 -228
- package/dist/commands/revive.js +2 -2
- package/dist/commands/{canvas-tmux-spread.js → surface-tmux-spread.js} +9 -6
- package/dist/commands/surface.js +3 -2
- package/dist/commands/sys/config.js +6 -21
- package/dist/commands/sys/daemon.d.ts +2 -0
- package/dist/commands/{daemon.js → sys/daemon.js} +12 -12
- package/dist/commands/sys/doctor.js +1 -0
- package/dist/commands/sys/prompt-review.js +90 -17
- package/dist/commands/sys.js +4 -3
- package/dist/core/__tests__/daemon-boot.test.js +1 -1
- package/dist/core/__tests__/daemon-wedge.test.d.ts +1 -0
- package/dist/core/__tests__/daemon-wedge.test.js +87 -0
- package/dist/core/__tests__/hearth-bootstrap.test.js +2 -2
- package/dist/core/__tests__/history-inbox.test.d.ts +1 -0
- package/dist/core/__tests__/history-inbox.test.js +105 -0
- package/dist/core/__tests__/kickoff.test.js +3 -3
- package/dist/core/__tests__/revive.test.js +39 -1
- package/dist/core/canvas/canvas.js +10 -9
- package/dist/core/canvas/db.js +11 -0
- package/dist/core/canvas/history.d.ts +1 -1
- package/dist/core/canvas/history.js +91 -3
- package/dist/core/canvas/paths.d.ts +6 -0
- package/dist/core/canvas/paths.js +9 -0
- package/dist/core/canvas/status-glyph.js +1 -0
- package/dist/core/canvas/types.d.ts +10 -0
- package/dist/core/config.d.ts +44 -1
- package/dist/core/config.js +155 -12
- package/dist/core/fault-classifier.d.ts +2 -2
- package/dist/core/feed/inbox.d.ts +7 -12
- package/dist/core/feed/inbox.js +45 -29
- package/dist/core/hearth/providers/blaxel-bootstrap.js +1 -1
- package/dist/core/memory-resolver.d.ts +26 -15
- package/dist/core/memory-resolver.js +158 -40
- package/dist/core/preview-registry.js +14 -112
- package/dist/core/profiles/manifest.d.ts +33 -0
- package/dist/core/profiles/manifest.js +332 -0
- package/dist/core/profiles/select.d.ts +11 -0
- package/dist/core/profiles/select.js +115 -0
- package/dist/core/render.js +1 -1
- package/dist/core/runtime/bearings.d.ts +9 -0
- package/dist/core/runtime/bearings.js +31 -0
- package/dist/core/runtime/busy.d.ts +15 -0
- package/dist/core/runtime/busy.js +32 -1
- package/dist/core/runtime/close.d.ts +10 -0
- package/dist/core/runtime/close.js +18 -13
- package/dist/core/runtime/fault-recovery.js +4 -0
- package/dist/core/runtime/front-door.js +9 -2
- package/dist/core/runtime/kickoff.js +5 -7
- package/dist/core/runtime/launch.d.ts +25 -7
- package/dist/core/runtime/launch.js +42 -55
- package/dist/core/runtime/nodes.d.ts +7 -0
- package/dist/core/runtime/nodes.js +6 -0
- package/dist/core/runtime/persona.js +18 -32
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/revive.js +9 -1
- package/dist/core/runtime/spawn.d.ts +13 -0
- package/dist/core/runtime/spawn.js +25 -0
- package/dist/core/runtime/tmux.d.ts +2 -2
- package/dist/core/runtime/tmux.js +2 -2
- package/dist/core/scope.d.ts +14 -7
- package/dist/core/scope.js +76 -20
- package/dist/core/substrate/index.d.ts +3 -3
- package/dist/core/substrate/index.js +5 -3
- package/dist/core/substrate/on-read.js +3 -2
- package/dist/core/substrate/render.d.ts +16 -11
- package/dist/core/substrate/render.js +249 -62
- package/dist/core/substrate/schema.d.ts +11 -3
- package/dist/core/substrate/schema.js +25 -0
- package/dist/core/substrate/subject.d.ts +15 -2
- package/dist/core/substrate/subject.js +24 -2
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.d.ts +24 -0
- package/dist/daemon/crtrd.js +213 -5
- package/dist/daemon/manage.js +2 -2
- package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
- package/dist/pi-extensions/canvas-nav.js +2 -2
- package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
- package/dist/pi-extensions/canvas-stophook.js +59 -2
- package/dist/types.d.ts +57 -1
- package/dist/types.js +83 -1
- package/dist/web-client/assets/{index-IAJVtuVe.js → index-CbO8L0mN.js} +4 -4
- package/dist/web-client/assets/index-DwO46Cs5.css +2 -0
- package/dist/web-client/index.html +2 -2
- package/package.json +2 -2
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +0 -56
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +0 -57
- package/dist/builtin-memory/crouter-development/personas.md +0 -112
- package/dist/builtin-personas/spine/no-manager.md +0 -2
- package/dist/commands/daemon.d.ts +0 -2
- package/dist/core/personas/index.d.ts +0 -13
- package/dist/core/personas/index.js +0 -11
- package/dist/core/personas/loader.d.ts +0 -159
- package/dist/core/personas/loader.js +0 -327
- package/dist/core/personas/resolve.d.ts +0 -59
- package/dist/core/personas/resolve.js +0 -376
- package/dist/web-client/assets/index-DUThOUzU.css +0 -2
- /package/dist/commands/{canvas-tmux-spread.d.ts → surface-tmux-spread.d.ts} +0 -0
|
@@ -36,11 +36,11 @@ function openBrowser(url) {
|
|
|
36
36
|
}
|
|
37
37
|
const webServeLeaf = defineLeaf({
|
|
38
38
|
name: 'serve',
|
|
39
|
-
description: 'start the crouter web UI server — the
|
|
40
|
-
whenToUse: 'you want the crouter web UI
|
|
39
|
+
description: 'start the crouter web UI server — the browser alternative to a tmux pane for watching the canvas and driving headless nodes',
|
|
40
|
+
whenToUse: 'you want the crouter web UI in a browser instead of a tmux pane — watching the canvas and driving headless nodes from a page rather than a terminal surface. Binds 127.0.0.1 by default; pass --host to bind elsewhere, in which case --token is required so the page can authorize. Pass --dev only if you are iterating on the shell itself (Vite HMR) rather than just running it. The node is picked in the browser via the URL, not on the command line; the server runs until ctrl+c.',
|
|
41
41
|
help: {
|
|
42
42
|
name: 'web serve',
|
|
43
|
-
summary: 'start the
|
|
43
|
+
summary: 'start the crouter web UI server — the browser alternative to a tmux pane for watching the canvas and driving headless nodes',
|
|
44
44
|
params: [
|
|
45
45
|
{
|
|
46
46
|
kind: 'flag',
|
|
@@ -125,14 +125,14 @@ export function registerWeb() {
|
|
|
125
125
|
return defineBranch({
|
|
126
126
|
name: 'web',
|
|
127
127
|
rootEntry: {
|
|
128
|
-
concept: 'the crouter web UI server —
|
|
128
|
+
concept: 'the crouter web UI server — the browser alternative to a tmux pane for watching the canvas and driving headless nodes',
|
|
129
129
|
desc: 'serve the crouter web UI for the canvas and headless nodes',
|
|
130
|
-
useWhen: 'you want the crouter web UI in a browser instead of a tmux pane: watch the canvas and drive headless nodes
|
|
130
|
+
useWhen: 'you want the crouter web UI in a browser instead of a tmux pane: watch the canvas and drive headless nodes from a page. Binds 127.0.0.1 by default; a non-loopback bind requires a token so the page can authorize. The node is selected in the browser via the URL, not on the command line.',
|
|
131
131
|
},
|
|
132
132
|
help: {
|
|
133
133
|
name: 'web',
|
|
134
|
-
summary: 'serve the crouter web UI
|
|
135
|
-
model: 'The branch is a long-running browser surface
|
|
134
|
+
summary: 'serve the crouter web UI — the browser alternative to a tmux pane for the canvas and headless nodes',
|
|
135
|
+
model: 'The branch is a long-running browser surface, an alternative to a tmux pane. `serve` binds a host and port (loopback by default; --token required off-loopback) and runs until interrupted. The node is chosen in the browser via the URL, not on the command line; the server itself only hosts the surface and never spawns an engine.',
|
|
136
136
|
},
|
|
137
137
|
children: [webServeLeaf],
|
|
138
138
|
});
|
|
@@ -100,7 +100,7 @@ describe('human show: params', () => {
|
|
|
100
100
|
});
|
|
101
101
|
});
|
|
102
102
|
// ---------------------------------------------------------------------------
|
|
103
|
-
// human ask — --context-file (context-file kind, key=deckFile)
|
|
103
|
+
// human ask — --context-file (context-file kind, key=deckFile)
|
|
104
104
|
//
|
|
105
105
|
// NOTE: The argv parser hardcodes the CLI token as `--context-file` regardless
|
|
106
106
|
// of the param's `name` field. The `name` field ("deckFile") becomes the key
|
|
@@ -111,7 +111,6 @@ describe('human show: params', () => {
|
|
|
111
111
|
describe('human ask: params', () => {
|
|
112
112
|
const params = [
|
|
113
113
|
{ kind: 'context-file', name: 'deckFile', required: true, constraint: 'Humanloop deck JSON.' },
|
|
114
|
-
{ kind: 'flag', name: 'wait', type: 'bool', required: false, constraint: 'Presence-only.' },
|
|
115
114
|
];
|
|
116
115
|
test('--context-file parses JSON file and yields input.deckFile', async () => {
|
|
117
116
|
const deck = { interactions: [{ id: 'q', title: 'Go?', options: [{ id: 'yes', label: 'Yes' }] }] };
|
|
@@ -132,18 +131,6 @@ describe('human ask: params', () => {
|
|
|
132
131
|
writeFileSync(p, 'not json at all');
|
|
133
132
|
await assert.rejects(() => parseArgv(params, ['--context-file', p]), (err) => { assert.match(err.message, /not valid JSON/); return true; });
|
|
134
133
|
});
|
|
135
|
-
test('--wait absent → false', async () => {
|
|
136
|
-
const deck = { interactions: [] };
|
|
137
|
-
const path = tmpJson(deck);
|
|
138
|
-
const result = await parseArgv(params, ['--context-file', path]);
|
|
139
|
-
assert.equal(result['wait'], false);
|
|
140
|
-
});
|
|
141
|
-
test('--wait present → true', async () => {
|
|
142
|
-
const deck = { interactions: [] };
|
|
143
|
-
const path = tmpJson(deck);
|
|
144
|
-
const result = await parseArgv(params, ['--context-file', path, '--wait']);
|
|
145
|
-
assert.equal(result['wait'], true);
|
|
146
|
-
});
|
|
147
134
|
});
|
|
148
135
|
// ---------------------------------------------------------------------------
|
|
149
136
|
// human ask — shorthand question + strict --context-file deck
|
|
@@ -159,7 +146,6 @@ describe('human ask: shorthand', () => {
|
|
|
159
146
|
test('parses a positional question into input.question', async () => {
|
|
160
147
|
const result = await parseArgv(humanAsk.help.params ?? [], ['Should we ship today?']);
|
|
161
148
|
assert.equal(result['question'], 'Should we ship today?');
|
|
162
|
-
assert.equal(result['wait'], false);
|
|
163
149
|
});
|
|
164
150
|
test('parses --context-file into input.deck while keeping the strict deck path', async () => {
|
|
165
151
|
const deck = {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// `crtr canvas attention` — aggregate pending human asks across the canvas.
|
|
2
2
|
//
|
|
3
3
|
// Pending asks are stored per-cwd by humanloop. This subtree surfaces two
|
|
4
|
-
// views:
|
|
5
|
-
// count — a single integer (stdout.count is
|
|
4
|
+
// public views:
|
|
5
|
+
// count — a single integer (stdout.count is machine-parseable)
|
|
6
6
|
// list — itemised entries with cwd, node id, and per-cwd ask count
|
|
7
|
+
// `map` (hidden) is the batched per-node form the attach viewer's nav chrome
|
|
8
|
+
// polls; it is not an agent-facing decision.
|
|
7
9
|
//
|
|
8
10
|
// All three scope modes share the same underlying helpers in attention.ts:
|
|
9
11
|
// --node <id> → countAsks(id) (one cwd)
|
|
@@ -21,7 +23,7 @@ import { countAsks, pendingAsksForView, asksAcrossCanvas, asksForNodes, } from '
|
|
|
21
23
|
const attentionCount = defineLeaf({
|
|
22
24
|
name: 'count',
|
|
23
25
|
description: 'total pending ask count (machine-parseable stdout.count)',
|
|
24
|
-
whenToUse: '
|
|
26
|
+
whenToUse: 'a lightweight summary when you just need the number, not which cwds are blocked — scope it to a node or a sub-DAG, or default to canvas-wide. Use `list` when you need to act on where to go answer.',
|
|
25
27
|
help: {
|
|
26
28
|
name: 'canvas attention count',
|
|
27
29
|
// stdout.count is parsed directly by the nav chrome — keep the contract.
|
|
@@ -93,7 +95,7 @@ const attentionCount = defineLeaf({
|
|
|
93
95
|
const attentionList = defineLeaf({
|
|
94
96
|
name: 'list',
|
|
95
97
|
description: 'itemised list of cwds with pending asks',
|
|
96
|
-
whenToUse: 'finding which agents are blocked waiting on a human — an itemised list of the cwds with pending asks, oldest first, so you know where to go answer. Scope it to a sub-DAG or list canvas-wide. Use `canvas attention count` instead when
|
|
98
|
+
whenToUse: 'finding which agents are blocked waiting on a human — an itemised list of the cwds with pending asks, oldest first, so you know where to go answer. Scope it to a sub-DAG or list canvas-wide. Use `canvas attention count` instead when you just need the number.',
|
|
97
99
|
help: {
|
|
98
100
|
name: 'canvas attention list',
|
|
99
101
|
summary: 'list nodes with pending human asks, grouped by cwd, oldest first',
|
|
@@ -145,6 +147,7 @@ const attentionMap = defineLeaf({
|
|
|
145
147
|
name: 'map',
|
|
146
148
|
description: 'per-node ask counts for a visible set, batched in one pass',
|
|
147
149
|
whenToUse: 'labelling every node in a UI with its pending-ask count in one batched pass — the form nav chrome polls (one process, one JSON blob) instead of N count shell-outs',
|
|
150
|
+
tier: 'hidden',
|
|
148
151
|
help: {
|
|
149
152
|
name: 'canvas attention map',
|
|
150
153
|
summary: 'per-node pending-ask counts for a visible set of nodes in ONE pass — the batched form the nav chrome polls (one process, one JSON blob) instead of N count shell-outs',
|
|
@@ -211,11 +214,11 @@ const attentionMap = defineLeaf({
|
|
|
211
214
|
export const attentionBranch = defineBranch({
|
|
212
215
|
name: 'attention',
|
|
213
216
|
description: 'count/list pending human asks across the graph',
|
|
214
|
-
whenToUse: 'checking whether any agent on the canvas is blocked waiting on a human, and where: count the pending asks
|
|
217
|
+
whenToUse: 'checking whether any agent on the canvas is blocked waiting on a human, and where: count the pending asks or list the cwds that have them. Scope it to a node or a sub-DAG, or go canvas-wide. Use `canvas dashboard` instead for the graph SHAPE, or `node inspect list` for a plain node roster',
|
|
215
218
|
help: {
|
|
216
219
|
name: 'canvas attention',
|
|
217
220
|
summary: 'aggregate pending human asks across the canvas',
|
|
218
|
-
model: '
|
|
221
|
+
model: '`count` returns a single integer (stdout.count is machine-parseable); `list` returns itemised entries — the cwds with pending asks, oldest first. Scope with --node (one node) or --view (sub-DAG) — default is canvas-wide.',
|
|
219
222
|
},
|
|
220
223
|
children: [attentionCount, attentionList, attentionMap],
|
|
221
224
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineLeaf } from '../../core/command.js';
|
|
2
2
|
import { usage } from '../../core/errors.js';
|
|
3
3
|
import { buildCorpus, } from '../../core/canvas/index.js';
|
|
4
|
-
const TYPES = ['report', 'doc', 'roadmap', 'meta'];
|
|
4
|
+
const TYPES = ['report', 'doc', 'roadmap', 'meta', 'inbox'];
|
|
5
5
|
const NODE_KINDS = ['advisor', 'developer', 'spec', 'design', 'review', 'explore', 'plan', 'general'];
|
|
6
6
|
const STATUSES = ['active', 'idle', 'done', 'dead', 'canceled'];
|
|
7
7
|
const SORTS = ['relevance', 'recency', 'oldest'];
|
|
@@ -86,7 +86,7 @@ export const searchLeaf = defineLeaf({
|
|
|
86
86
|
{ kind: 'flag', name: 'all-cwds', type: 'bool', required: false, constraint: 'Search every cwd on the canvas. Mutually exclusive with --cwd.' },
|
|
87
87
|
{ kind: 'flag', name: 'under', type: 'string', required: false, constraint: 'Restrict to a node and its subscription descendants (one initiative / sub-DAG).' },
|
|
88
88
|
{ kind: 'flag', name: 'node', type: 'string', required: false, constraint: 'Restrict to specific node ids. Comma-separated for several.' },
|
|
89
|
-
{ kind: 'flag', name: 'type', type: 'string', required: false, constraint: `Corpus to search; comma-separated for several. One of: ${TYPES.join(', ')}. report = push history; doc = context artifacts; roadmap = roadmap.md specifically; meta = node name/description/kind. Default:
|
|
89
|
+
{ kind: 'flag', name: 'type', type: 'string', required: false, constraint: `Corpus to search; comma-separated for several. One of: ${TYPES.join(', ')}. report = push history; doc = context artifacts; roadmap = roadmap.md specifically; meta = node name/description/kind; inbox = raw inbox.jsonl history, cursor-independent and including full un-clipped direct-message bodies (diagnostic, not curated work). Default: report, doc, roadmap, meta — inbox is opt-in only, pass --type inbox explicitly.` },
|
|
90
90
|
{ kind: 'flag', name: 'report-kind', type: 'enum', choices: ['final', 'update'], required: false, constraint: 'Narrow reports to outcome summaries (final) or progress (update). Implies --type report.' },
|
|
91
91
|
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: `Node kind; comma-separated for several. One of: ${NODE_KINDS.join(', ')}.` },
|
|
92
92
|
{ kind: 'flag', name: 'status', type: 'string', required: false, constraint: `Node lifecycle status; comma-separated for several. One of: ${STATUSES.join(', ')} (e.g. done = completed work only).` },
|
|
@@ -2,7 +2,7 @@ import { defineLeaf } from '../../core/command.js';
|
|
|
2
2
|
import { notFound } from '../../core/errors.js';
|
|
3
3
|
import { getNode, nodeArtifacts } from '../../core/canvas/index.js';
|
|
4
4
|
import { statSync } from 'node:fs';
|
|
5
|
-
const TYPES = ['report', 'doc', 'roadmap'];
|
|
5
|
+
const TYPES = ['report', 'doc', 'roadmap', 'inbox'];
|
|
6
6
|
export const showLeaf = defineLeaf({
|
|
7
7
|
name: 'show',
|
|
8
8
|
description: 'enumerate one node\'s artifacts as refs',
|
|
@@ -12,12 +12,12 @@ export const showLeaf = defineLeaf({
|
|
|
12
12
|
summary: 'list one node\'s artifacts (reports + context docs) as refs ready for `canvas history read`',
|
|
13
13
|
params: [
|
|
14
14
|
{ kind: 'positional', name: 'node-id', required: true, constraint: 'The node whose artifacts to list.' },
|
|
15
|
-
{ kind: 'flag', name: 'type', type: 'enum', choices: [...TYPES], required: false, constraint: 'Narrow to one corpus: report | doc | roadmap. Default:
|
|
15
|
+
{ kind: 'flag', name: 'type', type: 'enum', choices: [...TYPES], required: false, constraint: 'Narrow to one corpus: report | doc | roadmap | inbox. Default: report, doc, roadmap (inbox is opt-in only — the node\'s raw inbox.jsonl history, cursor-independent and including full un-clipped direct-message bodies; a diagnostic surface, not curated past work).' },
|
|
16
16
|
{ kind: 'flag', name: 'sort', type: 'enum', choices: ['recency', 'oldest'], required: false, constraint: 'Order by artifact timestamp. Default recency.' },
|
|
17
17
|
],
|
|
18
18
|
output: [
|
|
19
19
|
{ name: 'node', type: 'string', required: true, constraint: 'Node name + id.' },
|
|
20
|
-
{ name: 'artifacts', type: 'object[]', required: true, constraint: 'Each: {ref, source, ts, detail}. source = report:<kind> | doc | roadmap. detail = report title / doc heading + size. ref passes verbatim to `canvas history read`.' },
|
|
20
|
+
{ name: 'artifacts', type: 'object[]', required: true, constraint: 'Each: {ref, source, ts, detail}. source = report:<kind> | doc | roadmap | inbox. detail = report title / doc heading + size (inbox: `[kind] label`, no size). ref passes verbatim to `canvas history read`.' },
|
|
21
21
|
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands.' },
|
|
22
22
|
],
|
|
23
23
|
outputKind: 'object',
|
|
@@ -23,7 +23,7 @@ export const historyBranch = defineBranch({
|
|
|
23
23
|
help: {
|
|
24
24
|
name: 'canvas history',
|
|
25
25
|
summary: 'search and recall the canvas\'s record of past work in this cwd',
|
|
26
|
-
model: 'The accumulated record of every node that ran in a cwd and the artifacts it left — its reports (final/update outcome summaries) and context docs (specs, designs, roadmaps, findings). `search` finds by content (ranked, filtered, sorted; omit the query to browse by recency); `read` pulls one hit\'s full body by its <node-id>:<relpath> ref; `show` lists everything one node left. This is the episodic record of what was DONE — distinct from `crtr memory`, which is curated semantic knowledge. To reopen a node you found, use `canvas revive`; for its place in the graph, `node inspect show`.',
|
|
26
|
+
model: 'The accumulated record of every node that ran in a cwd and the artifacts it left — its reports (final/update outcome summaries) and context docs (specs, designs, roadmaps, findings). `search` finds by content (ranked, filtered, sorted; omit the query to browse by recency); `read` pulls one hit\'s full body by its <node-id>:<relpath> ref; `show` lists everything one node left. This is the episodic record of what was DONE — distinct from `crtr memory`, which is curated semantic knowledge. A node\'s raw inbox history (`--type inbox`) is a separate, opt-in diagnostic corpus — the full cursor-independent inbox.jsonl for one node, including un-clipped direct-message bodies; reach for it only when the curated reports/docs above don\'t already answer the question. To reopen a node you found, use `canvas revive`; for its place in the graph, `node inspect show`.',
|
|
27
27
|
dynamicState: corpusBlock,
|
|
28
28
|
},
|
|
29
29
|
children: [searchLeaf, readLeaf, showLeaf],
|
|
@@ -66,6 +66,7 @@ export const issueNewLeaf = defineLeaf({
|
|
|
66
66
|
name: 'new',
|
|
67
67
|
description: 'capture a todo/idea/bug note into a GitHub issue (or a .todos/ markdown note)',
|
|
68
68
|
whenToUse: 'the alt+c \u2192 i chord runs this inside a tmux popup; rarely run by hand',
|
|
69
|
+
tier: 'hidden',
|
|
69
70
|
help: {
|
|
70
71
|
name: 'canvas issue new',
|
|
71
72
|
summary: 'Capture a free-text note as a GitHub issue labeled with its type (idea|bug). Reads the note from the popup TTY, auto-generates the title via a headless pi call, and files it with `gh issue create` when the cwd is a GitHub repo, else writes `<git-root>/.todos/<slug>.md`. Bound to the alt+c \u2192 i prefix chord.',
|
|
@@ -5,6 +5,7 @@ export const canvasSnapshotLeaf = defineLeaf({
|
|
|
5
5
|
name: 'snapshot',
|
|
6
6
|
description: 'emit the browser canvas roster as structured data',
|
|
7
7
|
whenToUse: 'you need a machine-readable roster of every canvas node for a browser or local tool; use dashboard for the human-readable tree',
|
|
8
|
+
tier: 'hidden',
|
|
8
9
|
help: {
|
|
9
10
|
name: 'canvas snapshot',
|
|
10
11
|
summary: 'machine-readable snapshot of the whole canvas roster',
|
package/dist/commands/canvas.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
// `crtr canvas` — observe and supervise the whole graph.
|
|
2
2
|
//
|
|
3
|
-
// Where `node` operates on one node and `push
|
|
4
|
-
//
|
|
3
|
+
// Where `node` operates on one node and `push` is a node's own spine write
|
|
4
|
+
// verb, `canvas` is the bird's-eye / supervisor surface over the entire canvas:
|
|
5
5
|
// render the subscription forest (`dashboard`), see who is blocked on a human
|
|
6
|
-
// (`attention`), bring a node back (`revive`)
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// (`attention`), and bring a node back (`revive`). It assembles leaves/branches
|
|
7
|
+
// the sibling command files own, so each piece declares its own help one level
|
|
8
|
+
// down.
|
|
9
9
|
import { defineBranch } from '../core/command.js';
|
|
10
10
|
import { dashboardLeaf } from './dashboard.js';
|
|
11
11
|
import { canvasSnapshotLeaf } from './canvas-snapshot.js';
|
|
12
12
|
import { browseLeaf } from './canvas-browse.js';
|
|
13
13
|
import { reviveLeaf } from './revive.js';
|
|
14
14
|
import { attentionBranch } from './attention.js';
|
|
15
|
-
import { daemonBranch } from './daemon.js';
|
|
16
15
|
import { chordLeaf } from './chord.js';
|
|
17
|
-
import { tmuxSpreadLeaf } from './canvas-tmux-spread.js';
|
|
18
16
|
import { canvasPruneLeaf } from './canvas-prune.js';
|
|
19
17
|
import { canvasRebuildIndexLeaf } from './canvas-rebuild-index.js';
|
|
20
18
|
import { historyBranch } from './canvas-history.js';
|
|
@@ -23,6 +21,7 @@ export const issueBranch = defineBranch({
|
|
|
23
21
|
name: 'issue',
|
|
24
22
|
description: 'capture a quick todo/idea/bug into a GitHub issue (or a .todos/ note)',
|
|
25
23
|
whenToUse: 'the alt+c \u2192 i chord uses this; capture a passing thought without leaving your pane',
|
|
24
|
+
tier: 'hidden',
|
|
26
25
|
help: {
|
|
27
26
|
name: 'canvas issue',
|
|
28
27
|
summary: 'capture a quick todo/idea/bug into a GitHub issue',
|
|
@@ -34,15 +33,15 @@ export function registerCanvas() {
|
|
|
34
33
|
return defineBranch({
|
|
35
34
|
name: 'canvas',
|
|
36
35
|
rootEntry: {
|
|
37
|
-
concept: 'the whole agent graph at a glance — render it, see who is blocked, revive a node
|
|
36
|
+
concept: 'the whole agent graph at a glance — render it, see who is blocked, revive a node',
|
|
38
37
|
desc: 'bird\'s-eye view and supervision of the entire canvas',
|
|
39
|
-
useWhen: 'surveying the full graph, finding blocked agents, or
|
|
38
|
+
useWhen: 'surveying the full graph, finding blocked agents, or reviving a node',
|
|
40
39
|
},
|
|
41
40
|
help: {
|
|
42
41
|
name: 'canvas',
|
|
43
42
|
summary: 'observe and supervise the whole agent graph',
|
|
44
|
-
model: 'Canvas-wide operations, distinct from per-node work (`node`) and a node\'s own spine
|
|
43
|
+
model: 'Canvas-wide operations, distinct from per-node work (`node`) and a node\'s own spine write verb (`push`). `dashboard` renders the subscription forest as a tree; `browse` opens an interactive full-screen navigator (tabs/tree/search) over the whole canvas and resumes the chosen node; `attention` aggregates pending human asks across the graph; `revive` reopens a window for a done/idle/dead/canceled node; `history` searches and recalls the content record (reports + context docs) of past work in a cwd; `prune` bounds growth by deleting terminal nodes past a TTL.',
|
|
45
44
|
},
|
|
46
|
-
children: [dashboardLeaf, canvasSnapshotLeaf, browseLeaf, attentionBranch, reviveLeaf, historyBranch,
|
|
45
|
+
children: [dashboardLeaf, canvasSnapshotLeaf, browseLeaf, attentionBranch, reviveLeaf, historyBranch, chordLeaf, issueBranch, canvasPruneLeaf, canvasRebuildIndexLeaf],
|
|
47
46
|
});
|
|
48
47
|
}
|
package/dist/commands/chord.js
CHANGED
|
@@ -154,6 +154,7 @@ export const chordLeaf = defineLeaf({
|
|
|
154
154
|
name: 'chord',
|
|
155
155
|
description: 'tmux prefix-menu dispatcher (bound by alt+c; not run by hand)',
|
|
156
156
|
whenToUse: 'never directly — the alt+c menu routes node-relative actions through it',
|
|
157
|
+
tier: 'hidden',
|
|
157
158
|
help: {
|
|
158
159
|
name: 'canvas chord',
|
|
159
160
|
summary: 'tmux prefix-menu dispatcher — resolve the node in --pane, interpolate --run against it, and exec `crtr <argv>`. Bound by the alt+c menu; not meant to be run by hand.',
|
|
@@ -40,7 +40,6 @@ export const humanAsk = defineLeaf({
|
|
|
40
40
|
params: [
|
|
41
41
|
{ kind: 'positional', name: 'question', type: 'string', required: false, constraint: 'Bare-question shorthand for a simple open-text ask. Mutually exclusive with `--context-file`.' },
|
|
42
42
|
{ kind: 'context-file', name: 'deck', required: false, constraint: 'Strict complex-ask deck JSON. Use this when you need multiple interactions, options, or other deck structure. Mutually exclusive with the question shorthand.', shape: DECK_SCHEMA_HINT },
|
|
43
|
-
{ kind: 'flag', name: 'wait', type: 'bool', required: false, constraint: 'Accepted for symmetry with the job contract; the kickoff never blocks.' },
|
|
44
43
|
],
|
|
45
44
|
output: [
|
|
46
45
|
{ name: 'job_id', type: 'string', required: true, constraint: 'Node id of this human interaction. Its answer is pushed to your inbox when the human responds.' },
|
|
@@ -520,6 +520,7 @@ export const humanResolve = defineLeaf({
|
|
|
520
520
|
name: 'resolve',
|
|
521
521
|
description: 'resolve one humanloop deck from stdin answers',
|
|
522
522
|
whenToUse: 'a browser or local tool is submitting answers for a pending human interaction; this writes through the crouter/humanloop finalize path',
|
|
523
|
+
tier: 'hidden',
|
|
523
524
|
help: {
|
|
524
525
|
name: 'human resolve',
|
|
525
526
|
summary: 'write deck answers atomically and deliver them back to the asking node',
|
|
@@ -7,19 +7,19 @@ import { MEMORY_KINDS } from './shared.js';
|
|
|
7
7
|
export const readLeaf = defineLeaf({
|
|
8
8
|
name: 'read',
|
|
9
9
|
description: 'load a memory document body by name',
|
|
10
|
-
whenToUse: 'a task in front of you matches a stored document and you already know its name — read it before improvising. Resolves the path-derived name across scopes by precedence (project > user > builtin), with leaf-name fallback. You name the document by its crtr identifier, never a file path — do not cat or find the markdown off disk. Reach for `crtr memory find` first when you do not yet know which document applies.',
|
|
10
|
+
whenToUse: 'a task in front of you matches a stored document and you already know its name — read it before improvising. Resolves the path-derived name across scopes by precedence (project stack > profile > user > builtin), with leaf-name fallback. You name the document by its crtr identifier, never a file path — do not cat or find the markdown off disk. Reach for `crtr memory find` first when you do not yet know which document applies.',
|
|
11
11
|
help: {
|
|
12
12
|
name: 'memory read',
|
|
13
13
|
summary: 'resolve a path-derived name to its document body, frontmatter stripped unless --frontmatter',
|
|
14
14
|
params: [
|
|
15
|
-
{ kind: 'positional', name: 'name', required: true, constraint: 'Path-derived memory identifier (e.g. `topic` or `area/topic`). Resolved across scopes by precedence: project > user > builtin, with leaf-name fallback.' },
|
|
15
|
+
{ kind: 'positional', name: 'name', required: true, constraint: 'Path-derived memory identifier (e.g. `topic` or `area/topic`). Resolved across scopes by precedence: project stack > profile > user > builtin, with leaf-name fallback.' },
|
|
16
16
|
{ kind: 'flag', name: 'kind', type: 'enum', choices: [...MEMORY_KINDS], required: false, constraint: 'Narrows resolution when the name is ambiguous across kinds.' },
|
|
17
17
|
{ kind: 'flag', name: 'frontmatter', type: 'bool', required: false, constraint: 'When present, includes the YAML frontmatter in the returned body. Off by default — only the body is returned.' },
|
|
18
18
|
],
|
|
19
19
|
output: [
|
|
20
20
|
{ name: 'name', type: 'string', required: true, constraint: 'Resolved document name.' },
|
|
21
21
|
{ name: 'kind', type: 'string', required: true, constraint: 'Resolved kind: knowledge or preference.' },
|
|
22
|
-
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the document was resolved from: project, user, or builtin.' },
|
|
22
|
+
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the document was resolved from: project, profile, user, or builtin.' },
|
|
23
23
|
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the document on disk — edit this file directly to tweak the doc in place.' },
|
|
24
24
|
{ name: 'content', type: 'string', required: true, constraint: 'Document body. Frontmatter stripped unless --frontmatter is set.' },
|
|
25
25
|
{ name: 'follow_up', type: 'string', required: true, constraint: 'Hints at variant flags or next commands.' },
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MemoryScope } from '../../core/memory-resolver.js';
|
|
2
2
|
export declare const MEMORY_KINDS: readonly ["knowledge", "preference"];
|
|
3
3
|
export declare const VISIBILITY_RUNGS: readonly ["none", "name", "preview", "content"];
|
|
4
|
-
export declare const MEMORY_SCOPES: readonly ["user", "project"];
|
|
5
|
-
/** Scope sort weight matching resolution precedence (project >
|
|
6
|
-
* Used by `list` for its "scope then kind then name"
|
|
7
|
-
|
|
4
|
+
export declare const MEMORY_SCOPES: readonly ["user", "project", "profile"];
|
|
5
|
+
/** Scope sort weight matching resolution precedence (project stack > profile >
|
|
6
|
+
* user > builtin). Used by `list` for its "scope then kind then name"
|
|
7
|
+
* ordering. */
|
|
8
|
+
export declare function scopeRank(scope: MemoryScope): number;
|
|
8
9
|
/** Resolve the write target scope + its memory dir. Default: project when a
|
|
9
10
|
* project scope exists for the cwd, else user. An explicit `--scope project`
|
|
10
11
|
* with no project scope yet scaffolds one (ensureProjectScopeRoot). User scope
|
|
11
|
-
* always resolves.
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
* always resolves. `--scope profile` is NEVER a default — it requires a
|
|
13
|
+
* selected profile, from `profileArg` (an explicit `--profile <id-or-name>`)
|
|
14
|
+
* or else the process's `CRTR_PROFILE_ID`, resolved through the centralized
|
|
15
|
+
* `loadProfileManifest` (never a raw path join). Returns the absolute
|
|
16
|
+
* `<root>/memory` dir to write under. */
|
|
17
|
+
export declare function resolveWriteTarget(scopeArg: string | undefined, profileArg?: string): {
|
|
18
|
+
scope: MemoryScope;
|
|
14
19
|
memoryDir: string;
|
|
15
20
|
};
|
|
16
21
|
/** Map a path-derived name (`topic` or `area/topic`) to its file path under a
|
|
@@ -7,6 +7,7 @@ import { join } from 'node:path';
|
|
|
7
7
|
import { stringify as yamlStringify, parse as yamlParse } from 'yaml';
|
|
8
8
|
import { usage } from '../../core/errors.js';
|
|
9
9
|
import { scopeMemoryDir, projectScopeRoot, ensureProjectScopeRoot, } from '../../core/scope.js';
|
|
10
|
+
import { loadProfileManifest, profileMemoryDir } from '../../core/profiles/manifest.js';
|
|
10
11
|
// The two memory kinds — knowledge (consult: procedural playbooks + factual
|
|
11
12
|
// references merged) vs preference (behave: standing directives). Used as the
|
|
12
13
|
// `--kind` enum choices everywhere.
|
|
@@ -15,27 +16,40 @@ export const MEMORY_KINDS = ['knowledge', 'preference'];
|
|
|
15
16
|
// content). Shared by --system-prompt-visibility and --file-read-visibility.
|
|
16
17
|
export const VISIBILITY_RUNGS = ['none', 'name', 'preview', 'content'];
|
|
17
18
|
// Scope choices for filtering / targeting (builtin is read-only, not writable).
|
|
18
|
-
export const MEMORY_SCOPES = ['user', 'project'];
|
|
19
|
-
/** Scope sort weight matching resolution precedence (project >
|
|
20
|
-
* Used by `list` for its "scope then kind then name"
|
|
19
|
+
export const MEMORY_SCOPES = ['user', 'project', 'profile'];
|
|
20
|
+
/** Scope sort weight matching resolution precedence (project stack > profile >
|
|
21
|
+
* user > builtin). Used by `list` for its "scope then kind then name"
|
|
22
|
+
* ordering. */
|
|
21
23
|
export function scopeRank(scope) {
|
|
22
|
-
return scope === 'project' ? 0 : scope === '
|
|
24
|
+
return scope === 'project' ? 0 : scope === 'profile' ? 1 : scope === 'user' ? 2 : 3;
|
|
23
25
|
}
|
|
24
26
|
/** Resolve the write target scope + its memory dir. Default: project when a
|
|
25
27
|
* project scope exists for the cwd, else user. An explicit `--scope project`
|
|
26
28
|
* with no project scope yet scaffolds one (ensureProjectScopeRoot). User scope
|
|
27
|
-
* always resolves.
|
|
28
|
-
|
|
29
|
+
* always resolves. `--scope profile` is NEVER a default — it requires a
|
|
30
|
+
* selected profile, from `profileArg` (an explicit `--profile <id-or-name>`)
|
|
31
|
+
* or else the process's `CRTR_PROFILE_ID`, resolved through the centralized
|
|
32
|
+
* `loadProfileManifest` (never a raw path join). Returns the absolute
|
|
33
|
+
* `<root>/memory` dir to write under. */
|
|
34
|
+
export function resolveWriteTarget(scopeArg, profileArg) {
|
|
29
35
|
let scope;
|
|
30
|
-
if (scopeArg === 'user' || scopeArg === 'project') {
|
|
36
|
+
if (scopeArg === 'user' || scopeArg === 'project' || scopeArg === 'profile') {
|
|
31
37
|
scope = scopeArg;
|
|
32
38
|
}
|
|
33
39
|
else if (scopeArg !== undefined) {
|
|
34
|
-
throw usage(`invalid --scope: ${scopeArg} (expected user|project)`);
|
|
40
|
+
throw usage(`invalid --scope: ${scopeArg} (expected user|project|profile)`);
|
|
35
41
|
}
|
|
36
42
|
else {
|
|
37
43
|
scope = projectScopeRoot() !== null ? 'project' : 'user';
|
|
38
44
|
}
|
|
45
|
+
if (scope === 'profile') {
|
|
46
|
+
const profileIdOrName = profileArg && profileArg !== '' ? profileArg : process.env['CRTR_PROFILE_ID'] || '';
|
|
47
|
+
if (profileIdOrName === '') {
|
|
48
|
+
throw usage('profile scope requires a selected profile; rerun inside a profiled node or pass --profile');
|
|
49
|
+
}
|
|
50
|
+
const { profileId } = loadProfileManifest(profileIdOrName);
|
|
51
|
+
return { scope: 'profile', memoryDir: profileMemoryDir(profileId) };
|
|
52
|
+
}
|
|
39
53
|
let memoryDir = scopeMemoryDir(scope);
|
|
40
54
|
if (!memoryDir && scope === 'project') {
|
|
41
55
|
// Explicit --scope project with no project root yet → scaffold it.
|
|
@@ -27,13 +27,14 @@ export const writeLeaf = defineLeaf({
|
|
|
27
27
|
{ kind: 'flag', name: 'gate', type: 'string', required: false, constraint: 'Frontmatter gate — YAML/JSON object predicate over node config using the same field/matcher vocabulary described in the guide.' },
|
|
28
28
|
{ kind: 'flag', name: 'applies-to', type: 'string', required: false, constraint: 'Frontmatter applies-to — glob/path scope the document applies to.' },
|
|
29
29
|
{ kind: 'flag', name: 'read-when', type: 'string', required: false, constraint: 'Frontmatter read-when — YAML/JSON object predicate over a read file’s own frontmatter using the same field/matcher vocabulary described in the guide.' },
|
|
30
|
-
{ kind: 'flag', name: 'scope', type: 'enum', choices: [...MEMORY_SCOPES], required: false, constraint: 'Target scope. Default: project when inside a project, else user.' },
|
|
30
|
+
{ kind: 'flag', name: 'scope', type: 'enum', choices: [...MEMORY_SCOPES], required: false, constraint: 'Target scope. Default: project when inside a project, else user. `profile` requires a selected profile (CRTR_PROFILE_ID) or an explicit --profile.' },
|
|
31
|
+
{ kind: 'flag', name: 'profile', type: 'string', required: false, constraint: 'Profile id or name to write under, for --scope profile. Default: the process CRTR_PROFILE_ID (the node\u2019s selected profile). Resolved through the same profile lookup as `crtr profile show`; ignored for any other --scope.' },
|
|
31
32
|
{ kind: 'stdin', name: 'body', required: true, constraint: 'Document body (markdown, no frontmatter). Piped on stdin, or passed as the bare positional after <name>.' },
|
|
32
33
|
],
|
|
33
34
|
output: [
|
|
34
35
|
{ name: 'name', type: 'string', required: true, constraint: 'The path-derived document name written.' },
|
|
35
36
|
{ name: 'kind', type: 'string', required: true, constraint: 'Kind recorded in frontmatter.' },
|
|
36
|
-
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the document was written to: user or
|
|
37
|
+
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the document was written to: user, project, or profile.' },
|
|
37
38
|
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the written document — edit this file directly for later body tweaks instead of re-running write.' },
|
|
38
39
|
{ name: 'created', type: 'boolean', required: true, constraint: 'true when a new document was created, false when an existing one was updated in place.' },
|
|
39
40
|
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands — read it back or list the inventory.' },
|
|
@@ -47,8 +48,9 @@ export const writeLeaf = defineLeaf({
|
|
|
47
48
|
const name = input['name'];
|
|
48
49
|
const kind = input['kind'];
|
|
49
50
|
const scopeArg = input['scope'];
|
|
51
|
+
const profileArg = input['profile'];
|
|
50
52
|
const body = input['body'] ?? '';
|
|
51
|
-
const { scope, memoryDir } = resolveWriteTarget(scopeArg);
|
|
53
|
+
const { scope, memoryDir } = resolveWriteTarget(scopeArg, profileArg);
|
|
52
54
|
const path = memoryFilePath(memoryDir, name);
|
|
53
55
|
const created = !pathExists(path);
|
|
54
56
|
// CREATE requires the read-routing line that becomes the preview — without
|
|
@@ -63,6 +63,7 @@ export const nodeSnapshotLeaf = defineLeaf({
|
|
|
63
63
|
name: 'snapshot',
|
|
64
64
|
description: 'read a dormant node session snapshot without launching its broker',
|
|
65
65
|
whenToUse: 'you need a read-only broker-compatible snapshot of a dormant node; it copies the session JSONL before parsing and never revives the node',
|
|
66
|
+
tier: 'hidden',
|
|
66
67
|
help: {
|
|
67
68
|
name: 'node inspect snapshot',
|
|
68
69
|
summary: 'read-only dormant node snapshot in the broker welcome shape',
|