@crouton-kit/crouter 0.3.37 → 0.3.39
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 +1 -0
- package/dist/{builtin-personas/runtime-base.md → builtin-memory/00-runtime-base.md} +7 -0
- 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-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/attach-cmd.js +416 -416
- 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.js +40 -11
- 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/sys/config.js +6 -21
- package/dist/commands/sys/prompt-review.js +90 -17
- package/dist/core/canvas/canvas.js +10 -9
- package/dist/core/canvas/db.js +11 -0
- package/dist/core/canvas/history.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/hearth/provider.d.ts +8 -0
- package/dist/core/hearth/providers/__tests__/sweep-and-release.test.d.ts +1 -0
- package/dist/core/hearth/providers/__tests__/sweep-and-release.test.js +254 -0
- package/dist/core/hearth/providers/blaxel-home.d.ts +39 -0
- package/dist/core/hearth/providers/blaxel-home.js +271 -21
- package/dist/core/hearth/providers/blaxel.d.ts +5 -0
- package/dist/core/hearth/providers/blaxel.js +86 -4
- package/dist/core/hearth/providers/types.d.ts +16 -0
- package/dist/core/memory-resolver.d.ts +26 -15
- package/dist/core/memory-resolver.js +158 -40
- 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/runtime/bearings.d.ts +9 -0
- package/dist/core/runtime/bearings.js +31 -0
- package/dist/core/runtime/front-door.js +9 -2
- 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/spawn.d.ts +13 -0
- package/dist/core/runtime/spawn.js +25 -0
- 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/hearth/control-plane/__tests__/error-serialization.test.d.ts +1 -0
- package/dist/hearth/control-plane/__tests__/error-serialization.test.js +29 -0
- package/dist/hearth/control-plane/__tests__/oauth-serving-marker.test.d.ts +1 -0
- package/dist/hearth/control-plane/__tests__/oauth-serving-marker.test.js +44 -0
- package/dist/hearth/control-plane/__tests__/wake-roll.test.d.ts +1 -0
- package/dist/hearth/control-plane/__tests__/wake-roll.test.js +230 -0
- package/dist/hearth/control-plane/db.js +27 -0
- package/dist/hearth/control-plane/hearth-target.d.ts +23 -0
- package/dist/hearth/control-plane/hearth-target.js +68 -0
- package/dist/hearth/control-plane/registry.d.ts +6 -1
- package/dist/hearth/control-plane/registry.js +7 -0
- package/dist/hearth/control-plane/relay.d.ts +4 -0
- package/dist/hearth/control-plane/relay.js +72 -3
- package/dist/hearth/control-plane/secrets.d.ts +14 -0
- package/dist/hearth/control-plane/secrets.js +21 -0
- package/dist/hearth/control-plane/server.js +140 -4
- package/dist/hearth/control-plane/serving.d.ts +15 -0
- package/dist/hearth/control-plane/serving.js +106 -0
- package/dist/hearth/control-plane/types.d.ts +20 -0
- package/dist/hearth/control-plane/wake.d.ts +8 -2
- package/dist/hearth/control-plane/wake.js +241 -3
- package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
- package/dist/types.d.ts +57 -1
- package/dist/types.js +83 -1
- package/dist/web-client/assets/{index-MSKSWwV0.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/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
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { defineLeaf } from '../../core/command.js';
|
|
4
|
+
import { loadProfileManifest, profileRoot } from '../../core/profiles/manifest.js';
|
|
5
|
+
import { CONFIG_FILE } from '../../types.js';
|
|
6
|
+
export const showLeaf = defineLeaf({
|
|
7
|
+
name: 'show',
|
|
8
|
+
description: "one profile's manifest in full",
|
|
9
|
+
whenToUse: "you need a profile's full project list, id, and timestamps — after `profile list` narrows to a name, or to inspect what a node's bearings named as its profile.",
|
|
10
|
+
help: {
|
|
11
|
+
name: 'profile show',
|
|
12
|
+
summary: "print one profile's manifest plus its on-disk path and config.json location",
|
|
13
|
+
params: [
|
|
14
|
+
{
|
|
15
|
+
kind: 'positional',
|
|
16
|
+
name: 'profile',
|
|
17
|
+
required: true,
|
|
18
|
+
constraint: 'Exact profile id, or a unique manifest name. An ambiguous name fails listing every matching id.',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
output: [
|
|
22
|
+
{ name: 'profile_id', type: 'string', required: true, constraint: 'Stable directory id.' },
|
|
23
|
+
{ name: 'name', type: 'string', required: true, constraint: 'Manifest name.' },
|
|
24
|
+
{ name: 'projects', type: 'string[]', required: true, constraint: 'Absolute project directories, in manifest order.' },
|
|
25
|
+
{ name: 'created_at', type: 'string', required: true, constraint: 'ISO 8601 creation timestamp.' },
|
|
26
|
+
{ name: 'last_used_at', type: 'string | null', required: true, constraint: 'ISO 8601 timestamp of the most recent selection, or null if never selected.' },
|
|
27
|
+
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the profile directory.' },
|
|
28
|
+
{ name: 'config_path', type: 'string', required: true, constraint: 'Absolute path to the profile\'s config.json (hand-edited the same way as user/project config.json — no profile-specific editor verb exists).' },
|
|
29
|
+
{ name: 'config_exists', type: 'boolean', required: true, constraint: 'Whether config.json exists at that path yet.' },
|
|
30
|
+
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands.' },
|
|
31
|
+
],
|
|
32
|
+
outputKind: 'object',
|
|
33
|
+
effects: ['None. Read-only.'],
|
|
34
|
+
},
|
|
35
|
+
run: async (input) => {
|
|
36
|
+
const { profileId, manifest } = loadProfileManifest(input['profile']);
|
|
37
|
+
const configPath = join(profileRoot(profileId), CONFIG_FILE);
|
|
38
|
+
return {
|
|
39
|
+
profile_id: profileId,
|
|
40
|
+
name: manifest.name,
|
|
41
|
+
projects: manifest.projects,
|
|
42
|
+
created_at: manifest.created_at,
|
|
43
|
+
last_used_at: manifest.last_used_at,
|
|
44
|
+
path: profileRoot(profileId),
|
|
45
|
+
config_path: configPath,
|
|
46
|
+
config_exists: existsSync(configPath),
|
|
47
|
+
follow_up: `Add a project with \`crtr profile add-project ${profileId} --dir <path>\`, or rename with \`crtr profile rename ${profileId} --name <name>\`.`,
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// `crtr profile` subtree — the profile store (spec §2.1/§2.5): agent
|
|
2
|
+
// identities defined at the user root, each owning a manifest naming project
|
|
3
|
+
// directories plus its own memory store. Flat leaves; no sub-branches — 7
|
|
4
|
+
// verbs fits the 5-7 hard cap.
|
|
5
|
+
//
|
|
6
|
+
// Every verb but `new`/`list` takes <profile> as an exact id OR a unique
|
|
7
|
+
// manifest name (never two positionals: `add-project`/`remove-project` pair
|
|
8
|
+
// <profile> with `--dir`, `rename` pairs it with `--name`, matching the
|
|
9
|
+
// one-positional-per-leaf argv contract used across the whole tree).
|
|
10
|
+
import { defineBranch } from '../core/command.js';
|
|
11
|
+
import { newLeaf } from './profile/new.js';
|
|
12
|
+
import { listLeaf } from './profile/list.js';
|
|
13
|
+
import { showLeaf } from './profile/show.js';
|
|
14
|
+
import { addProjectLeaf } from './profile/add-project.js';
|
|
15
|
+
import { removeProjectLeaf } from './profile/remove-project.js';
|
|
16
|
+
import { renameLeaf } from './profile/rename.js';
|
|
17
|
+
import { deleteLeaf } from './profile/delete.js';
|
|
18
|
+
export function registerProfile() {
|
|
19
|
+
return defineBranch({
|
|
20
|
+
name: 'profile',
|
|
21
|
+
rootEntry: {
|
|
22
|
+
concept: 'an agent identity defined at the user root — a manifest naming project directories plus its own memory store',
|
|
23
|
+
desc: 'create, inspect, and manage profiles',
|
|
24
|
+
useWhen: 'creating a new agent identity, inspecting or listing existing ones, or changing a profile\u2019s project purview or display name. Selecting a profile for a running node (`--profile`, startup selection) lives elsewhere; this family only manages the manifest.',
|
|
25
|
+
},
|
|
26
|
+
help: {
|
|
27
|
+
name: 'profile',
|
|
28
|
+
summary: 'create, inspect, and manage profiles \u2014 agent identities with their own project purview and memory store',
|
|
29
|
+
model: '`new` creates one from a name (+ at most one initial `--project`). `list` inventories every profile as JSONL. `show` prints one manifest in full. `add-project` / `remove-project` mutate the ordered project list after creation, including mid-session on an already-running profile. `rename` changes only the manifest name \u2014 the profile_id is stable across a rename. `delete` removes a profile\u2019s directory (manifest + its own memory store) entirely and does not touch the project directories it pointed at. Every verb but `new`/`list` takes <profile> as an exact id or a unique manifest name; an ambiguous name fails listing every matching id.',
|
|
30
|
+
},
|
|
31
|
+
children: [newLeaf, listLeaf, showLeaf, addProjectLeaf, removeProjectLeaf, renameLeaf, deleteLeaf],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -13,7 +13,6 @@ const TOP_LEVEL_KEYS = new Set([
|
|
|
13
13
|
'max_panes_per_window',
|
|
14
14
|
'canvasNav',
|
|
15
15
|
'modelLadders',
|
|
16
|
-
'personaStrengths',
|
|
17
16
|
]);
|
|
18
17
|
const MODEL_PROVIDERS = new Set(['anthropic', 'openai']);
|
|
19
18
|
const MODEL_STRENGTHS = new Set(['ultra', 'strong', 'medium', 'light']);
|
|
@@ -105,20 +104,6 @@ function setNestedValue(cfg, key, rawValue, value) {
|
|
|
105
104
|
}
|
|
106
105
|
throw usage(`unsupported key path for set: ${key}`);
|
|
107
106
|
}
|
|
108
|
-
if (topKey === 'personaStrengths') {
|
|
109
|
-
if (parts.length !== 2) {
|
|
110
|
-
throw usage(`unsupported key path for set: ${key}`);
|
|
111
|
-
}
|
|
112
|
-
const persona = parts[1];
|
|
113
|
-
if (persona.trim() === '' || persona !== persona.trim()) {
|
|
114
|
-
throw usage(`personaStrengths.<persona-kind> must be a non-empty persona kind without leading or trailing whitespace`);
|
|
115
|
-
}
|
|
116
|
-
if (!isModelStrength(rawValue)) {
|
|
117
|
-
throw usage(`personaStrengths.<persona-kind> must be ultra, strong, medium, or light`);
|
|
118
|
-
}
|
|
119
|
-
cfg.personaStrengths[persona] = rawValue;
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
107
|
if (parts.length === 1) {
|
|
123
108
|
cfg[topKey] = value;
|
|
124
109
|
return;
|
|
@@ -136,12 +121,12 @@ function setNestedValue(cfg, key, rawValue, value) {
|
|
|
136
121
|
const configGet = defineLeaf({
|
|
137
122
|
name: 'get',
|
|
138
123
|
description: 'read a config value by key',
|
|
139
|
-
whenToUse: 'you want to read a single config value by its dotted key — the current auto_update policy, max_panes_per_window, the canvasNav prefix key, model ladders
|
|
124
|
+
whenToUse: 'you want to read a single config value by its dotted key — the current auto_update policy, max_panes_per_window, the canvasNav prefix key, or model ladders — optionally from a specific scope. Use sys config set instead to change a value, sys config path to locate the file for hand-editing.',
|
|
140
125
|
help: {
|
|
141
126
|
name: 'sys config get',
|
|
142
127
|
summary: 'read a config value by dotted key',
|
|
143
128
|
params: [
|
|
144
|
-
{ kind: 'positional', name: 'key', type: 'string', required: true, constraint: 'Dotted key path. Top-level keys: auto_update, marketplaces, plugins, max_panes_per_window, canvasNav, modelLadders
|
|
129
|
+
{ kind: 'positional', name: 'key', type: 'string', required: true, constraint: 'Dotted key path. Top-level keys: auto_update, marketplaces, plugins, max_panes_per_window, canvasNav, modelLadders (read whole; edit canvasNav.prefixBinds/graphBinds in config.json directly).' },
|
|
145
130
|
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Scope to read from. Default: user.' },
|
|
146
131
|
],
|
|
147
132
|
output: [
|
|
@@ -166,12 +151,12 @@ const configGet = defineLeaf({
|
|
|
166
151
|
const configSet = defineLeaf({
|
|
167
152
|
name: 'set',
|
|
168
153
|
description: 'write a config value by key',
|
|
169
|
-
whenToUse: 'you want to change a crtr setting — flip auto_update.crtr or auto_update.content to notify, apply, or off, raise max_panes_per_window, rebind canvasNav.prefixKey, set model ladders
|
|
154
|
+
whenToUse: 'you want to change a crtr setting — flip auto_update.crtr or auto_update.content to notify, apply, or off, raise max_panes_per_window, rebind canvasNav.prefixKey, or set model ladders — written to the user or project scope. Use sys config get instead to read a value; the canvasNav record tables are not settable here, so edit config.json directly (sys config path) for those.',
|
|
170
155
|
help: {
|
|
171
156
|
name: 'sys config set',
|
|
172
157
|
summary: 'write a config value by dotted key',
|
|
173
158
|
params: [
|
|
174
|
-
{ kind: 'positional', name: 'key', type: 'string', required: true, constraint: 'Dotted key path. Supported: auto_update.crtr, auto_update.content, auto_update.interval_hours, max_panes_per_window, canvasNav.prefixKey, modelLadders.defaultProvider, modelLadders.<anthropic|openai>.<ultra|strong|medium|light
|
|
159
|
+
{ kind: 'positional', name: 'key', type: 'string', required: true, constraint: 'Dotted key path. Supported: auto_update.crtr, auto_update.content, auto_update.interval_hours, max_panes_per_window, canvasNav.prefixKey, modelLadders.defaultProvider, modelLadders.<anthropic|openai>.<ultra|strong|medium|light>. The canvasNav.prefixBinds/graphBinds record tables are not settable here — edit config.json directly (`crtr sys config path`).' },
|
|
175
160
|
{ kind: 'flag', name: 'value', type: 'string', required: true, constraint: 'value VALUE — string, required. Stored as-is if quoted; coerced to number or boolean when unambiguous.' },
|
|
176
161
|
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Scope to write to. Default: user.' },
|
|
177
162
|
],
|
|
@@ -240,10 +225,10 @@ const configPath = defineLeaf({
|
|
|
240
225
|
export const configBranch = defineBranch({
|
|
241
226
|
name: 'config',
|
|
242
227
|
description: 'read and write configuration',
|
|
243
|
-
whenToUse: 'inspecting or changing crtr settings — read a value with sys config get, change one with sys config set (auto_update policy, max_panes_per_window, canvasNav.prefixKey, model ladders
|
|
228
|
+
whenToUse: 'inspecting or changing crtr settings — read a value with sys config get, change one with sys config set (auto_update policy, max_panes_per_window, canvasNav.prefixKey, model ladders), or locate config.json with sys config path to hand-edit the record tables set cannot reach.',
|
|
244
229
|
help: {
|
|
245
230
|
name: 'sys config',
|
|
246
|
-
summary: 'read and write crtr configuration, including model ladders
|
|
231
|
+
summary: 'read and write crtr configuration, including model ladders',
|
|
247
232
|
},
|
|
248
233
|
children: [configGet, configSet, configPath],
|
|
249
234
|
});
|
|
@@ -3,8 +3,10 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { defineLeaf } from '../../core/command.js';
|
|
4
4
|
import { InputError, readStdinRaw } from '../../core/io.js';
|
|
5
5
|
import { workspaceRoot } from '../../core/artifact.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { getNode } from '../../core/canvas/index.js';
|
|
7
|
+
import { readMergedLaunchConfig, subKindsAvailableTo } from '../../core/config.js';
|
|
8
|
+
import { LAUNCH_SYSTEM_PROMPT } from '../../core/runtime/launch.js';
|
|
9
|
+
import { renderPreferencesForSubject, renderKnowledgeBlock, scopeForCwd, spineDepth, profileNameFor, } from '../../core/substrate/index.js';
|
|
8
10
|
function resolveLifecycle(mode, lifecycle) {
|
|
9
11
|
if (lifecycle !== undefined)
|
|
10
12
|
return lifecycle;
|
|
@@ -41,24 +43,47 @@ function parseBool(value, field, defaultValue) {
|
|
|
41
43
|
function optionalString(value) {
|
|
42
44
|
return typeof value === 'string' && value.trim() !== '' ? value : null;
|
|
43
45
|
}
|
|
44
|
-
function
|
|
45
|
-
return
|
|
46
|
+
function approxTokens(text) {
|
|
47
|
+
return Math.ceil(text.length / 4);
|
|
46
48
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
+
function topLevelKinds() {
|
|
50
|
+
const registry = readMergedLaunchConfig().kinds;
|
|
51
|
+
return Object.entries(registry)
|
|
52
|
+
.filter(([kind]) => !kind.includes('/'))
|
|
53
|
+
.map(([kind, cfg]) => ({ kind, whenToUse: cfg.whenToUse }))
|
|
54
|
+
.sort((a, b) => a.kind.localeCompare(b.kind));
|
|
55
|
+
}
|
|
56
|
+
function subKindsFor(kind) {
|
|
57
|
+
return subKindsAvailableTo(kind);
|
|
49
58
|
}
|
|
50
59
|
function reviewList() {
|
|
51
|
-
const kinds =
|
|
60
|
+
const kinds = topLevelKinds();
|
|
52
61
|
const subPersonas = {};
|
|
53
62
|
for (const { kind } of kinds)
|
|
54
|
-
subPersonas[kind] =
|
|
63
|
+
subPersonas[kind] = subKindsFor(kind);
|
|
64
|
+
return { kinds, modes: ['base', 'orchestrator'], lifecycles: ['terminal', 'resident'], subPersonas };
|
|
65
|
+
}
|
|
66
|
+
function buildReviewSubject(kind, mode, lifecycle, hasManager, nodeId) {
|
|
67
|
+
const node = nodeId !== null ? getNode(nodeId) : null;
|
|
68
|
+
const cwd = node?.cwd ?? process.cwd();
|
|
55
69
|
return {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
kind,
|
|
71
|
+
mode,
|
|
72
|
+
lifecycle,
|
|
73
|
+
hasManager,
|
|
74
|
+
cwd,
|
|
75
|
+
scope: scopeForCwd(cwd),
|
|
76
|
+
orchestration: { depth: node !== null ? spineDepth(node.node_id) : 0 },
|
|
77
|
+
profile: profileNameFor(node?.profile_id),
|
|
60
78
|
};
|
|
61
79
|
}
|
|
80
|
+
function spliceIntoScaffold(scaffold, block) {
|
|
81
|
+
const anchor = '\n\nGuidelines:';
|
|
82
|
+
const idx = scaffold.indexOf(anchor);
|
|
83
|
+
if (idx === -1)
|
|
84
|
+
return `${scaffold}\n\n${block}`;
|
|
85
|
+
return `${scaffold.slice(0, idx)}\n\n${block}${scaffold.slice(idx)}`;
|
|
86
|
+
}
|
|
62
87
|
function promptReviewPath() {
|
|
63
88
|
const dir = workspaceRoot();
|
|
64
89
|
const reviewsDir = join(dir, 'prompt-reviews');
|
|
@@ -118,14 +143,62 @@ function resolveDeck(input) {
|
|
|
118
143
|
const mode = input['mode'] ?? 'base';
|
|
119
144
|
const lifecycle = resolveLifecycle(mode, input['lifecycle']);
|
|
120
145
|
const hasManager = parseBool(input['hasManager'], 'hasManager', true);
|
|
121
|
-
const
|
|
146
|
+
const nodeId = optionalString(input['node']);
|
|
122
147
|
if (kind === undefined || kind.trim() === '') {
|
|
123
148
|
throw new InputError({ error: 'missing_parameter', message: 'kind is required', field: 'kind', next: 'Pass --kind <kind> or use --list.' });
|
|
124
149
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
150
|
+
const node = nodeId !== null ? getNode(nodeId) : null;
|
|
151
|
+
const subject = buildReviewSubject(kind, mode, lifecycle, hasManager, node?.node_id ?? null);
|
|
152
|
+
const { block, contentDocs, tree } = renderPreferencesForSubject(subject);
|
|
153
|
+
const layers = [
|
|
154
|
+
{
|
|
155
|
+
id: 'launch-scaffold', label: 'Launch scaffold', group: 'generated',
|
|
156
|
+
source: 'generated: launch scaffold', sourcePath: null, scope: 'generated',
|
|
157
|
+
included: true, condition: null, text: LAUNCH_SYSTEM_PROMPT,
|
|
158
|
+
tokens: approxTokens(LAUNCH_SYSTEM_PROMPT), chars: LAUNCH_SYSTEM_PROMPT.length,
|
|
159
|
+
},
|
|
160
|
+
...contentDocs.map((d) => ({
|
|
161
|
+
id: d.name, label: d.name, group: 'substrate',
|
|
162
|
+
source: `memory: ${d.name}`, sourcePath: d.path, scope: d.scope,
|
|
163
|
+
included: true, condition: null, text: d.body,
|
|
164
|
+
tokens: approxTokens(d.body), chars: d.body.length,
|
|
165
|
+
})),
|
|
166
|
+
];
|
|
167
|
+
if (tree !== '') {
|
|
168
|
+
layers.push({
|
|
169
|
+
id: 'preference-catalog', label: 'Preference catalog (routing entries)', group: 'substrate',
|
|
170
|
+
source: 'generated: preference catalog', sourcePath: null, scope: 'generated',
|
|
171
|
+
included: true, condition: null, text: tree, tokens: approxTokens(tree), chars: tree.length,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (node !== null) {
|
|
175
|
+
const knowledge = renderKnowledgeBlock(node.node_id);
|
|
176
|
+
if (knowledge !== '') {
|
|
177
|
+
layers.push({
|
|
178
|
+
id: 'memory-knowledge', label: 'Memory (knowledge) — context message, not system prompt',
|
|
179
|
+
group: 'substrate', source: 'runtime-spliced', sourcePath: null, scope: 'runtime',
|
|
180
|
+
included: false, condition: 'session_start context message, not the system prompt',
|
|
181
|
+
text: knowledge, tokens: approxTokens(knowledge), chars: knowledge.length,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const assembled = spliceIntoScaffold(LAUNCH_SYSTEM_PROMPT, block);
|
|
186
|
+
const sources = [];
|
|
187
|
+
const seen = new Set();
|
|
188
|
+
for (const d of contentDocs) {
|
|
189
|
+
const key = `${d.scope}:${d.path}`;
|
|
190
|
+
if (seen.has(key))
|
|
191
|
+
continue;
|
|
192
|
+
seen.add(key);
|
|
193
|
+
sources.push({ id: d.name, label: d.name, path: d.path, scope: d.scope });
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
config: { kind, mode, lifecycle, hasManager, node: node?.node_id ?? null },
|
|
197
|
+
layers,
|
|
198
|
+
assembled,
|
|
199
|
+
total: { tokens: approxTokens(assembled), chars: assembled.length },
|
|
200
|
+
sources,
|
|
201
|
+
};
|
|
129
202
|
}
|
|
130
203
|
export const promptReviewLeaf = defineLeaf({
|
|
131
204
|
name: 'prompt-review',
|
|
@@ -21,7 +21,7 @@ import { ensureHome, ensureNodeDirs, nodeMetaPath, nodeDir, nodesRoot, jobDir, }
|
|
|
21
21
|
/** The identity keys meta.json persists. Listed explicitly so no runtime field
|
|
22
22
|
* can ever leak onto disk even when a fully-hydrated NodeMeta is handed in. */
|
|
23
23
|
const IDENTITY_KEYS = [
|
|
24
|
-
'node_id', 'name', 'description', 'cycles', 'created', 'cwd', 'host_kind', 'kind', 'mode',
|
|
24
|
+
'node_id', 'name', 'description', 'cycles', 'created', 'cwd', 'host_kind', 'profile_id', 'kind', 'mode',
|
|
25
25
|
'lifecycle', 'persona_ack', 'parent', 'spawned_by', 'fork_from', 'passive_default',
|
|
26
26
|
'pi_session_id', 'pi_session_file', 'model_override', 'launch',
|
|
27
27
|
];
|
|
@@ -101,13 +101,13 @@ function writeMeta(meta) {
|
|
|
101
101
|
* state. A fresh insert takes the schema defaults for runtime. */
|
|
102
102
|
function upsertRow(meta) {
|
|
103
103
|
openDb()
|
|
104
|
-
.prepare(`INSERT INTO nodes (node_id, name, kind, mode, lifecycle, cwd, host_kind, parent, created)
|
|
105
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
104
|
+
.prepare(`INSERT INTO nodes (node_id, name, kind, mode, lifecycle, cwd, host_kind, profile_id, parent, created)
|
|
105
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
106
106
|
ON CONFLICT(node_id) DO UPDATE SET
|
|
107
107
|
name=excluded.name, kind=excluded.kind, mode=excluded.mode,
|
|
108
108
|
lifecycle=excluded.lifecycle, cwd=excluded.cwd, host_kind=excluded.host_kind,
|
|
109
|
-
parent=excluded.parent`)
|
|
110
|
-
.run(meta.node_id, meta.name, meta.kind, meta.mode, meta.lifecycle, meta.cwd, meta.host_kind ?? null, meta.parent ?? null, meta.created);
|
|
109
|
+
profile_id=excluded.profile_id, parent=excluded.parent`)
|
|
110
|
+
.run(meta.node_id, meta.name, meta.kind, meta.mode, meta.lifecycle, meta.cwd, meta.host_kind ?? null, meta.profile_id ?? null, meta.parent ?? null, meta.created);
|
|
111
111
|
}
|
|
112
112
|
/** Seed a node's row at BIRTH: identity columns + runtime columns taken from the
|
|
113
113
|
* incoming meta (defaults: status='active', the rest null). The only writer
|
|
@@ -116,17 +116,17 @@ function upsertRow(meta) {
|
|
|
116
116
|
function seedRow(meta) {
|
|
117
117
|
openDb()
|
|
118
118
|
.prepare(`INSERT INTO nodes
|
|
119
|
-
(node_id, name, kind, mode, lifecycle, cwd, host_kind, parent, created,
|
|
119
|
+
(node_id, name, kind, mode, lifecycle, cwd, host_kind, profile_id, parent, created,
|
|
120
120
|
status, intent, pi_pid, "window", tmux_session, pane)
|
|
121
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
121
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
122
122
|
ON CONFLICT(node_id) DO UPDATE SET
|
|
123
123
|
name=excluded.name, kind=excluded.kind, mode=excluded.mode,
|
|
124
124
|
lifecycle=excluded.lifecycle, cwd=excluded.cwd, host_kind=excluded.host_kind,
|
|
125
|
-
parent=excluded.parent,
|
|
125
|
+
profile_id=excluded.profile_id, parent=excluded.parent,
|
|
126
126
|
status=excluded.status, intent=excluded.intent, pi_pid=excluded.pi_pid,
|
|
127
127
|
"window"=excluded."window", tmux_session=excluded.tmux_session,
|
|
128
128
|
pane=excluded.pane`)
|
|
129
|
-
.run(meta.node_id, meta.name, meta.kind, meta.mode, meta.lifecycle, meta.cwd, meta.host_kind ?? null, meta.parent ?? null, meta.created, meta.status ?? 'active', meta.intent ?? null, meta.pi_pid ?? null, meta.window ?? null, meta.tmux_session ?? null, meta.pane ?? null);
|
|
129
|
+
.run(meta.node_id, meta.name, meta.kind, meta.mode, meta.lifecycle, meta.cwd, meta.host_kind ?? null, meta.profile_id ?? null, meta.parent ?? null, meta.created, meta.status ?? 'active', meta.intent ?? null, meta.pi_pid ?? null, meta.window ?? null, meta.tmux_session ?? null, meta.pane ?? null);
|
|
130
130
|
}
|
|
131
131
|
function rowFrom(r) {
|
|
132
132
|
return {
|
|
@@ -138,6 +138,7 @@ function rowFrom(r) {
|
|
|
138
138
|
status: r['status'],
|
|
139
139
|
cwd: r['cwd'],
|
|
140
140
|
host_kind: r['host_kind'] ?? null,
|
|
141
|
+
profile_id: r['profile_id'] ?? null,
|
|
141
142
|
parent: r['parent'] ?? null,
|
|
142
143
|
created: r['created'],
|
|
143
144
|
intent: r['intent'] ?? null,
|
package/dist/core/canvas/db.js
CHANGED
|
@@ -349,6 +349,16 @@ CREATE TABLE IF NOT EXISTS canvas_meta (
|
|
|
349
349
|
);
|
|
350
350
|
`);
|
|
351
351
|
}
|
|
352
|
+
/** v11 — additive identity column `profile_id`: the profile-directory id
|
|
353
|
+
* (`<slug>-<id>`) a node runs under, chosen once at spawn (inherited from the
|
|
354
|
+
* spawner, or `--profile`). Durable IDENTITY mirrored from meta.json like
|
|
355
|
+
* `cwd`/`host_kind` (NOT runtime like `pane`), so it survives an index rebuild
|
|
356
|
+
* via the `IDENTITY_KEYS`/`upsertRow` path. Defaults NULL (root/no-profile);
|
|
357
|
+
* no data backfill. Additive, forward-only. */
|
|
358
|
+
function addProfileIdColumn(db) {
|
|
359
|
+
const columns = nodeColumns(db);
|
|
360
|
+
addNodeColumnIfMissing(db, columns, 'profile_id', `ALTER TABLE nodes ADD COLUMN profile_id TEXT;`);
|
|
361
|
+
}
|
|
352
362
|
/** The ordered migration list. Index `i` is migration version `i + 1`; the db's
|
|
353
363
|
* `user_version` tracks how many have been applied. Append only. */
|
|
354
364
|
export const MIGRATIONS = [
|
|
@@ -362,6 +372,7 @@ export const MIGRATIONS = [
|
|
|
362
372
|
/* v8 */ addHostKindColumn,
|
|
363
373
|
/* v9 */ migrateWakeupsToTriggers,
|
|
364
374
|
/* v10 */ addCanvasMetaTable,
|
|
375
|
+
/* v11 */ addProfileIdColumn,
|
|
365
376
|
];
|
|
366
377
|
/** Bring `db` up to the latest schema version. Reads `user_version`, runs each
|
|
367
378
|
* pending migration in order, and bumps `user_version` after each so the work
|
|
@@ -404,6 +404,7 @@ export function nodeArtifacts(nodeId, types) {
|
|
|
404
404
|
status: node.status,
|
|
405
405
|
cwd: node.cwd,
|
|
406
406
|
host_kind: node.host_kind ?? null,
|
|
407
|
+
profile_id: node.profile_id ?? null,
|
|
407
408
|
parent: node.parent ?? null,
|
|
408
409
|
created: node.created,
|
|
409
410
|
intent: node.intent ?? null,
|
|
@@ -58,6 +58,13 @@ export interface NodeIdentity {
|
|
|
58
58
|
* `cwd`, re-derived on index rebuild), NOT live runtime like `pane`.
|
|
59
59
|
* NULL ⇒ 'tmux' (every pre-broker node). */
|
|
60
60
|
host_kind?: 'tmux' | 'broker' | null;
|
|
61
|
+
/** The profile this node runs under, a stable profile-directory id
|
|
62
|
+
* (`<slug>-<id>`, see `core/profiles/manifest.ts`). Durable IDENTITY mirrored
|
|
63
|
+
* to the row (like `cwd`/`host_kind`), NOT re-derived by `rebuildIndex()` —
|
|
64
|
+
* it is chosen once at spawn (inherited from the spawner, or `--profile`) and
|
|
65
|
+
* is the runtime→resolver seam (`CRTR_PROFILE_ID`) the memory/gate substrate
|
|
66
|
+
* reads. NULL for a root/no-profile node — never invent a literal root id. */
|
|
67
|
+
profile_id?: string | null;
|
|
61
68
|
/** Role the node was born as: explore | developer | plan | review | general… */
|
|
62
69
|
kind: string;
|
|
63
70
|
mode: Mode;
|
|
@@ -161,6 +168,9 @@ export interface NodeRow {
|
|
|
161
168
|
cwd: string;
|
|
162
169
|
/** Which HOST launches + supervises this node; see NodeIdentity.host_kind. */
|
|
163
170
|
host_kind: 'tmux' | 'broker' | null;
|
|
171
|
+
/** The profile this node runs under; see NodeIdentity.profile_id. NULL for a
|
|
172
|
+
* root/no-profile node. */
|
|
173
|
+
profile_id: string | null;
|
|
164
174
|
parent: string | null;
|
|
165
175
|
created: string;
|
|
166
176
|
/** Authoritative runtime columns (see NodeRuntime). */
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Scope, ScopeConfig, ScopeState } from '../types.js';
|
|
1
|
+
import type { Scope, ScopeConfig, ScopeState, KindConfig, ModelLaddersConfig } from '../types.js';
|
|
2
2
|
export declare function configPath(scope: Scope): string | null;
|
|
3
3
|
export declare function statePath(scope: Scope): string | null;
|
|
4
4
|
export declare function readConfig(scope: Scope): ScopeConfig;
|
|
@@ -6,5 +6,48 @@ export declare function readState(scope: Scope): ScopeState;
|
|
|
6
6
|
export declare function writeConfig(scope: Scope, config: ScopeConfig): void;
|
|
7
7
|
export declare function writeState(scope: Scope, state: ScopeState): void;
|
|
8
8
|
export declare function ensureScopeInitialized(scope: Scope, root: string): void;
|
|
9
|
+
export interface MergedLaunchConfig {
|
|
10
|
+
kinds: Record<string, KindConfig>;
|
|
11
|
+
modelLadders: ModelLaddersConfig;
|
|
12
|
+
}
|
|
13
|
+
/** Merge launch knobs (`kinds`, `modelLadders`) across scopes in
|
|
14
|
+
* project stack > profile > user > builtin precedence — the same precedence
|
|
15
|
+
* order used for memory resolution. A kind or ladder cell declared at a
|
|
16
|
+
* more-specific scope shadows the same key from a less-specific scope; the
|
|
17
|
+
* project STACK (`findProjectScopeRoots` — every ancestor `.crouter/`,
|
|
18
|
+
* widened by a selected profile's `projects`) layers nearest-root-strongest;
|
|
19
|
+
* a key no scope declares falls through to the builtin default registry
|
|
20
|
+
* (`defaultScopeConfig().kinds` / `.modelLadders`).
|
|
21
|
+
*
|
|
22
|
+
* Layers RAW (un-defaulted) partial config per scope, not `readConfig(scope)`
|
|
23
|
+
* — `readConfig` already fills in every default kind for a scope that
|
|
24
|
+
* customizes even one, so naively overlaying two already-defaulted
|
|
25
|
+
* `ScopeConfig.kinds` objects would let an untouched project-scope kind
|
|
26
|
+
* (silently defaulted) clobber a real user-scope customization of that same
|
|
27
|
+
* kind. Layering the raw partials avoids that.
|
|
28
|
+
*
|
|
29
|
+
* Callers (launch, kind registry) go through this function rather than
|
|
30
|
+
* `readConfig` directly, so `ScopeConfig.kinds`/`modelLadders`/tools/
|
|
31
|
+
* extensions/`availableTo` all honor the same profile + multi-project
|
|
32
|
+
* precedence. */
|
|
33
|
+
export declare function readMergedLaunchConfig(): MergedLaunchConfig;
|
|
34
|
+
/** The effective `KindConfig` for one full kind string (top-level, e.g.
|
|
35
|
+
* `developer`, or sub-kind, e.g. `plan/reviewers/security`), across
|
|
36
|
+
* project > user > builtin precedence. Returns `undefined` for a kind no
|
|
37
|
+
* scope registers — existence is deliberately NOT validated here (kind
|
|
38
|
+
* existence/launch-menu enumeration is a Phase 3 caller concern); this only
|
|
39
|
+
* resolves the config for a kind the caller already knows about. */
|
|
40
|
+
export declare function resolveKindConfig(kind: string): KindConfig | undefined;
|
|
41
|
+
/** The sub-kinds available to spawn FROM a given top-level kind — every
|
|
42
|
+
* registered sub-kind (full path contains `/`) whose `availableTo` (default:
|
|
43
|
+
* its own top-level ancestor, e.g. `plan/reviewers/security` defaults to
|
|
44
|
+
* `['plan']`) includes `kind` or `'*'`. The single source both `sys
|
|
45
|
+
* prompt-review --list`'s `subPersonas` metadata and the live sub-persona
|
|
46
|
+
* spawn-menu splice (`core/substrate/render.ts`) read, so the two can never
|
|
47
|
+
* drift apart. Sorted by full kind name for stable rendering. */
|
|
48
|
+
export declare function subKindsAvailableTo(kind: string): {
|
|
49
|
+
kind: string;
|
|
50
|
+
whenToUse: string;
|
|
51
|
+
}[];
|
|
9
52
|
export declare function updateConfig(scope: Scope, mutate: (cfg: ScopeConfig) => void): ScopeConfig;
|
|
10
53
|
export declare function updateState(scope: Scope, mutate: (s: ScopeState) => void): ScopeState;
|