@crouton-kit/crouter 0.3.11 → 0.3.12
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/bin/crtrd +2 -0
- package/dist/builtin-personas/design/base.md +9 -0
- package/dist/builtin-personas/design/orchestrator.md +10 -0
- package/dist/builtin-personas/developer/base.md +9 -0
- package/dist/builtin-personas/developer/orchestrator.md +12 -0
- package/dist/builtin-personas/explore/base.md +9 -0
- package/dist/builtin-personas/explore/orchestrator.md +9 -0
- package/dist/builtin-personas/general/base.md +5 -0
- package/dist/builtin-personas/general/orchestrator.md +7 -0
- package/dist/builtin-personas/orchestration-kernel.md +71 -0
- package/dist/builtin-personas/plan/base.md +7 -0
- package/dist/builtin-personas/plan/orchestrator.md +12 -0
- package/dist/builtin-personas/review/base.md +7 -0
- package/dist/builtin-personas/review/orchestrator.md +9 -0
- package/dist/builtin-personas/runtime-base.md +39 -0
- package/dist/builtin-personas/spec/base.md +7 -0
- package/dist/builtin-personas/spec/orchestrator.md +10 -0
- package/dist/builtin-skills/skills/design/SKILL.md +51 -0
- package/dist/builtin-skills/skills/development/SKILL.md +109 -0
- package/dist/builtin-skills/skills/planning/SKILL.md +59 -0
- package/dist/builtin-skills/skills/spec/SKILL.md +83 -0
- package/dist/cli.js +14 -6
- package/dist/commands/{mode.d.ts → attention.d.ts} +1 -1
- package/dist/commands/attention.js +152 -0
- package/dist/commands/canvas.d.ts +2 -0
- package/dist/commands/canvas.js +35 -0
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +111 -0
- package/dist/commands/dashboard.d.ts +2 -0
- package/dist/commands/dashboard.js +65 -0
- package/dist/commands/human/prompts.d.ts +5 -0
- package/dist/commands/human/prompts.js +269 -0
- package/dist/commands/human/queue.d.ts +3 -0
- package/dist/commands/human/queue.js +133 -0
- package/dist/commands/human/shared.d.ts +43 -0
- package/dist/commands/human/shared.js +107 -0
- package/dist/commands/human.js +10 -454
- package/dist/commands/node.d.ts +2 -0
- package/dist/commands/node.js +354 -0
- package/dist/commands/pkg/market-inspect.d.ts +1 -0
- package/dist/commands/pkg/market-inspect.js +157 -0
- package/dist/commands/pkg/market-manage.d.ts +1 -0
- package/dist/commands/pkg/market-manage.js +316 -0
- package/dist/commands/pkg/market.d.ts +1 -0
- package/dist/commands/pkg/market.js +16 -0
- package/dist/commands/pkg/plugin-inspect.d.ts +1 -0
- package/dist/commands/pkg/plugin-inspect.js +142 -0
- package/dist/commands/pkg/plugin-manage.d.ts +1 -0
- package/dist/commands/pkg/plugin-manage.js +294 -0
- package/dist/commands/pkg/plugin.d.ts +1 -0
- package/dist/commands/pkg/plugin.js +16 -0
- package/dist/commands/pkg/shared.d.ts +5 -0
- package/dist/commands/pkg/shared.js +61 -0
- package/dist/commands/pkg.js +3 -1004
- package/dist/commands/push.d.ts +3 -0
- package/dist/commands/push.js +159 -0
- package/dist/commands/revive.d.ts +2 -0
- package/dist/commands/revive.js +64 -0
- package/dist/commands/skill/author.d.ts +3 -0
- package/dist/commands/skill/author.js +147 -0
- package/dist/commands/skill/find.d.ts +4 -0
- package/dist/commands/skill/find.js +254 -0
- package/dist/commands/skill/read.d.ts +1 -0
- package/dist/commands/skill/read.js +89 -0
- package/dist/commands/skill/shared.d.ts +19 -0
- package/dist/commands/skill/shared.js +207 -0
- package/dist/commands/skill/state.d.ts +3 -0
- package/dist/commands/skill/state.js +69 -0
- package/dist/commands/skill.js +6 -691
- package/dist/commands/sys/config.d.ts +1 -0
- package/dist/commands/sys/config.js +186 -0
- package/dist/commands/sys/doctor.d.ts +1 -0
- package/dist/commands/sys/doctor.js +369 -0
- package/dist/commands/sys/shared.d.ts +3 -0
- package/dist/commands/sys/shared.js +24 -0
- package/dist/commands/sys/update.d.ts +2 -0
- package/dist/commands/sys/update.js +114 -0
- package/dist/commands/sys.js +4 -694
- package/dist/core/__tests__/argv-parser.test.js +19 -1
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +100 -0
- package/dist/core/__tests__/canvas.test.js +154 -0
- package/dist/core/__tests__/reset.test.js +105 -0
- package/dist/core/canvas/attention.d.ts +24 -0
- package/dist/core/canvas/attention.js +94 -0
- package/dist/core/canvas/canvas.d.ts +40 -0
- package/dist/core/canvas/canvas.js +210 -0
- package/dist/core/canvas/db.d.ts +7 -0
- package/dist/core/canvas/db.js +61 -0
- package/dist/core/canvas/index.d.ts +4 -0
- package/dist/core/canvas/index.js +6 -0
- package/dist/core/canvas/paths.d.ts +16 -0
- package/dist/core/canvas/paths.js +62 -0
- package/dist/core/canvas/render.d.ts +30 -0
- package/dist/core/canvas/render.js +186 -0
- package/dist/core/canvas/types.d.ts +87 -0
- package/dist/core/canvas/types.js +8 -0
- package/dist/core/command.d.ts +5 -0
- package/dist/core/command.js +35 -10
- package/dist/core/feed/feed.d.ts +43 -0
- package/dist/core/feed/feed.js +116 -0
- package/dist/core/feed/inbox.d.ts +50 -0
- package/dist/core/feed/inbox.js +124 -0
- package/dist/core/help.js +5 -3
- package/dist/core/io.d.ts +15 -1
- package/dist/core/io.js +56 -6
- package/dist/core/personas/index.d.ts +12 -0
- package/dist/core/personas/index.js +10 -0
- package/dist/core/personas/loader.d.ts +44 -0
- package/dist/core/personas/loader.js +157 -0
- package/dist/core/personas/resolve.d.ts +36 -0
- package/dist/core/personas/resolve.js +110 -0
- package/dist/core/render.d.ts +11 -0
- package/dist/core/render.js +126 -0
- package/dist/core/resolver.d.ts +10 -0
- package/dist/core/resolver.js +109 -1
- package/dist/core/runtime/front-door.d.ts +10 -0
- package/dist/core/runtime/front-door.js +97 -0
- package/dist/core/runtime/kickoff.d.ts +23 -0
- package/dist/core/runtime/kickoff.js +134 -0
- package/dist/core/runtime/launch.d.ts +34 -0
- package/dist/core/runtime/launch.js +85 -0
- package/dist/core/runtime/nodes.d.ts +38 -0
- package/dist/core/runtime/nodes.js +95 -0
- package/dist/core/runtime/presence.d.ts +38 -0
- package/dist/core/runtime/presence.js +152 -0
- package/dist/core/runtime/promote.d.ts +30 -0
- package/dist/core/runtime/promote.js +105 -0
- package/dist/core/runtime/reset.d.ts +13 -0
- package/dist/core/runtime/reset.js +97 -0
- package/dist/core/runtime/revive.d.ts +26 -0
- package/dist/core/runtime/revive.js +89 -0
- package/dist/core/runtime/roadmap.d.ts +12 -0
- package/dist/core/runtime/roadmap.js +52 -0
- package/dist/core/runtime/spawn.d.ts +33 -0
- package/dist/core/runtime/spawn.js +118 -0
- package/dist/core/runtime/stop-guard.d.ts +18 -0
- package/dist/core/runtime/stop-guard.js +33 -0
- package/dist/core/runtime/tmux.d.ts +88 -0
- package/dist/core/runtime/tmux.js +198 -0
- package/dist/core/spawn.d.ts +17 -197
- package/dist/core/spawn.js +16 -539
- package/dist/daemon/crtrd-cli.js +4 -0
- package/dist/daemon/crtrd.d.ts +20 -0
- package/dist/daemon/crtrd.js +200 -0
- package/dist/daemon/manage.d.ts +17 -0
- package/dist/daemon/manage.js +57 -0
- package/dist/pi-extensions/canvas-inbox-watcher.d.ts +16 -0
- package/dist/pi-extensions/canvas-inbox-watcher.js +229 -0
- package/dist/pi-extensions/canvas-nav.d.ts +32 -0
- package/dist/pi-extensions/canvas-nav.js +536 -0
- package/dist/pi-extensions/canvas-stophook.d.ts +17 -0
- package/dist/pi-extensions/canvas-stophook.js +373 -0
- package/package.json +6 -5
- package/dist/commands/agent.d.ts +0 -6
- package/dist/commands/agent.js +0 -585
- package/dist/commands/debug.d.ts +0 -3
- package/dist/commands/debug.js +0 -192
- package/dist/commands/job.d.ts +0 -11
- package/dist/commands/job.js +0 -384
- package/dist/commands/mode.js +0 -231
- package/dist/commands/plan.d.ts +0 -4
- package/dist/commands/plan.js +0 -322
- package/dist/commands/spec.d.ts +0 -3
- package/dist/commands/spec.js +0 -299
- package/dist/core/__tests__/flow-leaves.test.js +0 -248
- package/dist/core/__tests__/job.test.js +0 -310
- package/dist/core/__tests__/jobs.test.js +0 -98
- package/dist/core/__tests__/spawn.test.js +0 -138
- package/dist/core/__tests__/subagents.test.d.ts +0 -1
- package/dist/core/__tests__/subagents.test.js +0 -75
- package/dist/core/jobs.d.ts +0 -107
- package/dist/core/jobs.js +0 -565
- package/dist/core/subagents.d.ts +0 -18
- package/dist/core/subagents.js +0 -163
- package/dist/prompts/agent.d.ts +0 -27
- package/dist/prompts/agent.js +0 -184
- package/dist/prompts/debug.d.ts +0 -8
- package/dist/prompts/debug.js +0 -44
- /package/dist/core/__tests__/{flow-leaves.test.d.ts → canvas-inbox-watcher.test.d.ts} +0 -0
- /package/dist/core/__tests__/{job.test.d.ts → canvas.test.d.ts} +0 -0
- /package/dist/core/__tests__/{jobs.test.d.ts → reset.test.d.ts} +0 -0
- /package/dist/{core/__tests__/spawn.test.d.ts → daemon/crtrd-cli.d.ts} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { defineRoot, runCli } from './core/command.js';
|
|
3
|
-
import { registerAgent } from './commands/agent.js';
|
|
4
|
-
import { registerMode } from './commands/mode.js';
|
|
5
3
|
import { registerSkill } from './commands/skill.js';
|
|
6
|
-
import { registerJob } from './commands/job.js';
|
|
7
4
|
import { registerPkg } from './commands/pkg.js';
|
|
8
5
|
import { registerHuman } from './commands/human.js';
|
|
9
6
|
import { registerSys } from './commands/sys.js';
|
|
7
|
+
import { registerPush, registerFeed } from './commands/push.js';
|
|
8
|
+
import { registerNode } from './commands/node.js';
|
|
9
|
+
import { registerCanvas } from './commands/canvas.js';
|
|
10
|
+
import { maybeBootRoot } from './core/runtime/front-door.js';
|
|
10
11
|
import { maybeAutoUpdate } from './core/auto-update.js';
|
|
11
12
|
import { ensureBootSkill, ensureOfficialMarketplace, ensureProjectScope, ensureSlashCommands } from './core/bootstrap.js';
|
|
12
13
|
// Root owns only the tagline and globals. Every subtree's concept line,
|
|
@@ -20,15 +21,22 @@ const root = defineRoot({
|
|
|
20
21
|
{ name: '-h', desc: 'print help for any node — append to any subcommand path' },
|
|
21
22
|
],
|
|
22
23
|
subtrees: [
|
|
23
|
-
registerAgent(),
|
|
24
|
-
registerMode(),
|
|
25
24
|
registerSkill(),
|
|
26
25
|
registerPkg(),
|
|
27
|
-
registerJob(),
|
|
28
26
|
registerHuman(),
|
|
29
27
|
registerSys(),
|
|
28
|
+
registerNode(),
|
|
29
|
+
registerPush(),
|
|
30
|
+
registerFeed(),
|
|
31
|
+
registerCanvas(),
|
|
30
32
|
],
|
|
31
33
|
});
|
|
34
|
+
// The front door: bare `crtr` (or `crtr [dir] ["prompt"]`) boots a resident
|
|
35
|
+
// root node and execs pi in this terminal. Recognized subcommands fall through
|
|
36
|
+
// to the normal dispatcher. Must run before anything that assumes a subcommand.
|
|
37
|
+
if (maybeBootRoot(root, process.argv)) {
|
|
38
|
+
// bootRoot exec'd pi inline and exited; unreachable.
|
|
39
|
+
}
|
|
32
40
|
ensureOfficialMarketplace(process.argv);
|
|
33
41
|
ensureBootSkill(process.argv);
|
|
34
42
|
ensureSlashCommands(root, process.argv);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { BranchDef } from '../core/command.js';
|
|
2
|
-
export declare
|
|
2
|
+
export declare const attentionBranch: BranchDef;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// `crtr canvas attention` — aggregate pending human asks across the canvas.
|
|
2
|
+
//
|
|
3
|
+
// Pending asks are stored per-cwd by humanloop. This subtree surfaces two
|
|
4
|
+
// views:
|
|
5
|
+
// count — a single integer (stdout.count is parsed by nav chrome)
|
|
6
|
+
// list — itemised entries with cwd, node id, and per-cwd ask count
|
|
7
|
+
//
|
|
8
|
+
// All three scope modes share the same underlying helpers in attention.ts:
|
|
9
|
+
// --node <id> → countAsks(id) (one cwd)
|
|
10
|
+
// --view <id> → pendingAsksForView(id) (sub-DAG from root)
|
|
11
|
+
// (neither) → asksAcrossCanvas() (whole canvas)
|
|
12
|
+
//
|
|
13
|
+
// Exported as a branch; `crtr canvas` (canvas.ts) mounts it.
|
|
14
|
+
import { defineBranch, defineLeaf } from '../core/command.js';
|
|
15
|
+
import { InputError } from '../core/io.js';
|
|
16
|
+
import { getNode } from '../core/canvas/index.js';
|
|
17
|
+
import { countAsks, pendingAsksForView, asksAcrossCanvas, } from '../core/canvas/attention.js';
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// attention count
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
const attentionCount = defineLeaf({
|
|
22
|
+
name: 'count',
|
|
23
|
+
help: {
|
|
24
|
+
name: 'canvas attention count',
|
|
25
|
+
// stdout.count is parsed directly by the nav chrome — keep the contract.
|
|
26
|
+
summary: 'return the number of pending human asks; stdout.count is machine-parseable',
|
|
27
|
+
params: [
|
|
28
|
+
{
|
|
29
|
+
kind: 'flag',
|
|
30
|
+
name: 'node',
|
|
31
|
+
type: 'string',
|
|
32
|
+
required: false,
|
|
33
|
+
constraint: 'Count asks only for this node\'s cwd. Mutually exclusive with --view.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
kind: 'flag',
|
|
37
|
+
name: 'view',
|
|
38
|
+
type: 'string',
|
|
39
|
+
required: false,
|
|
40
|
+
constraint: 'Sum asks for all nodes in the sub-DAG rooted at this id. Mutually exclusive with --node.',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
output: [
|
|
44
|
+
{ name: 'count', type: 'integer', required: true, constraint: 'Total pending asks in the requested scope.' },
|
|
45
|
+
],
|
|
46
|
+
outputKind: 'object',
|
|
47
|
+
effects: ['Read-only: scans humanloop interaction dirs.'],
|
|
48
|
+
},
|
|
49
|
+
run: async (input) => {
|
|
50
|
+
const nodeId = input['node'];
|
|
51
|
+
const viewId = input['view'];
|
|
52
|
+
if (nodeId !== undefined && viewId !== undefined) {
|
|
53
|
+
throw new InputError({
|
|
54
|
+
error: 'ambiguous_scope',
|
|
55
|
+
message: '--node and --view are mutually exclusive',
|
|
56
|
+
next: 'Use one of --node <id>, --view <id>, or neither (canvas-wide).',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (nodeId !== undefined) {
|
|
60
|
+
// Validate node exists.
|
|
61
|
+
if (getNode(nodeId) === null) {
|
|
62
|
+
throw new InputError({
|
|
63
|
+
error: 'not_found',
|
|
64
|
+
message: `no node: ${nodeId}`,
|
|
65
|
+
next: 'List nodes with `crtr node inspect list`.',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return { count: countAsks(nodeId) };
|
|
69
|
+
}
|
|
70
|
+
if (viewId !== undefined) {
|
|
71
|
+
if (getNode(viewId) === null) {
|
|
72
|
+
throw new InputError({
|
|
73
|
+
error: 'not_found',
|
|
74
|
+
message: `no node: ${viewId}`,
|
|
75
|
+
next: 'List nodes with `crtr node inspect list`.',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const items = pendingAsksForView(viewId);
|
|
79
|
+
const total = items.reduce((s, e) => s + e.count, 0);
|
|
80
|
+
return { count: total };
|
|
81
|
+
}
|
|
82
|
+
// Canvas-wide.
|
|
83
|
+
const items = asksAcrossCanvas();
|
|
84
|
+
const total = items.reduce((s, e) => s + e.count, 0);
|
|
85
|
+
return { count: total };
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// attention list
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
const attentionList = defineLeaf({
|
|
92
|
+
name: 'list',
|
|
93
|
+
help: {
|
|
94
|
+
name: 'canvas attention list',
|
|
95
|
+
summary: 'list nodes with pending human asks, grouped by cwd, oldest first',
|
|
96
|
+
params: [
|
|
97
|
+
{
|
|
98
|
+
kind: 'flag',
|
|
99
|
+
name: 'view',
|
|
100
|
+
type: 'string',
|
|
101
|
+
required: false,
|
|
102
|
+
constraint: 'Scope the list to the sub-DAG rooted at this node id. Omit for canvas-wide.',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
output: [
|
|
106
|
+
{
|
|
107
|
+
name: 'items',
|
|
108
|
+
type: 'object[]',
|
|
109
|
+
required: true,
|
|
110
|
+
constraint: 'Each: {node_id, name, cwd, count}. One entry per distinct cwd with count > 0.',
|
|
111
|
+
},
|
|
112
|
+
{ name: 'total', type: 'integer', required: true, constraint: 'Sum of counts across all entries.' },
|
|
113
|
+
],
|
|
114
|
+
outputKind: 'object',
|
|
115
|
+
effects: ['Read-only: scans humanloop interaction dirs.'],
|
|
116
|
+
},
|
|
117
|
+
run: async (input) => {
|
|
118
|
+
const viewId = input['view'];
|
|
119
|
+
let items;
|
|
120
|
+
if (viewId !== undefined) {
|
|
121
|
+
if (getNode(viewId) === null) {
|
|
122
|
+
throw new InputError({
|
|
123
|
+
error: 'not_found',
|
|
124
|
+
message: `no node: ${viewId}`,
|
|
125
|
+
next: 'List nodes with `crtr node inspect list`.',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
items = pendingAsksForView(viewId);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
items = asksAcrossCanvas();
|
|
132
|
+
}
|
|
133
|
+
const total = items.reduce((s, e) => s + e.count, 0);
|
|
134
|
+
return { items, total };
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Export — mounted under `crtr canvas`
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
export const attentionBranch = defineBranch({
|
|
141
|
+
name: 'attention',
|
|
142
|
+
help: {
|
|
143
|
+
name: 'canvas attention',
|
|
144
|
+
summary: 'aggregate pending human asks across the canvas',
|
|
145
|
+
model: 'Human asks are stored per-cwd by humanloop. `count` returns a single integer (stdout.count is parsed by nav chrome); `list` returns itemised entries. Scope with --node (one node) or --view (sub-DAG) — default is canvas-wide.',
|
|
146
|
+
children: [
|
|
147
|
+
{ name: 'count', desc: 'total pending ask count (machine-parseable stdout.count)', useWhen: 'polling from a script or nav chrome' },
|
|
148
|
+
{ name: 'list', desc: 'itemised list of cwds with pending asks', useWhen: 'finding which agents need a human response' },
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
children: [attentionCount, attentionList],
|
|
152
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// `crtr canvas` — observe and supervise the whole graph.
|
|
2
|
+
//
|
|
3
|
+
// Where `node` operates on one node and `push`/`feed` are a node's own spine
|
|
4
|
+
// I/O, `canvas` is the bird's-eye / supervisor surface over the entire canvas:
|
|
5
|
+
// render the subscription forest (`dashboard`), see who is blocked on a human
|
|
6
|
+
// (`attention`), bring a node back (`revive`), and manage the supervisor
|
|
7
|
+
// process (`daemon`). It assembles leaves/branches the sibling command files
|
|
8
|
+
// own, so each piece declares its own help one level down.
|
|
9
|
+
import { defineBranch } from '../core/command.js';
|
|
10
|
+
import { dashboardLeaf } from './dashboard.js';
|
|
11
|
+
import { reviveLeaf } from './revive.js';
|
|
12
|
+
import { attentionBranch } from './attention.js';
|
|
13
|
+
import { daemonBranch } from './daemon.js';
|
|
14
|
+
export function registerCanvas() {
|
|
15
|
+
return defineBranch({
|
|
16
|
+
name: 'canvas',
|
|
17
|
+
rootEntry: {
|
|
18
|
+
concept: 'the whole agent graph at a glance — render it, see who is blocked, revive a node, supervise the daemon',
|
|
19
|
+
desc: 'bird\'s-eye view and supervision of the entire canvas',
|
|
20
|
+
useWhen: 'surveying the full graph, finding blocked agents, or managing revival/the daemon',
|
|
21
|
+
},
|
|
22
|
+
help: {
|
|
23
|
+
name: 'canvas',
|
|
24
|
+
summary: 'observe and supervise the whole agent graph',
|
|
25
|
+
model: 'Canvas-wide operations, distinct from per-node work (`node`) and a node\'s own spine I/O (`push`/`feed`). `dashboard` renders the subscription forest as a tree; `attention` aggregates pending human asks across the graph; `revive` reopens a window for a done/idle/dead node; `daemon` manages the thin crtrd supervisor that auto-revives nodes on window exit.',
|
|
26
|
+
children: [
|
|
27
|
+
{ name: 'dashboard', desc: 'render the canvas as a subscription tree', useWhen: 'inspecting the whole graph at a glance' },
|
|
28
|
+
{ name: 'attention', desc: 'count/list pending human asks across the graph', useWhen: 'checking whether any agent is blocked on a human' },
|
|
29
|
+
{ name: 'revive', desc: 'reopen a window for a done/idle/dead node', useWhen: 'manually waking a node (the daemon does this automatically)' },
|
|
30
|
+
{ name: 'daemon', desc: 'manage the crtrd supervisor process', useWhen: 'starting, checking, or stopping background supervision' },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
children: [dashboardLeaf, attentionBranch, reviveLeaf, daemonBranch],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// `crtr canvas daemon` — thin supervisor daemon management.
|
|
2
|
+
//
|
|
3
|
+
// The daemon (crtrd) polls active+idle nodes and handles window exit:
|
|
4
|
+
// • crash (window gone, no intent) → mark 'dead'
|
|
5
|
+
// • refresh-yield (intent=refresh) → fresh respawn
|
|
6
|
+
//
|
|
7
|
+
// This subtree starts, checks, and stops the daemon process.
|
|
8
|
+
import { defineLeaf, defineBranch } from '../core/command.js';
|
|
9
|
+
import { InputError } from '../core/io.js';
|
|
10
|
+
import { spawnDaemon } from '../daemon/manage.js';
|
|
11
|
+
import { readPidfile, isPidAlive } from '../daemon/crtrd.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// daemon start
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const daemonStart = defineLeaf({
|
|
16
|
+
name: 'start',
|
|
17
|
+
help: {
|
|
18
|
+
name: 'canvas daemon start',
|
|
19
|
+
summary: 'start the crtrd supervisor daemon in the background (no-op if already running)',
|
|
20
|
+
params: [],
|
|
21
|
+
output: [
|
|
22
|
+
{ name: 'started', type: 'boolean', required: true, constraint: 'True when a new daemon process was spawned; false when one was already running.' },
|
|
23
|
+
{ name: 'pid', type: 'number', required: false, constraint: 'PID of the newly spawned daemon.' },
|
|
24
|
+
{ name: 'existing_pid', type: 'number', required: false, constraint: 'PID of the already-running daemon (when started=false).' },
|
|
25
|
+
],
|
|
26
|
+
outputKind: 'object',
|
|
27
|
+
effects: [
|
|
28
|
+
'Spawns dist/daemon/crtrd-cli.js detached + unref\'d; it outlives this process.',
|
|
29
|
+
'Writes a pidfile at crtrHome()/crtrd.pid.',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
run: async (_input) => {
|
|
33
|
+
const result = spawnDaemon();
|
|
34
|
+
return result;
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// daemon status
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
const daemonStatus = defineLeaf({
|
|
41
|
+
name: 'status',
|
|
42
|
+
help: {
|
|
43
|
+
name: 'canvas daemon status',
|
|
44
|
+
summary: 'check whether the crtrd supervisor daemon is currently running',
|
|
45
|
+
params: [],
|
|
46
|
+
output: [
|
|
47
|
+
{ name: 'running', type: 'boolean', required: true, constraint: 'True when the daemon is alive.' },
|
|
48
|
+
{ name: 'pid', type: 'number', required: false, constraint: 'PID of the running daemon.' },
|
|
49
|
+
],
|
|
50
|
+
outputKind: 'object',
|
|
51
|
+
effects: ['Read-only: reads the pidfile and probes the pid.'],
|
|
52
|
+
},
|
|
53
|
+
run: async (_input) => {
|
|
54
|
+
const pid = readPidfile();
|
|
55
|
+
const running = pid !== null && isPidAlive(pid);
|
|
56
|
+
return running
|
|
57
|
+
? { running: true, pid }
|
|
58
|
+
: { running: false };
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// daemon stop
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
const daemonStop = defineLeaf({
|
|
65
|
+
name: 'stop',
|
|
66
|
+
help: {
|
|
67
|
+
name: 'canvas daemon stop',
|
|
68
|
+
summary: 'send SIGTERM to the crtrd supervisor daemon',
|
|
69
|
+
params: [],
|
|
70
|
+
output: [
|
|
71
|
+
{ name: 'stopped', type: 'boolean', required: true, constraint: 'True when a running daemon was signaled. False when no daemon was found.' },
|
|
72
|
+
{ name: 'pid', type: 'number', required: false, constraint: 'PID that was signaled.' },
|
|
73
|
+
],
|
|
74
|
+
outputKind: 'object',
|
|
75
|
+
effects: ['Sends SIGTERM to the recorded pid; the daemon removes its pidfile on exit.'],
|
|
76
|
+
},
|
|
77
|
+
run: async (_input) => {
|
|
78
|
+
const pid = readPidfile();
|
|
79
|
+
if (pid === null || !isPidAlive(pid)) {
|
|
80
|
+
return { stopped: false };
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
process.kill(pid, 'SIGTERM');
|
|
84
|
+
return { stopped: true, pid };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
throw new InputError({
|
|
88
|
+
error: 'kill_failed',
|
|
89
|
+
message: `failed to signal pid ${pid}: ${err.message}`,
|
|
90
|
+
next: 'The pidfile may be stale; remove ~/.crtr/crtrd.pid manually.',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Export — mounted under `crtr canvas`
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
export const daemonBranch = defineBranch({
|
|
99
|
+
name: 'daemon',
|
|
100
|
+
help: {
|
|
101
|
+
name: 'canvas daemon',
|
|
102
|
+
summary: 'manage the crtrd canvas supervisor daemon',
|
|
103
|
+
model: 'crtrd is a thin background daemon that polls active+idle nodes and acts on window exit: crashed windows become dead; refresh-yield windows get a fresh respawn. It holds no orchestration logic — just process supervision.',
|
|
104
|
+
children: [
|
|
105
|
+
{ name: 'start', desc: 'start the daemon in the background', useWhen: 'bringing up the supervisor for the first time in a session' },
|
|
106
|
+
{ name: 'status', desc: 'check whether the daemon is running', useWhen: 'verifying the daemon is up before spawning canvas nodes' },
|
|
107
|
+
{ name: 'stop', desc: 'stop the running daemon', useWhen: 'shutting down supervision' },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
children: [daemonStart, daemonStatus, daemonStop],
|
|
111
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// `crtr canvas dashboard` — canvas-wide visibility surface.
|
|
2
|
+
//
|
|
3
|
+
// Renders the subscription sub-DAG as an ASCII tree, optionally scoped to a
|
|
4
|
+
// single root. A human operator pastes the output into a terminal or pipes it
|
|
5
|
+
// to a renderer; a machine consumer reads the structured `rows` array.
|
|
6
|
+
//
|
|
7
|
+
// Exported as a leaf; `crtr canvas` (canvas.ts) mounts it.
|
|
8
|
+
import { defineLeaf } from '../core/command.js';
|
|
9
|
+
import { InputError } from '../core/io.js';
|
|
10
|
+
import { getNode, listNodes } from '../core/canvas/index.js';
|
|
11
|
+
import { renderTree, renderForest, dashboardRows, dashboardRowsAll } from '../core/canvas/render.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// dashboard show — the main leaf
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export const dashboardLeaf = defineLeaf({
|
|
16
|
+
name: 'dashboard',
|
|
17
|
+
help: {
|
|
18
|
+
name: 'canvas dashboard',
|
|
19
|
+
summary: 'render the canvas as an ASCII subscription tree — scoped to a root or the full forest',
|
|
20
|
+
params: [
|
|
21
|
+
{
|
|
22
|
+
kind: 'flag',
|
|
23
|
+
name: 'root',
|
|
24
|
+
type: 'string',
|
|
25
|
+
required: false,
|
|
26
|
+
constraint: 'Node id to use as the tree root. Omit for the full forest (all canvas roots).',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
output: [
|
|
30
|
+
{ name: 'tree', type: 'string', required: true, constraint: 'Multi-line ASCII tree.' },
|
|
31
|
+
{ name: 'nodes', type: 'integer', required: true, constraint: 'Total node count in this view.' },
|
|
32
|
+
{ name: 'rows', type: 'object[]', required: true, constraint: 'One per node: {node_id,name,status,kind,mode,ctx_tokens,asks}.' },
|
|
33
|
+
],
|
|
34
|
+
outputKind: 'object',
|
|
35
|
+
effects: ['Read-only: queries canvas.db and node telemetry files.'],
|
|
36
|
+
},
|
|
37
|
+
run: async (input) => {
|
|
38
|
+
const rootId = input['root'];
|
|
39
|
+
if (rootId !== undefined) {
|
|
40
|
+
// Scoped to a single root — validate the node exists.
|
|
41
|
+
const node = getNode(rootId);
|
|
42
|
+
if (node === null) {
|
|
43
|
+
throw new InputError({
|
|
44
|
+
error: 'not_found',
|
|
45
|
+
message: `no node: ${rootId}`,
|
|
46
|
+
next: 'List nodes with `crtr node inspect list` to find a valid id.',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const rows = dashboardRows(rootId);
|
|
50
|
+
return {
|
|
51
|
+
tree: renderTree(rootId),
|
|
52
|
+
nodes: rows.length,
|
|
53
|
+
rows,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Full forest: all nodes on the canvas.
|
|
57
|
+
const allNodes = listNodes();
|
|
58
|
+
const rows = dashboardRowsAll();
|
|
59
|
+
return {
|
|
60
|
+
tree: renderForest(),
|
|
61
|
+
nodes: allNodes.length,
|
|
62
|
+
rows,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const humanAsk: import("../../core/command.js").LeafDef;
|
|
2
|
+
export declare const humanApprove: import("../../core/command.js").LeafDef;
|
|
3
|
+
export declare const humanReview: import("../../core/command.js").LeafDef;
|
|
4
|
+
export declare const humanNotify: import("../../core/command.js").LeafDef;
|
|
5
|
+
export declare const humanShow: import("../../core/command.js").LeafDef;
|