greprag 5.74.9 → 5.74.11

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.
@@ -69,7 +69,7 @@ function context(input) {
69
69
  'Landing: the parent is the delivery owner for merge, post-merge branch/manifest bookkeeping, and any profile-declared push/deploy/release; the child owns routine archival of its own task after the terminal message is delivered. Do not edit the parent checkout or independently cross delivery boundaries. A mission whose first line begins `FIX:` (emitted by `greprag fix spawn`) is writable in its isolated checkout/worktree and hands its verified checkpoint to that owner without a human approval gate. If no live parent exists and the chip carries the full-goal mission, it becomes delivery owner. `greprag fix spawn` only prints the mission; visible Codex task dispatch creates the isolated checkout/worktree.',
70
70
  ];
71
71
  if ((0, model_1.chipMissionKind)(chip) === 'fix') {
72
- lines.push('Harness: Codex. Mission: visible native FIX chip with ordinary writable authority, not an internal subagent.', 'Scope: repair GrepRAG-owned harness surfaces in this checkout: load entries, skill templates, docs, hook context, CLI messages, and tests. Codex owns native task creation, worktrees, permissions, Git, and task lifecycle.', 'Own diagnosis, implementation, tests, commit, and parent report. Inspect Codex behavior only far enough to correct GrepRAG guidance or report a precise external blocker.', 'FIX peer handoff: if a peer offers to coordinate, integrate, rework, or take over a harness repair, hand off branch/commit, dirty files, checks, blockers, and caveats. Do not defend patch ownership; peers may take ownership within their assigned GrepRAG harness scope.', 'Visible delegation route: load `codex-chip-spawn` and create the child with `codex_app__create_thread` using the current project worktree target; load `chip-leader` for multi-chip seams. Never use `multi_agent_v1__spawn_agent` for a visible chip.');
72
+ lines.push('Harness: Codex. Mission: visible native FIX chip with ordinary writable authority, not a same-session helper.', 'Scope: repair GrepRAG-owned harness surfaces in this checkout: load entries, skill templates, docs, hook context, CLI messages, and tests. Codex owns native task creation, worktrees, permissions, Git, and task lifecycle.', 'Own diagnosis, implementation, tests, commit, and parent report. Inspect Codex behavior only far enough to correct GrepRAG guidance or report a precise external blocker.', 'FIX peer handoff: if a peer offers to coordinate, integrate, rework, or take over a harness repair, hand off branch/commit, dirty files, checks, blockers, and caveats. Do not defend patch ownership; peers may take ownership within their assigned GrepRAG harness scope.', 'Visible delegation route: load `codex-chip-spawn` and create the child with `codex_app__create_thread` using the current project worktree target; load `chip-leader` for multi-chip seams. Same-session helper tools never satisfy a visible-chip requirement.');
73
73
  }
74
74
  return output(input.hook_event_name || 'SessionStart', lines.join('\n'));
75
75
  }
@@ -15,8 +15,9 @@ exports.CODEX_CHIP_HELP = `greprag codex chip — Codex task orchestration
15
15
 
16
16
  Native Codex Desktop is the default: omit --runtime. Use --runtime cli only for
17
17
  the explicit headless fallback. Spawn prepares the Desktop create request and
18
- handoff with an isolated worktree and starting branch. The standalone CLI does
19
- not create the Desktop task itself. The active topology is an implicit LEAD for
18
+ handoff with a Codex worktree environment plus
19
+ \`startingState.branchName\`. The standalone CLI does not create the Desktop
20
+ task itself. The active topology is an implicit LEAD for
20
21
  quick chips, an explicit LEAD for multi-chip orchestration, and Chip A/B/C with
21
22
  optional ADVISOR orientation. FIX missions are visible one-friction tasks from
22
23
  \`greprag fix spawn\`: they select \`chip.fix\` and load mechanic doctrine.
@@ -26,7 +26,8 @@ function chipPrompt(manifest, _cliCommand = 'greprag') {
26
26
 
27
27
  Setup — do this FIRST:
28
28
  ${mechanicSetup}${leaderSetup}- Stay in ${executionPath}. Applicable AGENTS instructions and the session-start recap are already in context; inspect the current repository state.
29
- - Bootstrap this checkout before build/test: if \`scripts/ensure-npm-deps.cjs\` exists, run \`node scripts/ensure-npm-deps.cjs\`; if \`scripts/worktree-bootstrap.cjs\` exists, run \`node scripts/worktree-bootstrap.cjs\`. Never link or junction \`node_modules\` to another checkout.
29
+ - Bootstrap this checkout before build/test: if \`scripts/worktree-bootstrap.cjs\` exists, run \`node scripts/worktree-bootstrap.cjs\`; if only \`scripts/ensure-npm-deps.cjs\` exists, run \`node scripts/ensure-npm-deps.cjs\`. Never link or junction \`node_modules\` to another checkout.
30
+ - When running build/test or other env-driven commands, use \`node scripts/codex-run.cjs -- <command ...>\` if that wrapper exists. It loads ignored env files from the main checkout; never copy or print secrets.
30
31
  - Do not create a second worktree. The selected workspace is fully writable; there are no leases, read-only mode, or GrepRAG goal gates.
31
32
  - The durable manifest is ${manifest.id}; it is task bookkeeping, not a scope or permission gate.
32
33
  ${startupInstruction}
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.cleanupCodexGeneratedDist = cleanupCodexGeneratedDist;
37
+ exports.runCodexCleanGenerated = runCodexCleanGenerated;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const proc_1 = require("../proc");
41
+ function samePath(left, right) {
42
+ const l = path.resolve(left);
43
+ const r = path.resolve(right);
44
+ return process.platform === 'win32' ? l.toLowerCase() === r.toLowerCase() : l === r;
45
+ }
46
+ function isInside(parent, child) {
47
+ const relative = path.relative(path.resolve(parent), path.resolve(child));
48
+ return !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);
49
+ }
50
+ function gitRootFor(start) {
51
+ try {
52
+ return path.resolve(String((0, proc_1.safeExecFileSync)('git', ['-C', start, 'rev-parse', '--show-toplevel'], {
53
+ encoding: 'utf8',
54
+ stdio: ['ignore', 'pipe', 'ignore'],
55
+ })).trim());
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ function assertDistLeaf(target) {
62
+ if (path.basename(target).toLowerCase() !== 'dist') {
63
+ throw new Error(`Refusing generated cleanup for non-dist path: ${target}`);
64
+ }
65
+ }
66
+ function assertNoRepoMetadata(target) {
67
+ if (fs.existsSync(path.join(target, '.git'))) {
68
+ throw new Error(`Refusing to remove a directory containing .git metadata: ${target}`);
69
+ }
70
+ }
71
+ function cleanupBound(target, opts) {
72
+ const cwd = path.resolve(opts.cwd || process.cwd());
73
+ if (opts.under) {
74
+ const bound = path.resolve(cwd, opts.under);
75
+ if (samePath(bound, target) || !isInside(bound, target)) {
76
+ throw new Error(`Refusing cleanup outside explicit --under bound: ${target}`);
77
+ }
78
+ return { bound, boundKind: 'explicit-under' };
79
+ }
80
+ const parent = path.dirname(target);
81
+ if (!fs.existsSync(parent)) {
82
+ throw new Error(`Refusing cleanup because parent directory does not exist: ${parent}`);
83
+ }
84
+ const gitStart = fs.existsSync(target) && fs.lstatSync(target).isDirectory() ? target : parent;
85
+ const gitRoot = gitRootFor(gitStart);
86
+ if (!gitRoot) {
87
+ throw new Error(`Refusing cleanup outside a Git worktree; pass --under <dir> for an explicit bound: ${target}`);
88
+ }
89
+ if (samePath(gitRoot, target) || !isInside(gitRoot, target)) {
90
+ throw new Error(`Refusing cleanup outside Git root ${gitRoot}: ${target}`);
91
+ }
92
+ return { bound: gitRoot, boundKind: 'git-root' };
93
+ }
94
+ function cleanupCodexGeneratedDist(targetArg, opts = {}) {
95
+ if (!targetArg || !targetArg.trim())
96
+ throw new Error('Missing generated directory path.');
97
+ const cwd = path.resolve(opts.cwd || process.cwd());
98
+ const target = path.resolve(cwd, targetArg);
99
+ assertDistLeaf(target);
100
+ const bound = cleanupBound(target, opts);
101
+ const dryRun = !!opts.dryRun;
102
+ if (!fs.existsSync(target)) {
103
+ return { target, ...bound, removed: false, dryRun, reason: 'missing' };
104
+ }
105
+ const stat = fs.lstatSync(target);
106
+ if (stat.isSymbolicLink()) {
107
+ throw new Error(`Refusing to remove symlink/reparse target: ${target}`);
108
+ }
109
+ if (!stat.isDirectory()) {
110
+ throw new Error(`Refusing to remove non-directory generated path: ${target}`);
111
+ }
112
+ assertNoRepoMetadata(target);
113
+ if (dryRun) {
114
+ return { target, ...bound, removed: false, dryRun, reason: 'dry-run' };
115
+ }
116
+ fs.rmSync(target, { recursive: true, force: false });
117
+ if (fs.existsSync(target))
118
+ throw new Error(`Cleanup did not remove target: ${target}`);
119
+ return { target, ...bound, removed: true, dryRun };
120
+ }
121
+ function parseArgs(args) {
122
+ let under;
123
+ let dryRun = false;
124
+ let json = false;
125
+ const positional = [];
126
+ for (let i = 0; i < args.length; i++) {
127
+ const arg = args[i];
128
+ if (arg === '--dry-run') {
129
+ dryRun = true;
130
+ continue;
131
+ }
132
+ if (arg === '--json') {
133
+ json = true;
134
+ continue;
135
+ }
136
+ if (arg === '--under') {
137
+ under = args[++i];
138
+ if (!under)
139
+ throw new Error('Missing value for --under.');
140
+ continue;
141
+ }
142
+ if (arg.startsWith('--'))
143
+ throw new Error(`Unknown clean-generated flag: ${arg}`);
144
+ positional.push(arg);
145
+ }
146
+ if (positional.length !== 1) {
147
+ throw new Error('Usage: greprag codex clean-generated <path-to-dist> [--under <dir>] [--dry-run] [--json]');
148
+ }
149
+ return { target: positional[0], under, dryRun, json };
150
+ }
151
+ function runCodexCleanGenerated(args) {
152
+ const parsed = parseArgs(args);
153
+ const result = cleanupCodexGeneratedDist(parsed.target, {
154
+ under: parsed.under,
155
+ dryRun: parsed.dryRun,
156
+ });
157
+ if (parsed.json) {
158
+ console.log(JSON.stringify(result));
159
+ return;
160
+ }
161
+ const action = result.reason === 'missing'
162
+ ? 'already absent'
163
+ : result.reason === 'dry-run'
164
+ ? 'would remove'
165
+ : result.removed
166
+ ? 'removed'
167
+ : 'unchanged';
168
+ console.log(`Codex generated cleanup ${action}: ${result.target}`);
169
+ console.log(`Bound: ${result.boundKind} ${result.bound}`);
170
+ }
@@ -36,7 +36,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.KNOWN_CODEX_MODEL_EFFORTS = exports.DEFAULT_CODEX_MODEL_POLICY = exports.CODEX_MODEL_EFFORTS = void 0;
37
37
  exports.loadCodexModelPolicy = loadCodexModelPolicy;
38
38
  exports.resolveChipModelSlot = resolveChipModelSlot;
39
- exports.resolveSubagentModelSlot = resolveSubagentModelSlot;
40
39
  exports.printCodexModelPolicy = printCodexModelPolicy;
41
40
  const fs = __importStar(require("fs"));
42
41
  const os = __importStar(require("os"));
@@ -51,11 +50,6 @@ exports.DEFAULT_CODEX_MODEL_POLICY = {
51
50
  advisor: { model: 'gpt-5.6-sol', effort: 'high' },
52
51
  fix: { model: 'gpt-5.5', effort: 'high' },
53
52
  },
54
- subagent: {
55
- fast_scan: { model: 'gpt-5.5', effort: 'medium' },
56
- routine_worker: { model: 'gpt-5.5', effort: 'high' },
57
- deep_worker: { model: 'gpt-5.6-luna', effort: 'xhigh' },
58
- },
59
53
  };
60
54
  exports.KNOWN_CODEX_MODEL_EFFORTS = {
61
55
  'gpt-5.6-sol': ['low', 'medium', 'high', 'xhigh', 'max', 'ultra'],
@@ -90,11 +84,6 @@ function applyPolicy(base, patch, source) {
90
84
  throw new Error(`${source} has unknown chip model slot ${key}.`);
91
85
  base.chip[key] = applySlot(base.chip[key], chipPatch[key] || {}, `${source} chip.${key}`);
92
86
  }
93
- for (const key of Object.keys(patch.subagent || {})) {
94
- if (!(key in base.subagent))
95
- throw new Error(`${source} has unknown subagent model slot ${key}.`);
96
- base.subagent[key] = applySlot(base.subagent[key], patch.subagent[key] || {}, `${source} subagent.${key}`);
97
- }
98
87
  return base;
99
88
  }
100
89
  function readPolicyFile(filePath) {
@@ -148,9 +137,6 @@ function loadCodexModelPolicy(cwd = process.cwd(), homeDir = process.env.HOME ||
148
137
  function resolveChipModelSlot(role, policy = loadCodexModelPolicy()) {
149
138
  return policy.chip[role];
150
139
  }
151
- function resolveSubagentModelSlot(role, policy = loadCodexModelPolicy()) {
152
- return policy.subagent[role];
153
- }
154
140
  function printCodexModelPolicy(args = []) {
155
141
  const json = args.includes('--json');
156
142
  const policy = loadCodexModelPolicy();
@@ -160,6 +146,4 @@ function printCodexModelPolicy(args = []) {
160
146
  console.log('Config files: ~/.greprag/codex-models.json, then .greprag/codex-models.json');
161
147
  for (const [role, slot] of Object.entries(policy.chip))
162
148
  console.log(` chip.${role}: ${slot.model} / ${slot.effort}`);
163
- for (const [role, slot] of Object.entries(policy.subagent))
164
- console.log(` subagent.${role}: ${slot.model} / ${slot.effort}`);
165
149
  }
@@ -53,6 +53,7 @@ const codex_app_server_1 = require("./codex-app-server");
53
53
  const codex_delivery_1 = require("./codex-delivery");
54
54
  const codex_model_policy_1 = require("./codex-model-policy");
55
55
  const codex_startup_1 = require("./codex-startup");
56
+ const codex_generated_cleanup_1 = require("./codex-generated-cleanup");
56
57
  const codex_watch_health_1 = require("./codex-watch-health");
57
58
  var codex_startup_2 = require("./codex-startup");
58
59
  Object.defineProperty(exports, "codexStartupInfo", { enumerable: true, get: function () { return codex_startup_2.codexStartupInfo; } });
@@ -458,6 +459,7 @@ const HELP = `greprag codex — Codex-specific helpers.
458
459
  greprag codex models show [--json]
459
460
  greprag codex chip spawn "<task>" --name <name> [--role worker|leader|planner|advisor] [--runtime cli]
460
461
  greprag codex chip list|status|steer|stop|report|block|cleanup|reconcile
462
+ greprag codex clean-generated <path-to-dist> [--under <dir>] [--dry-run] [--json]
461
463
  greprag codex doctor
462
464
  greprag codex startup remove
463
465
 
@@ -518,6 +520,10 @@ async function runCodex(args) {
518
520
  await (0, command_1.runCodexChip)(args.slice(1));
519
521
  return;
520
522
  }
523
+ if (sub === 'clean-generated') {
524
+ (0, codex_generated_cleanup_1.runCodexCleanGenerated)(args.slice(1));
525
+ return;
526
+ }
521
527
  if (sub !== 'watch' && sub !== 'arm') {
522
528
  console.error(`Unknown codex command: ${sub}\n`);
523
529
  console.log(HELP);
@@ -275,8 +275,12 @@ async function runShimAudit(opts) {
275
275
  console.log('Windows shims:');
276
276
  for (const s of shims) {
277
277
  const ver = s.version ? `v${s.version}` : '(version unknown)';
278
- const missing = s.incomplete ? ` missing ${s.missingFiles.join(', ')}` : '';
279
- const flag = s.stale ? ` ⚠ STALE${missing}` : s.incomplete ? ` ⚠ INCOMPLETE${missing}` : s.unresolvable ? ' ? unresolvable' : '';
278
+ const details = [
279
+ ...(s.incomplete ? [`missing ${s.missingFiles.join(', ')}`] : []),
280
+ ...(s.volatileForward ? ['fnm temp forward'] : []),
281
+ ];
282
+ const suffix = details.length ? ` ${details.join(', ')}` : '';
283
+ const flag = s.stale ? ` ⚠ STALE${suffix}` : s.incomplete ? ` ⚠ INCOMPLETE${suffix}` : s.volatileForward ? ` ⚠ VOLATILE${suffix}` : s.unresolvable ? ' ? unresolvable' : '';
280
284
  console.log(` ${s.name}${s.active ? '' : ' (shadowed)'}: ${s.shimPath} → ${ver}${flag}`);
281
285
  }
282
286
  if (unhealthy.length === 0) {
@@ -291,7 +295,7 @@ async function runShimAudit(opts) {
291
295
  if (!opts.yes) {
292
296
  const fixable = repairs.filter(r => r.forwardTo);
293
297
  for (const r of repairs.filter(x => !x.forwardTo)) {
294
- console.log(` ✗ ${r.shim.shimPath} is unhealthy and no current ${r.shim.name} shim exists on PATH to forward to — run \`npm i -g greprag@latest\` first.`);
298
+ console.log(` ✗ ${r.shim.shimPath} is unhealthy and no durable current ${r.shim.name} shim exists on PATH to forward to — run \`${(0, windows_shims_1.shimInstallCommand)()}\` first.`);
295
299
  }
296
300
  if (fixable.length === 0) {
297
301
  console.log('');
@@ -5,10 +5,10 @@
5
5
  * live stress level) rather than a binary resolvable deficiency.
6
6
  *
7
7
  * A reminder-interrupt MODULE is `{ id, detect, announce, reminder }` (reminder-types.ts):
8
- * `detect(env)` reads the live state → a tier (`silent` = nothing to fix); a SessionStart
9
- * `announce` loads the schema ONCE; a per-turn `reminder` fires a thin, grounded pointer
10
- * back at it. The no-orphan invariant requires the PAIR. The container (reminder-registry.ts)
11
- * wires every module; the hook (hook.ts) assembles the env and emits — see `injectReminders`.
8
+ * `detect(env)` reads the live state → a tier (`silent` = nothing to fix); the grepragOS
9
+ * primer owns the startup schema, and this module contributes only a thin live reminder.
10
+ * The container (reminder-registry.ts) wires every module; the hook (hook.ts) assembles
11
+ * the env and emits — see `injectReminders`.
12
12
  *
13
13
  * PURE: imports only the stress constants; returns strings + a tier + a tally. No fs, no
14
14
  * network, no clock — the hook does ALL I/O. Keeping detect/tier a pure function is what
@@ -19,10 +19,10 @@ exports.frictionReminderTier = frictionReminderTier;
19
19
  exports.buildMechanicLiveNotice = buildMechanicLiveNotice;
20
20
  exports.buildFrictionReminder = buildFrictionReminder;
21
21
  exports.buildBootstrapFrictionReminder = buildBootstrapFrictionReminder;
22
- exports.buildMechanicAnnounce = buildMechanicAnnounce;
23
22
  exports.tallyFrictionFire = tallyFrictionFire;
24
23
  exports.tallyMechanicSpawn = tallyMechanicSpawn;
25
24
  const state_trigger_1 = require("./state-trigger");
25
+ // adr: adr/friction-memory-first.md
26
26
  function quoteForCommand(value) {
27
27
  return value.replace(/[\r\n]+/g, ' ').replace(/"/g, '\\"').trim();
28
28
  }
@@ -49,21 +49,22 @@ function frictionReminderTier(stress) {
49
49
  return 'nudge';
50
50
  return 'silent';
51
51
  }
52
- /** The per-turn reminder line — fires only on detected stress, points at the ONE
53
- * friction reflex (fix spawn), ends on a forced binary so it converts. null = calm.
52
+ /** The per-turn reminder line — fires only on detected stress, points first at
53
+ * Memory for a known overcome, then at fix spawn for unresolved friction.
54
+ * Ends on a forced binary so it converts. null = calm.
54
55
  * The queue-route (`mechanic friction`) and log-route (`fix log`) verbs were
55
- * RETIRED as reflexes 2026-07-12 (grepragOS): friction is fixed at the moment,
56
- * one chip per unit. */
56
+ * RETIRED as reflexes 2026-07-12 (grepragOS). */
57
57
  const FIX_SPAWN = 'greprag fix spawn --type <harness|doctrine|injection|env|code> "<one unit>"';
58
+ const MEMORY_SEARCH = 'greprag memory search "<exact error/friction + repo/tool>"';
58
59
  function buildMechanicLiveNotice(_env) {
59
- return `GrepRAG Mechanic is live. Friction reflex: \`${FIX_SPAWN}\` one fix chip per unit, spawned at the moment; then keep working. Check role only when needed: \`greprag mechanic role\`.`;
60
+ return `GrepRAG Mechanic is live. Friction order: \`${MEMORY_SEARCH}\` first; apply a clear overcome and continue. No answer, failed overcome, or repeated friction \`${FIX_SPAWN}\`. Check role only when needed: \`greprag mechanic role\`.`;
60
61
  }
61
62
  function buildFrictionReminder(tier, env) {
62
63
  switch (tier) {
63
64
  case 'nag':
64
- return `⚠ FRICTION HIGH (live signal: repetition / errors / churn) — STOP pushing through. Name the ONE unit, choose type by repair surface, and spawn now: \`${FIX_SPAWN}\` (chip fixes, verifies, checkpoints, and hands it to the mission delivery owner). No friction? say "clear" + continue.`;
65
+ return `⚠ FRICTION HIGH (live signal: repetition / errors / churn) — STOP pushing through. MEMORY FIRST: \`${MEMORY_SEARCH}\`. Clear overcome apply + continue. No answer, remembered overcome fails, or same friction repeats \`${FIX_SPAWN}\`. No friction? say "clear" + continue.`;
65
66
  case 'nudge':
66
- return `⚠ Friction detected (live signal) — repeated yourself, fought a tool, or hit a wall? Choose type by repair surface and spawn: \`${FIX_SPAWN}\`, then keep working. Otherwise say "clear" + continue.`;
67
+ return `⚠ Friction detected (live signal) — repeated yourself, fought a tool, or hit a wall? Search first: \`${MEMORY_SEARCH}\`. Apply a clear overcome + continue; no answer, failed overcome, or repeat → \`${FIX_SPAWN}\`. Otherwise say "clear" + continue.`;
67
68
  default:
68
69
  return null;
69
70
  }
@@ -74,25 +75,8 @@ function buildBootstrapFrictionReminder(env) {
74
75
  return null;
75
76
  const repeats = b.repeats && b.repeats > 1 ? ` repeated ${b.repeats}x` : '';
76
77
  const error = b.error ? ` Last error: ${b.error}` : '';
77
- return `⚠ BOOTSTRAP FRICTION detected${repeats}: setup/toolchain failure (${b.signal || 'setup'}) around \`${b.command || 'unknown command'}\`.${error} If this is not caused by the code you just edited, spawn a fix chip now: \`greprag fix spawn --type env "${bootstrapSummary(env)}"\`. The chip owns the root-cause repair, verifies it, and hands it to the mission delivery owner so future sessions stop hitting it.`;
78
- }
79
- // ---------- The fix-reflex primer (announce-only) ----------------------------
80
- /** SessionStart primer — the fix reflex, loaded ONCE. Full doctrine inline
81
- * (a PRIMER, not a pointer): it teaches WHEN friction is a spawn-now signal
82
- * and the chip's delivery-owner contract. Rewritten 2026-07-12 (grepragOS):
83
- * the queue-route (`mechanic friction`), log-route (`fix log`) and the
84
- * one-Mechanic-absorbs-all-friction model are RETIRED as reflexes — one unit
85
- * of friction ⇒ one fix chip, spawned at the moment. */
86
- function buildMechanicAnnounce() {
87
- return [
88
- '[Fix reflex — friction is fixed at the MOMENT it happens, one chip per unit (grepragOS law; full doctrine: `greprag load os`).]',
89
- 'WHEN friction happens — repeated yourself, fought a tool, got corrected >=2x on the same thing, rediscovered something already known, or hit a setup/toolchain failure not caused by code you just edited — spawn its fix chip NOW, then keep working. Ordinary misunderstanding or misreading user intent is not friction unless it repeats or exposes a durable doctrine/harness/injection/env/code failure. One unit = one chip; adjacent friction gets its own spawn. Never queue friction for later.',
90
- 'TYPE = durable repair surface: harness=hooks/watchers/task dispatch; doctrine=greprag load/skills/AGENTS; injection=recap/Capture/doc-pointer/stateful injection; env=bootstrap/deps/scripts/worktree setup; code=product/source behavior. Use: `greprag fix spawn --type <type> "<one unit>"`.',
91
- 'WORKSPACE ROUTING: `fix spawn` detects usable Git history before dispatch — Git uses an isolated worktree; non-Git, unavailable Git, or no commit uses the project-local task with serialized writes. No fail-then-fallback attempt.',
92
- 'THE CHIP\'S CONTRACT (it self-enforces; you just spawn): identify the exact friction → make the smallest durable root-cause fix → explain and verify it → checkpoint → hand it to the mission delivery owner. With no live parent and a full-goal mission, the chip becomes delivery owner and follows the repo profile. No second lifecycle approval.',
93
- 'Every repair is ROOT-CAUSE — fix the pattern that makes the friction class possible, never a guard on today\'s trigger.',
94
- 'A per-turn reminder fires ONLY when live friction is DETECTED (the stress signal — repetition / errors / churn), never on a timer — act on it, or say "clear" and continue.',
95
- ].join('\n');
78
+ const summary = bootstrapSummary(env);
79
+ return `⚠ BOOTSTRAP FRICTION detected${repeats}: setup/toolchain failure (${b.signal || 'setup'}) around \`${b.command || 'unknown command'}\`.${error} MEMORY FIRST: \`greprag memory search "${summary}"\`. Apply a clear overcome + continue. No answer, remembered overcome fails, or the same failure repeats → \`greprag fix spawn --type env "${summary}"\`.`;
96
80
  }
97
81
  /** Normalize any prior-stats blob (possibly missing/partial/corrupt) into a fully
98
82
  * populated FrictionStats. Pure, total. */
@@ -136,13 +120,10 @@ function tallyMechanicSpawn(prior) {
136
120
  return s;
137
121
  }
138
122
  // ---------- Registry module --------------------------------------------------
139
- /** The active Mechanic a PRIMER-ONLY module (docs/load-system.md): one strong
140
- * SessionStart announce, no per-turn reminder (the friction nag was removed
141
- * 2026-06-22 as wallpaper). `dependsOn` the chip-spawn pointer so the chip concept
142
- * it references is already loaded — the boot sequence places it AFTER chips. */
123
+ /** The active Mechanic reminder. The grepragOS primer owns the one startup schema;
124
+ * this module is reminder-only and fires only from live stress/bootstrap state. */
143
125
  exports.mechanicFrictionModule = {
144
126
  id: 'mechanic-friction',
145
- dependsOn: ['chip-spawn-pointer'],
146
127
  // Stress fires the real friction reminder. A designated Mechanic also creates a
147
128
  // one-shot ambient route notice per source session/role epoch (hook-stamped).
148
129
  detect: (env) => {
@@ -155,12 +136,7 @@ exports.mechanicFrictionModule = {
155
136
  return { tier: 'ambient' };
156
137
  return { tier: 'silent' };
157
138
  },
158
- announce: (env = {}) => {
159
- const base = buildMechanicAnnounce();
160
- if (env.mechanicLive && !env.mechanic)
161
- return `${base}\n\n${buildMechanicLiveNotice(env)}`;
162
- return base;
163
- },
139
+ announce: () => null,
164
140
  reminder: (d, env) => {
165
141
  if (d.detail?.kind === 'bootstrap-friction')
166
142
  return buildBootstrapFrictionReminder(env);
@@ -46,7 +46,7 @@ exports.OPENCODE_CHIP_SPAWN_POINTER = [
46
46
  /** POINTER — Codex Desktop's native chip path. This is intentionally distinct
47
47
  * from Claude Code spawn_task: different lifecycle, runtime, and handoff. */
48
48
  exports.CODEX_CHIP_SPAWN_POINTER = [
49
- '[greprag Codex delegation — internal subagent, 1–2-chip quick path with the initiator as LEAD, or a separate LEAD for larger/seamed missions.]',
49
+ '[greprag Codex delegation — 1–2-chip quick path with the initiator as LEAD, or a separate LEAD for larger/seamed missions.]',
50
50
  '• About to delegate a Codex task? → run `greprag load codex-chip-spawn` FIRST. Use exact first-line titles `LEAD: <Mission>`, `Chip A/B/C: <Specific Purview>`, and `FIX: [type] <one friction unit>`. Chips are ordinary writable native tasks; completion is a native Codex task reply to the LEAD after committing. A `FIX:` task loads `greprag load mechanic` first.',
51
51
  ].join('\n');
52
52
  exports.loadPrimerModule = {
@@ -63,7 +63,7 @@ const doc_mirror_client_1 = require("../doc-mirror-client");
63
63
  const LIBRARY = {
64
64
  os: {
65
65
  files: ['skill/templates/os.md'],
66
- purpose: 'grepragOS — the operating laws: doctrine vs state, discoverability, pull-before-derive, friction ⇒ fix spawn, teach the system not the chat.',
66
+ purpose: 'grepragOS — the operating laws: doctrine vs state, discoverability, pull-before-derive, memory-first friction recovery, unresolved friction ⇒ fix spawn, teach the system not the chat.',
67
67
  },
68
68
  'chip-spawn': {
69
69
  files: ['skill/templates/chip-spawn.md'],
@@ -73,10 +73,6 @@ const LIBRARY = {
73
73
  files: ['skill/templates/codex-chip-spawn.md'],
74
74
  purpose: 'Spawn an independent writable native Codex Desktop task with an isolated worktree and native completion/cleanup.',
75
75
  },
76
- 'codex-subagent-spawn': {
77
- files: ['skill/templates/codex-subagent-spawn.md'],
78
- purpose: 'Use bounded ephemeral Codex subagents inside the current session without a visible task, worktree, manifest, inbox identity, or goal.',
79
- },
80
76
  'skill-change': {
81
77
  files: ['skill/templates/skill-change.md'],
82
78
  purpose: 'Internal bundled schema for safely updating a skill after a run: when to edit, Convention A/B shapes, and when to propose instead.',
@@ -432,7 +428,8 @@ async function runLoad(args) {
432
428
  return;
433
429
  console.error(`Unknown load entry: ${name}\n`);
434
430
  await printCatalog();
435
- process.exit(1);
431
+ process.exitCode = 1;
432
+ return;
436
433
  }
437
434
  const bodies = [];
438
435
  for (const file of entry.files) {
@@ -148,8 +148,9 @@ function buildFixMission(friction, scope, parentSession, type = inferFixType(fri
148
148
  '1. `greprag load mechanic`',
149
149
  ...workspace.setup,
150
150
  '4. Read AGENTS.md and the session-start recap, then inspect the current repository state.',
151
- '5. Bootstrap this checkout before build/test: if `scripts/ensure-npm-deps.cjs` exists, run `node scripts/ensure-npm-deps.cjs`; if `scripts/worktree-bootstrap.cjs` exists, run `node scripts/worktree-bootstrap.cjs`. Never link or junction `node_modules` to another checkout.',
152
- '6. Reproduce the friction before changing anything.',
151
+ '5. Bootstrap this checkout before build/test: if `scripts/worktree-bootstrap.cjs` exists, run `node scripts/worktree-bootstrap.cjs`; if only `scripts/ensure-npm-deps.cjs` exists, run `node scripts/ensure-npm-deps.cjs`. Never link or junction `node_modules` to another checkout.',
152
+ '6. When running build/test or other env-driven commands, use `node scripts/codex-run.cjs -- <command ...>` if that wrapper exists. It loads ignored env files from the main checkout; never copy or print secrets.',
153
+ '7. Reproduce the friction before changing anything.',
153
154
  '',
154
155
  '**Repair contract**',
155
156
  `- ${workspace.work}`,
@@ -29,9 +29,9 @@ function buildOpenCodeEnv(params) {
29
29
  // No opencode-native friction detector is wired yet: Claude Code's stress /
30
30
  // bootstrap-friction signals come from state-trigger.ts reading the
31
31
  // transcript in hook.ts, and opencode has no equivalent source plumbed.
32
- // 0 = calm keeps the mechanic-friction REMINDER silent while its ANNOUNCE
33
- // (the fix-spawn doctrine) still lands every session. Detector design is
34
- // parked with scored options in the chip report
32
+ // 0 = calm keeps the reminder-only mechanic-friction module silent. The
33
+ // os-primer still lands the memory-first escalation doctrine every session.
34
+ // Detector design is parked with scored options in the chip report
35
35
  // (chip/opencode-fix-chip-system-parity).
36
36
  stress: 0,
37
37
  armed: params.armed ?? false,
@@ -13,6 +13,7 @@
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.osPrimerModule = void 0;
15
15
  exports.buildOsPrimer = buildOsPrimer;
16
+ // adr: adr/friction-memory-first.md
16
17
  function buildOsPrimer(env) {
17
18
  // The chip-spawn method is per-harness (Codex never sees the Claude entry —
18
19
  // the same wall the codex-chip-spawn pointer module enforces; opencode's
@@ -24,8 +25,8 @@ function buildOsPrimer(env) {
24
25
  '[grepragOS — the operating laws. Full doctrine: `greprag load os`.]',
25
26
  '• Doctrine vs state: methods ship in the CLI (`greprag load`); live state lives in the repo. A skill that depends on repo state carries a "STATE — read these first" block naming exact paths.',
26
27
  '• Discoverability: every durable artifact must be findable next session — docs auto-register, skills auto-mirror, decisions get a dated ADR/decision-log entry, everything else gets its path named in the owning skill/doc. If nothing points at it, you didn\'t finish.',
27
- '• Pull before derive: `greprag memory search` / `corpus search` / `load` BEFORE asking the operator or re-deriving what the project already knows. Named person/org/project/repo/customer/handle or unexplained proper noun → search Memory before guessing, unless fully defined in-turn.',
28
- `• Friction ⇒ fix NOW: type by durable repair surface (\`harness|doctrine|injection|env|code\`) ⇒ \`greprag fix spawn --type <type> "<unit>"\`. It PRINTS a fix-chip mission — YOU then create the visible child task with that mission as its first message (how: \`greprag load ${spawnEntry}\`, or your harness's native task tool). Repo write = isolated worktree; data-only row/diagnosis = no repo write. One unit per chip; the chip fixes, verifies, checkpoints, and hands it to the mission delivery owner. Never queue friction.`,
28
+ '• Pull before derive: `greprag memory search` / `corpus search` / `load` BEFORE asking the operator or re-deriving what the project already knows. Friction or an env/toolchain/worktree/secret bootstrap roadblock → search Memory for the exact error/friction + repo/tool before inventing a workaround. Clear overcome → apply it and continue. Named person/org/project/repo/customer/handle or unexplained proper noun → search Memory before guessing, unless fully defined in-turn.',
29
+ `• Unresolved friction ⇒ fix: only when Memory has no answer, the remembered overcome fails, or the same friction repeats. Then type by durable repair surface (\`harness|doctrine|injection|env|code\`) ⇒ \`greprag fix spawn --type <type> "<unit>"\`. It PRINTS a fix-chip mission — YOU then create the visible child task with that mission as its first message (how: \`greprag load ${spawnEntry}\`, or your harness's native task tool). Repo write = isolated worktree; data-only row/diagnosis = no repo write. One unresolved unit per chip; the chip fixes, verifies, checkpoints, and hands it to the mission delivery owner.`,
29
30
  '• Teach the system, not the chat: explained twice by the operator ⇒ it belongs in a skill / load entry / STATE block / ADR, not the conversation.',
30
31
  ].join('\n');
31
32
  }
@@ -30,10 +30,9 @@ const loadout_reminder_1 = require("./loadout-reminder");
30
30
  const delivery_reminder_1 = require("./delivery-reminder");
31
31
  /** Registry order = display order. THE single agent-facing announce/reminder assembly:
32
32
  * the hook does I/O → fills ReminderEnv → collectAnnounces (SessionStart) / collectReminders
33
- * (per turn) render every module here in this order. Order preserves the historical recap
34
- * preamble (setup-warning front-desk checkpoint → assistant-doctrine) and keeps the two
35
- * loud, action-first modules last (watcher-arm mechanic) so they read most-recent at
36
- * SessionStart. Add a module here to wire it into BOTH surfaces at once. */
33
+ * (per turn) render every module here in this order. A module may own either surface or both;
34
+ * os-primer owns startup friction doctrine and mechanic-friction is reminder-only.
35
+ * Add a module here to wire it into the appropriate surfaces at once. */
37
36
  exports.REGISTRY = [
38
37
  os_primer_reminder_1.osPrimerModule, // grepragOS constitution — the frame every other primer hangs off; boots FIRST
39
38
  inbox_primer_reminder_1.inboxPrimerModule,
@@ -327,8 +327,12 @@ function renderShims(w) {
327
327
  const lines = ['', 'Windows shims (what each PowerShell/CMD shim on PATH actually executes):'];
328
328
  for (const s of w.shims) {
329
329
  const ver = s.version ? `v${s.version}` : '(version unknown)';
330
- const missing = s.incomplete ? ` missing ${s.missingFiles.join(', ')}` : '';
331
- const flag = s.stale ? ` ⚠ STALE${missing}` : s.incomplete ? ` ⚠ INCOMPLETE${missing}` : s.unresolvable ? ' ? unresolvable' : '';
330
+ const details = [
331
+ ...(s.incomplete ? [`missing ${s.missingFiles.join(', ')}`] : []),
332
+ ...(s.volatileForward ? ['fnm temp forward'] : []),
333
+ ];
334
+ const suffix = details.length ? ` ${details.join(', ')}` : '';
335
+ const flag = s.stale ? ` ⚠ STALE${suffix}` : s.incomplete ? ` ⚠ INCOMPLETE${suffix}` : s.volatileForward ? ` ⚠ VOLATILE${suffix}` : s.unresolvable ? ' ? unresolvable' : '';
332
336
  lines.push(` ${s.name}${s.active ? '' : ' (shadowed)'}: ${s.shimPath} → ${ver}${flag}`);
333
337
  }
334
338
  if (w.mismatch) {