@vortex-os/base 0.11.0 → 0.12.0

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/index.js CHANGED
@@ -1,3 +1,14 @@
1
+ import {
2
+ FAILURES_DIR,
3
+ GUARD_DENIAL_KEY,
4
+ failureReportSlice,
5
+ isValidFailureKey,
6
+ ladderStage,
7
+ recordFailure,
8
+ recordGuardDenial,
9
+ runFailureCli,
10
+ scanFailures
11
+ } from "./chunk-UV76ZEDC.js";
1
12
  import {
2
13
  SESSION_END_COMMAND,
3
14
  SESSION_START_COMMAND,
@@ -16,7 +27,30 @@ import {
16
27
  serializeSettings,
17
28
  sniffEffortFromTranscript,
18
29
  statuslineCommand
19
- } from "./chunk-DWANI3LV.js";
30
+ } from "./chunk-EAKDR5B2.js";
31
+ import {
32
+ GUARD_WRITE_COMMAND,
33
+ GUARD_WRITE_MATCHER,
34
+ buildDenyDecision,
35
+ findControlChar,
36
+ guardWriteDecision,
37
+ resolveInstanceRoot,
38
+ runGuardCli,
39
+ scanToolInput
40
+ } from "./chunk-2FVNWW77.js";
41
+ import {
42
+ atomicWriteFile,
43
+ dist_exports,
44
+ exclusiveCreateFile,
45
+ isVisibleAt,
46
+ loadVortexConfig,
47
+ makeContext,
48
+ normalizePrivacy,
49
+ parseFrontmatter,
50
+ resolveEnvironment,
51
+ serializeFrontmatter,
52
+ validateDataRelativePath
53
+ } from "./chunk-T53UWSTR.js";
20
54
  import {
21
55
  catchUpSessions
22
56
  } from "./chunk-3L5DLEGP.js";
@@ -24,287 +58,6 @@ import {
24
58
  __export
25
59
  } from "./chunk-PZ5AY32C.js";
26
60
 
27
- // ../core/dist/index.js
28
- var dist_exports = {};
29
- __export(dist_exports, {
30
- Privacy: () => Privacy,
31
- atomicWriteFile: () => atomicWriteFile,
32
- exclusiveCreateFile: () => exclusiveCreateFile,
33
- isVisibleAt: () => isVisibleAt,
34
- loadVortexConfig: () => loadVortexConfig,
35
- makeContext: () => makeContext,
36
- maxPrivacy: () => maxPrivacy,
37
- moduleDir: () => moduleDir,
38
- normalizePrivacy: () => normalizePrivacy,
39
- parseFrontmatter: () => parseFrontmatter,
40
- resolveEnvironment: () => resolveEnvironment,
41
- serializeFrontmatter: () => serializeFrontmatter,
42
- validateDataRelativePath: () => validateDataRelativePath,
43
- vortexConfigPath: () => vortexConfigPath
44
- });
45
-
46
- // ../core/dist/types.js
47
- var Privacy = {
48
- Public: "public",
49
- Internal: "internal",
50
- Personal: "personal"
51
- };
52
-
53
- // ../core/dist/frontmatter.js
54
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
55
- var FENCE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
56
- var BOM = "\uFEFF";
57
- function parseFrontmatter(source) {
58
- const cleaned = source.startsWith(BOM) ? source.slice(1) : source;
59
- const match = cleaned.match(FENCE);
60
- if (!match) {
61
- return {
62
- frontmatter: {},
63
- body: cleaned
64
- };
65
- }
66
- const yaml = match[1] ?? "";
67
- const body = cleaned.slice(match[0].length);
68
- let parsed;
69
- try {
70
- const value = parseYaml(yaml);
71
- parsed = typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
72
- } catch {
73
- parsed = {};
74
- }
75
- return { frontmatter: parsed, body };
76
- }
77
- function serializeFrontmatter(doc) {
78
- const keys = Object.keys(doc.frontmatter ?? {});
79
- if (keys.length === 0)
80
- return doc.body;
81
- const yaml = stringifyYaml(doc.frontmatter).trimEnd();
82
- return `---
83
- ${yaml}
84
- ---
85
- ${doc.body}`;
86
- }
87
-
88
- // ../core/dist/privacy.js
89
- var ORDER = {
90
- public: 0,
91
- internal: 1,
92
- personal: 2
93
- };
94
- function isVisibleAt(docPrivacy, viewerPrivacy) {
95
- return ORDER[docPrivacy] <= ORDER[viewerPrivacy];
96
- }
97
- function maxPrivacy(a, b2) {
98
- return ORDER[a] >= ORDER[b2] ? a : b2;
99
- }
100
- function normalizePrivacy(value, fallback = "internal") {
101
- if (value === "public" || value === "internal" || value === "personal") {
102
- return value;
103
- }
104
- return fallback;
105
- }
106
-
107
- // ../core/dist/paths.js
108
- import { resolve, join } from "path";
109
- function makeContext(repoRoot) {
110
- const root = resolve(repoRoot);
111
- return {
112
- repoRoot: root,
113
- agentDir: join(root, ".agent"),
114
- dataDir: join(root, "data"),
115
- modulesDir: join(root, "modules"),
116
- pluginsDir: join(root, "plugins")
117
- };
118
- }
119
- function moduleDir(ctx, moduleName) {
120
- return join(ctx.modulesDir, moduleName);
121
- }
122
-
123
- // ../core/dist/config.js
124
- import { existsSync, readFileSync } from "fs";
125
- import { join as join2 } from "path";
126
- var DEFAULT_CONFIG = {
127
- autoRecord: { sessionStart: true, worklog: true, decision: true, ambientRecall: true, archive: true, vectorize: true, vectorizeAutoDownload: true, commitFrameworkChanges: true, handoff: true, handoffRetentionDays: 7, reindex: true, backfill: true },
128
- updates: { check: "session" },
129
- environments: []
130
- };
131
- function vortexConfigPath(ctx) {
132
- return join2(ctx.agentDir, "vortex.json");
133
- }
134
- function parseEnvironmentRule(raw) {
135
- if (typeof raw !== "object" || raw === null || Array.isArray(raw))
136
- return null;
137
- const candidate = raw;
138
- if (typeof candidate.label !== "string")
139
- return null;
140
- const rule = {
141
- label: candidate.label
142
- };
143
- if (typeof candidate.pathExists === "string")
144
- rule.pathExists = candidate.pathExists;
145
- if (typeof candidate.hostname === "string")
146
- rule.hostname = candidate.hostname;
147
- if (typeof candidate.envVar === "string") {
148
- rule.envVar = candidate.envVar;
149
- } else if (typeof candidate.envVar === "object" && candidate.envVar !== null) {
150
- const ev = candidate.envVar;
151
- if (typeof ev.name === "string") {
152
- rule.envVar = typeof ev.equals === "string" ? { name: ev.name, equals: ev.equals } : { name: ev.name };
153
- }
154
- }
155
- return rule;
156
- }
157
- function loadVortexConfig(ctx) {
158
- const path = vortexConfigPath(ctx);
159
- if (!existsSync(path))
160
- return DEFAULT_CONFIG;
161
- try {
162
- const raw = JSON.parse(readFileSync(path, "utf8"));
163
- const environments = Array.isArray(raw.environments) ? raw.environments.map(parseEnvironmentRule).filter((rule) => rule !== null) : [];
164
- const rawUpdates = raw.updates && typeof raw.updates === "object" && !Array.isArray(raw.updates) ? raw.updates : {};
165
- const rawCheck = rawUpdates.check;
166
- const check = rawCheck === void 0 ? "session" : typeof rawCheck === "string" && rawCheck.trim().toLowerCase() === "session" ? "session" : "off";
167
- const rawAuto = raw.autoRecord && typeof raw.autoRecord === "object" && !Array.isArray(raw.autoRecord) ? raw.autoRecord : {};
168
- const vectorizeAutoDownload = rawAuto.vectorizeAutoDownload === void 0 ? true : rawAuto.vectorizeAutoDownload === true;
169
- const commitFrameworkChanges = rawAuto.commitFrameworkChanges === void 0 ? true : rawAuto.commitFrameworkChanges === true;
170
- const handoff = rawAuto.handoff === void 0 ? true : rawAuto.handoff === true;
171
- const reindex = rawAuto.reindex === void 0 ? true : rawAuto.reindex === true;
172
- const backfill = rawAuto.backfill === void 0 ? true : rawAuto.backfill === true;
173
- const rawDays = rawAuto.handoffRetentionDays;
174
- const handoffRetentionDays = typeof rawDays === "number" && Number.isFinite(rawDays) && rawDays > 0 ? Math.floor(rawDays) : DEFAULT_CONFIG.autoRecord.handoffRetentionDays;
175
- return {
176
- autoRecord: {
177
- ...DEFAULT_CONFIG.autoRecord,
178
- ...raw.autoRecord ?? {},
179
- vectorizeAutoDownload,
180
- commitFrameworkChanges,
181
- handoff,
182
- handoffRetentionDays,
183
- reindex,
184
- backfill
185
- },
186
- updates: { check },
187
- environments
188
- };
189
- } catch {
190
- return DEFAULT_CONFIG;
191
- }
192
- }
193
- function resolveEnvironment(config, signals) {
194
- const host = signals.hostname?.toLowerCase();
195
- const env = signals.env ?? {};
196
- const pathExists = signals.pathExists ?? (() => false);
197
- for (const rule of config.environments) {
198
- if (rule.pathExists && pathExists(rule.pathExists))
199
- return rule.label;
200
- if (rule.hostname && host && rule.hostname.toLowerCase() === host)
201
- return rule.label;
202
- if (rule.envVar) {
203
- if (typeof rule.envVar === "string") {
204
- if (env[rule.envVar] !== void 0)
205
- return rule.label;
206
- } else {
207
- const v2 = env[rule.envVar.name];
208
- if (v2 !== void 0 && (rule.envVar.equals === void 0 || v2 === rule.envVar.equals)) {
209
- return rule.label;
210
- }
211
- }
212
- }
213
- }
214
- return null;
215
- }
216
-
217
- // ../core/dist/safe-fs.js
218
- import { rename, writeFile } from "fs/promises";
219
- import { isAbsolute, relative, resolve as resolve2, sep } from "path";
220
- var SYSTEM_META_DIRS = /* @__PURE__ */ new Set([
221
- "worklog",
222
- "decision-log",
223
- "runbooks",
224
- "hubs",
225
- "_memory",
226
- "_templates",
227
- "_proactive-curator",
228
- // Framework metadata carve-out: `data/.vortex/` holds the update-lifecycle
229
- // ownership manifest and template backups. It is NOT user space — the curate
230
- // value loop (and any LLM-chosen write path) must never target it, even
231
- // though it does not start with `_`. (The leading-`_` rule below does not
232
- // cover a leading-dot dir, so it is listed explicitly.)
233
- ".vortex"
234
- ]);
235
- var DRIVE_QUALIFIED = /^[a-zA-Z]:/;
236
- var CONTROL_CHARS = /[\u0000-\u001F]/;
237
- function validateDataRelativePath(dataDir, rel, _options = {}) {
238
- if (typeof rel !== "string" || rel.length === 0) {
239
- throw new Error("Invalid data-relative path: must be a non-empty string.");
240
- }
241
- if (CONTROL_CHARS.test(rel)) {
242
- throw new Error("Invalid data-relative path: contains control characters.");
243
- }
244
- const normalized = rel.replace(/\\/g, "/");
245
- if (normalized === "" || normalized === ".") {
246
- throw new Error(`Invalid data-relative path: "${rel}" is empty or '.'.`);
247
- }
248
- if (DRIVE_QUALIFIED.test(normalized)) {
249
- throw new Error(`Invalid data-relative path: "${rel}" is drive-qualified (must be data-relative).`);
250
- }
251
- if (isAbsolute(normalized) || normalized.startsWith("/")) {
252
- throw new Error(`Invalid data-relative path: "${rel}" is absolute (must be data-relative).`);
253
- }
254
- const segments = normalized.split("/");
255
- for (const segment of segments) {
256
- if (segment === "" || segment === "." || segment === "..") {
257
- throw new Error(`Invalid data-relative path: "${rel}" contains an empty, '.', or '..' segment (path traversal).`);
258
- }
259
- }
260
- const filename = segments[segments.length - 1];
261
- if (filename.length === 0 || filename.includes("/") || filename.includes("\\")) {
262
- throw new Error(`Invalid data-relative path: "${rel}" has an invalid filename.`);
263
- }
264
- const first = segments[0];
265
- if (SYSTEM_META_DIRS.has(first) || first.startsWith("_")) {
266
- throw new Error(`Invalid data-relative path: "${rel}" targets a reserved system/meta directory ("${first}"). The curate value loop writes user documents only \u2014 not worklog/decision-log/runbooks/hubs or any _* directory.`);
267
- }
268
- const absPath = resolve2(dataDir, normalized);
269
- const rootResolved = resolve2(dataDir);
270
- let relToData = relative(rootResolved, absPath);
271
- let relCompare = relToData;
272
- let upPrefix = ".." + sep;
273
- if (sep === "\\") {
274
- relCompare = relToData.toLowerCase();
275
- upPrefix = upPrefix.toLowerCase();
276
- }
277
- if (relCompare === ".." || relCompare.startsWith(upPrefix) || isAbsolute(relToData)) {
278
- throw new Error(`Invalid data-relative path: "${rel}" resolves outside the data directory.`);
279
- }
280
- return absPath;
281
- }
282
- async function exclusiveCreateFile(absPath, body) {
283
- try {
284
- await writeFile(absPath, body, { encoding: "utf8", flag: "wx" });
285
- } catch (e) {
286
- if (e.code === "EEXIST") {
287
- throw new Error(`Refusing to overwrite existing file: ${absPath}. create-file is an exclusive create; to add to an existing document use append-section instead.`);
288
- }
289
- throw e;
290
- }
291
- }
292
- var atomicWriteCounter = 0;
293
- async function atomicWriteFile(absPath, body) {
294
- const tmp = `${absPath}.tmp-${process.pid}-${atomicWriteCounter++}`;
295
- try {
296
- await writeFile(tmp, body, { encoding: "utf8" });
297
- await rename(tmp, absPath);
298
- } catch (e) {
299
- try {
300
- const { rm } = await import("fs/promises");
301
- await rm(tmp, { force: true });
302
- } catch {
303
- }
304
- throw e;
305
- }
306
- }
307
-
308
61
  // ../modules/slash-commands/dist/index.js
309
62
  var dist_exports2 = {};
310
63
  __export(dist_exports2, {
@@ -418,8 +171,8 @@ var MemoryType = {
418
171
  };
419
172
 
420
173
  // ../modules/memory-system/dist/store.js
421
- import { readdir, readFile, writeFile as writeFile2, mkdir, unlink, stat } from "fs/promises";
422
- import { join as join3, basename, extname } from "path";
174
+ import { readdir, readFile, writeFile, mkdir, unlink, stat } from "fs/promises";
175
+ import { join, basename, extname } from "path";
423
176
  var MemoryStore = class {
424
177
  dir;
425
178
  constructor(dir) {
@@ -453,7 +206,7 @@ var MemoryStore = class {
453
206
  frontmatter: memory.frontmatter,
454
207
  body: memory.body
455
208
  });
456
- await writeFile2(this.pathFor(memory.id), source, "utf8");
209
+ await writeFile(this.pathFor(memory.id), source, "utf8");
457
210
  }
458
211
  /** Delete a memory. Returns false if it did not exist. */
459
212
  async delete(id) {
@@ -477,13 +230,13 @@ var MemoryStore = class {
477
230
  }
478
231
  /** Absolute path of a memory file (file may not exist). */
479
232
  pathFor(id) {
480
- return join3(this.dir, `${id}.md`);
233
+ return join(this.dir, `${id}.md`);
481
234
  }
482
235
  };
483
236
 
484
237
  // ../modules/memory-system/dist/memory-index.js
485
- import { writeFile as writeFile3 } from "fs/promises";
486
- import { join as join4 } from "path";
238
+ import { writeFile as writeFile2 } from "fs/promises";
239
+ import { join as join2 } from "path";
487
240
  async function writeMemoryIndex(store, options = {}) {
488
241
  const ids = await store.list();
489
242
  const lines = [];
@@ -495,7 +248,7 @@ async function writeMemoryIndex(store, options = {}) {
495
248
  const memory = await store.read(id);
496
249
  lines.push(`- [${memory.frontmatter.name}](${id}.md) \u2014 ${memory.frontmatter.description}`);
497
250
  }
498
- await writeFile3(join4(store.dir, "MEMORY.md"), `${lines.join("\n")}
251
+ await writeFile2(join2(store.dir, "MEMORY.md"), `${lines.join("\n")}
499
252
  `, "utf8");
500
253
  }
501
254
 
@@ -533,7 +286,7 @@ __export(dist_exports4, {
533
286
 
534
287
  // ../modules/data-lint/dist/runner.js
535
288
  import { readdir as readdir2, readFile as readFile3 } from "fs/promises";
536
- import { join as join5 } from "path";
289
+ import { join as join3 } from "path";
537
290
  async function lintDirectory(options) {
538
291
  const start = Date.now();
539
292
  const extensions = options.extensions ?? [".md"];
@@ -570,7 +323,7 @@ async function collectFiles(dir, extensions) {
570
323
  throw e;
571
324
  }
572
325
  for (const entry of entries) {
573
- const full = join5(current, entry.name);
326
+ const full = join3(current, entry.name);
574
327
  if (entry.isDirectory()) {
575
328
  stack.push(full);
576
329
  } else if (entry.isFile() && extensions.some((ext) => entry.name.endsWith(ext))) {
@@ -631,7 +384,7 @@ function privacyValid() {
631
384
 
632
385
  // ../modules/data-lint/dist/rules/wiki-link-resolves.js
633
386
  import { readdir as readdir3 } from "fs/promises";
634
- import { basename as basename2, extname as extname2, join as join6 } from "path";
387
+ import { basename as basename2, extname as extname2, join as join4 } from "path";
635
388
  var WIKI_LINK = /\[\[([^\]|#]+)(?:[|#][^\]]*)?\]\]/g;
636
389
  function wikiLinkResolves(options) {
637
390
  let cache;
@@ -652,7 +405,7 @@ function wikiLinkResolves(options) {
652
405
  continue;
653
406
  }
654
407
  for (const entry of entries) {
655
- const full = join6(current, entry.name);
408
+ const full = join4(current, entry.name);
656
409
  if (entry.isDirectory()) {
657
410
  stack.push(full);
658
411
  } else if (entry.isFile()) {
@@ -737,7 +490,7 @@ __export(dist_exports5, {
737
490
 
738
491
  // ../modules/ai-coding-pitfalls/dist/catalog.js
739
492
  import { readdir as readdir4, readFile as readFile4 } from "fs/promises";
740
- import { basename as basename3, extname as extname3, join as join7 } from "path";
493
+ import { basename as basename3, extname as extname3, join as join5 } from "path";
741
494
  var PitfallCatalog = class {
742
495
  dir;
743
496
  constructor(dir) {
@@ -765,7 +518,7 @@ var PitfallCatalog = class {
765
518
  async entries() {
766
519
  try {
767
520
  const names = await readdir4(this.dir);
768
- return names.filter((n) => n.endsWith(".md")).map((n) => join7(this.dir, n));
521
+ return names.filter((n) => n.endsWith(".md")).map((n) => join5(this.dir, n));
769
522
  } catch (e) {
770
523
  if (e.code === "ENOENT")
771
524
  return [];
@@ -797,7 +550,7 @@ __export(dist_exports6, {
797
550
 
798
551
  // ../modules/tool-rules/dist/catalog.js
799
552
  import { readdir as readdir5, readFile as readFile5 } from "fs/promises";
800
- import { basename as basename4, extname as extname4, join as join8 } from "path";
553
+ import { basename as basename4, extname as extname4, join as join6 } from "path";
801
554
  var ToolRuleCatalog = class {
802
555
  dir;
803
556
  constructor(dir) {
@@ -830,7 +583,7 @@ var ToolRuleCatalog = class {
830
583
  async entries() {
831
584
  try {
832
585
  const names = await readdir5(this.dir);
833
- return names.filter((n) => n.endsWith(".md")).map((n) => join8(this.dir, n));
586
+ return names.filter((n) => n.endsWith(".md")).map((n) => join6(this.dir, n));
834
587
  } catch (e) {
835
588
  if (e.code === "ENOENT")
836
589
  return [];
@@ -2094,7 +1847,7 @@ __export(dist_exports8, {
2094
1847
 
2095
1848
  // ../modules/worklog/dist/store.js
2096
1849
  import { readdir as readdir6, readFile as readFile6, stat as stat2 } from "fs/promises";
2097
- import { join as join9, resolve as resolve3, sep as sep2 } from "path";
1850
+ import { join as join7, resolve, sep } from "path";
2098
1851
  var FILENAME_PATTERN = /^(\d{4}-\d{2}-\d{2})(?:_(\d{4}))?-(.+)\.md$/;
2099
1852
  var MONTH_PATTERN = /^\d{2}$/;
2100
1853
  var YEAR_PATTERN = /^\d{4}$/;
@@ -2108,17 +1861,17 @@ var WorklogStore = class {
2108
1861
  const years = await this.listSubdirs(this.rootDir, YEAR_PATTERN);
2109
1862
  const entries = [];
2110
1863
  for (const year of years) {
2111
- const yearDir = join9(this.rootDir, year);
1864
+ const yearDir = join7(this.rootDir, year);
2112
1865
  const months = await this.listSubdirs(yearDir, MONTH_PATTERN);
2113
1866
  for (const month of months) {
2114
- entries.push(...await this.entriesIn(join9(yearDir, month)));
1867
+ entries.push(...await this.entriesIn(join7(yearDir, month)));
2115
1868
  }
2116
1869
  }
2117
1870
  return entries.sort(compareWorklog);
2118
1871
  }
2119
1872
  /** Entries within one calendar month. */
2120
1873
  async listByMonth(year, month) {
2121
- const monthDir = join9(this.rootDir, String(year).padStart(4, "0"), String(month).padStart(2, "0"));
1874
+ const monthDir = join7(this.rootDir, String(year).padStart(4, "0"), String(month).padStart(2, "0"));
2122
1875
  const entries = await this.entriesIn(monthDir);
2123
1876
  return entries.sort(compareWorklog);
2124
1877
  }
@@ -2131,7 +1884,7 @@ var WorklogStore = class {
2131
1884
  const [year, month] = date.split("-");
2132
1885
  if (!year || !month)
2133
1886
  return void 0;
2134
- const monthDir = join9(this.rootDir, year, month);
1887
+ const monthDir = join7(this.rootDir, year, month);
2135
1888
  const entries = (await this.entriesIn(monthDir)).filter((e) => e.date === date).sort(compareWorklog);
2136
1889
  return entries[0];
2137
1890
  }
@@ -2153,7 +1906,7 @@ var WorklogStore = class {
2153
1906
  const [year, month] = date.split("-");
2154
1907
  validateSegment("keyword", keyword);
2155
1908
  const stem = time ? `${date}_${time}-${keyword}` : `${date}-${keyword}`;
2156
- const abs = join9(this.rootDir, year, month, `${stem}.md`);
1909
+ const abs = join7(this.rootDir, year, month, `${stem}.md`);
2157
1910
  assertContained(abs, this.rootDir);
2158
1911
  return abs;
2159
1912
  }
@@ -2181,7 +1934,7 @@ var WorklogStore = class {
2181
1934
  const match = name.match(FILENAME_PATTERN);
2182
1935
  if (!match)
2183
1936
  continue;
2184
- const path = join9(monthDir, name);
1937
+ const path = join7(monthDir, name);
2185
1938
  try {
2186
1939
  const info = await stat2(path);
2187
1940
  if (!info.isFile())
@@ -2222,15 +1975,15 @@ function validateSegment(label, value) {
2222
1975
  throw new Error(`${label} must not contain NUL or control characters: ${value}`);
2223
1976
  }
2224
1977
  function assertContained(abs, rootDir) {
2225
- const root = resolve3(rootDir);
2226
- const target = resolve3(abs);
2227
- if (target !== root && !(target + sep2).startsWith(root + sep2)) {
1978
+ const root = resolve(rootDir);
1979
+ const target = resolve(abs);
1980
+ if (target !== root && !(target + sep).startsWith(root + sep)) {
2228
1981
  throw new Error(`Refusing to write outside the store directory: ${abs}`);
2229
1982
  }
2230
1983
  }
2231
1984
 
2232
1985
  // ../modules/worklog/dist/append.js
2233
- import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
1986
+ import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
2234
1987
  async function appendSection(entry, title, body) {
2235
1988
  const original = await readFile7(entry.path, "utf8");
2236
1989
  const trimmed = original.replace(/\s+$/u, "");
@@ -2241,7 +1994,7 @@ ${body.trimEnd()}
2241
1994
  const next = `${trimmed}
2242
1995
 
2243
1996
  ${section}`;
2244
- await writeFile4(entry.path, next, "utf8");
1997
+ await writeFile3(entry.path, next, "utf8");
2245
1998
  return next;
2246
1999
  }
2247
2000
 
@@ -2254,7 +2007,7 @@ __export(dist_exports9, {
2254
2007
 
2255
2008
  // ../modules/decision-log/dist/store.js
2256
2009
  import { readdir as readdir7, readFile as readFile8, stat as stat3 } from "fs/promises";
2257
- import { join as join10, resolve as resolve4, sep as sep3 } from "path";
2010
+ import { join as join8, resolve as resolve2, sep as sep2 } from "path";
2258
2011
  var FILENAME_PATTERN2 = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
2259
2012
  var DecisionStore = class {
2260
2013
  rootDir;
@@ -2276,7 +2029,7 @@ var DecisionStore = class {
2276
2029
  const match = name.match(FILENAME_PATTERN2);
2277
2030
  if (!match)
2278
2031
  continue;
2279
- const path = join10(this.rootDir, name);
2032
+ const path = join8(this.rootDir, name);
2280
2033
  try {
2281
2034
  const info = await stat3(path);
2282
2035
  if (!info.isFile())
@@ -2348,7 +2101,7 @@ var DecisionStore = class {
2348
2101
  throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);
2349
2102
  }
2350
2103
  validateSegment2("slug", slug);
2351
- const abs = join10(this.rootDir, `${date}-${slug}.md`);
2104
+ const abs = join8(this.rootDir, `${date}-${slug}.md`);
2352
2105
  assertContained2(abs, this.rootDir);
2353
2106
  return abs;
2354
2107
  }
@@ -2367,9 +2120,9 @@ function validateSegment2(label, value) {
2367
2120
  throw new Error(`${label} must not contain NUL or control characters: ${value}`);
2368
2121
  }
2369
2122
  function assertContained2(abs, rootDir) {
2370
- const root = resolve4(rootDir);
2371
- const target = resolve4(abs);
2372
- if (target !== root && !(target + sep3).startsWith(root + sep3)) {
2123
+ const root = resolve2(rootDir);
2124
+ const target = resolve2(abs);
2125
+ if (target !== root && !(target + sep2).startsWith(root + sep2)) {
2373
2126
  throw new Error(`Refusing to write outside the store directory: ${abs}`);
2374
2127
  }
2375
2128
  }
@@ -2434,7 +2187,7 @@ __export(dist_exports10, {
2434
2187
 
2435
2188
  // ../modules/index-generator/dist/scan.js
2436
2189
  import { readdir as readdir8, readFile as readFile9, stat as stat4 } from "fs/promises";
2437
- import { basename as basename5, extname as extname5, join as join11, relative as relative2 } from "path";
2190
+ import { basename as basename5, extname as extname5, join as join9, relative } from "path";
2438
2191
  var RESERVED_FILES = /* @__PURE__ */ new Set(["README.md", "_INDEX.md"]);
2439
2192
  var H1_PATTERN = /^#\s+(.+?)\s*$/m;
2440
2193
  async function scanDirectory(rootDir, opts = {}) {
@@ -2464,7 +2217,7 @@ async function walk(rootDir, currentDir, recursive, skipFilenames, skipPrefixes,
2464
2217
  continue;
2465
2218
  if (name.startsWith(".") || name.startsWith("_"))
2466
2219
  continue;
2467
- await walk(rootDir, join11(currentDir, name), recursive, skipFilenames, skipPrefixes, out);
2220
+ await walk(rootDir, join9(currentDir, name), recursive, skipFilenames, skipPrefixes, out);
2468
2221
  continue;
2469
2222
  }
2470
2223
  if (!dirent.isFile())
@@ -2476,7 +2229,7 @@ async function walk(rootDir, currentDir, recursive, skipFilenames, skipPrefixes,
2476
2229
  const nameNoExt = basename5(name, ".md");
2477
2230
  if (skipPrefixes.some((p) => nameNoExt.startsWith(p)))
2478
2231
  continue;
2479
- const fullPath = join11(currentDir, name);
2232
+ const fullPath = join9(currentDir, name);
2480
2233
  let info;
2481
2234
  try {
2482
2235
  info = await stat4(fullPath);
@@ -2493,7 +2246,7 @@ async function walk(rootDir, currentDir, recursive, skipFilenames, skipPrefixes,
2493
2246
  const updated = stringField(frontmatter, "updated") ?? stringField(frontmatter, "created");
2494
2247
  const scope = stringField(frontmatter, "scope");
2495
2248
  out.push({
2496
- relPath: relative2(rootDir, fullPath).split(/[\\/]/).join("/"),
2249
+ relPath: relative(rootDir, fullPath).split(/[\\/]/).join("/"),
2497
2250
  name: nameNoExt,
2498
2251
  title,
2499
2252
  description,
@@ -2632,7 +2385,7 @@ function today() {
2632
2385
 
2633
2386
  // ../modules/index-generator/dist/nested.js
2634
2387
  import { readdir as readdir9, stat as stat5 } from "fs/promises";
2635
- import { extname as extname6, join as join12 } from "path";
2388
+ import { extname as extname6, join as join10 } from "path";
2636
2389
  async function findIndexableDirs(rootDir, options = {}) {
2637
2390
  const minEntries = options.minEntries ?? 1;
2638
2391
  const skipPrefixes = options.skipPrefixes ?? [];
@@ -2668,7 +2421,7 @@ async function walk2(dir, minEntries, skipPrefixes, out) {
2668
2421
  if (skipPrefixes.some((p) => nameNoExt.startsWith(p)))
2669
2422
  continue;
2670
2423
  try {
2671
- const info = await stat5(join12(dir, dirent.name));
2424
+ const info = await stat5(join10(dir, dirent.name));
2672
2425
  if (!info.isFile())
2673
2426
  continue;
2674
2427
  } catch {
@@ -2680,7 +2433,7 @@ async function walk2(dir, minEntries, skipPrefixes, out) {
2680
2433
  out.push(dir);
2681
2434
  }
2682
2435
  for (const name of subdirs) {
2683
- await walk2(join12(dir, name), minEntries, skipPrefixes, out);
2436
+ await walk2(join10(dir, name), minEntries, skipPrefixes, out);
2684
2437
  }
2685
2438
  }
2686
2439
 
@@ -2692,7 +2445,7 @@ __export(dist_exports11, {
2692
2445
 
2693
2446
  // ../modules/runbooks/dist/store.js
2694
2447
  import { readdir as readdir10, readFile as readFile10, stat as stat6 } from "fs/promises";
2695
- import { extname as extname7, join as join13 } from "path";
2448
+ import { extname as extname7, join as join11 } from "path";
2696
2449
  var RESERVED_FILES2 = /* @__PURE__ */ new Set(["README.md", "_INDEX.md"]);
2697
2450
  var RunbookStore = class {
2698
2451
  rootDir;
@@ -2715,7 +2468,7 @@ var RunbookStore = class {
2715
2468
  continue;
2716
2469
  if (RESERVED_FILES2.has(name))
2717
2470
  continue;
2718
- const path = join13(this.rootDir, name);
2471
+ const path = join11(this.rootDir, name);
2719
2472
  try {
2720
2473
  const info = await stat6(path);
2721
2474
  if (!info.isFile())
@@ -2824,7 +2577,7 @@ function extractWikiLinks(body) {
2824
2577
 
2825
2578
  // ../modules/link-rewriter/dist/resolve.js
2826
2579
  import { readdir as readdir11 } from "fs/promises";
2827
- import { basename as basename6, dirname, extname as extname8, isAbsolute as isAbsolute2, join as join14, relative as relative3, resolve as pathResolve } from "path";
2580
+ import { basename as basename6, dirname, extname as extname8, isAbsolute, join as join12, relative as relative2, resolve as pathResolve } from "path";
2828
2581
  async function buildFileIndex(rootDir, options = {}) {
2829
2582
  const byBasename = /* @__PURE__ */ new Map();
2830
2583
  const byRelPath = /* @__PURE__ */ new Map();
@@ -2857,7 +2610,7 @@ async function walk3(rootDir, dir, byBasename, byRelPath, additionalExts) {
2857
2610
  if (dirent.isDirectory()) {
2858
2611
  if (name.startsWith("."))
2859
2612
  continue;
2860
- await walk3(rootDir, join14(dir, name), byBasename, byRelPath, additionalExts);
2613
+ await walk3(rootDir, join12(dir, name), byBasename, byRelPath, additionalExts);
2861
2614
  continue;
2862
2615
  }
2863
2616
  if (!dirent.isFile())
@@ -2866,7 +2619,7 @@ async function walk3(rootDir, dir, byBasename, byRelPath, additionalExts) {
2866
2619
  const isMd = ext === ".md";
2867
2620
  if (!isMd && !additionalExts.has(ext))
2868
2621
  continue;
2869
- const path = join14(dir, name);
2622
+ const path = join12(dir, name);
2870
2623
  const key = isMd ? basename6(name, ".md") : name;
2871
2624
  const list = byBasename.get(key);
2872
2625
  if (list) {
@@ -2874,7 +2627,7 @@ async function walk3(rootDir, dir, byBasename, byRelPath, additionalExts) {
2874
2627
  } else {
2875
2628
  byBasename.set(key, [path]);
2876
2629
  }
2877
- const relRaw = relative3(rootDir, path).split(/[\\/]/).join("/");
2630
+ const relRaw = relative2(rootDir, path).split(/[\\/]/).join("/");
2878
2631
  const rel = isMd ? relRaw.replace(/\.md$/, "") : relRaw;
2879
2632
  byRelPath.set(rel, path);
2880
2633
  }
@@ -2895,8 +2648,8 @@ function resolveLink(name, index, opts = {}) {
2895
2648
  return { kind: "not-found" };
2896
2649
  const baseDir = dirname(opts.sourcePath);
2897
2650
  const absolute = pathResolve(baseDir, normalized);
2898
- const rel = relative3(index.rootDir, absolute).split(/[\\/]/).join("/");
2899
- if (rel === ".." || rel.startsWith("../") || isAbsolute2(rel)) {
2651
+ const rel = relative2(index.rootDir, absolute).split(/[\\/]/).join("/");
2652
+ if (rel === ".." || rel.startsWith("../") || isAbsolute(rel)) {
2900
2653
  return { kind: "not-found" };
2901
2654
  }
2902
2655
  return lookupRelPath(rel, index);
@@ -2915,7 +2668,7 @@ function lookupRelPath(rel, index) {
2915
2668
  return { kind: "not-found" };
2916
2669
  }
2917
2670
  function toRel(path, rootDir) {
2918
- return relative3(rootDir, path).split(/[\\/]/).join("/");
2671
+ return relative2(rootDir, path).split(/[\\/]/).join("/");
2919
2672
  }
2920
2673
 
2921
2674
  // ../modules/link-rewriter/dist/checker.js
@@ -2965,7 +2718,7 @@ function topBrokenTargets(broken, limit = 20) {
2965
2718
  }
2966
2719
 
2967
2720
  // ../modules/link-rewriter/dist/rewrite.js
2968
- import { readFile as readFile12, writeFile as writeFile5 } from "fs/promises";
2721
+ import { readFile as readFile12, writeFile as writeFile4 } from "fs/promises";
2969
2722
  import { extname as extname10 } from "path";
2970
2723
  async function rewriteDirectory(rootDir, opts) {
2971
2724
  const { redirections, dryRun = false } = opts;
@@ -2987,7 +2740,7 @@ async function rewriteDirectory(rootDir, opts) {
2987
2740
  rewritesApplied += fileRewrites.length;
2988
2741
  details.push({ sourcePath: path, rewrites: fileRewrites });
2989
2742
  if (!dryRun) {
2990
- await writeFile5(path, newBody, "utf8");
2743
+ await writeFile4(path, newBody, "utf8");
2991
2744
  }
2992
2745
  }
2993
2746
  }
@@ -3091,18 +2844,18 @@ function normalizePath(p) {
3091
2844
  }
3092
2845
 
3093
2846
  // ../modules/proactive-curator/dist/doc-writer.js
3094
- import { existsSync as existsSync2 } from "fs";
2847
+ import { existsSync } from "fs";
3095
2848
  import { appendFile, mkdir as mkdir2, readFile as readFile13 } from "fs/promises";
3096
- import { dirname as dirname2, join as join15 } from "path";
2849
+ import { dirname as dirname2, join as join13 } from "path";
3097
2850
  async function writeDocAction(cwd, action) {
3098
- const dataDir = join15(cwd, "data");
2851
+ const dataDir = join13(cwd, "data");
3099
2852
  const abs = validateDataRelativePath(dataDir, action.targetRelPath);
3100
2853
  if (action.kind === "create-file") {
3101
2854
  await mkdir2(dirname2(abs), { recursive: true });
3102
2855
  await exclusiveCreateFile(abs, action.body);
3103
2856
  return { writtenPath: abs, kind: "create-file" };
3104
2857
  }
3105
- if (!existsSync2(abs)) {
2858
+ if (!existsSync(abs)) {
3106
2859
  throw new Error(`Cannot append-section: target file does not exist: ${action.targetRelPath}. append-section adds to an existing document; use create-file for a new one.`);
3107
2860
  }
3108
2861
  const existing = await readFile13(abs, "utf8");
@@ -3115,9 +2868,9 @@ ${action.body}`;
3115
2868
  }
3116
2869
 
3117
2870
  // ../modules/proactive-curator/dist/decline-store.js
3118
- import { existsSync as existsSync3 } from "fs";
3119
- import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile14, writeFile as writeFile6 } from "fs/promises";
3120
- import { join as join16 } from "path";
2871
+ import { existsSync as existsSync2 } from "fs";
2872
+ import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile14, writeFile as writeFile5 } from "fs/promises";
2873
+ import { join as join14 } from "path";
3121
2874
  var STORE_DIR = "data/_proactive-curator";
3122
2875
  var DECLINED_FILE = "declined.json";
3123
2876
  var ACCEPTED_LOG = "accepted.log";
@@ -3155,7 +2908,7 @@ async function recordDecline(cwd, args) {
3155
2908
  ...args.sourceDocs ? { sourceDocs: args.sourceDocs } : {}
3156
2909
  };
3157
2910
  updated[args.kind] = { ...updated[args.kind], [args.fingerprint]: entry };
3158
- await writeFile6(join16(cwd, STORE_DIR, DECLINED_FILE), JSON.stringify(updated, null, 2) + "\n", "utf8");
2911
+ await writeFile5(join14(cwd, STORE_DIR, DECLINED_FILE), JSON.stringify(updated, null, 2) + "\n", "utf8");
3159
2912
  }
3160
2913
  async function recordAcceptance(cwd, args) {
3161
2914
  await ensureStoreDir(cwd);
@@ -3167,19 +2920,19 @@ async function recordAcceptance(cwd, args) {
3167
2920
  actionKind: args.actionKind,
3168
2921
  writtenPath: args.writtenPath
3169
2922
  });
3170
- await appendFile2(join16(cwd, STORE_DIR, ACCEPTED_LOG), line + "\n", "utf8");
2923
+ await appendFile2(join14(cwd, STORE_DIR, ACCEPTED_LOG), line + "\n", "utf8");
3171
2924
  }
3172
2925
  async function resetDeclined(cwd, kind) {
3173
- const file = join16(cwd, STORE_DIR, DECLINED_FILE);
3174
- if (!existsSync3(file))
2926
+ const file = join14(cwd, STORE_DIR, DECLINED_FILE);
2927
+ if (!existsSync2(file))
3175
2928
  return;
3176
2929
  if (kind === void 0) {
3177
- await writeFile6(file, JSON.stringify(emptyDeclinedFile(), null, 2) + "\n", "utf8");
2930
+ await writeFile5(file, JSON.stringify(emptyDeclinedFile(), null, 2) + "\n", "utf8");
3178
2931
  return;
3179
2932
  }
3180
2933
  const parsed = await readDeclinedFile(cwd) ?? emptyDeclinedFile();
3181
2934
  parsed[kind] = {};
3182
- await writeFile6(file, JSON.stringify(parsed, null, 2) + "\n", "utf8");
2935
+ await writeFile5(file, JSON.stringify(parsed, null, 2) + "\n", "utf8");
3183
2936
  }
3184
2937
  function isActive(entry, nowMs) {
3185
2938
  const expiresMs = new Date(entry.expiresAt).getTime();
@@ -3200,8 +2953,8 @@ function purgeExpired(entries, now) {
3200
2953
  return out;
3201
2954
  }
3202
2955
  async function readDeclinedFile(cwd) {
3203
- const file = join16(cwd, STORE_DIR, DECLINED_FILE);
3204
- if (!existsSync3(file))
2956
+ const file = join14(cwd, STORE_DIR, DECLINED_FILE);
2957
+ if (!existsSync2(file))
3205
2958
  return null;
3206
2959
  try {
3207
2960
  const raw = await readFile14(file, "utf8");
@@ -3218,14 +2971,14 @@ function emptyDeclinedFile() {
3218
2971
  return { "capture-insight": {}, "create-hub": {} };
3219
2972
  }
3220
2973
  async function ensureStoreDir(cwd) {
3221
- await mkdir3(join16(cwd, STORE_DIR), { recursive: true });
2974
+ await mkdir3(join14(cwd, STORE_DIR), { recursive: true });
3222
2975
  }
3223
2976
 
3224
2977
  // ../modules/proactive-curator/dist/insight-proposer.js
3225
- import { existsSync as existsSync4 } from "fs";
3226
- import { mkdir as mkdir4, readFile as readFile15, readdir as readdir12, writeFile as writeFile7 } from "fs/promises";
3227
- import { dirname as dirname3, join as join17 } from "path";
3228
- var SYSTEM_META_DIRS2 = /* @__PURE__ */ new Set([
2978
+ import { existsSync as existsSync3 } from "fs";
2979
+ import { mkdir as mkdir4, readFile as readFile15, readdir as readdir12, writeFile as writeFile6 } from "fs/promises";
2980
+ import { dirname as dirname3, join as join15 } from "path";
2981
+ var SYSTEM_META_DIRS = /* @__PURE__ */ new Set([
3229
2982
  "worklog",
3230
2983
  "decision-log",
3231
2984
  "runbooks",
@@ -3435,7 +3188,7 @@ function normalizePlacementDecision(raw) {
3435
3188
  function isSystemMetaPath(p) {
3436
3189
  const normalized = p.replace(/\\/g, "/").replace(/^\/+/, "");
3437
3190
  const first = normalized.split("/")[0] ?? "";
3438
- if (SYSTEM_META_DIRS2.has(first))
3191
+ if (SYSTEM_META_DIRS.has(first))
3439
3192
  return true;
3440
3193
  if (first.startsWith("_"))
3441
3194
  return true;
@@ -3530,7 +3283,7 @@ function joinDataPath(...parts) {
3530
3283
  return parts.filter((p) => p.length > 0).map((p) => p.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "")).join("/");
3531
3284
  }
3532
3285
  async function applyAction(cwd, action) {
3533
- const dataDir = join17(cwd, "data");
3286
+ const dataDir = join15(cwd, "data");
3534
3287
  switch (action.kind) {
3535
3288
  case "create-file": {
3536
3289
  const res = await writeDocAction(cwd, {
@@ -3560,7 +3313,7 @@ async function applyAction(cwd, action) {
3560
3313
  const rel = joinDataPath(action.filePath);
3561
3314
  const file = validateDataRelativePath(dataDir, rel);
3562
3315
  await mkdir4(dirname3(file), { recursive: true });
3563
- await writeFile7(file, action.body, "utf8");
3316
+ await writeFile6(file, action.body, "utf8");
3564
3317
  return file;
3565
3318
  }
3566
3319
  }
@@ -3575,8 +3328,8 @@ function nextActionHintFor(action) {
3575
3328
  return `New file at ${action.folderPath}/${action.filename}. Add cross-links from related docs as the topic grows.`;
3576
3329
  }
3577
3330
  async function scanTopicTree(cwd, maxEntries) {
3578
- const dataDir = join17(cwd, "data");
3579
- if (!existsSync4(dataDir)) {
3331
+ const dataDir = join15(cwd, "data");
3332
+ if (!existsSync3(dataDir)) {
3580
3333
  return { folders: [], truncated: false };
3581
3334
  }
3582
3335
  const folders = [];
@@ -3603,7 +3356,7 @@ async function scanTopicTree(cwd, maxEntries) {
3603
3356
  } else if (e.isFile() && e.name.endsWith(".md")) {
3604
3357
  if (e.name === "README.md" || e.name === "_INDEX.md" || e.name === "MEMORY.md")
3605
3358
  continue;
3606
- const filePath = join17(absDir, e.name);
3359
+ const filePath = join15(absDir, e.name);
3607
3360
  let frontmatterTopic;
3608
3361
  let tags;
3609
3362
  try {
@@ -3640,14 +3393,14 @@ async function scanTopicTree(cwd, maxEntries) {
3640
3393
  return;
3641
3394
  }
3642
3395
  const childRel = joinDataPath(relDir, d2);
3643
- await visit(join17(absDir, d2), childRel);
3396
+ await visit(join15(absDir, d2), childRel);
3644
3397
  }
3645
3398
  }
3646
3399
  await visit(dataDir, "");
3647
3400
  return { folders, truncated };
3648
3401
  }
3649
3402
  function isReservedDir(name, atRoot) {
3650
- if (atRoot && SYSTEM_META_DIRS2.has(name))
3403
+ if (atRoot && SYSTEM_META_DIRS.has(name))
3651
3404
  return true;
3652
3405
  if (name.startsWith("."))
3653
3406
  return true;
@@ -3657,9 +3410,9 @@ function isReservedDir(name, atRoot) {
3657
3410
  }
3658
3411
 
3659
3412
  // ../modules/proactive-curator/dist/hub-proposer.js
3660
- import { existsSync as existsSync5 } from "fs";
3413
+ import { existsSync as existsSync4 } from "fs";
3661
3414
  import { mkdir as mkdir5, readFile as readFile16, readdir as readdir13 } from "fs/promises";
3662
- import { join as join18 } from "path";
3415
+ import { join as join16 } from "path";
3663
3416
  var DEFAULT_CATEGORIES = [
3664
3417
  "worklog",
3665
3418
  "decision-log",
@@ -3746,13 +3499,13 @@ var HubProposer = class {
3746
3499
  }
3747
3500
  };
3748
3501
  async function scanDocs(cwd, categories) {
3749
- const dataDir = join18(cwd, "data");
3750
- if (!existsSync5(dataDir))
3502
+ const dataDir = join16(cwd, "data");
3503
+ if (!existsSync4(dataDir))
3751
3504
  return [];
3752
3505
  const out = [];
3753
3506
  for (const category of categories) {
3754
- const abs = join18(dataDir, category);
3755
- if (!existsSync5(abs))
3507
+ const abs = join16(dataDir, category);
3508
+ if (!existsSync4(abs))
3756
3509
  continue;
3757
3510
  await walk4(abs, category, out);
3758
3511
  }
@@ -3769,13 +3522,13 @@ async function walk4(absDir, relPath, acc) {
3769
3522
  if (e.isDirectory()) {
3770
3523
  if (e.name.startsWith(".") || e.name.startsWith("_"))
3771
3524
  continue;
3772
- await walk4(join18(absDir, e.name), `${relPath}/${e.name}`, acc);
3525
+ await walk4(join16(absDir, e.name), `${relPath}/${e.name}`, acc);
3773
3526
  } else if (e.isFile() && e.name.endsWith(".md")) {
3774
3527
  if (e.name === "README.md" || e.name === "_INDEX.md" || e.name === "MEMORY.md")
3775
3528
  continue;
3776
3529
  if (e.name.startsWith("_TEMPLATE"))
3777
3530
  continue;
3778
- const filePath = join18(absDir, e.name);
3531
+ const filePath = join16(absDir, e.name);
3779
3532
  let frontmatterTopic;
3780
3533
  let tags = [];
3781
3534
  try {
@@ -3846,8 +3599,8 @@ function pickCluster(clusters, weakThreshold, cwd) {
3846
3599
  for (const c of clusters) {
3847
3600
  if (c.docs.length < weakThreshold)
3848
3601
  return null;
3849
- const hubPath = join18(cwd, "data", HUB_DIR, `_HUB-${c.topic}.md`);
3850
- if (existsSync5(hubPath))
3602
+ const hubPath = join16(cwd, "data", HUB_DIR, `_HUB-${c.topic}.md`);
3603
+ if (existsSync4(hubPath))
3851
3604
  continue;
3852
3605
  return c;
3853
3606
  }
@@ -3970,9 +3723,9 @@ async function applyHubCreate(cwd, action) {
3970
3723
  if (fn.trim().length === 0 || fn === "." || fn === ".." || unsafe.test(fn)) {
3971
3724
  throw new Error(`Refusing to create hub: unsafe filename "${action.filename}" \u2014 must be a plain basename with no path separators, traversal, or reserved characters (including ":").`);
3972
3725
  }
3973
- const folder = join18(cwd, "data", HUB_DIR);
3726
+ const folder = join16(cwd, "data", HUB_DIR);
3974
3727
  await mkdir5(folder, { recursive: true });
3975
- const file = join18(folder, fn);
3728
+ const file = join16(folder, fn);
3976
3729
  await exclusiveCreateFile(file, action.body);
3977
3730
  return file;
3978
3731
  }
@@ -4259,6 +4012,10 @@ var ClaudeDesktopLLMJudge = class extends InjectedLLMJudge {
4259
4012
  var dist_exports14 = {};
4260
4013
  __export(dist_exports14, {
4261
4014
  DEFAULT_GAP_WINDOW_DAYS: () => DEFAULT_GAP_WINDOW_DAYS,
4015
+ FAILURES_DIR: () => FAILURES_DIR,
4016
+ GUARD_DENIAL_KEY: () => GUARD_DENIAL_KEY,
4017
+ GUARD_WRITE_COMMAND: () => GUARD_WRITE_COMMAND,
4018
+ GUARD_WRITE_MATCHER: () => GUARD_WRITE_MATCHER,
4262
4019
  HANDOFF_ARCHIVE_DIR: () => HANDOFF_ARCHIVE_DIR,
4263
4020
  HANDOFF_DIR: () => HANDOFF_DIR,
4264
4021
  OWNERSHIP_SCHEMA: () => OWNERSHIP_SCHEMA,
@@ -4269,6 +4026,7 @@ __export(dist_exports14, {
4269
4026
  applyGlobalSetup: () => applyGlobalSetup,
4270
4027
  argvToSlash: () => argvToSlash,
4271
4028
  autoReindexMemory: () => autoReindexMemory,
4029
+ buildDenyDecision: () => buildDenyDecision,
4272
4030
  buildInstallCommand: () => buildInstallCommand,
4273
4031
  buildOwnershipManifest: () => buildOwnershipManifest,
4274
4032
  buildRegistry: () => buildRegistry,
@@ -4294,6 +4052,8 @@ __export(dist_exports14, {
4294
4052
  ensureWorklogEntry: () => ensureWorklogEntry,
4295
4053
  extractNextUp: () => extractNextUp,
4296
4054
  extractOpenTasks: () => extractOpenTasks,
4055
+ failureReportSlice: () => failureReportSlice,
4056
+ findControlChar: () => findControlChar,
4297
4057
  formatTokens: () => formatTokens,
4298
4058
  formatWindow: () => formatWindow,
4299
4059
  gapWindowSinceArg: () => gapWindowSinceArg,
@@ -4301,12 +4061,15 @@ __export(dist_exports14, {
4301
4061
  globalSettingsHasHook: () => globalSettingsHasHook,
4302
4062
  globalSettingsPath: () => globalSettingsPath,
4303
4063
  globalStatePath: () => globalStatePath,
4064
+ guardWriteDecision: () => guardWriteDecision,
4304
4065
  handoffCommand: () => handoffCommand,
4305
4066
  inspectGlobalSetup: () => inspectGlobalSetup,
4306
4067
  inspectOwnership: () => inspectOwnership,
4307
4068
  isInstanceRoot: () => isInstanceRoot,
4308
4069
  isNewer: () => isNewer,
4309
4070
  isStableUpdate: () => isStableUpdate,
4071
+ isValidFailureKey: () => isValidFailureKey,
4072
+ ladderStage: () => ladderStage,
4310
4073
  logCommand: () => logCommand,
4311
4074
  makeBar: () => makeBar,
4312
4075
  ownershipManifestPath: () => ownershipManifestPath,
@@ -4318,23 +4081,30 @@ __export(dist_exports14, {
4318
4081
  readGlobalInstancePointer: () => readGlobalInstancePointer,
4319
4082
  readInstalledBaseVersion: () => readInstalledBaseVersion,
4320
4083
  recallCommand: () => recallCommand,
4084
+ recordFailure: () => recordFailure,
4321
4085
  recordGlobalSetupDecline: () => recordGlobalSetupDecline,
4086
+ recordGuardDenial: () => recordGuardDenial,
4322
4087
  reindexCommand: () => reindexCommand,
4323
4088
  renderAgenda: () => renderAgenda,
4324
4089
  renderGlobalBlock: () => renderGlobalBlock,
4325
4090
  renderSessionStartReport: () => renderSessionStartReport,
4326
4091
  renderStatusline: () => renderStatusline,
4327
4092
  repairOwnershipManifest: () => repairOwnershipManifest,
4093
+ resolveInstanceRoot: () => resolveInstanceRoot,
4328
4094
  resolveRepoRoot: () => resolveRepoRoot,
4329
4095
  runCurateAccept: () => runCurateAccept,
4330
4096
  runCurateCandidates: () => runCurateCandidates,
4331
4097
  runCurateDecline: () => runCurateDecline,
4332
4098
  runCuratePreview: () => runCuratePreview,
4099
+ runFailureCli: () => runFailureCli,
4100
+ runGuardCli: () => runGuardCli,
4333
4101
  runStatuslineCli: () => runStatuslineCli,
4334
4102
  runTemplatesUpdate: () => runTemplatesUpdate,
4335
4103
  runVortexCli: () => runVortexCli,
4336
4104
  safeSegment: () => safeSegment,
4105
+ scanFailures: () => scanFailures,
4337
4106
  scanHandoffs: () => scanHandoffs,
4107
+ scanToolInput: () => scanToolInput,
4338
4108
  serializeSettings: () => serializeSettings,
4339
4109
  sessionStartCommand: () => sessionStartCommand,
4340
4110
  sniffEffortFromTranscript: () => sniffEffortFromTranscript,
@@ -4448,7 +4218,7 @@ function curateCommand(options) {
4448
4218
  }
4449
4219
 
4450
4220
  // ../plugins/session-rituals/dist/commands/recall.js
4451
- import { join as join19 } from "path";
4221
+ import { join as join17 } from "path";
4452
4222
  function asMode(s) {
4453
4223
  return s === "keyword" || s === "semantic" || s === "hybrid" ? s : void 0;
4454
4224
  }
@@ -4484,7 +4254,7 @@ function parseRecallArgs(rest, defaultK) {
4484
4254
  return out;
4485
4255
  }
4486
4256
  function defaultDbPath(ctx) {
4487
- return join19(ctx.dataDir, "_indexes", "memory.sqlite");
4257
+ return join17(ctx.dataDir, "_indexes", "memory.sqlite");
4488
4258
  }
4489
4259
  function recallCommand(options) {
4490
4260
  const defaultK = options.defaultK ?? 5;
@@ -4542,9 +4312,9 @@ function recallCommand(options) {
4542
4312
  }
4543
4313
 
4544
4314
  // ../plugins/session-rituals/dist/commands/decision.js
4545
- import { writeFile as writeFile8 } from "fs/promises";
4546
- import { join as join20 } from "path";
4547
- import { existsSync as existsSync6 } from "fs";
4315
+ import { writeFile as writeFile7 } from "fs/promises";
4316
+ import { join as join18 } from "path";
4317
+ import { existsSync as existsSync5 } from "fs";
4548
4318
  var decisionCommand = {
4549
4319
  name: "decision",
4550
4320
  description: "Create a new Decision Log entry from the canonical template at `data/decision-log/<today>-<slug>.md`. Refuses to overwrite an existing file.",
@@ -4562,14 +4332,14 @@ var decisionCommand = {
4562
4332
  throw new Error("`/decision` requires a title after the slug.");
4563
4333
  }
4564
4334
  const date = todayIso();
4565
- const dir = join20(input.context.dataDir, "decision-log");
4335
+ const dir = join18(input.context.dataDir, "decision-log");
4566
4336
  const store = new DecisionStore(dir);
4567
4337
  const path = store.pathFor(date, slug);
4568
- if (existsSync6(path)) {
4338
+ if (existsSync5(path)) {
4569
4339
  throw new Error(`Refusing to overwrite existing entry: ${path}`);
4570
4340
  }
4571
4341
  const body = renderTemplate({ date, slug, title });
4572
- await writeFile8(path, body, "utf8");
4342
+ await writeFile7(path, body, "utf8");
4573
4343
  return { path, date, slug };
4574
4344
  }
4575
4345
  };
@@ -4589,9 +4359,9 @@ function todayIso() {
4589
4359
  }
4590
4360
 
4591
4361
  // ../plugins/session-rituals/dist/commands/reindex.js
4592
- import { existsSync as existsSync7 } from "fs";
4593
- import { readFile as readFile17, writeFile as writeFile9, utimes } from "fs/promises";
4594
- import { join as join21 } from "path";
4362
+ import { existsSync as existsSync6 } from "fs";
4363
+ import { readFile as readFile17, writeFile as writeFile8, utimes } from "fs/promises";
4364
+ import { join as join19 } from "path";
4595
4365
  var TARGETS = [
4596
4366
  {
4597
4367
  dir: "_memory",
@@ -4701,8 +4471,8 @@ var reindexCommand = {
4701
4471
  }
4702
4472
  const results = [];
4703
4473
  for (const t of targets) {
4704
- const dir = join21(input.context.dataDir, t.dir);
4705
- if (!existsSync7(dir)) {
4474
+ const dir = join19(input.context.dataDir, t.dir);
4475
+ if (!existsSync6(dir)) {
4706
4476
  results.push({ dir: t.dir, status: "missing", entries: 0, bytes: 0 });
4707
4477
  continue;
4708
4478
  }
@@ -4717,7 +4487,7 @@ var reindexCommand = {
4717
4487
  entries,
4718
4488
  privacy: t.privacy
4719
4489
  });
4720
- const target = join21(dir, "_INDEX.md");
4490
+ const target = join19(dir, "_INDEX.md");
4721
4491
  let existing;
4722
4492
  try {
4723
4493
  existing = await readFile17(target, "utf8");
@@ -4733,7 +4503,7 @@ var reindexCommand = {
4733
4503
  });
4734
4504
  continue;
4735
4505
  }
4736
- await writeFile9(target, body, "utf8");
4506
+ await writeFile8(target, body, "utf8");
4737
4507
  results.push({
4738
4508
  dir: t.dir,
4739
4509
  status: "written",
@@ -4749,8 +4519,8 @@ async function autoReindexMemory(ctx) {
4749
4519
  const target = TARGETS.find((t) => t.dir === "_memory");
4750
4520
  if (!target)
4751
4521
  return "missing";
4752
- const dir = join21(ctx.dataDir, target.dir);
4753
- if (!existsSync7(dir))
4522
+ const dir = join19(ctx.dataDir, target.dir);
4523
+ if (!existsSync6(dir))
4754
4524
  return "missing";
4755
4525
  const entries = await scanDirectory(dir, {
4756
4526
  recursive: target.recursive,
@@ -4763,7 +4533,7 @@ async function autoReindexMemory(ctx) {
4763
4533
  entries,
4764
4534
  privacy: target.privacy
4765
4535
  });
4766
- const indexPath = join21(dir, "_INDEX.md");
4536
+ const indexPath = join19(dir, "_INDEX.md");
4767
4537
  let existing;
4768
4538
  try {
4769
4539
  existing = await readFile17(indexPath, "utf8");
@@ -4775,10 +4545,10 @@ async function autoReindexMemory(ctx) {
4775
4545
  if (sameListing) {
4776
4546
  status = "unchanged";
4777
4547
  } else {
4778
- await writeFile9(indexPath, body, "utf8");
4548
+ await writeFile8(indexPath, body, "utf8");
4779
4549
  status = "written";
4780
4550
  }
4781
- if (existsSync7(indexPath)) {
4551
+ if (existsSync6(indexPath)) {
4782
4552
  const now = /* @__PURE__ */ new Date();
4783
4553
  await utimes(indexPath, now, now);
4784
4554
  }
@@ -4792,9 +4562,9 @@ function stripIndexDate(body) {
4792
4562
  }
4793
4563
 
4794
4564
  // ../plugins/session-rituals/dist/commands/session-start.js
4795
- import { existsSync as existsSync8 } from "fs";
4565
+ import { existsSync as existsSync7 } from "fs";
4796
4566
  import { readdir as readdir14 } from "fs/promises";
4797
- import { join as join22 } from "path";
4567
+ import { join as join20 } from "path";
4798
4568
  var COUNTED_DIRS = ["_memory", "worklog", "decision-log"];
4799
4569
  var sessionStartCommand = {
4800
4570
  name: "session-start",
@@ -4804,8 +4574,8 @@ var sessionStartCommand = {
4804
4574
  const counts = {};
4805
4575
  const missing = [];
4806
4576
  for (const name of COUNTED_DIRS) {
4807
- const dir = join22(dataDir, name);
4808
- if (!existsSync8(dir)) {
4577
+ const dir = join20(dataDir, name);
4578
+ if (!existsSync7(dir)) {
4809
4579
  missing.push(name);
4810
4580
  counts[name] = 0;
4811
4581
  continue;
@@ -4837,7 +4607,7 @@ async function countMarkdown(dir, recursive) {
4837
4607
  } else if (e.isDirectory() && recursive) {
4838
4608
  if (e.name.startsWith(".") || e.name.startsWith("_"))
4839
4609
  continue;
4840
- total += await countMarkdown(join22(dir, e.name), recursive);
4610
+ total += await countMarkdown(join20(dir, e.name), recursive);
4841
4611
  }
4842
4612
  }
4843
4613
  return total;
@@ -4883,9 +4653,9 @@ function todayIso2() {
4883
4653
  }
4884
4654
 
4885
4655
  // ../plugins/session-rituals/dist/handoff.js
4886
- import { existsSync as existsSync9 } from "fs";
4887
- import { mkdir as mkdir6, open, readdir as readdir15, readFile as readFile18, rename as rename2, stat as stat7 } from "fs/promises";
4888
- import { join as join23 } from "path";
4656
+ import { existsSync as existsSync8 } from "fs";
4657
+ import { mkdir as mkdir6, open, readdir as readdir15, readFile as readFile18, rename, stat as stat7 } from "fs/promises";
4658
+ import { join as join21 } from "path";
4889
4659
 
4890
4660
  // ../plugins/session-rituals/dist/agenda.js
4891
4661
  var DEFAULT_RECENT = 7;
@@ -5083,7 +4853,7 @@ async function createHandoffSkeleton(dataDir, opts) {
5083
4853
  const now = opts?.now ?? /* @__PURE__ */ new Date();
5084
4854
  const date = isoDate(now);
5085
4855
  const time = isoTime(now);
5086
- const dir = join23(dataDir, HANDOFF_DIR);
4856
+ const dir = join21(dataDir, HANDOFF_DIR);
5087
4857
  await mkdir6(dir, { recursive: true });
5088
4858
  const stamp = `${date} ${time.slice(0, 2)}:${time.slice(2)}`;
5089
4859
  const title = (opts?.title ?? "").trim();
@@ -5091,7 +4861,7 @@ async function createHandoffSkeleton(dataDir, opts) {
5091
4861
  const base = `${date}_${time}`;
5092
4862
  for (let i = 0; i < MAX_COLLISION_TRIES; i++) {
5093
4863
  const name = i === 0 ? `${base}.md` : `${base}-${i + 1}.md`;
5094
- const abs = join23(dir, name);
4864
+ const abs = join21(dir, name);
5095
4865
  try {
5096
4866
  const fh = await open(abs, "wx");
5097
4867
  try {
@@ -5125,8 +4895,8 @@ ${heading}
5125
4895
  `;
5126
4896
  }
5127
4897
  async function scanHandoffs(dataDir, opts) {
5128
- const dir = join23(dataDir, HANDOFF_DIR);
5129
- if (!existsSync9(dir))
4898
+ const dir = join21(dataDir, HANDOFF_DIR);
4899
+ if (!existsSync8(dir))
5130
4900
  return { active: [], omitted: 0 };
5131
4901
  let names;
5132
4902
  try {
@@ -5140,7 +4910,7 @@ async function scanHandoffs(dataDir, opts) {
5140
4910
  const omitted = Math.max(0, matched.length - take.length);
5141
4911
  const active = [];
5142
4912
  for (const { name, m: m2 } of take) {
5143
- const abs = join23(dir, name);
4913
+ const abs = join21(dir, name);
5144
4914
  let title = name.replace(/\.md$/, "");
5145
4915
  let nextUp = [];
5146
4916
  try {
@@ -5160,8 +4930,8 @@ async function scanHandoffs(dataDir, opts) {
5160
4930
  async function pruneHandoffs(dataDir, opts) {
5161
4931
  const now = opts.now ?? /* @__PURE__ */ new Date();
5162
4932
  const retentionDays = opts.retentionDays;
5163
- const dir = join23(dataDir, HANDOFF_DIR);
5164
- if (!existsSync9(dir) || !(retentionDays > 0))
4933
+ const dir = join21(dataDir, HANDOFF_DIR);
4934
+ if (!existsSync8(dir) || !(retentionDays > 0))
5165
4935
  return { archived: 0 };
5166
4936
  let names;
5167
4937
  try {
@@ -5173,21 +4943,21 @@ async function pruneHandoffs(dataDir, opts) {
5173
4943
  const stale = names.map((name) => ({ name, m: name.match(HANDOFF_PATTERN) })).filter((x2) => x2.m !== null && x2.m[1] < cutoff);
5174
4944
  if (stale.length === 0)
5175
4945
  return { archived: 0 };
5176
- const archiveDir = join23(dir, HANDOFF_ARCHIVE_DIR);
4946
+ const archiveDir = join21(dir, HANDOFF_ARCHIVE_DIR);
5177
4947
  await mkdir6(archiveDir, { recursive: true });
5178
4948
  let archived = 0;
5179
4949
  for (const { name } of stale) {
5180
- const from = join23(dir, name);
5181
- let to = join23(archiveDir, name);
5182
- if (existsSync9(to)) {
4950
+ const from = join21(dir, name);
4951
+ let to = join21(archiveDir, name);
4952
+ if (existsSync8(to)) {
5183
4953
  const stem = name.replace(/\.md$/, "");
5184
4954
  let i = 2;
5185
- while (existsSync9(join23(archiveDir, `${stem}-${i}.md`)))
4955
+ while (existsSync8(join21(archiveDir, `${stem}-${i}.md`)))
5186
4956
  i++;
5187
- to = join23(archiveDir, `${stem}-${i}.md`);
4957
+ to = join21(archiveDir, `${stem}-${i}.md`);
5188
4958
  }
5189
4959
  try {
5190
- await rename2(from, to);
4960
+ await rename(from, to);
5191
4961
  archived++;
5192
4962
  } catch {
5193
4963
  }
@@ -5235,16 +5005,16 @@ var handoffCommand = {
5235
5005
 
5236
5006
  // ../plugins/session-rituals/dist/commands/vortex.js
5237
5007
  import { spawn } from "child_process";
5238
- import { constants, existsSync as existsSync12 } from "fs";
5239
- import { copyFile as copyFile2, mkdir as mkdir9, readdir as readdir16, readFile as readFile21, stat as stat8, writeFile as writeFile11 } from "fs/promises";
5240
- import { basename as basename7, dirname as dirname5, extname as extname11, join as join26, relative as relative5 } from "path";
5008
+ import { constants, existsSync as existsSync11 } from "fs";
5009
+ import { copyFile as copyFile2, mkdir as mkdir9, readdir as readdir16, readFile as readFile21, stat as stat8, writeFile as writeFile10 } from "fs/promises";
5010
+ import { basename as basename7, dirname as dirname5, extname as extname11, join as join24, relative as relative4 } from "path";
5241
5011
  import { fileURLToPath } from "url";
5242
5012
 
5243
5013
  // ../plugins/session-rituals/dist/global-setup.js
5244
5014
  import { homedir } from "os";
5245
- import { existsSync as existsSync10, readFileSync as readFileSync2 } from "fs";
5246
- import { mkdir as mkdir7, readFile as readFile19, writeFile as writeFile10 } from "fs/promises";
5247
- import { isAbsolute as isAbsolute3, join as join24 } from "path";
5015
+ import { existsSync as existsSync9, readFileSync } from "fs";
5016
+ import { mkdir as mkdir7, readFile as readFile19, writeFile as writeFile9 } from "fs/promises";
5017
+ import { isAbsolute as isAbsolute2, join as join22 } from "path";
5248
5018
  async function readFileIfExists(path) {
5249
5019
  try {
5250
5020
  return await readFile19(path, "utf8");
@@ -5255,23 +5025,23 @@ async function readFileIfExists(path) {
5255
5025
  }
5256
5026
  }
5257
5027
  function isSafeInstanceRoot(dir) {
5258
- return typeof dir === "string" && dir.trim().length > 0 && isAbsolute3(dir) && !/[\r\n`]/.test(dir) && isInstanceRoot(dir);
5028
+ return typeof dir === "string" && dir.trim().length > 0 && isAbsolute2(dir) && !/[\r\n`]/.test(dir) && isInstanceRoot(dir);
5259
5029
  }
5260
5030
  function globalClaudeDir(home = homedir()) {
5261
- return join24(home, ".claude");
5031
+ return join22(home, ".claude");
5262
5032
  }
5263
5033
  function globalSettingsPath(home = homedir()) {
5264
- return join24(globalClaudeDir(home), "settings.json");
5034
+ return join22(globalClaudeDir(home), "settings.json");
5265
5035
  }
5266
5036
  function globalStatePath(home = homedir()) {
5267
- return join24(globalClaudeDir(home), "vortex-global.json");
5037
+ return join22(globalClaudeDir(home), "vortex-global.json");
5268
5038
  }
5269
5039
  function globalMemoryPath(home = homedir()) {
5270
- return join24(globalClaudeDir(home), "CLAUDE.md");
5040
+ return join22(globalClaudeDir(home), "CLAUDE.md");
5271
5041
  }
5272
5042
  function readGlobalStateRaw(home = homedir()) {
5273
5043
  try {
5274
- const parsed = JSON.parse(readFileSync2(globalStatePath(home), "utf8"));
5044
+ const parsed = JSON.parse(readFileSync(globalStatePath(home), "utf8"));
5275
5045
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
5276
5046
  return parsed;
5277
5047
  }
@@ -5284,11 +5054,11 @@ function readGlobalInstancePointer(home = homedir()) {
5284
5054
  return typeof root === "string" && root.trim().length > 0 ? root.trim() : null;
5285
5055
  }
5286
5056
  function isInstanceRoot(dir) {
5287
- return existsSync10(join24(dir, ".agent", "vortex.json")) || existsSync10(join24(dir, "data", "_memory", "user_profile.md"));
5057
+ return existsSync9(join22(dir, ".agent", "vortex.json")) || existsSync9(join22(dir, "data", "_memory", "user_profile.md"));
5288
5058
  }
5289
5059
  function globalSettingsHasHook(home = homedir()) {
5290
5060
  try {
5291
- const settings = parseSettings(readFileSync2(globalSettingsPath(home), "utf8"));
5061
+ const settings = parseSettings(readFileSync(globalSettingsPath(home), "utf8"));
5292
5062
  const wired = (event, command) => Boolean(settings.hooks?.[event]?.some((g) => g.hooks?.some((h) => h.command === command)));
5293
5063
  return wired("SessionStart", SESSION_START_COMMAND) && wired("SessionEnd", SESSION_END_COMMAND);
5294
5064
  } catch {
@@ -5332,9 +5102,9 @@ async function applyGlobalSetup(opts) {
5332
5102
  const skipped = [];
5333
5103
  const statePath = globalStatePath(home);
5334
5104
  const settingsPath = globalSettingsPath(home);
5335
- const instSettingsPath = join24(instanceRoot, ".claude", "settings.json");
5105
+ const instSettingsPath = join22(instanceRoot, ".claude", "settings.json");
5336
5106
  const mdPath = globalMemoryPath(home);
5337
- const hadState = existsSync10(statePath);
5107
+ const hadState = existsSync9(statePath);
5338
5108
  const prevState = readGlobalStateRaw(home) ?? {};
5339
5109
  const settingsText = await readFileIfExists(settingsPath);
5340
5110
  const mergedGlobal = ensureVortexHooks(parseSettings(settingsText));
@@ -5347,27 +5117,27 @@ async function applyGlobalSetup(opts) {
5347
5117
  const { declinedAt: _wasDeclined, ...restState } = prevState;
5348
5118
  const nextState = { ...restState, instanceRoot };
5349
5119
  if (!hadState || prevState.instanceRoot !== instanceRoot || typeof prevState.declinedAt === "string") {
5350
- await writeFile10(statePath, JSON.stringify(nextState, null, 2) + "\n", "utf8");
5120
+ await writeFile9(statePath, JSON.stringify(nextState, null, 2) + "\n", "utf8");
5351
5121
  (hadState ? modified : created).push(statePath);
5352
5122
  } else {
5353
5123
  skipped.push(statePath);
5354
5124
  }
5355
5125
  if (!mergedGlobal.alreadyWired) {
5356
- await writeFile10(settingsPath, serializeSettings(mergedGlobal.settings), "utf8");
5126
+ await writeFile9(settingsPath, serializeSettings(mergedGlobal.settings), "utf8");
5357
5127
  (settingsText === null ? created : modified).push(settingsPath);
5358
5128
  } else {
5359
5129
  skipped.push(settingsPath);
5360
5130
  }
5361
5131
  if (mergedInst !== null) {
5362
5132
  if (!mergedInst.alreadyWired) {
5363
- await writeFile10(instSettingsPath, serializeSettings(mergedInst.settings), "utf8");
5133
+ await writeFile9(instSettingsPath, serializeSettings(mergedInst.settings), "utf8");
5364
5134
  modified.push(instSettingsPath);
5365
5135
  } else {
5366
5136
  skipped.push(instSettingsPath);
5367
5137
  }
5368
5138
  }
5369
5139
  if (nextMd !== mdText) {
5370
- await writeFile10(mdPath, nextMd, "utf8");
5140
+ await writeFile9(mdPath, nextMd, "utf8");
5371
5141
  (mdRead === null ? created : modified).push(mdPath);
5372
5142
  } else {
5373
5143
  skipped.push(mdPath);
@@ -5381,23 +5151,23 @@ async function recordGlobalSetupDecline(opts) {
5381
5151
  const statePath = globalStatePath(home);
5382
5152
  const prevState = readGlobalStateRaw(home) ?? {};
5383
5153
  const nextState = { ...prevState, declinedAt: now.toISOString() };
5384
- await writeFile10(statePath, JSON.stringify(nextState, null, 2) + "\n", "utf8");
5154
+ await writeFile9(statePath, JSON.stringify(nextState, null, 2) + "\n", "utf8");
5385
5155
  return statePath;
5386
5156
  }
5387
5157
 
5388
5158
  // ../plugins/session-rituals/dist/update.js
5389
5159
  import { createHash as createHash2 } from "crypto";
5390
- import { existsSync as existsSync11 } from "fs";
5160
+ import { existsSync as existsSync10 } from "fs";
5391
5161
  import { copyFile, mkdir as mkdir8, readFile as readFile20 } from "fs/promises";
5392
- import { dirname as dirname4, isAbsolute as isAbsolute4, join as join25, relative as relative4, sep as sep4 } from "path";
5162
+ import { dirname as dirname4, isAbsolute as isAbsolute3, join as join23, relative as relative3, sep as sep3 } from "path";
5393
5163
  var OWNERSHIP_SCHEMA = "vortex-ownership/2";
5394
5164
  var OWNERSHIP_SCHEMA_V1 = "vortex-ownership/1";
5395
5165
  var MANIFEST_NAME = "manifest.json";
5396
5166
  function ownershipManifestPath(ctx) {
5397
- return join25(ctx.dataDir, ".vortex", "ownership.json");
5167
+ return join23(ctx.dataDir, ".vortex", "ownership.json");
5398
5168
  }
5399
5169
  function frameworkBookkeepingPrefix(ctx) {
5400
- return toPosix(relative4(ctx.repoRoot, join25(ctx.dataDir, ".vortex"))) + "/";
5170
+ return toPosix(relative3(ctx.repoRoot, join23(ctx.dataDir, ".vortex"))) + "/";
5401
5171
  }
5402
5172
  function committableUpdatePaths(ctx, result) {
5403
5173
  const out = /* @__PURE__ */ new Set();
@@ -5408,11 +5178,11 @@ function committableUpdatePaths(ctx, result) {
5408
5178
  out.add(a.path);
5409
5179
  }
5410
5180
  }
5411
- out.add(toPosix(relative4(ctx.repoRoot, ownershipManifestPath(ctx))));
5181
+ out.add(toPosix(relative3(ctx.repoRoot, ownershipManifestPath(ctx))));
5412
5182
  return [...out];
5413
5183
  }
5414
5184
  function toPosix(p) {
5415
- return p.split(sep4).join("/");
5185
+ return p.split(sep3).join("/");
5416
5186
  }
5417
5187
  function normalizeEol(input) {
5418
5188
  const s = typeof input === "string" ? input : input.toString("utf8");
@@ -5443,24 +5213,24 @@ function templateDestRelPath(templateRelPath) {
5443
5213
  if (top === "routers")
5444
5214
  return tail;
5445
5215
  if (top === "commands")
5446
- return join25(".claude", "commands", tail);
5216
+ return join23(".claude", "commands", tail);
5447
5217
  if (top === "config")
5448
- return join25(".agent", tail);
5218
+ return join23(".agent", tail);
5449
5219
  return null;
5450
5220
  }
5451
5221
  function assertUnderRoot(rootAbs, candidateAbs) {
5452
- const rel = relative4(rootAbs, candidateAbs);
5453
- const up = ".." + sep4;
5454
- const winsensitive = sep4 === "\\";
5222
+ const rel = relative3(rootAbs, candidateAbs);
5223
+ const up = ".." + sep3;
5224
+ const winsensitive = sep3 === "\\";
5455
5225
  const cmp = winsensitive ? rel.toLowerCase() : rel;
5456
5226
  const upCmp = winsensitive ? up.toLowerCase() : up;
5457
- if (rel === ".." || cmp.startsWith(upCmp) || isAbsolute4(rel)) {
5227
+ if (rel === ".." || cmp.startsWith(upCmp) || isAbsolute3(rel)) {
5458
5228
  throw new Error(`Refusing to write outside the instance root: ${candidateAbs}`);
5459
5229
  }
5460
5230
  }
5461
5231
  async function readTemplateIndex(templatesDir) {
5462
- const indexPath = join25(templatesDir, MANIFEST_NAME);
5463
- if (!existsSync11(indexPath))
5232
+ const indexPath = join23(templatesDir, MANIFEST_NAME);
5233
+ if (!existsSync10(indexPath))
5464
5234
  return null;
5465
5235
  try {
5466
5236
  const parsed = JSON.parse(await readFile20(indexPath, "utf8"));
@@ -5484,14 +5254,14 @@ async function buildOwnershipManifest(ctx, templatesDir) {
5484
5254
  if (seenDest.has(destRel))
5485
5255
  continue;
5486
5256
  seenDest.add(destRel);
5487
- const shippedAbs = join25(templatesDir, entry.path);
5488
- if (!existsSync11(shippedAbs))
5257
+ const shippedAbs = join23(templatesDir, entry.path);
5258
+ if (!existsSync10(shippedAbs))
5489
5259
  continue;
5490
5260
  const sourceSha256 = await sha256File(shippedAbs);
5491
- const destAbs = join25(ctx.repoRoot, destRel);
5261
+ const destAbs = join23(ctx.repoRoot, destRel);
5492
5262
  assertUnderRoot(ctx.repoRoot, destAbs);
5493
5263
  let installedSha256 = null;
5494
- if (existsSync11(destAbs)) {
5264
+ if (existsSync10(destAbs)) {
5495
5265
  const onDisk = await sha256File(destAbs);
5496
5266
  installedSha256 = onDisk === sourceSha256 ? sourceSha256 : null;
5497
5267
  }
@@ -5512,14 +5282,14 @@ async function writeOwnershipManifest(ctx, templatesDir) {
5512
5282
  if (!manifest)
5513
5283
  return null;
5514
5284
  const mp = ownershipManifestPath(ctx);
5515
- await mkdir8(join25(ctx.dataDir, ".vortex"), { recursive: true });
5285
+ await mkdir8(join23(ctx.dataDir, ".vortex"), { recursive: true });
5516
5286
  await atomicWriteFile(mp, JSON.stringify(manifest, null, 2) + "\n");
5517
5287
  return { path: mp, fileCount: manifest.files.length };
5518
5288
  }
5519
5289
  async function inspectOwnership(ctx, templatesDir) {
5520
5290
  let own = await readOwnershipManifest(ctx);
5521
5291
  if (!own) {
5522
- const malformed = existsSync11(ownershipManifestPath(ctx));
5292
+ const malformed = existsSync10(ownershipManifestPath(ctx));
5523
5293
  return { present: false, malformed, total: 0, pristine: 0, modified: 0, missing: 0, unmanaged: 0 };
5524
5294
  }
5525
5295
  if (templatesDir && own.schema === OWNERSHIP_SCHEMA_V1) {
@@ -5534,8 +5304,8 @@ async function inspectOwnership(ctx, templatesDir) {
5534
5304
  unmanaged++;
5535
5305
  continue;
5536
5306
  }
5537
- const abs = join25(ctx.repoRoot, e.path);
5538
- if (!existsSync11(abs)) {
5307
+ const abs = join23(ctx.repoRoot, e.path);
5308
+ if (!existsSync10(abs)) {
5539
5309
  missing++;
5540
5310
  continue;
5541
5311
  }
@@ -5552,7 +5322,7 @@ async function inspectOwnership(ctx, templatesDir) {
5552
5322
  }
5553
5323
  async function repairOwnershipManifest(ctx, templatesDir) {
5554
5324
  const mp = ownershipManifestPath(ctx);
5555
- if (existsSync11(mp)) {
5325
+ if (existsSync10(mp)) {
5556
5326
  const existing = await readOwnershipManifest(ctx);
5557
5327
  return existing ? { status: "already-present", path: mp, fileCount: existing.files.length } : { status: "unreadable", path: mp };
5558
5328
  }
@@ -5561,7 +5331,7 @@ async function repairOwnershipManifest(ctx, templatesDir) {
5561
5331
  }
5562
5332
  async function readOwnershipManifest(ctx) {
5563
5333
  const mp = ownershipManifestPath(ctx);
5564
- if (!existsSync11(mp))
5334
+ if (!existsSync10(mp))
5565
5335
  return null;
5566
5336
  try {
5567
5337
  const parsed = JSON.parse(await readFile20(mp, "utf8"));
@@ -5585,13 +5355,13 @@ async function migrateOwnershipToV2(own, ctx, templatesDir) {
5585
5355
  if (index) {
5586
5356
  for (const idx of index.files) {
5587
5357
  if (templateDestRelPath(idx.path))
5588
- tmplAbsById.set(idx.templateId, join25(templatesDir, idx.path));
5358
+ tmplAbsById.set(idx.templateId, join23(templatesDir, idx.path));
5589
5359
  }
5590
5360
  }
5591
5361
  const files = [];
5592
5362
  for (const e of own.files) {
5593
5363
  const tmplAbs = tmplAbsById.get(e.templateId);
5594
- if (!tmplAbs || !existsSync11(tmplAbs)) {
5364
+ if (!tmplAbs || !existsSync10(tmplAbs)) {
5595
5365
  files.push(e);
5596
5366
  continue;
5597
5367
  }
@@ -5602,10 +5372,10 @@ async function migrateOwnershipToV2(own, ctx, templatesDir) {
5602
5372
  continue;
5603
5373
  }
5604
5374
  const srcUnchanged = matchesLegacyRawHash(e.sourceSha256, tmplBuf);
5605
- const destAbs = join25(ctx.repoRoot, e.path);
5375
+ const destAbs = join23(ctx.repoRoot, e.path);
5606
5376
  let diskPristine = false;
5607
5377
  let normDisk = null;
5608
- if (existsSync11(destAbs)) {
5378
+ if (existsSync10(destAbs)) {
5609
5379
  try {
5610
5380
  const diskBuf = await readFile20(destAbs);
5611
5381
  normDisk = sha256(diskBuf);
@@ -5674,15 +5444,15 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5674
5444
  continue;
5675
5445
  seenDest.add(destRel);
5676
5446
  seenTemplateIds.add(idx.templateId);
5677
- const shippedAbs = join25(templatesDir, idx.path);
5678
- if (!existsSync11(shippedAbs))
5447
+ const shippedAbs = join23(templatesDir, idx.path);
5448
+ if (!existsSync10(shippedAbs))
5679
5449
  continue;
5680
5450
  const newSource = await sha256File(shippedAbs);
5681
- const destAbs = join25(ctx.repoRoot, destRel);
5451
+ const destAbs = join23(ctx.repoRoot, destRel);
5682
5452
  assertUnderRoot(ctx.repoRoot, destAbs);
5683
5453
  const path = toPosix(destRel);
5684
5454
  const templateId = idx.templateId;
5685
- const exists = existsSync11(destAbs);
5455
+ const exists = existsSync10(destAbs);
5686
5456
  const curHash = exists ? await sha256File(destAbs) : null;
5687
5457
  const prior = ownByTemplateId.get(templateId);
5688
5458
  if (adopt.has(path)) {
@@ -5725,7 +5495,7 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5725
5495
  templateId,
5726
5496
  action: "conflict",
5727
5497
  detail: "a file already exists in a newly-shipped slot \u2014 wrote .new",
5728
- newFilePath: toPosix(relative4(ctx.repoRoot, destAbs + ".new"))
5498
+ newFilePath: toPosix(relative3(ctx.repoRoot, destAbs + ".new"))
5729
5499
  },
5730
5500
  shippedAbs,
5731
5501
  destAbs,
@@ -5783,7 +5553,7 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5783
5553
  templateId,
5784
5554
  action: "conflict",
5785
5555
  detail: "you edited this and the template changed \u2014 wrote .new; your file is untouched",
5786
- newFilePath: toPosix(relative4(ctx.repoRoot, destAbs + ".new"))
5556
+ newFilePath: toPosix(relative3(ctx.repoRoot, destAbs + ".new"))
5787
5557
  },
5788
5558
  shippedAbs,
5789
5559
  destAbs,
@@ -5805,18 +5575,18 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5805
5575
  const allOps = [...ops, ...orphanOps];
5806
5576
  const appliedActions = [];
5807
5577
  const finalEntries = [];
5808
- const backupRoot = join25(ctx.dataDir, ".vortex", "backups", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
5578
+ const backupRoot = join23(ctx.dataDir, ".vortex", "backups", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
5809
5579
  let applyError = false;
5810
5580
  const writeDotNew = async (destAbs, content) => {
5811
5581
  const newPath = destAbs + ".new";
5812
- if (existsSync11(newPath)) {
5582
+ if (existsSync10(newPath)) {
5813
5583
  if (await readFile20(newPath, "utf8") === content)
5814
5584
  return void 0;
5815
- const backupAbs = join25(backupRoot, toPosix(relative4(ctx.repoRoot, newPath)));
5585
+ const backupAbs = join23(backupRoot, toPosix(relative3(ctx.repoRoot, newPath)));
5816
5586
  await mkdir8(dirname4(backupAbs), { recursive: true });
5817
5587
  await copyFile(newPath, backupAbs);
5818
5588
  await atomicWriteFile(newPath, content);
5819
- return toPosix(relative4(ctx.repoRoot, backupAbs));
5589
+ return toPosix(relative3(ctx.repoRoot, backupAbs));
5820
5590
  }
5821
5591
  await atomicWriteFile(newPath, content);
5822
5592
  return void 0;
@@ -5831,15 +5601,15 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5831
5601
  const newSource = op.entry ? op.entry.sourceSha256 : sha256(content);
5832
5602
  if (action.action === "replace") {
5833
5603
  const prior = ownByTemplateId.get(action.templateId);
5834
- if (!existsSync11(destAbs)) {
5604
+ if (!existsSync10(destAbs)) {
5835
5605
  await mkdir8(dirname4(destAbs), { recursive: true });
5836
5606
  await atomicWriteFile(destAbs, content);
5837
5607
  } else if (await sha256File(destAbs) === (prior?.installedSha256 ?? null)) {
5838
- const backupAbs = join25(backupRoot, action.path);
5608
+ const backupAbs = join23(backupRoot, action.path);
5839
5609
  await mkdir8(dirname4(backupAbs), { recursive: true });
5840
5610
  await copyFile(destAbs, backupAbs);
5841
5611
  await atomicWriteFile(destAbs, content);
5842
- action = { ...action, backupPath: toPosix(relative4(ctx.repoRoot, backupAbs)) };
5612
+ action = { ...action, backupPath: toPosix(relative3(ctx.repoRoot, backupAbs)) };
5843
5613
  } else {
5844
5614
  const backupPath = await writeDotNew(destAbs, content);
5845
5615
  action = {
@@ -5847,20 +5617,20 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5847
5617
  templateId: action.templateId,
5848
5618
  action: "conflict",
5849
5619
  detail: "file changed since planning \u2014 wrote .new instead of overwriting",
5850
- newFilePath: toPosix(relative4(ctx.repoRoot, destAbs + ".new")),
5620
+ newFilePath: toPosix(relative3(ctx.repoRoot, destAbs + ".new")),
5851
5621
  ...backupPath ? { backupPath } : {}
5852
5622
  };
5853
5623
  entry = { templateId: action.templateId, path: action.path, sourceSha256: newSource, installedSha256: prior?.installedSha256 ?? null };
5854
5624
  }
5855
5625
  } else if (action.action === "restore" || action.action === "install") {
5856
- if (existsSync11(destAbs) && await sha256File(destAbs) !== newSource) {
5626
+ if (existsSync10(destAbs) && await sha256File(destAbs) !== newSource) {
5857
5627
  const backupPath = await writeDotNew(destAbs, content);
5858
5628
  action = {
5859
5629
  path: action.path,
5860
5630
  templateId: action.templateId,
5861
5631
  action: "conflict",
5862
5632
  detail: "target appeared since planning \u2014 wrote .new instead of overwriting",
5863
- newFilePath: toPosix(relative4(ctx.repoRoot, destAbs + ".new")),
5633
+ newFilePath: toPosix(relative3(ctx.repoRoot, destAbs + ".new")),
5864
5634
  ...backupPath ? { backupPath } : {}
5865
5635
  };
5866
5636
  entry = { templateId: action.templateId, path: action.path, sourceSha256: newSource, installedSha256: null };
@@ -5874,11 +5644,11 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5874
5644
  if (backupPath)
5875
5645
  action = { ...action, backupPath };
5876
5646
  } else if (action.action === "adopt") {
5877
- if (existsSync11(destAbs)) {
5878
- const backupAbs = join25(backupRoot, action.path);
5647
+ if (existsSync10(destAbs)) {
5648
+ const backupAbs = join23(backupRoot, action.path);
5879
5649
  await mkdir8(dirname4(backupAbs), { recursive: true });
5880
5650
  await copyFile(destAbs, backupAbs);
5881
- action = { ...action, backupPath: toPosix(relative4(ctx.repoRoot, backupAbs)) };
5651
+ action = { ...action, backupPath: toPosix(relative3(ctx.repoRoot, backupAbs)) };
5882
5652
  }
5883
5653
  await mkdir8(dirname4(destAbs), { recursive: true });
5884
5654
  await atomicWriteFile(destAbs, content);
@@ -5907,7 +5677,7 @@ async function runTemplatesUpdate(ctx, templatesDir, options = {}) {
5907
5677
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
5908
5678
  files: newEntries
5909
5679
  };
5910
- await mkdir8(join25(ctx.dataDir, ".vortex"), { recursive: true });
5680
+ await mkdir8(join23(ctx.dataDir, ".vortex"), { recursive: true });
5911
5681
  await atomicWriteFile(ownershipManifestPath(ctx), JSON.stringify(manifest, null, 2) + "\n");
5912
5682
  }
5913
5683
  const summary = summarize(appliedActions);
@@ -6163,15 +5933,15 @@ var DEFAULT_INIT_TASK = "Setting up my VortEX instance";
6163
5933
  function resolveTemplatesDir() {
6164
5934
  const here = dirname5(fileURLToPath(import.meta.url));
6165
5935
  const candidates = [
6166
- join26(here, "..", "..", "templates"),
5936
+ join24(here, "..", "..", "templates"),
6167
5937
  // session-rituals: dist/commands -> templates
6168
- join26(here, "..", "templates"),
5938
+ join24(here, "..", "templates"),
6169
5939
  // base aggregate: dist -> templates
6170
- join26(here, "templates")
5940
+ join24(here, "templates")
6171
5941
  // defensive: alongside the bundle
6172
5942
  ];
6173
5943
  for (const c of candidates) {
6174
- if (existsSync12(join26(c, "commands")) || existsSync12(join26(c, "routers")))
5944
+ if (existsSync11(join24(c, "commands")) || existsSync11(join24(c, "routers")))
6175
5945
  return c;
6176
5946
  }
6177
5947
  return null;
@@ -6179,19 +5949,19 @@ function resolveTemplatesDir() {
6179
5949
  async function installCommandTemplates(repoRoot, templatesDir) {
6180
5950
  if (!templatesDir)
6181
5951
  return [];
6182
- const commandsDir = join26(templatesDir, "commands");
6183
- if (!existsSync12(commandsDir))
5952
+ const commandsDir = join24(templatesDir, "commands");
5953
+ if (!existsSync11(commandsDir))
6184
5954
  return [];
6185
- const destDir = join26(repoRoot, ".claude", "commands");
5955
+ const destDir = join24(repoRoot, ".claude", "commands");
6186
5956
  await mkdir9(destDir, { recursive: true });
6187
5957
  const written = [];
6188
5958
  for (const name of await readdir16(commandsDir)) {
6189
5959
  if (!name.endsWith(".md"))
6190
5960
  continue;
6191
- const dest = join26(destDir, name);
6192
- if (existsSync12(dest))
5961
+ const dest = join24(destDir, name);
5962
+ if (existsSync11(dest))
6193
5963
  continue;
6194
- await copyFile2(join26(commandsDir, name), dest);
5964
+ await copyFile2(join24(commandsDir, name), dest);
6195
5965
  written.push(dest);
6196
5966
  }
6197
5967
  return written;
@@ -6206,16 +5976,16 @@ var ROUTER_FILES = [
6206
5976
  async function installRouterTemplates(repoRoot, templatesDir) {
6207
5977
  if (!templatesDir)
6208
5978
  return [];
6209
- const routersDir = join26(templatesDir, "routers");
6210
- if (!existsSync12(routersDir))
5979
+ const routersDir = join24(templatesDir, "routers");
5980
+ if (!existsSync11(routersDir))
6211
5981
  return [];
6212
5982
  const written = [];
6213
5983
  for (const name of ROUTER_FILES) {
6214
- const src = join26(routersDir, name);
6215
- if (!existsSync12(src))
5984
+ const src = join24(routersDir, name);
5985
+ if (!existsSync11(src))
6216
5986
  continue;
6217
- const dest = join26(repoRoot, name);
6218
- if (existsSync12(dest))
5987
+ const dest = join24(repoRoot, name);
5988
+ if (existsSync11(dest))
6219
5989
  continue;
6220
5990
  await copyFile2(src, dest);
6221
5991
  written.push(dest);
@@ -6224,15 +5994,15 @@ async function installRouterTemplates(repoRoot, templatesDir) {
6224
5994
  }
6225
5995
  async function seedInstanceConfig(repoRoot, templatesDir) {
6226
5996
  const written = [];
6227
- const agentDir = join26(repoRoot, ".agent");
6228
- const vortexJson = join26(agentDir, "vortex.json");
6229
- if (!existsSync12(vortexJson)) {
5997
+ const agentDir = join24(repoRoot, ".agent");
5998
+ const vortexJson = join24(agentDir, "vortex.json");
5999
+ if (!existsSync11(vortexJson)) {
6230
6000
  await mkdir9(agentDir, { recursive: true });
6231
- const tmpl = templatesDir ? join26(templatesDir, "config", "vortex.json") : null;
6232
- if (tmpl && existsSync12(tmpl)) {
6001
+ const tmpl = templatesDir ? join24(templatesDir, "config", "vortex.json") : null;
6002
+ if (tmpl && existsSync11(tmpl)) {
6233
6003
  await copyFile2(tmpl, vortexJson);
6234
6004
  } else {
6235
- await writeFile11(vortexJson, JSON.stringify({
6005
+ await writeFile10(vortexJson, JSON.stringify({
6236
6006
  autoRecord: {
6237
6007
  sessionStart: true,
6238
6008
  worklog: true,
@@ -6247,9 +6017,9 @@ async function seedInstanceConfig(repoRoot, templatesDir) {
6247
6017
  }
6248
6018
  written.push(vortexJson);
6249
6019
  }
6250
- const pkgPath = join26(repoRoot, "package.json");
6251
- if (!existsSync12(pkgPath)) {
6252
- await writeFile11(pkgPath, JSON.stringify({
6020
+ const pkgPath = join24(repoRoot, "package.json");
6021
+ if (!existsSync11(pkgPath)) {
6022
+ await writeFile10(pkgPath, JSON.stringify({
6253
6023
  name: "vortex-instance",
6254
6024
  version: "0.0.0",
6255
6025
  private: true,
@@ -6266,8 +6036,8 @@ async function runInit(input, tokens) {
6266
6036
  const templatesDir = resolveTemplatesDir();
6267
6037
  const requiredDirs = ["_memory", "worklog", "decision-log", "hubs", "inbox", "runbooks"];
6268
6038
  for (const d2 of requiredDirs) {
6269
- const p = join26(dataDir, d2);
6270
- if (!existsSync12(p))
6039
+ const p = join24(dataDir, d2);
6040
+ if (!existsSync11(p))
6271
6041
  await mkdir9(p, { recursive: true });
6272
6042
  }
6273
6043
  const scaffolded = [];
@@ -6279,8 +6049,8 @@ async function runInit(input, tokens) {
6279
6049
  scaffolded.push(...await seedInstanceConfig(repoRoot, templatesDir));
6280
6050
  } catch {
6281
6051
  }
6282
- const profilePath = join26(dataDir, "_memory", "user_profile.md");
6283
- if (existsSync12(profilePath) && !args.force) {
6052
+ const profilePath = join24(dataDir, "_memory", "user_profile.md");
6053
+ if (existsSync11(profilePath) && !args.force) {
6284
6054
  const manifestNotes = [];
6285
6055
  try {
6286
6056
  const m2 = await writeOwnershipManifest(input.context, templatesDir);
@@ -6341,24 +6111,24 @@ async function runInit(input, tokens) {
6341
6111
  const name = args.name.trim();
6342
6112
  const role = args.role.trim();
6343
6113
  const task = args.task?.trim() || DEFAULT_INIT_TASK;
6344
- await writeFile11(profilePath, renderUserProfile(name, role, task, today2), "utf8");
6114
+ await writeFile10(profilePath, renderUserProfile(name, role, task, today2), "utf8");
6345
6115
  created.push(profilePath);
6346
6116
  const [year, month] = today2.split("-");
6347
- const worklogDir = join26(dataDir, "worklog", year, month);
6117
+ const worklogDir = join24(dataDir, "worklog", year, month);
6348
6118
  await mkdir9(worklogDir, { recursive: true });
6349
- const worklogPath = join26(worklogDir, `${today2}-vortex-init.md`);
6350
- await writeFile11(worklogPath, renderFirstWorklog(name, role, task, today2), "utf8");
6119
+ const worklogPath = join24(worklogDir, `${today2}-vortex-init.md`);
6120
+ await writeFile10(worklogPath, renderFirstWorklog(name, role, task, today2), "utf8");
6351
6121
  created.push(worklogPath);
6352
6122
  const hookNotes = [];
6353
6123
  try {
6354
- const settingsPath = join26(input.context.repoRoot, ".claude", "settings.json");
6355
- const existingText = existsSync12(settingsPath) ? await readFile21(settingsPath, "utf8") : null;
6356
- const { settings, added, alreadyWired } = ensureVortexHooks(parseSettings(existingText));
6124
+ const settingsPath = join24(input.context.repoRoot, ".claude", "settings.json");
6125
+ const existingText = existsSync11(settingsPath) ? await readFile21(settingsPath, "utf8") : null;
6126
+ const { settings, added, alreadyWired } = ensureVortexHooks(parseSettings(existingText), { guard: true });
6357
6127
  if (!alreadyWired) {
6358
- await mkdir9(join26(input.context.repoRoot, ".claude"), { recursive: true });
6359
- await writeFile11(settingsPath, serializeSettings(settings), "utf8");
6128
+ await mkdir9(join24(input.context.repoRoot, ".claude"), { recursive: true });
6129
+ await writeFile10(settingsPath, serializeSettings(settings), "utf8");
6360
6130
  created.push(settingsPath);
6361
- hookNotes.push(`Wired ${added.join(" + ")} hook(s) into .claude/settings.json \u2014 the VortEX boot report runs automatically at session start.`);
6131
+ hookNotes.push(`Wired ${added.join(" + ")} hook(s) into .claude/settings.json \u2014 the VortEX boot report runs automatically at session start` + (added.includes("PreToolUse") ? ", and the write guard now denies literal control bytes in file writes (remove the PreToolUse group to opt out)." : "."));
6362
6132
  } else {
6363
6133
  hookNotes.push("Session hooks already wired in .claude/settings.json.");
6364
6134
  }
@@ -6619,18 +6389,18 @@ var COUNT_KEY_TO_DIR = {
6619
6389
  };
6620
6390
  async function runStatus(input) {
6621
6391
  const { dataDir } = input.context;
6622
- const profilePath = join26(dataDir, "_memory", "user_profile.md");
6623
- const initialized = existsSync12(profilePath);
6392
+ const profilePath = join24(dataDir, "_memory", "user_profile.md");
6393
+ const initialized = existsSync11(profilePath);
6624
6394
  const counts = {
6625
- memory: await safeCount(join26(dataDir, "_memory"), false),
6626
- worklog: await safeCount(join26(dataDir, "worklog"), true),
6627
- decisionLog: await safeCount(join26(dataDir, "decision-log"), false),
6628
- runbooks: await safeCount(join26(dataDir, "runbooks"), false),
6629
- hubs: await safeCount(join26(dataDir, "hubs"), false)
6395
+ memory: await safeCount(join24(dataDir, "_memory"), false),
6396
+ worklog: await safeCount(join24(dataDir, "worklog"), true),
6397
+ decisionLog: await safeCount(join24(dataDir, "decision-log"), false),
6398
+ runbooks: await safeCount(join24(dataDir, "runbooks"), false),
6399
+ hubs: await safeCount(join24(dataDir, "hubs"), false)
6630
6400
  };
6631
6401
  let latestWorklog;
6632
6402
  try {
6633
- const store = new WorklogStore(join26(dataDir, "worklog"));
6403
+ const store = new WorklogStore(join24(dataDir, "worklog"));
6634
6404
  const latest = await store.getLatest();
6635
6405
  if (latest) {
6636
6406
  latestWorklog = {
@@ -6657,8 +6427,8 @@ async function runStatus(input) {
6657
6427
  for (const [key, count] of Object.entries(counts)) {
6658
6428
  if (count === 0) {
6659
6429
  const dirName = COUNT_KEY_TO_DIR[key];
6660
- const dirPath = join26(dataDir, dirName);
6661
- missing.push(existsSync12(dirPath) ? `${dirName}/ is empty` : `${dirName}/ does not exist`);
6430
+ const dirPath = join24(dataDir, dirName);
6431
+ missing.push(existsSync11(dirPath) ? `${dirName}/ is empty` : `${dirName}/ does not exist`);
6662
6432
  }
6663
6433
  }
6664
6434
  const nextActions = [];
@@ -6693,7 +6463,7 @@ function extractProfile(body) {
6693
6463
  return out;
6694
6464
  }
6695
6465
  async function safeCount(dir, recursive) {
6696
- if (!existsSync12(dir))
6466
+ if (!existsSync11(dir))
6697
6467
  return 0;
6698
6468
  try {
6699
6469
  return await countMarkdown2(dir, recursive);
@@ -6717,7 +6487,7 @@ async function countMarkdown2(dir, recursive) {
6717
6487
  } else if (e.isDirectory() && recursive) {
6718
6488
  if (e.name.startsWith(".") || e.name.startsWith("_"))
6719
6489
  continue;
6720
- total += await countMarkdown2(join26(dir, e.name), recursive);
6490
+ total += await countMarkdown2(join24(dir, e.name), recursive);
6721
6491
  }
6722
6492
  }
6723
6493
  return total;
@@ -6852,7 +6622,7 @@ async function runImport(input, tokens) {
6852
6622
  ]
6853
6623
  };
6854
6624
  }
6855
- if (!existsSync12(args.from)) {
6625
+ if (!existsSync11(args.from)) {
6856
6626
  return {
6857
6627
  subcommand: "import",
6858
6628
  status: "source-missing",
@@ -6886,8 +6656,8 @@ async function runImport(input, tokens) {
6886
6656
  const systemDirsCreated = [];
6887
6657
  if (!args.dryRun) {
6888
6658
  for (const d2 of systemDirs) {
6889
- const p = join26(dataDir, d2);
6890
- if (!existsSync12(p)) {
6659
+ const p = join24(dataDir, d2);
6660
+ if (!existsSync11(p)) {
6891
6661
  await mkdir9(p, { recursive: true });
6892
6662
  systemDirsCreated.push(d2);
6893
6663
  }
@@ -6983,7 +6753,7 @@ async function runImport(input, tokens) {
6983
6753
  async function walkAndImport(rootSource, currentDir, dataDir, dryRun, stats) {
6984
6754
  const entries = await readdir16(currentDir, { withFileTypes: true });
6985
6755
  for (const e of entries) {
6986
- const sourcePath = join26(currentDir, e.name);
6756
+ const sourcePath = join24(currentDir, e.name);
6987
6757
  if (e.isDirectory()) {
6988
6758
  if (IMPORT_SKIP_DIRS.has(e.name.toLowerCase()))
6989
6759
  continue;
@@ -7024,7 +6794,7 @@ async function walkAndImport(rootSource, currentDir, dataDir, dryRun, stats) {
7024
6794
  body: parsed.body
7025
6795
  });
7026
6796
  try {
7027
- await writeFile11(targetPath, out, { encoding: "utf8", flag: "wx" });
6797
+ await writeFile10(targetPath, out, { encoding: "utf8", flag: "wx" });
7028
6798
  stats.copied++;
7029
6799
  } catch (e2) {
7030
6800
  if (e2.code === "EEXIST") {
@@ -7057,7 +6827,7 @@ async function importAttachment(sourcePath, relPath, filename, dataDir, dryRun,
7057
6827
  stats.importedExtensions.add(ext);
7058
6828
  if (dryRun)
7059
6829
  return;
7060
- const targetPath = join26(dataDir, relPath);
6830
+ const targetPath = join24(dataDir, relPath);
7061
6831
  await mkdir9(dirname5(targetPath), { recursive: true });
7062
6832
  try {
7063
6833
  await copyFile2(sourcePath, targetPath, constants.COPYFILE_EXCL);
@@ -7121,27 +6891,27 @@ function computeTargetPath(category, sourcePath, rootSource, dataDir, filename)
7121
6891
  const mdName = withMdExtension(filename);
7122
6892
  if (category === "preserved") {
7123
6893
  const relPath = withMdExtension(sourcePath.substring(rootSource.length).replace(/^[/\\]/, ""));
7124
- return join26(dataDir, relPath);
6894
+ return join24(dataDir, relPath);
7125
6895
  }
7126
6896
  if (category === "worklog") {
7127
6897
  const match = mdName.match(/^(\d{4})-(\d{2})-/);
7128
6898
  if (match) {
7129
- return join26(dataDir, "worklog", match[1], match[2], mdName);
6899
+ return join24(dataDir, "worklog", match[1], match[2], mdName);
7130
6900
  }
7131
6901
  const d2 = /* @__PURE__ */ new Date();
7132
6902
  const y2 = String(d2.getFullYear());
7133
6903
  const m2 = String(d2.getMonth() + 1).padStart(2, "0");
7134
- return join26(dataDir, "worklog", y2, m2, mdName);
6904
+ return join24(dataDir, "worklog", y2, m2, mdName);
7135
6905
  }
7136
6906
  if (category === "decisionLog")
7137
- return join26(dataDir, "decision-log", mdName);
6907
+ return join24(dataDir, "decision-log", mdName);
7138
6908
  if (category === "runbooks")
7139
- return join26(dataDir, "runbooks", mdName);
6909
+ return join24(dataDir, "runbooks", mdName);
7140
6910
  if (category === "hubs")
7141
- return join26(dataDir, "hubs", mdName);
6911
+ return join24(dataDir, "hubs", mdName);
7142
6912
  if (category === "memory")
7143
- return join26(dataDir, "_memory", mdName);
7144
- return join26(dataDir, mdName);
6913
+ return join24(dataDir, "_memory", mdName);
6914
+ return join24(dataDir, mdName);
7145
6915
  }
7146
6916
  function withMdExtension(name) {
7147
6917
  const ext = extname11(name);
@@ -7288,7 +7058,7 @@ async function checkControlBytes(dataDir) {
7288
7058
  return;
7289
7059
  }
7290
7060
  for (const e of entries) {
7291
- const p = join26(dir, e.name);
7061
+ const p = join24(dir, e.name);
7292
7062
  if (e.isDirectory()) {
7293
7063
  if (SKIP_DIRS.has(e.name))
7294
7064
  continue;
@@ -7299,7 +7069,7 @@ async function checkControlBytes(dataDir) {
7299
7069
  for (let i = 0; i < buf.length; i++) {
7300
7070
  const x2 = buf[i];
7301
7071
  if (x2 < 32 && x2 !== 9 && x2 !== 10 && x2 !== 13) {
7302
- offenders.push(`${relative5(dataDir, p).replace(/\\/g, "/")} @ byte ${i}`);
7072
+ offenders.push(`${relative4(dataDir, p).replace(/\\/g, "/")} @ byte ${i}`);
7303
7073
  break;
7304
7074
  }
7305
7075
  }
@@ -7322,7 +7092,7 @@ async function checkControlBytes(dataDir) {
7322
7092
  };
7323
7093
  }
7324
7094
  function checkSystemDirs(dataDir) {
7325
- const missing = DOCTOR_SYSTEM_DIRS.filter((d2) => !existsSync12(join26(dataDir, d2)));
7095
+ const missing = DOCTOR_SYSTEM_DIRS.filter((d2) => !existsSync11(join24(dataDir, d2)));
7326
7096
  if (missing.length === 0) {
7327
7097
  return {
7328
7098
  id: "system-dirs",
@@ -7338,8 +7108,8 @@ function checkSystemDirs(dataDir) {
7338
7108
  };
7339
7109
  }
7340
7110
  function checkUserProfile(dataDir) {
7341
- const profilePath = join26(dataDir, "_memory", "user_profile.md");
7342
- if (existsSync12(profilePath)) {
7111
+ const profilePath = join24(dataDir, "_memory", "user_profile.md");
7112
+ if (existsSync11(profilePath)) {
7343
7113
  return {
7344
7114
  id: "user-profile",
7345
7115
  label: "user_profile.md exists",
@@ -7356,11 +7126,11 @@ function checkUserProfile(dataDir) {
7356
7126
  async function checkIndexes(dataDir) {
7357
7127
  const missing = [];
7358
7128
  for (const d2 of DOCTOR_SYSTEM_DIRS) {
7359
- const dirPath = join26(dataDir, d2);
7360
- if (!existsSync12(dirPath))
7129
+ const dirPath = join24(dataDir, d2);
7130
+ if (!existsSync11(dirPath))
7361
7131
  continue;
7362
- const indexPath = join26(dirPath, "_INDEX.md");
7363
- if (!existsSync12(indexPath))
7132
+ const indexPath = join24(dirPath, "_INDEX.md");
7133
+ if (!existsSync11(indexPath))
7364
7134
  missing.push(`${d2}/_INDEX.md`);
7365
7135
  }
7366
7136
  if (missing.length === 0) {
@@ -7393,7 +7163,7 @@ async function collectAttachmentExtensions(dataDir) {
7393
7163
  if (e.name.startsWith(".") || e.name === "_session-archive" || e.name === "node_modules") {
7394
7164
  continue;
7395
7165
  }
7396
- stack.push(join26(current, e.name));
7166
+ stack.push(join24(current, e.name));
7397
7167
  } else if (e.isFile()) {
7398
7168
  const ext = extname11(e.name);
7399
7169
  if (ext && ext.toLowerCase() !== ".md")
@@ -7490,8 +7260,8 @@ async function checkFrontmatterLint(dataDir, additionalExtensions = []) {
7490
7260
  }
7491
7261
  }
7492
7262
  async function checkRunbookAging(dataDir) {
7493
- const runbooksDir = join26(dataDir, "runbooks");
7494
- if (!existsSync12(runbooksDir)) {
7263
+ const runbooksDir = join24(dataDir, "runbooks");
7264
+ if (!existsSync11(runbooksDir)) {
7495
7265
  return {
7496
7266
  id: "runbook-aging",
7497
7267
  label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,
@@ -7511,7 +7281,7 @@ async function checkRunbookAging(dataDir) {
7511
7281
  continue;
7512
7282
  }
7513
7283
  total++;
7514
- const filePath = join26(runbooksDir, e.name);
7284
+ const filePath = join24(runbooksDir, e.name);
7515
7285
  const raw = await readFile21(filePath, "utf8");
7516
7286
  const { frontmatter } = parseFrontmatter(raw);
7517
7287
  if (!frontmatter.last_tested) {
@@ -7574,8 +7344,8 @@ function checkNodeVersion() {
7574
7344
  };
7575
7345
  }
7576
7346
  async function checkGitRemote(repoRoot) {
7577
- const gitConfig = join26(repoRoot, ".git", "config");
7578
- if (!existsSync12(gitConfig)) {
7347
+ const gitConfig = join24(repoRoot, ".git", "config");
7348
+ if (!existsSync11(gitConfig)) {
7579
7349
  return {
7580
7350
  id: "git-remote",
7581
7351
  label: "git remote for sync",
@@ -7614,11 +7384,11 @@ async function detectExternalFolders(excludePath) {
7614
7384
  if (!home)
7615
7385
  return void 0;
7616
7386
  const candidates = [
7617
- join26(home, "Documents", "obsidian-vault"),
7618
- join26(home, "Documents", "notes"),
7619
- join26(home, "Documents", "Notebook"),
7620
- join26(home, "notes"),
7621
- join26(home, "Notes")
7387
+ join24(home, "Documents", "obsidian-vault"),
7388
+ join24(home, "Documents", "notes"),
7389
+ join24(home, "Documents", "Notebook"),
7390
+ join24(home, "notes"),
7391
+ join24(home, "Notes")
7622
7392
  ];
7623
7393
  const excludeNorm = excludePath.replace(/[/\\]+$/, "");
7624
7394
  const found = [];
@@ -7627,7 +7397,7 @@ async function detectExternalFolders(excludePath) {
7627
7397
  if (candNorm === excludeNorm || candNorm.startsWith(excludeNorm + "/") || candNorm.startsWith(excludeNorm + "\\") || excludeNorm.startsWith(candNorm + "/") || excludeNorm.startsWith(candNorm + "\\")) {
7628
7398
  continue;
7629
7399
  }
7630
- if (!existsSync12(candidate))
7400
+ if (!existsSync11(candidate))
7631
7401
  continue;
7632
7402
  let mdCount = 0;
7633
7403
  try {
@@ -7751,7 +7521,7 @@ async function runSync(input, tokens) {
7751
7521
  var SYNC_TAIL_LENGTH = 1e3;
7752
7522
  async function runShellCommand(cmd, cmdArgs, cwd) {
7753
7523
  const start = Date.now();
7754
- return new Promise((resolve5) => {
7524
+ return new Promise((resolve3) => {
7755
7525
  let stdout = "";
7756
7526
  let stderr = "";
7757
7527
  const child = spawn(cmd, [...cmdArgs], { cwd, shell: true });
@@ -7762,7 +7532,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
7762
7532
  stderr += chunk.toString("utf8");
7763
7533
  });
7764
7534
  child.on("close", (code) => {
7765
- resolve5({
7535
+ resolve3({
7766
7536
  exitCode: code ?? -1,
7767
7537
  durationMs: Date.now() - start,
7768
7538
  stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
@@ -7770,7 +7540,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
7770
7540
  });
7771
7541
  });
7772
7542
  child.on("error", (err) => {
7773
- resolve5({
7543
+ resolve3({
7774
7544
  exitCode: -1,
7775
7545
  durationMs: Date.now() - start,
7776
7546
  stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
@@ -7816,22 +7586,22 @@ function createRitualRegistry(options) {
7816
7586
 
7817
7587
  // ../plugins/session-rituals/dist/cli-dispatch.js
7818
7588
  import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
7819
- import { existsSync as existsSync16, readFileSync as readFileSync4, mkdirSync, openSync, writeSync, closeSync, linkSync, rmSync, statSync } from "fs";
7589
+ import { existsSync as existsSync15, readFileSync as readFileSync3, mkdirSync, openSync, writeSync, closeSync, linkSync, rmSync, statSync } from "fs";
7820
7590
  import { createRequire } from "module";
7821
7591
  import { hostname } from "os";
7822
- import { isAbsolute as isAbsolute5, join as join30 } from "path";
7592
+ import { isAbsolute as isAbsolute4, join as join28 } from "path";
7823
7593
 
7824
7594
  // ../plugins/session-rituals/dist/update-check.js
7825
7595
  import { execSync } from "child_process";
7826
- import { existsSync as existsSync13, readFileSync as readFileSync3 } from "fs";
7827
- import { join as join27 } from "path";
7596
+ import { existsSync as existsSync12, readFileSync as readFileSync2 } from "fs";
7597
+ import { join as join25 } from "path";
7828
7598
  var PKG = "@vortex-os/base";
7829
7599
  var NPM_TIMEOUT_MS = 4e3;
7830
7600
  function readInstalledBaseVersion(templatesDir = resolveTemplatesDir()) {
7831
7601
  if (!templatesDir)
7832
7602
  return null;
7833
7603
  try {
7834
- const m2 = JSON.parse(readFileSync3(join27(templatesDir, "manifest.json"), "utf8"));
7604
+ const m2 = JSON.parse(readFileSync2(join25(templatesDir, "manifest.json"), "utf8"));
7835
7605
  return typeof m2.baseVersion === "string" && parseCore(m2.baseVersion) ? m2.baseVersion.trim() : null;
7836
7606
  } catch {
7837
7607
  return null;
@@ -7903,8 +7673,8 @@ function isStableUpdate(latest, installed) {
7903
7673
  return compareSemver(latest, installed) === 1;
7904
7674
  }
7905
7675
  function buildInstallCommand(repoRoot) {
7906
- const has = (f) => existsSync13(join27(repoRoot, f));
7907
- const local = existsSync13(join27(repoRoot, "node_modules", "@vortex-os", "base"));
7676
+ const has = (f) => existsSync12(join25(repoRoot, f));
7677
+ const local = existsSync12(join25(repoRoot, "node_modules", "@vortex-os", "base"));
7908
7678
  let installPart;
7909
7679
  if (!local) {
7910
7680
  installPart = `npm i -g ${PKG}@latest`;
@@ -7932,9 +7702,9 @@ function checkBaseUpdate(ctx) {
7932
7702
  }
7933
7703
 
7934
7704
  // ../plugins/session-rituals/dist/session-start-report.js
7935
- import { existsSync as existsSync14 } from "fs";
7705
+ import { existsSync as existsSync13 } from "fs";
7936
7706
  import { readdir as readdir17, readFile as readFile22, stat as stat9 } from "fs/promises";
7937
- import { join as join28 } from "path";
7707
+ import { join as join26 } from "path";
7938
7708
  var COUNTED_DIRS2 = ["_memory", "worklog", "decision-log"];
7939
7709
  var DEFAULT_GAP_WINDOW_DAYS = 30;
7940
7710
  function gapWindowSinceArg() {
@@ -7951,8 +7721,8 @@ async function collectSessionStartReport(ctx, opts) {
7951
7721
  const counts = {};
7952
7722
  const missing = [];
7953
7723
  for (const name of COUNTED_DIRS2) {
7954
- const dir = join28(ctx.dataDir, name);
7955
- if (!existsSync14(dir)) {
7724
+ const dir = join26(ctx.dataDir, name);
7725
+ if (!existsSync13(dir)) {
7956
7726
  missing.push(name);
7957
7727
  counts[name] = 0;
7958
7728
  continue;
@@ -7962,7 +7732,7 @@ async function collectSessionStartReport(ctx, opts) {
7962
7732
  const { recent, recentGroup, recentWorklogsOmitted, dates, latestBodies } = await scanWorklog(ctx.dataDir);
7963
7733
  const cutoff = isoDate2(addDays2(now, -(opts?.gapWindowDays ?? DEFAULT_GAP_WINDOW_DAYS)));
7964
7734
  const recentWorklogDates = dates.filter((d2) => d2 >= cutoff);
7965
- const mem = await scanMemoryTiers(join28(ctx.dataDir, "_memory"));
7735
+ const mem = await scanMemoryTiers(join26(ctx.dataDir, "_memory"));
7966
7736
  const ho = await scanHandoffs(ctx.dataDir);
7967
7737
  const handoffs = ho.active.map((h) => ({
7968
7738
  date: h.date,
@@ -8029,7 +7799,7 @@ async function scanMemoryTiers(memoryDir) {
8029
7799
  for (const e of entries) {
8030
7800
  if (!e.isFile() || !e.name.endsWith(".md"))
8031
7801
  continue;
8032
- const full = join28(memoryDir, e.name);
7802
+ const full = join26(memoryDir, e.name);
8033
7803
  if (e.name === "_INDEX.md") {
8034
7804
  indexExists = true;
8035
7805
  try {
@@ -8189,6 +7959,16 @@ function renderSessionStartReport(report, extras) {
8189
7959
  if (carry && carry.uncommitted > 0) {
8190
7960
  lines.push(`- \u21A9\uFE0F ${carry.uncommitted} uncommitted change(s) carried over from a prior session \u2014 likely normal work in progress.`);
8191
7961
  }
7962
+ const fl = extras?.failures;
7963
+ if (fl && fl.warnings.length > 0) {
7964
+ lines.push(`- \u{1F501} recurring failures (open ledger entries: ${fl.totalOpen}):`);
7965
+ for (const w2 of fl.warnings) {
7966
+ const stageText = w2.stage === "promote" ? "3rd+ occurrence \u2014 PROPOSE a deterministic guard to the user (ladder: promote; never self-install)" : `2nd occurrence \u2014 the covering rule's write-time gate is MANDATORY this session${w2.rule ? ` (rule: ${w2.rule})` : ""}`;
7967
+ lines.push(` - ${w2.key} \xD7${w2.count} (last ${w2.lastDate}) \u2014 ${stageText}`);
7968
+ }
7969
+ if (fl.omitted > 0)
7970
+ lines.push(` - \u2026(+${fl.omitted} more \u2014 \`vortex failure list\`)`);
7971
+ }
8192
7972
  const cu = extras?.catchUp;
8193
7973
  if (cu && (cu.ingestedLocal > 0 || cu.indexedPulled > 0 || cu.errors > 0)) {
8194
7974
  const parts = [];
@@ -8258,15 +8038,15 @@ async function countMarkdown3(dir, recursive) {
8258
8038
  } else if (e.isDirectory() && recursive) {
8259
8039
  if (e.name.startsWith(".") || e.name.startsWith("_"))
8260
8040
  continue;
8261
- total += await countMarkdown3(join28(dir, e.name), recursive);
8041
+ total += await countMarkdown3(join26(dir, e.name), recursive);
8262
8042
  }
8263
8043
  }
8264
8044
  return total;
8265
8045
  }
8266
8046
  var MAX_GROUP_READ = 20;
8267
8047
  async function scanWorklog(dataDir) {
8268
- const root = join28(dataDir, "worklog");
8269
- if (!existsSync14(root))
8048
+ const root = join26(dataDir, "worklog");
8049
+ if (!existsSync13(root))
8270
8050
  return { recent: null, recentGroup: [], recentWorklogsOmitted: 0, dates: [], latestBodies: [] };
8271
8051
  const dates = /* @__PURE__ */ new Set();
8272
8052
  const consistent = [];
@@ -8281,7 +8061,7 @@ async function scanWorklog(dataDir) {
8281
8061
  for (const e of entries) {
8282
8062
  const childRel = rel ? `${rel}/${e.name}` : e.name;
8283
8063
  if (e.isDirectory()) {
8284
- await walk5(join28(absDir, e.name), childRel);
8064
+ await walk5(join26(absDir, e.name), childRel);
8285
8065
  } else if (e.isFile()) {
8286
8066
  const m2 = e.name.match(/^(\d{4})-(\d{2})-(\d{2})(?:_\d{4})?-.+\.md$/);
8287
8067
  if (!m2)
@@ -8310,7 +8090,7 @@ async function scanWorklog(dataDir) {
8310
8090
  const recentGroup = [];
8311
8091
  const latestBodies = [];
8312
8092
  for (const g of group) {
8313
- const { title, body } = await readWorklogTitleAndBody(join28(root, g.rel));
8093
+ const { title, body } = await readWorklogTitleAndBody(join26(root, g.rel));
8314
8094
  recentGroup.push({ path: defangReportPath(`worklog/${g.rel}`), title });
8315
8095
  latestBodies.push(body);
8316
8096
  }
@@ -8389,11 +8169,11 @@ function isoDate2(d2) {
8389
8169
  }
8390
8170
 
8391
8171
  // ../plugins/session-rituals/dist/curate-cli.js
8392
- import { existsSync as existsSync15 } from "fs";
8172
+ import { existsSync as existsSync14 } from "fs";
8393
8173
  import { createHash as createHash3 } from "crypto";
8394
8174
  import { readFile as readFile23, readdir as readdir18 } from "fs/promises";
8395
- import { join as join29 } from "path";
8396
- var SYSTEM_META_DIRS3 = /* @__PURE__ */ new Set([
8175
+ import { join as join27 } from "path";
8176
+ var SYSTEM_META_DIRS2 = /* @__PURE__ */ new Set([
8397
8177
  "worklog",
8398
8178
  "decision-log",
8399
8179
  "runbooks",
@@ -8416,7 +8196,7 @@ function firstSegment(rel) {
8416
8196
  }
8417
8197
  function isSystemMetaRel(rel) {
8418
8198
  const first = firstSegment(rel);
8419
- return SYSTEM_META_DIRS3.has(first) || first.startsWith("_");
8199
+ return SYSTEM_META_DIRS2.has(first) || first.startsWith("_");
8420
8200
  }
8421
8201
  function validateCuratePayload(payload) {
8422
8202
  const errors = [];
@@ -8472,10 +8252,10 @@ function joinRel(...parts) {
8472
8252
  }
8473
8253
  async function runCurateCandidates(repoRoot, options) {
8474
8254
  const maxEntries = options?.maxEntries ?? 200;
8475
- const dataDir = join29(repoRoot, "data");
8255
+ const dataDir = join27(repoRoot, "data");
8476
8256
  const candidates = [];
8477
8257
  let truncated = false;
8478
- if (existsSync15(dataDir)) {
8258
+ if (existsSync14(dataDir)) {
8479
8259
  async function visit(absDir, relDir) {
8480
8260
  if (candidates.length >= maxEntries) {
8481
8261
  truncated = true;
@@ -8496,9 +8276,9 @@ async function runCurateCandidates(repoRoot, options) {
8496
8276
  const atRoot = relDir === "";
8497
8277
  if (e.name.startsWith("."))
8498
8278
  continue;
8499
- if (atRoot && (SYSTEM_META_DIRS3.has(e.name) || e.name.startsWith("_")))
8279
+ if (atRoot && (SYSTEM_META_DIRS2.has(e.name) || e.name.startsWith("_")))
8500
8280
  continue;
8501
- await visit(join29(absDir, e.name), joinRel(relDir, e.name));
8281
+ await visit(join27(absDir, e.name), joinRel(relDir, e.name));
8502
8282
  } else if (e.isFile() && e.name.endsWith(".md")) {
8503
8283
  if (NON_DOC_FILES.has(e.name))
8504
8284
  continue;
@@ -8507,7 +8287,7 @@ async function runCurateCandidates(repoRoot, options) {
8507
8287
  let topic = null;
8508
8288
  let tags = [];
8509
8289
  try {
8510
- const raw = await readFile23(join29(absDir, e.name), "utf8");
8290
+ const raw = await readFile23(join27(absDir, e.name), "utf8");
8511
8291
  const parsed = parseFrontmatter(raw);
8512
8292
  if (typeof parsed.frontmatter.topic === "string") {
8513
8293
  topic = parsed.frontmatter.topic.trim().toLowerCase();
@@ -8545,7 +8325,7 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
8545
8325
  };
8546
8326
  }
8547
8327
  try {
8548
- validateDataRelativePath(join29(repoRoot, "data"), v2.effectiveRelPath);
8328
+ validateDataRelativePath(join27(repoRoot, "data"), v2.effectiveRelPath);
8549
8329
  } catch (e) {
8550
8330
  return {
8551
8331
  subcommand: "curate-preview",
@@ -8562,10 +8342,10 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
8562
8342
  let targetExists;
8563
8343
  let wouldDo;
8564
8344
  if (payload.action === "create-file") {
8565
- targetExists = existsSync15(join29(repoRoot, "data", v2.effectiveRelPath));
8345
+ targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
8566
8346
  wouldDo = targetExists ? `create-file at ${v2.effectiveRelPath} \u2014 but the file already EXISTS, so accept would REFUSE (no overwrite).` : `create a new document at data/${v2.effectiveRelPath}.`;
8567
8347
  } else {
8568
- targetExists = existsSync15(join29(repoRoot, "data", v2.effectiveRelPath));
8348
+ targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
8569
8349
  wouldDo = targetExists ? `append a "## ${payload.sectionHeader}" section to data/${v2.effectiveRelPath}.` : `append-section to data/${v2.effectiveRelPath} \u2014 but the file does NOT exist, so accept would FAIL (append-section never creates).`;
8570
8350
  }
8571
8351
  const nextActions = [];
@@ -8710,13 +8490,13 @@ function readCuratePayload(args) {
8710
8490
  break;
8711
8491
  }
8712
8492
  if (t === "--payload-file" && i + 1 < args.length) {
8713
- raw = readFileSync4(args[++i], "utf8");
8493
+ raw = readFileSync3(args[++i], "utf8");
8714
8494
  break;
8715
8495
  }
8716
8496
  }
8717
8497
  if (raw === null) {
8718
8498
  try {
8719
- raw = readFileSync4(0, "utf8");
8499
+ raw = readFileSync3(0, "utf8");
8720
8500
  } catch {
8721
8501
  raw = "";
8722
8502
  }
@@ -8740,11 +8520,22 @@ async function runVortexCli(argv, io) {
8740
8520
  const err = io?.stderr ?? ((s) => process.stderr.write(s));
8741
8521
  try {
8742
8522
  if (argv[0] === "statusline") {
8743
- const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-NQKJ3NWD.js");
8523
+ const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-6KSHISXO.js");
8744
8524
  const statuslineRoot = process.env.VORTEX_REPO_ROOT?.trim() || process.cwd();
8745
8525
  return runStatuslineCli2(argv.slice(1), statuslineRoot, out, err);
8746
8526
  }
8527
+ if (argv[0] === "guard") {
8528
+ const { runGuardCli: runGuardCli2 } = await import("./guard-IMJR6ET7.js");
8529
+ return runGuardCli2(argv.slice(1), out, err);
8530
+ }
8747
8531
  const repoRoot = resolveRepoRoot();
8532
+ if (argv[0] === "failure") {
8533
+ const { runFailureCli: runFailureCli2 } = await import("./failures-PMURLMVB.js");
8534
+ const { resolveInstanceRoot: resolveInstanceRoot2 } = await import("./guard-IMJR6ET7.js");
8535
+ const root = resolveInstanceRoot2(process.cwd()) ?? repoRoot;
8536
+ const ctx = makeContext(root);
8537
+ return runFailureCli2(argv.slice(1), ctx.dataDir, out, err);
8538
+ }
8748
8539
  if (argv[0] === "session-start") {
8749
8540
  await runSessionStart(repoRoot, out);
8750
8541
  return 0;
@@ -8784,6 +8575,8 @@ ${names}
8784
8575
  session-end \u2014 no-op (kept for hook compatibility; worklog gap handling is at session-start)
8785
8576
  check-updates \u2014 check the npm registry for a newer @vortex-os/base (read-only; prints the exact update command)
8786
8577
  statusline \u2014 render the Claude Code status bar from stdin JSON (\`lite\` for 1-line; \`install [--lite]\` wires .claude/settings.json)
8578
+ failure \u2014 failure ledger (\`record\` an occurrence by recurrence key / \`list\` open groups with their escalation stage)
8579
+ guard \u2014 deterministic write-time guards (\`write\` = PreToolUse hook body; wired by \`vortex init\`)
8787
8580
 
8788
8581
  Instance shortcuts (also available as \`/vortex <sub>\`):
8789
8582
  init \u2014 first-time setup: routers + data/ + hooks + slash-commands
@@ -8850,12 +8643,12 @@ function memoryExtendedPresent() {
8850
8643
  }
8851
8644
  var VECTORIZE_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
8852
8645
  function vectorizeLockPath(ctx) {
8853
- return join30(ctx.dataDir, "_indexes", ".vectorize.lock");
8646
+ return join28(ctx.dataDir, "_indexes", ".vectorize.lock");
8854
8647
  }
8855
8648
  function vectorizeSetupInProgress(ctx) {
8856
8649
  const lock = vectorizeLockPath(ctx);
8857
8650
  try {
8858
- if (!existsSync16(lock))
8651
+ if (!existsSync15(lock))
8859
8652
  return false;
8860
8653
  return Date.now() - statSync(lock).mtimeMs < VECTORIZE_LOCK_TTL_MS;
8861
8654
  } catch {
@@ -8876,9 +8669,9 @@ function spawnVectorizeSetup(repoRoot) {
8876
8669
  }
8877
8670
  async function runVectorizeSetup(repoRoot, out, err) {
8878
8671
  const ctx = makeContext(repoRoot);
8879
- const indexDir = join30(ctx.dataDir, "_indexes");
8880
- const finalDb = join30(indexDir, "memory.sqlite");
8881
- if (existsSync16(finalDb)) {
8672
+ const indexDir = join28(ctx.dataDir, "_indexes");
8673
+ const finalDb = join28(indexDir, "memory.sqlite");
8674
+ if (existsSync15(finalDb)) {
8882
8675
  out("recall index already present \u2014 nothing to do\n");
8883
8676
  return;
8884
8677
  }
@@ -8909,7 +8702,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8909
8702
  return;
8910
8703
  }
8911
8704
  }
8912
- const tmpDb = join30(indexDir, `memory.sqlite.building-${process.pid}`);
8705
+ const tmpDb = join28(indexDir, `memory.sqlite.building-${process.pid}`);
8913
8706
  const tmpSidecars = [tmpDb + "-wal", tmpDb + "-shm", tmpDb + "-journal"];
8914
8707
  const cleanTmp = () => {
8915
8708
  rmSync(tmpDb, { force: true });
@@ -8919,7 +8712,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8919
8712
  let tokenWritten = false;
8920
8713
  const releaseLock = () => {
8921
8714
  try {
8922
- const cur = existsSync16(lockPath) ? readFileSync4(lockPath, "utf8").trim() : "";
8715
+ const cur = existsSync15(lockPath) ? readFileSync3(lockPath, "utf8").trim() : "";
8923
8716
  if (cur === token || cur === "" && !tokenWritten)
8924
8717
  rmSync(lockPath, { force: true });
8925
8718
  } catch {
@@ -8932,7 +8725,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8932
8725
  } finally {
8933
8726
  closeSync(lockFd);
8934
8727
  }
8935
- if (existsSync16(finalDb)) {
8728
+ if (existsSync15(finalDb)) {
8936
8729
  out("recall index already present \u2014 nothing to do\n");
8937
8730
  return;
8938
8731
  }
@@ -8948,7 +8741,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8948
8741
  } finally {
8949
8742
  db.close();
8950
8743
  }
8951
- if (existsSync16(tmpDb + "-wal")) {
8744
+ if (existsSync15(tmpDb + "-wal")) {
8952
8745
  throw new Error("temp index retained a WAL sidecar after consolidation; refusing to publish");
8953
8746
  }
8954
8747
  try {
@@ -9032,7 +8825,7 @@ async function runSessionStart(repoRoot, out) {
9032
8825
  let vectorized = null;
9033
8826
  let vectorizeSetupStarted = false;
9034
8827
  if (config.autoRecord.vectorize) {
9035
- const dbExists = existsSync16(join30(ctx.dataDir, "_indexes", "memory.sqlite"));
8828
+ const dbExists = existsSync15(join28(ctx.dataDir, "_indexes", "memory.sqlite"));
9036
8829
  const action = decideVectorizeAction({
9037
8830
  vectorizeOn: true,
9038
8831
  dbExists,
@@ -9055,6 +8848,16 @@ async function runSessionStart(repoRoot, out) {
9055
8848
  }
9056
8849
  }
9057
8850
  }
8851
+ let failures = null;
8852
+ if (config.autoRecord.failures) {
8853
+ try {
8854
+ const { scanFailures: scanFailures2, failureReportSlice: failureReportSlice2 } = await import("./failures-PMURLMVB.js");
8855
+ const slice = failureReportSlice2(await scanFailures2(ctx.dataDir));
8856
+ if (slice.warnings.length > 0)
8857
+ failures = slice;
8858
+ } catch {
8859
+ }
8860
+ }
9058
8861
  let templateUpdate = null;
9059
8862
  try {
9060
8863
  const td = resolveTemplatesDir();
@@ -9094,7 +8897,8 @@ async function runSessionStart(repoRoot, out) {
9094
8897
  updateCheck: updateCheck ?? void 0,
9095
8898
  globalSetupOffer: globalSetupOffer || void 0,
9096
8899
  carryover: carryover ?? void 0,
9097
- handoffPrune: handoffPrune ?? void 0
8900
+ handoffPrune: handoffPrune ?? void 0,
8901
+ failures: failures ?? void 0
9098
8902
  }));
9099
8903
  }
9100
8904
  async function runSessionEnd(_repoRoot, _out) {
@@ -9121,7 +8925,7 @@ function detectInterruptedGitOp(repoRoot) {
9121
8925
  const resolved = gitOut(repoRoot, args).split(/\r?\n/).map((s) => s.trim());
9122
8926
  for (let i = 0; i < markers.length; i++) {
9123
8927
  const p = resolved[i];
9124
- if (p && existsSync16(isAbsolute5(p) ? p : join30(repoRoot, p)))
8928
+ if (p && existsSync15(isAbsolute4(p) ? p : join28(repoRoot, p)))
9125
8929
  return markers[i];
9126
8930
  }
9127
8931
  } catch {
@@ -9141,23 +8945,23 @@ function resolveSessionEnvironment(ctx, config) {
9141
8945
  let environment = resolveEnvironment(config, {
9142
8946
  hostname: hostname(),
9143
8947
  env: process.env,
9144
- pathExists: existsSync16
8948
+ pathExists: existsSync15
9145
8949
  });
9146
8950
  if (!environment)
9147
8951
  environment = process.env.VORTEX_ENV?.trim() || null;
9148
8952
  if (!environment) {
9149
- const envFile = join30(ctx.repoRoot, ".agent", "environment");
9150
- if (existsSync16(envFile)) {
9151
- environment = readFileSync4(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
8953
+ const envFile = join28(ctx.repoRoot, ".agent", "environment");
8954
+ if (existsSync15(envFile)) {
8955
+ environment = readFileSync3(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
9152
8956
  }
9153
8957
  }
9154
8958
  return environment;
9155
8959
  }
9156
8960
 
9157
8961
  // ../plugins/session-rituals/dist/ambient-recall.js
9158
- import { join as join31 } from "path";
8962
+ import { join as join29 } from "path";
9159
8963
  function defaultDbPath2(ctx) {
9160
- return join31(ctx.dataDir, "_indexes", "memory.sqlite");
8964
+ return join29(ctx.dataDir, "_indexes", "memory.sqlite");
9161
8965
  }
9162
8966
  function createAmbientRecaller(ctx, options) {
9163
8967
  const resolveDb = options.dbPath ?? defaultDbPath2;
@@ -9194,14 +8998,14 @@ function createAmbientRecaller(ctx, options) {
9194
8998
  }
9195
8999
 
9196
9000
  // ../plugins/session-rituals/dist/worklog-write.js
9197
- import { mkdir as mkdir10, writeFile as writeFile12 } from "fs/promises";
9198
- import { dirname as dirname6, join as join32 } from "path";
9001
+ import { mkdir as mkdir10, writeFile as writeFile11 } from "fs/promises";
9002
+ import { dirname as dirname6, join as join30 } from "path";
9199
9003
  async function ensureWorklogEntry(ctx, opts) {
9200
9004
  const now = opts?.now ?? /* @__PURE__ */ new Date();
9201
9005
  const date = isoDate3(now);
9202
9006
  const time = isoTime2(now);
9203
9007
  const keyword = (opts?.keyword ?? "worklog").trim() || "worklog";
9204
- const store = new WorklogStore(join32(ctx.dataDir, "worklog"));
9008
+ const store = new WorklogStore(join30(ctx.dataDir, "worklog"));
9205
9009
  const existing = await store.get(date);
9206
9010
  if (existing) {
9207
9011
  return { path: existing.path, date: existing.date, keyword: existing.keyword, created: false };
@@ -9209,7 +9013,7 @@ async function ensureWorklogEntry(ctx, opts) {
9209
9013
  const path = store.pathFor(date, keyword, time);
9210
9014
  const title = opts?.title ?? `${date} worklog`;
9211
9015
  await mkdir10(dirname6(path), { recursive: true });
9212
- await writeFile12(path, renderWorklogFile(date, title, opts?.body ?? ""), "utf8");
9016
+ await writeFile11(path, renderWorklogFile(date, title, opts?.body ?? ""), "utf8");
9213
9017
  return { path, date, keyword, created: true };
9214
9018
  }
9215
9019
  function renderWorklogFile(date, title, body) {