@north-light/crouter 0.3.162 → 0.3.163
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/builtin-memory/00-runtime-base.md +1 -0
- package/dist/builtin-memory/04-orchestration-kernel.md +1 -0
- package/dist/builtin-memory/init.md +38 -0
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +2 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +0 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +34 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +14 -3
- package/dist/clients/attach/__tests__/crtr-output.test.js +14 -9
- package/dist/clients/attach/__tests__/edit-diff.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/edit-diff.test.js +34 -0
- package/dist/clients/attach/__tests__/editor-frame-title.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/editor-frame-title.test.js +19 -0
- package/dist/clients/attach/render/chat-view.js +8 -3
- package/dist/clients/attach/render/crtr-output.js +31 -2
- package/dist/clients/attach/render/edit-diff.js +26 -2
- package/dist/clients/attach/render/tool-calls.d.ts +7 -2
- package/dist/clients/attach/render/tool-calls.js +25 -4
- package/dist/clients/attach/session/connection.d.ts +1 -1
- package/dist/clients/attach/session/editor-frame.d.ts +5 -1
- package/dist/clients/attach/session/editor-frame.js +21 -15
- package/dist/clients/attach/session/identity.d.ts +1 -1
- package/dist/clients/attach/viewer.js +621 -619
- package/dist/commands/__tests__/api-canvas-source.test.d.ts +1 -0
- package/dist/commands/__tests__/api-canvas-source.test.js +37 -0
- package/dist/commands/__tests__/human.test.js +2 -0
- package/dist/commands/__tests__/search-contents.test.d.ts +1 -0
- package/dist/commands/__tests__/search-contents.test.js +52 -0
- package/dist/commands/api-client.js +1 -0
- package/dist/commands/human/prompts.js +2 -2
- package/dist/commands/human/shared.d.ts +1 -0
- package/dist/commands/human/shared.js +7 -4
- package/dist/commands/memory/lint.d.ts +6 -0
- package/dist/commands/memory/lint.js +177 -35
- package/dist/commands/memory/read.js +22 -1
- package/dist/commands/memory/write.js +18 -4
- package/dist/commands/memory.js +1 -1
- package/dist/commands/search/contents.js +2 -2
- package/dist/commands/sys/__tests__/sync-deps.test.js +12 -21
- package/dist/commands/sys/__tests__/sync-import.test.js +30 -29
- package/dist/commands/sys/setup-wizard.d.ts +8 -1
- package/dist/commands/sys/setup-wizard.js +209 -58
- package/dist/commands/sys/sync-deps.js +14 -18
- package/dist/commands/sys/sync-project-guidance.js +16 -19
- package/dist/core/__tests__/migration.test.js +8 -3
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +7 -10
- package/dist/core/__tests__/on-read-dedup-resume.test.js +13 -25
- package/dist/core/__tests__/on-read-identity.test.js +8 -15
- package/dist/core/__tests__/revive.test.js +2 -2
- package/dist/core/__tests__/tmux-surface.test.js +10 -4
- package/dist/core/__tests__/worktree.test.js +3 -3
- package/dist/core/canvas/extensions.d.ts +1 -1
- package/dist/core/canvas/extensions.js +18 -11
- package/dist/core/canvas/labels.d.ts +4 -5
- package/dist/core/canvas/labels.js +9 -9
- package/dist/core/command-manifests/schema.js +18 -5
- package/dist/core/command.js +17 -7
- package/dist/core/configured-clis/invoker.js +2 -0
- package/dist/core/help.d.ts +3 -1
- package/dist/core/help.js +5 -2
- package/dist/core/keybindings/__tests__/resolve.test.js +5 -2
- package/dist/core/keybindings/catalog.d.ts +3 -2
- package/dist/core/keybindings/catalog.js +34 -25
- package/dist/core/keybindings/index.d.ts +1 -1
- package/dist/core/keybindings/resolve.js +8 -0
- package/dist/core/keybindings/types.d.ts +6 -1
- package/dist/core/memory/doc-link-grammar.d.ts +20 -0
- package/dist/core/memory/doc-link-grammar.js +110 -0
- package/dist/core/memory-resolver.d.ts +5 -0
- package/dist/core/memory-resolver.js +12 -1
- package/dist/core/runtime/bearings.d.ts +8 -8
- package/dist/core/runtime/bearings.js +20 -16
- package/dist/core/runtime/broker.js +3 -13
- package/dist/core/runtime/canvas-extensions.d.ts +1 -0
- package/dist/core/runtime/canvas-extensions.js +2 -0
- package/dist/core/runtime/launch.d.ts +1 -1
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/tmux.js +136 -100
- package/dist/core/scope.js +4 -5
- package/dist/core/substrate/ceiling.d.ts +3 -6
- package/dist/core/substrate/ceiling.js +13 -15
- package/dist/core/substrate/index.d.ts +2 -3
- package/dist/core/substrate/index.js +2 -2
- package/dist/core/substrate/on-read.d.ts +4 -13
- package/dist/core/substrate/on-read.js +142 -262
- package/dist/core/substrate/render.js +4 -4
- package/dist/core/substrate/schema.d.ts +3 -2
- package/dist/core/substrate/schema.js +5 -5
- package/dist/pi-extensions/__tests__/canvas-tool-guide.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-tool-guide.test.js +96 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +7 -8
- package/dist/pi-extensions/canvas-tool-guide.d.ts +14 -0
- package/dist/pi-extensions/canvas-tool-guide.js +74 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crouter-help.ts +0 -95
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function binding(id, group, name, description, defaults, inputKind, contexts, safety) {
|
|
1
|
+
function binding(id, group, name, description, defaults, inputKind, contexts, safety, pair) {
|
|
2
2
|
return Object.freeze({
|
|
3
3
|
id,
|
|
4
4
|
group,
|
|
@@ -8,9 +8,18 @@ function binding(id, group, name, description, defaults, inputKind, contexts, sa
|
|
|
8
8
|
inputKind,
|
|
9
9
|
contexts: Object.freeze([...contexts]),
|
|
10
10
|
...(safety === undefined ? {} : { safety }),
|
|
11
|
+
...(pair === undefined ? {} : { pair: Object.freeze({ ...pair }) }),
|
|
11
12
|
});
|
|
12
13
|
}
|
|
13
14
|
const b = binding;
|
|
15
|
+
function menuEntry(action, name, description, defaults, contexts) {
|
|
16
|
+
const menuId = `crtr.tmux.menu.${action}`;
|
|
17
|
+
const globalId = `crtr.tmux.menu-global.${action}`;
|
|
18
|
+
return [
|
|
19
|
+
b(menuId, 'Global tmux', name, description, defaults, 'tmux-menu-selector', contexts, undefined, { field: 'menu', pairedId: globalId }),
|
|
20
|
+
b(globalId, 'Global tmux', name, description, [], 'tmux-global-action', ['tmux.root'], undefined, { field: 'global', pairedId: menuId }),
|
|
21
|
+
];
|
|
22
|
+
}
|
|
14
23
|
const ATTACH_CONTEXTS = ['attach', 'graph', 'graph.confirm'];
|
|
15
24
|
const VIEW_CONTEXTS = [
|
|
16
25
|
'view.canvas', 'view.chat', 'view.git-pr',
|
|
@@ -27,28 +36,28 @@ const SETUP_CANCEL_CONTEXTS = [
|
|
|
27
36
|
const SETUP_TAB_CONTEXTS = ['setup.login', 'setup.list', 'setup.keybindings', 'setup.models'];
|
|
28
37
|
export const BINDING_CATALOG = Object.freeze([
|
|
29
38
|
b('crtr.tmux.menu.open', 'Global tmux', 'Open crouter menu', 'Open the crouter action menu.', ['alt+c'], 'host-global', ['tmux.root']),
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
...menuEntry('promote', 'Promote node', 'Promote the focused node to orchestrator.', ['o'], ['tmux.menu']),
|
|
40
|
+
...menuEntry('resume', 'Resume node', 'Open the node resume picker.', ['r'], ['tmux.menu']),
|
|
41
|
+
...menuEntry('fork', 'Fork node', 'Fork the focused node into an independent idle root.', ['f'], ['tmux.menu']),
|
|
42
|
+
...menuEntry('demote', 'Demote node', 'Demote the focused node to terminal.', ['d'], ['tmux.menu']),
|
|
43
|
+
...menuEntry('detach', 'Detach node', 'Detach the focused node to the background.', ['shift+d'], ['tmux.menu']),
|
|
44
|
+
...menuEntry('close-subtree', 'Close subtree', 'Close the focused node and its subtree.', ['x'], ['tmux.menu']),
|
|
45
|
+
...menuEntry('background-bash', 'Background bash', 'Hand the focused node’s running bash command to its background job system.', ['b'], ['tmux.menu']),
|
|
46
|
+
...menuEntry('file-review', 'Review a file', 'Open a line-anchored review of a file named in the transcript.', ['v'], ['tmux.menu']),
|
|
47
|
+
...menuEntry('pin', 'Pin conversation', 'Pin or unpin this conversation in the canvas navigator.', ['shift+f'], ['tmux.menu']),
|
|
48
|
+
...menuEntry('show', 'Show node', 'Open the focused node’s inspection menu.', ['s'], ['tmux.menu']),
|
|
49
|
+
...menuEntry('view-settings', 'View settings', 'Open the viewer display-settings menu.', ['w'], ['tmux.menu']),
|
|
50
|
+
...menuEntry('fold-tools', 'Fold finished tool calls', 'Fold every finished tool call in the transcript to its single call line.', ['f'], ['tmux.menu.view-settings']),
|
|
51
|
+
...menuEntry('metadata', 'Show metadata', 'Show the focused node’s metadata dossier.', ['m'], ['tmux.menu.show']),
|
|
52
|
+
...menuEntry('context', 'Browse context', 'Browse the focused node context.', ['c'], ['tmux.menu.show']),
|
|
53
|
+
...menuEntry('providers', 'Open settings', 'Open the crouter settings panel.', ['p'], ['tmux.menu']),
|
|
54
|
+
...menuEntry('graph', 'Open graph', 'Open the canvas graph.', ['g'], ['tmux.menu']),
|
|
55
|
+
...menuEntry('focus-manager', 'Focus manager', 'Focus the node manager.', ['m'], ['tmux.menu']),
|
|
56
|
+
...menuEntry('copy-id', 'Copy node id', 'Copy the focused node id to the system clipboard.', ['y'], ['tmux.menu']),
|
|
57
|
+
...menuEntry('reload-viewer', 'Reload viewer', 'Respawn this pane’s viewer onto the current runtime generation.', ['l'], ['tmux.menu']),
|
|
58
|
+
...menuEntry('issues', 'Open issue menu', 'Open the issue type submenu.', ['i'], ['tmux.menu']),
|
|
59
|
+
...menuEntry('issue.idea', 'Create idea', 'Create an idea issue.', ['i'], ['tmux.menu.issue']),
|
|
60
|
+
...menuEntry('issue.bug', 'Create bug', 'Create a bug issue.', ['b'], ['tmux.menu.issue']),
|
|
52
61
|
b('crtr.tmux.node.next', 'Global tmux', 'Next node', 'Focus the next canvas node.', ['alt+]'], 'host-global', ['tmux.root']),
|
|
53
62
|
b('crtr.tmux.node.previous', 'Global tmux', 'Previous node', 'Focus the previous canvas node.', ['alt+['], 'host-global', ['tmux.root']),
|
|
54
63
|
b('crtr.tmux.inbox.toggle', 'Global tmux', 'Toggle inbox', 'Open or close the human inbox popup.', ['alt+i'], 'host-global', ['tmux.root']),
|
|
@@ -244,8 +253,8 @@ function setupBindings() {
|
|
|
244
253
|
b('crtr.setup.keybindings.filter', 'Setup', 'Filter bindings', 'Open the keybinding filter.', ['/'], 'terminal', ['setup.keybindings']),
|
|
245
254
|
b('crtr.setup.keybindings.filter-delete', 'Setup', 'Delete filter text', 'Delete the previous filter character.', ['backspace'], 'terminal', ['setup.keybindings.filter']),
|
|
246
255
|
b('crtr.setup.keybindings.filter-clear', 'Setup', 'Clear filter', 'Clear the keybinding filter.', ['escape'], 'terminal', ['setup.keybindings.filter'], 'dismiss-modal'),
|
|
247
|
-
b('crtr.setup.cell-previous', 'Setup', 'Previous
|
|
248
|
-
b('crtr.setup.cell-next', 'Setup', 'Next
|
|
256
|
+
b('crtr.setup.cell-previous', 'Setup', 'Previous field', 'Select the previous field or setup table cell.', ['h'], 'terminal', ['setup.models', 'setup.keybindings']),
|
|
257
|
+
b('crtr.setup.cell-next', 'Setup', 'Next field', 'Select the next field or setup table cell.', ['l'], 'terminal', ['setup.models', 'setup.keybindings']),
|
|
249
258
|
b('crtr.setup.models.open', 'Setup', 'Edit model', 'Edit the selected model cell.', ['enter'], 'terminal', ['setup.models']),
|
|
250
259
|
b('crtr.setup.models.scope-next', 'Setup', 'Next model config scope', 'Edit the next applicable user, profile, or project config.', ['s'], 'terminal', ['setup.models']),
|
|
251
260
|
b('crtr.setup.models.commit', 'Setup', 'Commit pick', 'Commit the provider, strength, model, or thinking-level pick.', ['enter'], 'terminal', ['setup.models.picker', 'setup.models.dimension-picker']),
|
|
@@ -4,4 +4,4 @@ export { canonicalTerminalStroke, formatBinding, formatGesture, formatStroke, ma
|
|
|
4
4
|
export { inboxOpenHint, inboxOpenInstruction, inboxPopupHint, inboxShortcut, } from './inbox.js';
|
|
5
5
|
export { backgroundBashHint, backgroundBashShortcut, } from './background-bash.js';
|
|
6
6
|
export { KeybindingConcurrentEditError, persistUserKeybindings, type PersistedKeybindings, type PersistKeybindingsOptions, } from './persistence.js';
|
|
7
|
-
export type { BindingDefinition, BindingInputKind, BindingResolution, BindingSafetyCapability, EffectiveBinding, KeybindingDiagnostic, KeybindingDiagnosticCode, SafetyRequirement, SparseKeybindingOverrides, } from './types.js';
|
|
7
|
+
export type { BindingDefinition, BindingInputKind, BindingPair, BindingResolution, BindingSafetyCapability, EffectiveBinding, KeybindingDiagnostic, KeybindingDiagnosticCode, SafetyRequirement, SparseKeybindingOverrides, } from './types.js';
|
|
@@ -121,6 +121,14 @@ export function normalizeGesture(raw, definition) {
|
|
|
121
121
|
throw new GestureSyntaxError('a menu selector must be one printable character');
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
+
if (definition?.inputKind === 'tmux-global-action') {
|
|
125
|
+
if (normalized.length !== 1)
|
|
126
|
+
throw new GestureSyntaxError('a global menu shortcut must be one stroke');
|
|
127
|
+
const modifiers = normalized[0].split('+').slice(0, -1);
|
|
128
|
+
if (!modifiers.includes('ctrl') && !modifiers.includes('alt')) {
|
|
129
|
+
throw new GestureSyntaxError('a global menu shortcut must include Ctrl or Alt');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
124
132
|
return normalized.join(' > ');
|
|
125
133
|
}
|
|
126
134
|
function normalizeList(raw, definition) {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export type BindingInputKind = 'terminal' | 'tmux-sequence' | 'tmux-menu-selector' | 'host-global';
|
|
1
|
+
export type BindingInputKind = 'terminal' | 'tmux-sequence' | 'tmux-menu-selector' | 'tmux-global-action' | 'host-global';
|
|
2
|
+
export interface BindingPair {
|
|
3
|
+
readonly field: 'menu' | 'global';
|
|
4
|
+
readonly pairedId: string;
|
|
5
|
+
}
|
|
2
6
|
export type BindingSafetyCapability = 'dismiss-modal' | 'leave-screen' | 'save-keybindings';
|
|
3
7
|
export interface BindingDefinition<Id extends string = string> {
|
|
4
8
|
readonly id: Id;
|
|
@@ -9,6 +13,7 @@ export interface BindingDefinition<Id extends string = string> {
|
|
|
9
13
|
readonly inputKind: BindingInputKind;
|
|
10
14
|
readonly contexts: readonly string[];
|
|
11
15
|
readonly safety?: BindingSafetyCapability;
|
|
16
|
+
readonly pair?: BindingPair;
|
|
12
17
|
}
|
|
13
18
|
export interface EffectiveBinding<Id extends string = string> {
|
|
14
19
|
readonly definition: BindingDefinition<Id>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** One `[[name]]` link occurrence found in a document body. */
|
|
2
|
+
export interface DocLink {
|
|
3
|
+
/** Character index of the first `[` of `[[`. */
|
|
4
|
+
start: number;
|
|
5
|
+
/** Character index just past the closing `]]`. */
|
|
6
|
+
end: number;
|
|
7
|
+
/** The canonical document name between the brackets. */
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
/** Is `name` a well-formed canonical doc-link name? */
|
|
11
|
+
export declare function isDocLinkName(name: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Find every `[[name]]` doc link in a markdown body, in order of appearance,
|
|
14
|
+
* skipping fenced code blocks and inline code spans (a link mentioned inside
|
|
15
|
+
* code is an example, not a reference). Occurrences are NOT deduplicated —
|
|
16
|
+
* callers collapse as needed.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findDocLinks(body: string): DocLink[];
|
|
19
|
+
/** The distinct link names in a body, first-appearance order. */
|
|
20
|
+
export declare function docLinkNames(body: string): string[];
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// doc-link-grammar.ts — the single source of truth for the `[[canonical/name]]`
|
|
2
|
+
// memory-document link grammar. Zero imports, pure string ops, browser-safe —
|
|
3
|
+
// any surface that highlights, resolves, or lints doc links imports THIS module
|
|
4
|
+
// rather than re-implementing the bracket scan or the name shape.
|
|
5
|
+
//
|
|
6
|
+
// A doc link is a durable cross-reference written INSIDE a memory document's
|
|
7
|
+
// body, pointing at another memory document by its exact canonical name (the
|
|
8
|
+
// same identifier `crtr memory read <name>` takes; a directory INDEX is linked
|
|
9
|
+
// by its folded bare-directory name). It is distinct from the interactive
|
|
10
|
+
// `/name` inline-reference grammar (`inline-ref-grammar.ts`), which scans a
|
|
11
|
+
// human's live composer text — links live in stored markdown and survive there.
|
|
12
|
+
//
|
|
13
|
+
// Links are POINTERS, never transclusion: nothing in the runtime auto-loads a
|
|
14
|
+
// linked body into context. `crtr memory lint` fails a link that resolves to no
|
|
15
|
+
// document; `crtr memory read` surfaces the resolved links of the doc it loads.
|
|
16
|
+
//
|
|
17
|
+
// This module never resolves anything: `findDocLinks` returns candidate links;
|
|
18
|
+
// a caller decides a link is live by testing `name` against the corpus of
|
|
19
|
+
// resolvable canonical names.
|
|
20
|
+
// A canonical doc name: one or more `[A-Za-z0-9_-]+` segments joined by `/`.
|
|
21
|
+
// Anything else between `[[` `]]` (spaces, `|` aliases, empty segments) is NOT
|
|
22
|
+
// a doc link — the grammar has no alias/label form, by design.
|
|
23
|
+
const NAME_RE = /^[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/;
|
|
24
|
+
const LINK_RE = /\[\[([^\[\]\n]+)\]\]/g;
|
|
25
|
+
/** Is `name` a well-formed canonical doc-link name? */
|
|
26
|
+
export function isDocLinkName(name) {
|
|
27
|
+
return NAME_RE.test(name);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Find every `[[name]]` doc link in a markdown body, in order of appearance,
|
|
31
|
+
* skipping fenced code blocks and inline code spans (a link mentioned inside
|
|
32
|
+
* code is an example, not a reference). Occurrences are NOT deduplicated —
|
|
33
|
+
* callers collapse as needed.
|
|
34
|
+
*/
|
|
35
|
+
export function findDocLinks(body) {
|
|
36
|
+
const links = [];
|
|
37
|
+
for (const segment of proseSegments(body)) {
|
|
38
|
+
LINK_RE.lastIndex = 0;
|
|
39
|
+
let m;
|
|
40
|
+
while ((m = LINK_RE.exec(segment.text)) !== null) {
|
|
41
|
+
const name = m[1];
|
|
42
|
+
if (!isDocLinkName(name))
|
|
43
|
+
continue;
|
|
44
|
+
links.push({ start: segment.offset + m.index, end: segment.offset + m.index + m[0].length, name });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return links;
|
|
48
|
+
}
|
|
49
|
+
/** The distinct link names in a body, first-appearance order. */
|
|
50
|
+
export function docLinkNames(body) {
|
|
51
|
+
const seen = new Set();
|
|
52
|
+
const out = [];
|
|
53
|
+
for (const link of findDocLinks(body)) {
|
|
54
|
+
if (seen.has(link.name))
|
|
55
|
+
continue;
|
|
56
|
+
seen.add(link.name);
|
|
57
|
+
out.push(link.name);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
const FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;
|
|
62
|
+
function* proseSegments(body) {
|
|
63
|
+
let offset = 0;
|
|
64
|
+
let fence = null; // the opening fence marker while inside a block
|
|
65
|
+
for (const line of body.split('\n')) {
|
|
66
|
+
const lineLen = line.length + 1; // + '\n' (harmless overcount on last line)
|
|
67
|
+
const fenceMatch = line.match(FENCE_RE);
|
|
68
|
+
if (fence !== null) {
|
|
69
|
+
// Inside a fenced block: only a closing fence of the same char and at
|
|
70
|
+
// least the same length ends it. Nothing in here is prose.
|
|
71
|
+
if (fenceMatch && fenceMatch[1][0] === fence[0] && fenceMatch[1].length >= fence.length) {
|
|
72
|
+
fence = null;
|
|
73
|
+
}
|
|
74
|
+
offset += lineLen;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (fenceMatch) {
|
|
78
|
+
fence = fenceMatch[1];
|
|
79
|
+
offset += lineLen;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
// Prose line: split around inline code spans (single-backtick pairs).
|
|
83
|
+
yield* proseParts(line, offset);
|
|
84
|
+
offset += lineLen;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function* proseParts(line, offset) {
|
|
88
|
+
let i = 0;
|
|
89
|
+
while (i < line.length) {
|
|
90
|
+
const open = line.indexOf('`', i);
|
|
91
|
+
if (open === -1) {
|
|
92
|
+
yield { offset: offset + i, text: line.slice(i) };
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Backtick run: an inline span is delimited by runs of equal length.
|
|
96
|
+
let runEnd = open;
|
|
97
|
+
while (runEnd < line.length && line[runEnd] === '`')
|
|
98
|
+
runEnd++;
|
|
99
|
+
const run = line.slice(open, runEnd);
|
|
100
|
+
const close = line.indexOf(run, runEnd);
|
|
101
|
+
if (close === -1) {
|
|
102
|
+
// Unbalanced backticks: treat the rest as prose past the run.
|
|
103
|
+
yield { offset: offset + i, text: line.slice(i, open) };
|
|
104
|
+
i = runEnd;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
yield { offset: offset + i, text: line.slice(i, open) };
|
|
108
|
+
i = close + run.length;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -70,6 +70,11 @@ export declare function listMemoryDocs(scope: MemoryScope, quiet?: boolean): Mem
|
|
|
70
70
|
* doc's name exactly as `listMemoryDocs` does (path-relative, no extension,
|
|
71
71
|
* slash-separated) then prefixing the plugin name. Builtin has no plugins. */
|
|
72
72
|
export declare function listPluginMemoryDocs(plugin: InstalledPlugin, scope: MemoryScope, quiet?: boolean): MemoryDoc[];
|
|
73
|
+
/** All project-scoped docs visible from an explicit node workspace/profile.
|
|
74
|
+
* This target-addressed form is used when one process serves several nodes
|
|
75
|
+
* (notably warm-spare claims), where ambient cwd/profile belong to the host
|
|
76
|
+
* process rather than the node whose first-message context is being built. */
|
|
77
|
+
export declare function listProjectMemoryDocs(startDir?: string, profileId?: string | null, quiet?: boolean): MemoryDoc[];
|
|
73
78
|
/** All memory docs across the resolved sources, in precedence order: each
|
|
74
79
|
* ancestor project `.crouter/` from nearest to farthest, then the selected
|
|
75
80
|
* profile's memory (if any), then user, then builtin. Within each source,
|
|
@@ -158,7 +158,7 @@ function listMemoryDocsInDir(scope, dir, quiet = false) {
|
|
|
158
158
|
* through `loadProfileManifest`; user and builtin are singleton stores. */
|
|
159
159
|
export function listMemoryDocs(scope, quiet = false) {
|
|
160
160
|
if (scope === 'project') {
|
|
161
|
-
return
|
|
161
|
+
return listProjectMemoryDocs(process.cwd(), selectedProfileId() || null, quiet);
|
|
162
162
|
}
|
|
163
163
|
if (scope === 'profile') {
|
|
164
164
|
const profileId = selectedProfileId();
|
|
@@ -215,6 +215,17 @@ function sourceMemoryDocs(source, quiet = false) {
|
|
|
215
215
|
...source.plugins.flatMap((p) => listPluginMemoryDocs(p, source.scope, quiet)),
|
|
216
216
|
];
|
|
217
217
|
}
|
|
218
|
+
/** All project-scoped docs visible from an explicit node workspace/profile.
|
|
219
|
+
* This target-addressed form is used when one process serves several nodes
|
|
220
|
+
* (notably warm-spare claims), where ambient cwd/profile belong to the host
|
|
221
|
+
* process rather than the node whose first-message context is being built. */
|
|
222
|
+
export function listProjectMemoryDocs(startDir = process.cwd(), profileId = selectedProfileId() || null, quiet = false) {
|
|
223
|
+
return projectScopeRoots(startDir, profileId).flatMap((root) => sourceMemoryDocs({
|
|
224
|
+
scope: 'project',
|
|
225
|
+
memoryDir: join(root, 'memory'),
|
|
226
|
+
plugins: listInstalledPluginsInRoot('project', root).filter((plugin) => plugin.enabled),
|
|
227
|
+
}, quiet));
|
|
228
|
+
}
|
|
218
229
|
/** All memory docs across the resolved sources, in precedence order: each
|
|
219
230
|
* ancestor project `.crouter/` from nearest to farthest, then the selected
|
|
220
231
|
* profile's memory (if any), then user, then builtin. Within each source,
|
|
@@ -88,12 +88,12 @@ export declare function buildWakeBearings(origin: WakeOrigin): string;
|
|
|
88
88
|
* note. The across-cycles context-dir framing is added ONLY for an
|
|
89
89
|
* orchestrator (by mode) — the one node whose dir a future cycle resumes
|
|
90
90
|
* from.
|
|
91
|
-
* 2. `<memory kind="knowledge">` — the consultable catalog, a SIBLING of
|
|
92
|
-
* bearings (never nested under the context dir). Dropped when empty.
|
|
93
|
-
* 3. `<
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
91
|
+
* 2. `<memory kind="knowledge">` — the consultable boot catalog, a SIBLING of
|
|
92
|
+
* the bearings (never nested under the context dir). Dropped when empty.
|
|
93
|
+
* 3. `<auto-loaded-context>` — memories whose `applies-to: "."` fires because
|
|
94
|
+
* cwd/profile mounted their owning project store. Dropped when empty.
|
|
95
|
+
* 4. `<project_context>` — the cwd/git environment snapshot. pi's own
|
|
96
|
+
* AGENTS.md/CLAUDE.md injection stays suppressed (`noContextFiles` in
|
|
97
|
+
* broker.ts); `crtr sys sync project-guidance` imports that guidance into
|
|
98
|
+
* the directory's `.crouter/memory/INDEX.md` front door. */
|
|
99
99
|
export declare function buildContextBearings(nodeId: string): string;
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
// carries the <project_context> block (buildProjectContextBlock), which is
|
|
17
17
|
// now only the <environment> snapshot: a host/runtime line (platform,
|
|
18
18
|
// hostname, node, tmux-or-not), the cwd dir listing, and git status.
|
|
19
|
-
// Project guidance rides the
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// <memory kind="knowledge">
|
|
23
|
-
//
|
|
24
|
-
//
|
|
19
|
+
// Project guidance rides the document substrate instead: a workspace's
|
|
20
|
+
// `.crouter/memory/INDEX.md` declares `applies-to: "."` and surfaces through
|
|
21
|
+
// an <auto-loaded-context> block when cwd/profile mounts that workspace;
|
|
22
|
+
// ordinary boot-routed knowledge remains in the <memory kind="knowledge">
|
|
23
|
+
// block below. No parallel project-context loader lives here (see
|
|
24
|
+
// `crtr memory read taste/document-substrate`);
|
|
25
25
|
// • promote.ts folds orchestratorContextNote() into the promotion guidance
|
|
26
26
|
// dump, so a node that becomes an orchestrator MID-LIFE gets the
|
|
27
27
|
// orchestrator framing it never received at spawn — it spawned as a base
|
|
@@ -45,7 +45,7 @@ import { readdirSync } from 'node:fs';
|
|
|
45
45
|
import { spawnSync } from 'node:child_process';
|
|
46
46
|
import { hostname } from 'node:os';
|
|
47
47
|
import { cadenceDisplay } from '../wake.js';
|
|
48
|
-
import { renderKnowledgeBlock } from '../substrate/index.js';
|
|
48
|
+
import { renderKnowledgeBlock, renderWorkspaceOpenDocs } from '../substrate/index.js';
|
|
49
49
|
import { loadProfileManifest } from '../profiles/manifest.js';
|
|
50
50
|
import { situationalContextBlock } from './situational-context.js';
|
|
51
51
|
function escapeAttribute(value) {
|
|
@@ -391,14 +391,14 @@ export function buildWakeBearings(origin) {
|
|
|
391
391
|
* note. The across-cycles context-dir framing is added ONLY for an
|
|
392
392
|
* orchestrator (by mode) — the one node whose dir a future cycle resumes
|
|
393
393
|
* from.
|
|
394
|
-
* 2. `<memory kind="knowledge">` — the consultable catalog, a SIBLING of
|
|
395
|
-
* bearings (never nested under the context dir). Dropped when empty.
|
|
396
|
-
* 3. `<
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
394
|
+
* 2. `<memory kind="knowledge">` — the consultable boot catalog, a SIBLING of
|
|
395
|
+
* the bearings (never nested under the context dir). Dropped when empty.
|
|
396
|
+
* 3. `<auto-loaded-context>` — memories whose `applies-to: "."` fires because
|
|
397
|
+
* cwd/profile mounted their owning project store. Dropped when empty.
|
|
398
|
+
* 4. `<project_context>` — the cwd/git environment snapshot. pi's own
|
|
399
|
+
* AGENTS.md/CLAUDE.md injection stays suppressed (`noContextFiles` in
|
|
400
|
+
* broker.ts); `crtr sys sync project-guidance` imports that guidance into
|
|
401
|
+
* the directory's `.crouter/memory/INDEX.md` front door. */
|
|
402
402
|
export function buildContextBearings(nodeId) {
|
|
403
403
|
const node = getNode(nodeId);
|
|
404
404
|
const bearings = ['<crtr-bearings>', buildIdentityAssertion(nodeId)];
|
|
@@ -420,10 +420,14 @@ export function buildContextBearings(nodeId) {
|
|
|
420
420
|
bearings.push('</crtr-bearings>');
|
|
421
421
|
// The consultable catalog rides BESIDE the bearings, not inside them.
|
|
422
422
|
const knowledge = renderKnowledgeBlock(nodeId);
|
|
423
|
+
// A workspace mount is the initial read of its root (`applies-to: "."`).
|
|
424
|
+
const workspaceContext = renderWorkspaceOpenDocs(nodeId);
|
|
423
425
|
// Hidden applet/situation-origin ambient context (see situational-context.ts)
|
|
424
426
|
// — a SIBLING block, never nested under <crtr-bearings>, and never routed
|
|
425
427
|
// through the visible chat/digest path. '' when nothing was ever set.
|
|
426
428
|
const situational = situationalContextBlock(nodeId);
|
|
427
429
|
const projectCtx = node?.cwd !== undefined ? buildProjectContextBlock(node.cwd) : '';
|
|
428
|
-
return [bearings.join('\n'), knowledge, situational, projectCtx]
|
|
430
|
+
return [bearings.join('\n'), knowledge, workspaceContext, situational, projectCtx]
|
|
431
|
+
.filter((s) => s !== '')
|
|
432
|
+
.join('\n');
|
|
429
433
|
}
|
|
@@ -3117,15 +3117,6 @@ export async function buildBrokerSession(engine, cfg) {
|
|
|
3117
3117
|
// model comes from a custom-provider extension would get NO model. Mirrors pi
|
|
3118
3118
|
// main.js (createAgentSessionServices → …FromServices).
|
|
3119
3119
|
//
|
|
3120
|
-
// C4 note: the pinned SDK (0.78.1) has NO project-trust concept at all —
|
|
3121
|
-
// project context files (AGENTS.md/CLAUDE.md) load UNCONDITIONALLY (gated
|
|
3122
|
-
// only by `noContextFiles`, left default-false), so the headless "trust
|
|
3123
|
-
// resolves false → context silently dropped" gap cannot occur here. WHEN the
|
|
3124
|
-
// SDK pin bumps to 0.79.0+ (which adds project-trust), pass an explicit
|
|
3125
|
-
// `settingsManager: SettingsManager.create(cfg.cwd, getAgentDir(), { projectTrusted: true })`
|
|
3126
|
-
// so headless trust defaults TRUSTED — and do NOT re-introduce the CLI's
|
|
3127
|
-
// resolveProjectTrust, which returns false with no TTY.
|
|
3128
|
-
//
|
|
3129
3120
|
// T3 session-rebind: services + model + session creation is factored into
|
|
3130
3121
|
// `buildForManager` so it can serve BOTH the initial boot AND the
|
|
3131
3122
|
// AgentSessionRuntime factory it is reused as below (new_session/
|
|
@@ -3152,10 +3143,9 @@ export async function buildBrokerSession(engine, cfg) {
|
|
|
3152
3143
|
additionalExtensionPaths: cfg.extensionPaths,
|
|
3153
3144
|
appendSystemPrompt: cfg.appendSystemPromptPath !== undefined ? [cfg.appendSystemPromptPath] : undefined,
|
|
3154
3145
|
// Suppress pi's <project_context> AGENTS.md/CLAUDE.md injection in the
|
|
3155
|
-
//
|
|
3156
|
-
//
|
|
3157
|
-
//
|
|
3158
|
-
// bearings.ts and `crtr sys sync project-guidance`), never pi's own file-based loader.
|
|
3146
|
+
// system prompt. crouter imports either source into the project's root
|
|
3147
|
+
// memory INDEX and surfaces that front door in first-message context;
|
|
3148
|
+
// pi's file-based loader is not a second guidance path.
|
|
3159
3149
|
noContextFiles: true,
|
|
3160
3150
|
},
|
|
3161
3151
|
});
|
|
@@ -4,6 +4,7 @@ export declare const CANVAS_RECAP_PATH: string;
|
|
|
4
4
|
export declare const CANVAS_GOAL_CAPTURE_PATH: string;
|
|
5
5
|
export declare const CANVAS_PASSIVE_CONTEXT_PATH: string;
|
|
6
6
|
export declare const CANVAS_CONTEXT_INTRO_PATH: string;
|
|
7
|
+
export declare const CANVAS_TOOL_GUIDE_PATH: string;
|
|
7
8
|
export declare const CANVAS_DOC_SUBSTRATE_PATH: string;
|
|
8
9
|
export declare const CANVAS_STRUCTURED_OUTPUT_PATH: string;
|
|
9
10
|
export declare const CANVAS_BASH_VALVE_PATH: string;
|
|
@@ -16,6 +16,7 @@ export const CANVAS_RECAP_PATH = resolveExtension('canvas-recap');
|
|
|
16
16
|
export const CANVAS_GOAL_CAPTURE_PATH = resolveExtension('canvas-goal-capture');
|
|
17
17
|
export const CANVAS_PASSIVE_CONTEXT_PATH = resolveExtension('canvas-passive-context');
|
|
18
18
|
export const CANVAS_CONTEXT_INTRO_PATH = resolveExtension('canvas-context-intro');
|
|
19
|
+
export const CANVAS_TOOL_GUIDE_PATH = resolveExtension('canvas-tool-guide');
|
|
19
20
|
export const CANVAS_DOC_SUBSTRATE_PATH = resolveExtension('canvas-doc-substrate');
|
|
20
21
|
export const CANVAS_STRUCTURED_OUTPUT_PATH = resolveExtension('canvas-structured-output');
|
|
21
22
|
export const CANVAS_BASH_VALVE_PATH = resolveExtension('canvas-bash-valve');
|
|
@@ -32,6 +33,7 @@ export const CANVAS_EXTENSIONS = [
|
|
|
32
33
|
CANVAS_GOAL_CAPTURE_PATH,
|
|
33
34
|
CANVAS_PASSIVE_CONTEXT_PATH,
|
|
34
35
|
CANVAS_CONTEXT_INTRO_PATH,
|
|
36
|
+
CANVAS_TOOL_GUIDE_PATH,
|
|
35
37
|
CANVAS_DOC_SUBSTRATE_PATH,
|
|
36
38
|
CANVAS_STRUCTURED_OUTPUT_PATH,
|
|
37
39
|
CANVAS_BASH_VALVE_PATH,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CANVAS_EXTENSIONS, CANVAS_STOPHOOK_PATH, CANVAS_INBOX_WATCHER_PATH, CANVAS_RECAP_PATH, CANVAS_GOAL_CAPTURE_PATH, CANVAS_PASSIVE_CONTEXT_PATH, CANVAS_CONTEXT_INTRO_PATH, CANVAS_DOC_SUBSTRATE_PATH, CANVAS_STRUCTURED_OUTPUT_PATH, CANVAS_BASH_VALVE_PATH, } from './canvas-extensions.js';
|
|
1
|
+
export { CANVAS_EXTENSIONS, CANVAS_STOPHOOK_PATH, CANVAS_INBOX_WATCHER_PATH, CANVAS_RECAP_PATH, CANVAS_GOAL_CAPTURE_PATH, CANVAS_PASSIVE_CONTEXT_PATH, CANVAS_CONTEXT_INTRO_PATH, CANVAS_TOOL_GUIDE_PATH, CANVAS_DOC_SUBSTRATE_PATH, CANVAS_STRUCTURED_OUTPUT_PATH, CANVAS_BASH_VALVE_PATH, } from './canvas-extensions.js';
|
|
2
2
|
import type { NodeMeta, LaunchSpec, Mode, Lifecycle } from '../canvas/index.js';
|
|
3
3
|
import type { ModelProvider, ModelStrength, ScopeConfig } from '../../types.js';
|
|
4
4
|
export { OPENAI_PROVIDER_ENV, configuredLadderProviders, inferPortableModelSelection } from './model-selection.js';
|
|
@@ -14,7 +14,7 @@ import { readMergedLaunchConfig } from '../config.js';
|
|
|
14
14
|
import { LAUNCH_SYSTEM_PROMPT } from './launch-prompt.js';
|
|
15
15
|
import { nodeEnv } from './nodes.js';
|
|
16
16
|
import { editorLabel } from '../canvas/index.js';
|
|
17
|
-
export { CANVAS_EXTENSIONS, CANVAS_STOPHOOK_PATH, CANVAS_INBOX_WATCHER_PATH, CANVAS_RECAP_PATH, CANVAS_GOAL_CAPTURE_PATH, CANVAS_PASSIVE_CONTEXT_PATH, CANVAS_CONTEXT_INTRO_PATH, CANVAS_DOC_SUBSTRATE_PATH, CANVAS_STRUCTURED_OUTPUT_PATH, CANVAS_BASH_VALVE_PATH, } from './canvas-extensions.js';
|
|
17
|
+
export { CANVAS_EXTENSIONS, CANVAS_STOPHOOK_PATH, CANVAS_INBOX_WATCHER_PATH, CANVAS_RECAP_PATH, CANVAS_GOAL_CAPTURE_PATH, CANVAS_PASSIVE_CONTEXT_PATH, CANVAS_CONTEXT_INTRO_PATH, CANVAS_TOOL_GUIDE_PATH, CANVAS_DOC_SUBSTRATE_PATH, CANVAS_STRUCTURED_OUTPUT_PATH, CANVAS_BASH_VALVE_PATH, } from './canvas-extensions.js';
|
|
18
18
|
import { nodeDir } from '../canvas/paths.js';
|
|
19
19
|
import { CANVAS_EXTENSIONS, mergeCanvasExtensions, assertMandatoryCanvasExtensions } from './canvas-extensions.js';
|
|
20
20
|
import { modelLadders, defaultProvider, STRENGTH_ALIASES, MODEL_PROVIDER_KEYS, MODEL_STRENGTHS, THINKING_SUFFIXES, stripThinkingSuffix, } from './model-selection.js';
|