@crouton-kit/crouter 0.3.46 → 0.3.48

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.
@@ -13,10 +13,15 @@
13
13
  // the source's whole conversation and then impersonates it. A non-fork
14
14
  // node's bearings are its FIRST entry, so there is nothing earlier to
15
15
  // disown; it gets only the declarative identity line. The message also
16
- // carries the <project_context> block (buildProjectContextBlock) — the
17
- // AGENTS.md/CLAUDE.md project instructions, moved OUT of the system prompt
18
- // (pi's copy is suppressed via noContextFiles in broker.ts) so they ride
19
- // this user message instead;
16
+ // carries the <project_context> block (buildProjectContextBlock) — now just
17
+ // the cwd/git <environment> snapshot. Project instructions (what used to be
18
+ // a re-rendered AGENTS.md/CLAUDE.md here) come from the document substrate
19
+ // instead: `crtr sys sync` migrates each CLAUDE.md/AGENTS.md into that
20
+ // dir's own `.crouter/memory/AGENTS.md` at content/content, so it rides the
21
+ // <memory kind="knowledge"> block below (renderKnowledgeBlock) via the
22
+ // profile-widened boot render, exactly like any other substrate doc — no
23
+ // parallel re-implementation of pi's project-context loader lives here
24
+ // anymore (see `crtr memory read taste/document-substrate`);
20
25
  // • promote.ts folds orchestratorContextNote() into the promotion guidance
21
26
  // dump, so a node that becomes an orchestrator MID-LIFE gets the
22
27
  // orchestrator framing it never received at spawn — it spawned as a base
@@ -36,78 +41,10 @@
36
41
  // This across-cycles note is the ONE thing a terminal worker's bearings drop.
37
42
  import { contextDir, getNode, fullName, subscriptionsOf, } from '../canvas/index.js';
38
43
  import { execSync } from 'node:child_process';
39
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
40
- import { homedir } from 'node:os';
41
- import { join, resolve } from 'node:path';
44
+ import { readdirSync } from 'node:fs';
42
45
  import { cadenceDisplay } from '../wake.js';
43
46
  import { renderKnowledgeBlock } from '../substrate/index.js';
44
47
  import { loadProfileManifest } from '../profiles/manifest.js';
45
- // ---------------------------------------------------------------------------
46
- // Project context (<project_context>) — the AGENTS.md/CLAUDE.md files pi would
47
- // otherwise inject into its SYSTEM PROMPT, rendered here so they ride the
48
- // first-message bearings instead (pi's copy is suppressed via
49
- // resourceLoaderOptions.noContextFiles in broker.ts). We re-implement pi's
50
- // loadProjectContextFiles + getAgentDir (resource-loader.js / config.js) rather
51
- // than IMPORT pi: bearings.ts is statically imported by the thin daemon (crtrd,
52
- // for wakeOriginFrom), so a static @earendil-works import would pull the whole
53
- // pi engine into the supervisor. The discovery is a stable convention + pure fs.
54
- // ---------------------------------------------------------------------------
55
- /** pi's getAgentDir(): the global agent config dir holding a user-wide context
56
- * file. Honors PI_CODING_AGENT_DIR (tilde-expanded), else ~/.pi/agent (pi's
57
- * piConfig.configDir is ".pi"). */
58
- function piAgentDir() {
59
- const env = process.env['PI_CODING_AGENT_DIR'];
60
- if (env !== undefined && env !== '') {
61
- return env.startsWith('~') ? join(homedir(), env.slice(1)) : env;
62
- }
63
- return join(homedir(), '.pi', 'agent');
64
- }
65
- /** Per-dir context-file candidates, in pi's precedence order (first match wins). */
66
- const CONTEXT_FILE_CANDIDATES = ['AGENTS.md', 'AGENTS.MD', 'CLAUDE.md', 'CLAUDE.MD'];
67
- function loadContextFileFromDir(dir) {
68
- for (const name of CONTEXT_FILE_CANDIDATES) {
69
- const p = join(dir, name);
70
- if (existsSync(p)) {
71
- try {
72
- return { path: p, content: readFileSync(p, 'utf8') };
73
- }
74
- catch {
75
- // Unreadable candidate — skip, mirroring pi (best-effort).
76
- }
77
- }
78
- }
79
- return null;
80
- }
81
- /** Mirror of pi's loadProjectContextFiles: the global agent-dir file first, then
82
- * every AGENTS.md/CLAUDE.md up the cwd's ancestry, ordered root→cwd (so the
83
- * most-specific project file reads last). Deduped by absolute path. */
84
- function loadProjectContextFiles(cwd) {
85
- const files = [];
86
- const seen = new Set();
87
- const global = loadContextFileFromDir(piAgentDir());
88
- if (global !== null) {
89
- files.push(global);
90
- seen.add(global.path);
91
- }
92
- const ancestors = [];
93
- let dir = resolve(cwd);
94
- const root = resolve('/');
95
- for (;;) {
96
- const f = loadContextFileFromDir(dir);
97
- if (f !== null && !seen.has(f.path)) {
98
- ancestors.unshift(f);
99
- seen.add(f.path);
100
- }
101
- if (dir === root)
102
- break;
103
- const parent = resolve(dir, '..');
104
- if (parent === dir)
105
- break;
106
- dir = parent;
107
- }
108
- files.push(...ancestors);
109
- return files;
110
- }
111
48
  function escapeAttribute(value) {
112
49
  return value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
113
50
  }
@@ -175,18 +112,19 @@ function parseWorktrees(lines) {
175
112
  }
176
113
  return worktrees;
177
114
  }
178
- /** The `<project_context>` block for the files discovered from `cwd`, plus the
179
- * cwd/git environment snapshot that now rides at the end of the wrapper.
180
- * Always emits the wrapper because the environment snapshot is always present
181
- * even when no project instructions exist. Exported for testing. */
115
+ /** The `<project_context>` block now just the cwd/git `<environment>`
116
+ * snapshot (dir listing + git status/worktrees). This USED to also carry a
117
+ * `<project_instructions>` block re-rendering the node's AGENTS.md/CLAUDE.md;
118
+ * that machinery is gone (hard cut, 2026-07-06) project guidance now lives
119
+ * in the document substrate (`crtr sys sync` migrates each CLAUDE.md/AGENTS.md
120
+ * into that dir's own `.crouter/memory/AGENTS.md` at content/content, so it
121
+ * surfaces via the `<memory kind="knowledge">` block instead). Always emits
122
+ * the wrapper because the environment snapshot is always present. Exported
123
+ * for testing. */
182
124
  export function buildProjectContextBlock(cwd) {
183
- const files = loadProjectContextFiles(cwd);
184
125
  const envLines = directoryListingLines(cwd);
185
126
  const git = gitSnapshot(cwd);
186
- let out = '<project_context>\n\nProject-specific instructions and guidelines:\n\n';
187
- for (const { path, content } of files) {
188
- out += `<project_instructions path="${path}">\n${content}\n</project_instructions>\n\n`;
189
- }
127
+ let out = '<project_context>\n\n';
190
128
  out += `<environment cwd="${escapeAttribute(cwd)}">\n`;
191
129
  out += `Directory:\n${envLines.map((line) => ` ${line}`).join('\n')}\n`;
192
130
  out += `${git.lines.map((line) => `${line}`).join('\n')}\n`;
@@ -432,9 +370,12 @@ export function buildWakeBearings(origin) {
432
370
  * from.
433
371
  * 2. `<memory kind="knowledge">` — the consultable catalog, a SIBLING of the
434
372
  * bearings (never nested under the context dir). Dropped when empty.
435
- * 3. `<project_context>` — the AGENTS.md/CLAUDE.md instructions + the cwd/git
436
- * environment snapshot, moved OUT of the system prompt (pi's copy is
437
- * suppressed via noContextFiles in broker.ts) so it rides this message. */
373
+ * 3. `<project_context>` — the cwd/git environment snapshot. pi's own
374
+ * AGENTS.md/CLAUDE.md system-prompt injection stays suppressed
375
+ * (noContextFiles in broker.ts); project guidance instead rides the
376
+ * `<memory kind="knowledge">` block above via the document substrate
377
+ * (`crtr sys sync` migrates each CLAUDE.md/AGENTS.md into that dir's own
378
+ * `.crouter/memory/AGENTS.md`). */
438
379
  export function buildContextBearings(nodeId) {
439
380
  const node = getNode(nodeId);
440
381
  const bearings = ['<crtr-bearings>', buildIdentityAssertion(nodeId)];
@@ -1706,10 +1706,11 @@ export async function buildBrokerSession(engine, cfg) {
1706
1706
  resourceLoaderOptions: {
1707
1707
  additionalExtensionPaths: cfg.extensionPaths,
1708
1708
  appendSystemPrompt: cfg.appendSystemPromptPath !== undefined ? [cfg.appendSystemPromptPath] : undefined,
1709
- // Suppress pi's <project_context> in the SYSTEM PROMPT — crouter
1710
- // re-renders the same AGENTS.md/CLAUDE.md files into the first-message
1711
- // <crtr-context> bearings instead (buildProjectContextBlock), so all
1712
- // project instructions ride the user message, not the system prompt.
1709
+ // Suppress pi's <project_context> AGENTS.md/CLAUDE.md injection in the
1710
+ // SYSTEM PROMPT unconditionally crouter reads project guidance through
1711
+ // the document substrate instead (a migrated AGENTS.md doc rides the
1712
+ // <memory kind="knowledge"> block in the first-message bearings; see
1713
+ // bearings.ts and `crtr sys sync`), never pi's own file-based loader.
1713
1714
  noContextFiles: true,
1714
1715
  },
1715
1716
  });
@@ -9,10 +9,12 @@
9
9
  // • POSITIONAL — walk the read file's ancestor dirs; any doc living in an
10
10
  // ancestor PROJECT `.crouter/memory/` surfaces (a doc surfaces when a file
11
11
  // beside/under its own project scope dir is read), UNLESS it carries an
12
- // explicit read-trigger (see D5 below). This mirrors nested-context's
13
- // `.claude/rules` ancestor walk, but keyed on `.crouter/memory/`. The
14
- // user-global `~/.crouter/memory/` store is NOT positional; user docs only
15
- // fire on reads through explicit `applies-to` / `read-when` triggers.
12
+ // explicit read-trigger (see D5 below). This is the substrate's own
13
+ // ancestor walk keyed on `.crouter/memory/` — the same shape the retired
14
+ // nested-context pi-extension used for `.claude/rules` before that path
15
+ // was migrated into substrate docs (`crtr sys sync`). The user-global
16
+ // `~/.crouter/memory/` store is NOT positional; user docs only fire on
17
+ // reads through explicit `applies-to` / `read-when` triggers.
16
18
  // • applies-to GLOB — any RESOLVED substrate doc (user/project/builtin scope)
17
19
  // whose `appliesTo` glob matches the read file path surfaces, regardless of
18
20
  // where the read file sits relative to the doc.
@@ -63,8 +65,9 @@ import { cachedSubstrateDocs } from './session-cache.js';
63
65
  // is the segment we explicitly join onto each surviving ancestor).
64
66
  const JUNK_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.cache', '.yalc']);
65
67
  // ---------------------------------------------------------------------------
66
- // Small path helpers (mirror the on-read precedent — nested-context /
67
- // frontmatter-rules — so the injected envelope matches their faithful shape).
68
+ // Small path helpers (mirror the on-read precedent — frontmatter-rules, and
69
+ // the retired nested-context extension — so the injected envelope matches
70
+ // their faithful shape).
68
71
  // ---------------------------------------------------------------------------
69
72
  function realpathOrSelf(p) {
70
73
  try {