@vortex-os/base 0.11.0 → 0.12.1
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/README.md +29 -1
- package/dist/chunk-2FVNWW77.js +166 -0
- package/dist/chunk-2FVNWW77.js.map +1 -0
- package/dist/{chunk-DWANI3LV.js → chunk-P7IMUUNY.js} +41 -10
- package/dist/chunk-P7IMUUNY.js.map +1 -0
- package/dist/chunk-T53UWSTR.js +301 -0
- package/dist/chunk-T53UWSTR.js.map +1 -0
- package/dist/chunk-UV76ZEDC.js +292 -0
- package/dist/chunk-UV76ZEDC.js.map +1 -0
- package/dist/failures-PMURLMVB.js +25 -0
- package/dist/guard-IMJR6ET7.js +23 -0
- package/dist/guard-IMJR6ET7.js.map +1 -0
- package/dist/index.d.ts +295 -7
- package/dist/index.js +459 -629
- package/dist/index.js.map +1 -1
- package/dist/{statusline-NQKJ3NWD.js → statusline-JTSL5CCH.js} +8 -2
- package/dist/statusline-JTSL5CCH.js.map +1 -0
- package/package.json +1 -1
- package/templates/manifest.json +2 -2
- package/templates/routers/AI-RULES.md +3 -1
- package/dist/chunk-DWANI3LV.js.map +0 -1
- /package/dist/{statusline-NQKJ3NWD.js.map → failures-PMURLMVB.js.map} +0 -0
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-
|
|
30
|
+
} from "./chunk-P7IMUUNY.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
|
|
422
|
-
import { join
|
|
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
|
|
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
|
|
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
|
|
486
|
-
import { join as
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2226
|
-
const target =
|
|
2227
|
-
if (target !== root && !(target +
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2371
|
-
const target =
|
|
2372
|
-
if (target !== root && !(target +
|
|
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
|
|
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,
|
|
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 =
|
|
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:
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2899
|
-
if (rel === ".." || rel.startsWith("../") ||
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2849
|
+
import { dirname as dirname2, join as join13 } from "path";
|
|
3097
2850
|
async function writeDocAction(cwd, action) {
|
|
3098
|
-
const dataDir =
|
|
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 (!
|
|
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
|
|
3119
|
-
import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile14, writeFile as
|
|
3120
|
-
import { join as
|
|
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
|
|
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(
|
|
2923
|
+
await appendFile2(join14(cwd, STORE_DIR, ACCEPTED_LOG), line + "\n", "utf8");
|
|
3171
2924
|
}
|
|
3172
2925
|
async function resetDeclined(cwd, kind) {
|
|
3173
|
-
const file =
|
|
3174
|
-
if (!
|
|
2926
|
+
const file = join14(cwd, STORE_DIR, DECLINED_FILE);
|
|
2927
|
+
if (!existsSync2(file))
|
|
3175
2928
|
return;
|
|
3176
2929
|
if (kind === void 0) {
|
|
3177
|
-
await
|
|
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
|
|
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 =
|
|
3204
|
-
if (!
|
|
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(
|
|
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
|
|
3226
|
-
import { mkdir as mkdir4, readFile as readFile15, readdir as readdir12, writeFile as
|
|
3227
|
-
import { dirname as dirname3, join as
|
|
3228
|
-
var
|
|
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 (
|
|
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 =
|
|
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
|
|
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 =
|
|
3579
|
-
if (!
|
|
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 =
|
|
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(
|
|
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 &&
|
|
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
|
|
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
|
|
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 =
|
|
3750
|
-
if (!
|
|
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 =
|
|
3755
|
-
if (!
|
|
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(
|
|
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 =
|
|
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 =
|
|
3850
|
-
if (
|
|
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 =
|
|
3726
|
+
const folder = join16(cwd, "data", HUB_DIR);
|
|
3974
3727
|
await mkdir5(folder, { recursive: true });
|
|
3975
|
-
const file =
|
|
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
|
|
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
|
|
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
|
|
4546
|
-
import { join as
|
|
4547
|
-
import { existsSync as
|
|
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 =
|
|
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 (
|
|
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
|
|
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
|
|
4593
|
-
import { readFile as readFile17, writeFile as
|
|
4594
|
-
import { join as
|
|
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 =
|
|
4705
|
-
if (!
|
|
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 =
|
|
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
|
|
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 =
|
|
4753
|
-
if (!
|
|
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 =
|
|
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
|
|
4548
|
+
await writeFile8(indexPath, body, "utf8");
|
|
4779
4549
|
status = "written";
|
|
4780
4550
|
}
|
|
4781
|
-
if (
|
|
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
|
|
4565
|
+
import { existsSync as existsSync7 } from "fs";
|
|
4796
4566
|
import { readdir as readdir14 } from "fs/promises";
|
|
4797
|
-
import { join as
|
|
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 =
|
|
4808
|
-
if (!
|
|
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(
|
|
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
|
|
4887
|
-
import { mkdir as mkdir6, open, readdir as readdir15, readFile as readFile18, rename
|
|
4888
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5129
|
-
if (!
|
|
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 =
|
|
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 =
|
|
5164
|
-
if (!
|
|
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 =
|
|
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 =
|
|
5181
|
-
let to =
|
|
5182
|
-
if (
|
|
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 (
|
|
4955
|
+
while (existsSync8(join21(archiveDir, `${stem}-${i}.md`)))
|
|
5186
4956
|
i++;
|
|
5187
|
-
to =
|
|
4957
|
+
to = join21(archiveDir, `${stem}-${i}.md`);
|
|
5188
4958
|
}
|
|
5189
4959
|
try {
|
|
5190
|
-
await
|
|
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
|
|
5239
|
-
import { copyFile as copyFile2, mkdir as mkdir9, readdir as readdir16, readFile as readFile21, stat as stat8, writeFile as
|
|
5240
|
-
import { basename as basename7, dirname as dirname5, extname as extname11, join as
|
|
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
|
|
5246
|
-
import { mkdir as mkdir7, readFile as readFile19, writeFile as
|
|
5247
|
-
import { isAbsolute as
|
|
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 &&
|
|
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
|
|
5031
|
+
return join22(home, ".claude");
|
|
5262
5032
|
}
|
|
5263
5033
|
function globalSettingsPath(home = homedir()) {
|
|
5264
|
-
return
|
|
5034
|
+
return join22(globalClaudeDir(home), "settings.json");
|
|
5265
5035
|
}
|
|
5266
5036
|
function globalStatePath(home = homedir()) {
|
|
5267
|
-
return
|
|
5037
|
+
return join22(globalClaudeDir(home), "vortex-global.json");
|
|
5268
5038
|
}
|
|
5269
5039
|
function globalMemoryPath(home = homedir()) {
|
|
5270
|
-
return
|
|
5040
|
+
return join22(globalClaudeDir(home), "CLAUDE.md");
|
|
5271
5041
|
}
|
|
5272
5042
|
function readGlobalStateRaw(home = homedir()) {
|
|
5273
5043
|
try {
|
|
5274
|
-
const parsed = JSON.parse(
|
|
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
|
|
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(
|
|
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 =
|
|
5105
|
+
const instSettingsPath = join22(instanceRoot, ".claude", "settings.json");
|
|
5336
5106
|
const mdPath = globalMemoryPath(home);
|
|
5337
|
-
const hadState =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5167
|
+
return join23(ctx.dataDir, ".vortex", "ownership.json");
|
|
5398
5168
|
}
|
|
5399
5169
|
function frameworkBookkeepingPrefix(ctx) {
|
|
5400
|
-
return toPosix(
|
|
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(
|
|
5181
|
+
out.add(toPosix(relative3(ctx.repoRoot, ownershipManifestPath(ctx))));
|
|
5412
5182
|
return [...out];
|
|
5413
5183
|
}
|
|
5414
5184
|
function toPosix(p) {
|
|
5415
|
-
return p.split(
|
|
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
|
|
5216
|
+
return join23(".claude", "commands", tail);
|
|
5447
5217
|
if (top === "config")
|
|
5448
|
-
return
|
|
5218
|
+
return join23(".agent", tail);
|
|
5449
5219
|
return null;
|
|
5450
5220
|
}
|
|
5451
5221
|
function assertUnderRoot(rootAbs, candidateAbs) {
|
|
5452
|
-
const rel =
|
|
5453
|
-
const up = ".." +
|
|
5454
|
-
const winsensitive =
|
|
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) ||
|
|
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 =
|
|
5463
|
-
if (!
|
|
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 =
|
|
5488
|
-
if (!
|
|
5257
|
+
const shippedAbs = join23(templatesDir, entry.path);
|
|
5258
|
+
if (!existsSync10(shippedAbs))
|
|
5489
5259
|
continue;
|
|
5490
5260
|
const sourceSha256 = await sha256File(shippedAbs);
|
|
5491
|
-
const destAbs =
|
|
5261
|
+
const destAbs = join23(ctx.repoRoot, destRel);
|
|
5492
5262
|
assertUnderRoot(ctx.repoRoot, destAbs);
|
|
5493
5263
|
let installedSha256 = null;
|
|
5494
|
-
if (
|
|
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(
|
|
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 =
|
|
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 =
|
|
5538
|
-
if (!
|
|
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 (
|
|
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 (!
|
|
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,
|
|
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 || !
|
|
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 =
|
|
5375
|
+
const destAbs = join23(ctx.repoRoot, e.path);
|
|
5606
5376
|
let diskPristine = false;
|
|
5607
5377
|
let normDisk = null;
|
|
5608
|
-
if (
|
|
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 =
|
|
5678
|
-
if (!
|
|
5447
|
+
const shippedAbs = join23(templatesDir, idx.path);
|
|
5448
|
+
if (!existsSync10(shippedAbs))
|
|
5679
5449
|
continue;
|
|
5680
5450
|
const newSource = await sha256File(shippedAbs);
|
|
5681
|
-
const destAbs =
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 (
|
|
5582
|
+
if (existsSync10(newPath)) {
|
|
5813
5583
|
if (await readFile20(newPath, "utf8") === content)
|
|
5814
5584
|
return void 0;
|
|
5815
|
-
const backupAbs =
|
|
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(
|
|
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 (!
|
|
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 =
|
|
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(
|
|
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(
|
|
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 (
|
|
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(
|
|
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 (
|
|
5878
|
-
const backupAbs =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
5936
|
+
join24(here, "..", "..", "templates"),
|
|
6167
5937
|
// session-rituals: dist/commands -> templates
|
|
6168
|
-
|
|
5938
|
+
join24(here, "..", "templates"),
|
|
6169
5939
|
// base aggregate: dist -> templates
|
|
6170
|
-
|
|
5940
|
+
join24(here, "templates")
|
|
6171
5941
|
// defensive: alongside the bundle
|
|
6172
5942
|
];
|
|
6173
5943
|
for (const c of candidates) {
|
|
6174
|
-
if (
|
|
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 =
|
|
6183
|
-
if (!
|
|
5952
|
+
const commandsDir = join24(templatesDir, "commands");
|
|
5953
|
+
if (!existsSync11(commandsDir))
|
|
6184
5954
|
return [];
|
|
6185
|
-
const destDir =
|
|
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 =
|
|
6192
|
-
if (
|
|
5961
|
+
const dest = join24(destDir, name);
|
|
5962
|
+
if (existsSync11(dest))
|
|
6193
5963
|
continue;
|
|
6194
|
-
await copyFile2(
|
|
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 =
|
|
6210
|
-
if (!
|
|
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 =
|
|
6215
|
-
if (!
|
|
5984
|
+
const src = join24(routersDir, name);
|
|
5985
|
+
if (!existsSync11(src))
|
|
6216
5986
|
continue;
|
|
6217
|
-
const dest =
|
|
6218
|
-
if (
|
|
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 =
|
|
6228
|
-
const vortexJson =
|
|
6229
|
-
if (!
|
|
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 ?
|
|
6232
|
-
if (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
|
|
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 =
|
|
6251
|
-
if (!
|
|
6252
|
-
await
|
|
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 =
|
|
6270
|
-
if (!
|
|
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 =
|
|
6283
|
-
if (
|
|
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
|
|
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 =
|
|
6117
|
+
const worklogDir = join24(dataDir, "worklog", year, month);
|
|
6348
6118
|
await mkdir9(worklogDir, { recursive: true });
|
|
6349
|
-
const worklogPath =
|
|
6350
|
-
await
|
|
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 =
|
|
6355
|
-
const existingText =
|
|
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(
|
|
6359
|
-
await
|
|
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
|
}
|
|
@@ -6476,10 +6246,36 @@ async function runUpdate(input, tokens) {
|
|
|
6476
6246
|
const dryRun = tokens.includes("--dry-run");
|
|
6477
6247
|
const adopt = parseAdoptArgs(tokens);
|
|
6478
6248
|
const templatesDir = resolveTemplatesDir();
|
|
6479
|
-
|
|
6249
|
+
let result = await runTemplatesUpdate(input.context, templatesDir, {
|
|
6480
6250
|
dryRun,
|
|
6481
6251
|
adopt: adopt.size > 0 ? adopt : void 0
|
|
6482
6252
|
});
|
|
6253
|
+
if (!dryRun) {
|
|
6254
|
+
try {
|
|
6255
|
+
const settingsPath = join24(input.context.repoRoot, ".claude", "settings.json");
|
|
6256
|
+
const existingText = existsSync11(settingsPath) ? await readFile21(settingsPath, "utf8") : null;
|
|
6257
|
+
const { settings, added, alreadyWired } = ensureVortexHooks(parseSettings(existingText), { guard: true });
|
|
6258
|
+
if (!alreadyWired) {
|
|
6259
|
+
await mkdir9(join24(input.context.repoRoot, ".claude"), { recursive: true });
|
|
6260
|
+
await writeFile10(settingsPath, serializeSettings(settings), "utf8");
|
|
6261
|
+
result = {
|
|
6262
|
+
...result,
|
|
6263
|
+
nextActions: [
|
|
6264
|
+
...result.nextActions,
|
|
6265
|
+
`Wired missing ${added.join(" + ")} hook(s) into .claude/settings.json` + (added.includes("PreToolUse") ? " \u2014 the write guard now denies literal control bytes in file writes (remove the PreToolUse group to opt out)." : ".")
|
|
6266
|
+
]
|
|
6267
|
+
};
|
|
6268
|
+
}
|
|
6269
|
+
} catch (e) {
|
|
6270
|
+
result = {
|
|
6271
|
+
...result,
|
|
6272
|
+
nextActions: [
|
|
6273
|
+
...result.nextActions,
|
|
6274
|
+
`\u26A0\uFE0F Could not verify/wire session hooks: ${e.message}`
|
|
6275
|
+
]
|
|
6276
|
+
};
|
|
6277
|
+
}
|
|
6278
|
+
}
|
|
6483
6279
|
if (dryRun || result.status === "no-manifest" || result.status === "no-templates")
|
|
6484
6280
|
return result;
|
|
6485
6281
|
if (!loadVortexConfig(input.context).autoRecord.commitFrameworkChanges)
|
|
@@ -6619,18 +6415,18 @@ var COUNT_KEY_TO_DIR = {
|
|
|
6619
6415
|
};
|
|
6620
6416
|
async function runStatus(input) {
|
|
6621
6417
|
const { dataDir } = input.context;
|
|
6622
|
-
const profilePath =
|
|
6623
|
-
const initialized =
|
|
6418
|
+
const profilePath = join24(dataDir, "_memory", "user_profile.md");
|
|
6419
|
+
const initialized = existsSync11(profilePath);
|
|
6624
6420
|
const counts = {
|
|
6625
|
-
memory: await safeCount(
|
|
6626
|
-
worklog: await safeCount(
|
|
6627
|
-
decisionLog: await safeCount(
|
|
6628
|
-
runbooks: await safeCount(
|
|
6629
|
-
hubs: await safeCount(
|
|
6421
|
+
memory: await safeCount(join24(dataDir, "_memory"), false),
|
|
6422
|
+
worklog: await safeCount(join24(dataDir, "worklog"), true),
|
|
6423
|
+
decisionLog: await safeCount(join24(dataDir, "decision-log"), false),
|
|
6424
|
+
runbooks: await safeCount(join24(dataDir, "runbooks"), false),
|
|
6425
|
+
hubs: await safeCount(join24(dataDir, "hubs"), false)
|
|
6630
6426
|
};
|
|
6631
6427
|
let latestWorklog;
|
|
6632
6428
|
try {
|
|
6633
|
-
const store = new WorklogStore(
|
|
6429
|
+
const store = new WorklogStore(join24(dataDir, "worklog"));
|
|
6634
6430
|
const latest = await store.getLatest();
|
|
6635
6431
|
if (latest) {
|
|
6636
6432
|
latestWorklog = {
|
|
@@ -6657,8 +6453,8 @@ async function runStatus(input) {
|
|
|
6657
6453
|
for (const [key, count] of Object.entries(counts)) {
|
|
6658
6454
|
if (count === 0) {
|
|
6659
6455
|
const dirName = COUNT_KEY_TO_DIR[key];
|
|
6660
|
-
const dirPath =
|
|
6661
|
-
missing.push(
|
|
6456
|
+
const dirPath = join24(dataDir, dirName);
|
|
6457
|
+
missing.push(existsSync11(dirPath) ? `${dirName}/ is empty` : `${dirName}/ does not exist`);
|
|
6662
6458
|
}
|
|
6663
6459
|
}
|
|
6664
6460
|
const nextActions = [];
|
|
@@ -6693,7 +6489,7 @@ function extractProfile(body) {
|
|
|
6693
6489
|
return out;
|
|
6694
6490
|
}
|
|
6695
6491
|
async function safeCount(dir, recursive) {
|
|
6696
|
-
if (!
|
|
6492
|
+
if (!existsSync11(dir))
|
|
6697
6493
|
return 0;
|
|
6698
6494
|
try {
|
|
6699
6495
|
return await countMarkdown2(dir, recursive);
|
|
@@ -6717,7 +6513,7 @@ async function countMarkdown2(dir, recursive) {
|
|
|
6717
6513
|
} else if (e.isDirectory() && recursive) {
|
|
6718
6514
|
if (e.name.startsWith(".") || e.name.startsWith("_"))
|
|
6719
6515
|
continue;
|
|
6720
|
-
total += await countMarkdown2(
|
|
6516
|
+
total += await countMarkdown2(join24(dir, e.name), recursive);
|
|
6721
6517
|
}
|
|
6722
6518
|
}
|
|
6723
6519
|
return total;
|
|
@@ -6852,7 +6648,7 @@ async function runImport(input, tokens) {
|
|
|
6852
6648
|
]
|
|
6853
6649
|
};
|
|
6854
6650
|
}
|
|
6855
|
-
if (!
|
|
6651
|
+
if (!existsSync11(args.from)) {
|
|
6856
6652
|
return {
|
|
6857
6653
|
subcommand: "import",
|
|
6858
6654
|
status: "source-missing",
|
|
@@ -6886,8 +6682,8 @@ async function runImport(input, tokens) {
|
|
|
6886
6682
|
const systemDirsCreated = [];
|
|
6887
6683
|
if (!args.dryRun) {
|
|
6888
6684
|
for (const d2 of systemDirs) {
|
|
6889
|
-
const p =
|
|
6890
|
-
if (!
|
|
6685
|
+
const p = join24(dataDir, d2);
|
|
6686
|
+
if (!existsSync11(p)) {
|
|
6891
6687
|
await mkdir9(p, { recursive: true });
|
|
6892
6688
|
systemDirsCreated.push(d2);
|
|
6893
6689
|
}
|
|
@@ -6983,7 +6779,7 @@ async function runImport(input, tokens) {
|
|
|
6983
6779
|
async function walkAndImport(rootSource, currentDir, dataDir, dryRun, stats) {
|
|
6984
6780
|
const entries = await readdir16(currentDir, { withFileTypes: true });
|
|
6985
6781
|
for (const e of entries) {
|
|
6986
|
-
const sourcePath =
|
|
6782
|
+
const sourcePath = join24(currentDir, e.name);
|
|
6987
6783
|
if (e.isDirectory()) {
|
|
6988
6784
|
if (IMPORT_SKIP_DIRS.has(e.name.toLowerCase()))
|
|
6989
6785
|
continue;
|
|
@@ -7024,7 +6820,7 @@ async function walkAndImport(rootSource, currentDir, dataDir, dryRun, stats) {
|
|
|
7024
6820
|
body: parsed.body
|
|
7025
6821
|
});
|
|
7026
6822
|
try {
|
|
7027
|
-
await
|
|
6823
|
+
await writeFile10(targetPath, out, { encoding: "utf8", flag: "wx" });
|
|
7028
6824
|
stats.copied++;
|
|
7029
6825
|
} catch (e2) {
|
|
7030
6826
|
if (e2.code === "EEXIST") {
|
|
@@ -7057,7 +6853,7 @@ async function importAttachment(sourcePath, relPath, filename, dataDir, dryRun,
|
|
|
7057
6853
|
stats.importedExtensions.add(ext);
|
|
7058
6854
|
if (dryRun)
|
|
7059
6855
|
return;
|
|
7060
|
-
const targetPath =
|
|
6856
|
+
const targetPath = join24(dataDir, relPath);
|
|
7061
6857
|
await mkdir9(dirname5(targetPath), { recursive: true });
|
|
7062
6858
|
try {
|
|
7063
6859
|
await copyFile2(sourcePath, targetPath, constants.COPYFILE_EXCL);
|
|
@@ -7121,27 +6917,27 @@ function computeTargetPath(category, sourcePath, rootSource, dataDir, filename)
|
|
|
7121
6917
|
const mdName = withMdExtension(filename);
|
|
7122
6918
|
if (category === "preserved") {
|
|
7123
6919
|
const relPath = withMdExtension(sourcePath.substring(rootSource.length).replace(/^[/\\]/, ""));
|
|
7124
|
-
return
|
|
6920
|
+
return join24(dataDir, relPath);
|
|
7125
6921
|
}
|
|
7126
6922
|
if (category === "worklog") {
|
|
7127
6923
|
const match = mdName.match(/^(\d{4})-(\d{2})-/);
|
|
7128
6924
|
if (match) {
|
|
7129
|
-
return
|
|
6925
|
+
return join24(dataDir, "worklog", match[1], match[2], mdName);
|
|
7130
6926
|
}
|
|
7131
6927
|
const d2 = /* @__PURE__ */ new Date();
|
|
7132
6928
|
const y2 = String(d2.getFullYear());
|
|
7133
6929
|
const m2 = String(d2.getMonth() + 1).padStart(2, "0");
|
|
7134
|
-
return
|
|
6930
|
+
return join24(dataDir, "worklog", y2, m2, mdName);
|
|
7135
6931
|
}
|
|
7136
6932
|
if (category === "decisionLog")
|
|
7137
|
-
return
|
|
6933
|
+
return join24(dataDir, "decision-log", mdName);
|
|
7138
6934
|
if (category === "runbooks")
|
|
7139
|
-
return
|
|
6935
|
+
return join24(dataDir, "runbooks", mdName);
|
|
7140
6936
|
if (category === "hubs")
|
|
7141
|
-
return
|
|
6937
|
+
return join24(dataDir, "hubs", mdName);
|
|
7142
6938
|
if (category === "memory")
|
|
7143
|
-
return
|
|
7144
|
-
return
|
|
6939
|
+
return join24(dataDir, "_memory", mdName);
|
|
6940
|
+
return join24(dataDir, mdName);
|
|
7145
6941
|
}
|
|
7146
6942
|
function withMdExtension(name) {
|
|
7147
6943
|
const ext = extname11(name);
|
|
@@ -7288,7 +7084,7 @@ async function checkControlBytes(dataDir) {
|
|
|
7288
7084
|
return;
|
|
7289
7085
|
}
|
|
7290
7086
|
for (const e of entries) {
|
|
7291
|
-
const p =
|
|
7087
|
+
const p = join24(dir, e.name);
|
|
7292
7088
|
if (e.isDirectory()) {
|
|
7293
7089
|
if (SKIP_DIRS.has(e.name))
|
|
7294
7090
|
continue;
|
|
@@ -7299,7 +7095,7 @@ async function checkControlBytes(dataDir) {
|
|
|
7299
7095
|
for (let i = 0; i < buf.length; i++) {
|
|
7300
7096
|
const x2 = buf[i];
|
|
7301
7097
|
if (x2 < 32 && x2 !== 9 && x2 !== 10 && x2 !== 13) {
|
|
7302
|
-
offenders.push(`${
|
|
7098
|
+
offenders.push(`${relative4(dataDir, p).replace(/\\/g, "/")} @ byte ${i}`);
|
|
7303
7099
|
break;
|
|
7304
7100
|
}
|
|
7305
7101
|
}
|
|
@@ -7322,7 +7118,7 @@ async function checkControlBytes(dataDir) {
|
|
|
7322
7118
|
};
|
|
7323
7119
|
}
|
|
7324
7120
|
function checkSystemDirs(dataDir) {
|
|
7325
|
-
const missing = DOCTOR_SYSTEM_DIRS.filter((d2) => !
|
|
7121
|
+
const missing = DOCTOR_SYSTEM_DIRS.filter((d2) => !existsSync11(join24(dataDir, d2)));
|
|
7326
7122
|
if (missing.length === 0) {
|
|
7327
7123
|
return {
|
|
7328
7124
|
id: "system-dirs",
|
|
@@ -7338,8 +7134,8 @@ function checkSystemDirs(dataDir) {
|
|
|
7338
7134
|
};
|
|
7339
7135
|
}
|
|
7340
7136
|
function checkUserProfile(dataDir) {
|
|
7341
|
-
const profilePath =
|
|
7342
|
-
if (
|
|
7137
|
+
const profilePath = join24(dataDir, "_memory", "user_profile.md");
|
|
7138
|
+
if (existsSync11(profilePath)) {
|
|
7343
7139
|
return {
|
|
7344
7140
|
id: "user-profile",
|
|
7345
7141
|
label: "user_profile.md exists",
|
|
@@ -7356,11 +7152,11 @@ function checkUserProfile(dataDir) {
|
|
|
7356
7152
|
async function checkIndexes(dataDir) {
|
|
7357
7153
|
const missing = [];
|
|
7358
7154
|
for (const d2 of DOCTOR_SYSTEM_DIRS) {
|
|
7359
|
-
const dirPath =
|
|
7360
|
-
if (!
|
|
7155
|
+
const dirPath = join24(dataDir, d2);
|
|
7156
|
+
if (!existsSync11(dirPath))
|
|
7361
7157
|
continue;
|
|
7362
|
-
const indexPath =
|
|
7363
|
-
if (!
|
|
7158
|
+
const indexPath = join24(dirPath, "_INDEX.md");
|
|
7159
|
+
if (!existsSync11(indexPath))
|
|
7364
7160
|
missing.push(`${d2}/_INDEX.md`);
|
|
7365
7161
|
}
|
|
7366
7162
|
if (missing.length === 0) {
|
|
@@ -7393,7 +7189,7 @@ async function collectAttachmentExtensions(dataDir) {
|
|
|
7393
7189
|
if (e.name.startsWith(".") || e.name === "_session-archive" || e.name === "node_modules") {
|
|
7394
7190
|
continue;
|
|
7395
7191
|
}
|
|
7396
|
-
stack.push(
|
|
7192
|
+
stack.push(join24(current, e.name));
|
|
7397
7193
|
} else if (e.isFile()) {
|
|
7398
7194
|
const ext = extname11(e.name);
|
|
7399
7195
|
if (ext && ext.toLowerCase() !== ".md")
|
|
@@ -7490,8 +7286,8 @@ async function checkFrontmatterLint(dataDir, additionalExtensions = []) {
|
|
|
7490
7286
|
}
|
|
7491
7287
|
}
|
|
7492
7288
|
async function checkRunbookAging(dataDir) {
|
|
7493
|
-
const runbooksDir =
|
|
7494
|
-
if (!
|
|
7289
|
+
const runbooksDir = join24(dataDir, "runbooks");
|
|
7290
|
+
if (!existsSync11(runbooksDir)) {
|
|
7495
7291
|
return {
|
|
7496
7292
|
id: "runbook-aging",
|
|
7497
7293
|
label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,
|
|
@@ -7511,7 +7307,7 @@ async function checkRunbookAging(dataDir) {
|
|
|
7511
7307
|
continue;
|
|
7512
7308
|
}
|
|
7513
7309
|
total++;
|
|
7514
|
-
const filePath =
|
|
7310
|
+
const filePath = join24(runbooksDir, e.name);
|
|
7515
7311
|
const raw = await readFile21(filePath, "utf8");
|
|
7516
7312
|
const { frontmatter } = parseFrontmatter(raw);
|
|
7517
7313
|
if (!frontmatter.last_tested) {
|
|
@@ -7574,8 +7370,8 @@ function checkNodeVersion() {
|
|
|
7574
7370
|
};
|
|
7575
7371
|
}
|
|
7576
7372
|
async function checkGitRemote(repoRoot) {
|
|
7577
|
-
const gitConfig =
|
|
7578
|
-
if (!
|
|
7373
|
+
const gitConfig = join24(repoRoot, ".git", "config");
|
|
7374
|
+
if (!existsSync11(gitConfig)) {
|
|
7579
7375
|
return {
|
|
7580
7376
|
id: "git-remote",
|
|
7581
7377
|
label: "git remote for sync",
|
|
@@ -7614,11 +7410,11 @@ async function detectExternalFolders(excludePath) {
|
|
|
7614
7410
|
if (!home)
|
|
7615
7411
|
return void 0;
|
|
7616
7412
|
const candidates = [
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7413
|
+
join24(home, "Documents", "obsidian-vault"),
|
|
7414
|
+
join24(home, "Documents", "notes"),
|
|
7415
|
+
join24(home, "Documents", "Notebook"),
|
|
7416
|
+
join24(home, "notes"),
|
|
7417
|
+
join24(home, "Notes")
|
|
7622
7418
|
];
|
|
7623
7419
|
const excludeNorm = excludePath.replace(/[/\\]+$/, "");
|
|
7624
7420
|
const found = [];
|
|
@@ -7627,7 +7423,7 @@ async function detectExternalFolders(excludePath) {
|
|
|
7627
7423
|
if (candNorm === excludeNorm || candNorm.startsWith(excludeNorm + "/") || candNorm.startsWith(excludeNorm + "\\") || excludeNorm.startsWith(candNorm + "/") || excludeNorm.startsWith(candNorm + "\\")) {
|
|
7628
7424
|
continue;
|
|
7629
7425
|
}
|
|
7630
|
-
if (!
|
|
7426
|
+
if (!existsSync11(candidate))
|
|
7631
7427
|
continue;
|
|
7632
7428
|
let mdCount = 0;
|
|
7633
7429
|
try {
|
|
@@ -7751,7 +7547,7 @@ async function runSync(input, tokens) {
|
|
|
7751
7547
|
var SYNC_TAIL_LENGTH = 1e3;
|
|
7752
7548
|
async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
7753
7549
|
const start = Date.now();
|
|
7754
|
-
return new Promise((
|
|
7550
|
+
return new Promise((resolve3) => {
|
|
7755
7551
|
let stdout = "";
|
|
7756
7552
|
let stderr = "";
|
|
7757
7553
|
const child = spawn(cmd, [...cmdArgs], { cwd, shell: true });
|
|
@@ -7762,7 +7558,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
|
7762
7558
|
stderr += chunk.toString("utf8");
|
|
7763
7559
|
});
|
|
7764
7560
|
child.on("close", (code) => {
|
|
7765
|
-
|
|
7561
|
+
resolve3({
|
|
7766
7562
|
exitCode: code ?? -1,
|
|
7767
7563
|
durationMs: Date.now() - start,
|
|
7768
7564
|
stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
|
|
@@ -7770,7 +7566,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
|
7770
7566
|
});
|
|
7771
7567
|
});
|
|
7772
7568
|
child.on("error", (err) => {
|
|
7773
|
-
|
|
7569
|
+
resolve3({
|
|
7774
7570
|
exitCode: -1,
|
|
7775
7571
|
durationMs: Date.now() - start,
|
|
7776
7572
|
stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
|
|
@@ -7816,22 +7612,22 @@ function createRitualRegistry(options) {
|
|
|
7816
7612
|
|
|
7817
7613
|
// ../plugins/session-rituals/dist/cli-dispatch.js
|
|
7818
7614
|
import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
|
|
7819
|
-
import { existsSync as
|
|
7615
|
+
import { existsSync as existsSync15, readFileSync as readFileSync3, mkdirSync, openSync, writeSync, closeSync, linkSync, rmSync, statSync } from "fs";
|
|
7820
7616
|
import { createRequire } from "module";
|
|
7821
7617
|
import { hostname } from "os";
|
|
7822
|
-
import { isAbsolute as
|
|
7618
|
+
import { isAbsolute as isAbsolute4, join as join28 } from "path";
|
|
7823
7619
|
|
|
7824
7620
|
// ../plugins/session-rituals/dist/update-check.js
|
|
7825
7621
|
import { execSync } from "child_process";
|
|
7826
|
-
import { existsSync as
|
|
7827
|
-
import { join as
|
|
7622
|
+
import { existsSync as existsSync12, readFileSync as readFileSync2 } from "fs";
|
|
7623
|
+
import { join as join25 } from "path";
|
|
7828
7624
|
var PKG = "@vortex-os/base";
|
|
7829
7625
|
var NPM_TIMEOUT_MS = 4e3;
|
|
7830
7626
|
function readInstalledBaseVersion(templatesDir = resolveTemplatesDir()) {
|
|
7831
7627
|
if (!templatesDir)
|
|
7832
7628
|
return null;
|
|
7833
7629
|
try {
|
|
7834
|
-
const m2 = JSON.parse(
|
|
7630
|
+
const m2 = JSON.parse(readFileSync2(join25(templatesDir, "manifest.json"), "utf8"));
|
|
7835
7631
|
return typeof m2.baseVersion === "string" && parseCore(m2.baseVersion) ? m2.baseVersion.trim() : null;
|
|
7836
7632
|
} catch {
|
|
7837
7633
|
return null;
|
|
@@ -7903,8 +7699,8 @@ function isStableUpdate(latest, installed) {
|
|
|
7903
7699
|
return compareSemver(latest, installed) === 1;
|
|
7904
7700
|
}
|
|
7905
7701
|
function buildInstallCommand(repoRoot) {
|
|
7906
|
-
const has = (f) =>
|
|
7907
|
-
const local =
|
|
7702
|
+
const has = (f) => existsSync12(join25(repoRoot, f));
|
|
7703
|
+
const local = existsSync12(join25(repoRoot, "node_modules", "@vortex-os", "base"));
|
|
7908
7704
|
let installPart;
|
|
7909
7705
|
if (!local) {
|
|
7910
7706
|
installPart = `npm i -g ${PKG}@latest`;
|
|
@@ -7932,9 +7728,9 @@ function checkBaseUpdate(ctx) {
|
|
|
7932
7728
|
}
|
|
7933
7729
|
|
|
7934
7730
|
// ../plugins/session-rituals/dist/session-start-report.js
|
|
7935
|
-
import { existsSync as
|
|
7731
|
+
import { existsSync as existsSync13 } from "fs";
|
|
7936
7732
|
import { readdir as readdir17, readFile as readFile22, stat as stat9 } from "fs/promises";
|
|
7937
|
-
import { join as
|
|
7733
|
+
import { join as join26 } from "path";
|
|
7938
7734
|
var COUNTED_DIRS2 = ["_memory", "worklog", "decision-log"];
|
|
7939
7735
|
var DEFAULT_GAP_WINDOW_DAYS = 30;
|
|
7940
7736
|
function gapWindowSinceArg() {
|
|
@@ -7951,8 +7747,8 @@ async function collectSessionStartReport(ctx, opts) {
|
|
|
7951
7747
|
const counts = {};
|
|
7952
7748
|
const missing = [];
|
|
7953
7749
|
for (const name of COUNTED_DIRS2) {
|
|
7954
|
-
const dir =
|
|
7955
|
-
if (!
|
|
7750
|
+
const dir = join26(ctx.dataDir, name);
|
|
7751
|
+
if (!existsSync13(dir)) {
|
|
7956
7752
|
missing.push(name);
|
|
7957
7753
|
counts[name] = 0;
|
|
7958
7754
|
continue;
|
|
@@ -7962,7 +7758,7 @@ async function collectSessionStartReport(ctx, opts) {
|
|
|
7962
7758
|
const { recent, recentGroup, recentWorklogsOmitted, dates, latestBodies } = await scanWorklog(ctx.dataDir);
|
|
7963
7759
|
const cutoff = isoDate2(addDays2(now, -(opts?.gapWindowDays ?? DEFAULT_GAP_WINDOW_DAYS)));
|
|
7964
7760
|
const recentWorklogDates = dates.filter((d2) => d2 >= cutoff);
|
|
7965
|
-
const mem = await scanMemoryTiers(
|
|
7761
|
+
const mem = await scanMemoryTiers(join26(ctx.dataDir, "_memory"));
|
|
7966
7762
|
const ho = await scanHandoffs(ctx.dataDir);
|
|
7967
7763
|
const handoffs = ho.active.map((h) => ({
|
|
7968
7764
|
date: h.date,
|
|
@@ -8029,7 +7825,7 @@ async function scanMemoryTiers(memoryDir) {
|
|
|
8029
7825
|
for (const e of entries) {
|
|
8030
7826
|
if (!e.isFile() || !e.name.endsWith(".md"))
|
|
8031
7827
|
continue;
|
|
8032
|
-
const full =
|
|
7828
|
+
const full = join26(memoryDir, e.name);
|
|
8033
7829
|
if (e.name === "_INDEX.md") {
|
|
8034
7830
|
indexExists = true;
|
|
8035
7831
|
try {
|
|
@@ -8189,6 +7985,16 @@ function renderSessionStartReport(report, extras) {
|
|
|
8189
7985
|
if (carry && carry.uncommitted > 0) {
|
|
8190
7986
|
lines.push(`- \u21A9\uFE0F ${carry.uncommitted} uncommitted change(s) carried over from a prior session \u2014 likely normal work in progress.`);
|
|
8191
7987
|
}
|
|
7988
|
+
const fl = extras?.failures;
|
|
7989
|
+
if (fl && fl.warnings.length > 0) {
|
|
7990
|
+
lines.push(`- \u{1F501} recurring failures (open ledger entries: ${fl.totalOpen}):`);
|
|
7991
|
+
for (const w2 of fl.warnings) {
|
|
7992
|
+
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})` : ""}`;
|
|
7993
|
+
lines.push(` - ${w2.key} \xD7${w2.count} (last ${w2.lastDate}) \u2014 ${stageText}`);
|
|
7994
|
+
}
|
|
7995
|
+
if (fl.omitted > 0)
|
|
7996
|
+
lines.push(` - \u2026(+${fl.omitted} more \u2014 \`vortex failure list\`)`);
|
|
7997
|
+
}
|
|
8192
7998
|
const cu = extras?.catchUp;
|
|
8193
7999
|
if (cu && (cu.ingestedLocal > 0 || cu.indexedPulled > 0 || cu.errors > 0)) {
|
|
8194
8000
|
const parts = [];
|
|
@@ -8258,15 +8064,15 @@ async function countMarkdown3(dir, recursive) {
|
|
|
8258
8064
|
} else if (e.isDirectory() && recursive) {
|
|
8259
8065
|
if (e.name.startsWith(".") || e.name.startsWith("_"))
|
|
8260
8066
|
continue;
|
|
8261
|
-
total += await countMarkdown3(
|
|
8067
|
+
total += await countMarkdown3(join26(dir, e.name), recursive);
|
|
8262
8068
|
}
|
|
8263
8069
|
}
|
|
8264
8070
|
return total;
|
|
8265
8071
|
}
|
|
8266
8072
|
var MAX_GROUP_READ = 20;
|
|
8267
8073
|
async function scanWorklog(dataDir) {
|
|
8268
|
-
const root =
|
|
8269
|
-
if (!
|
|
8074
|
+
const root = join26(dataDir, "worklog");
|
|
8075
|
+
if (!existsSync13(root))
|
|
8270
8076
|
return { recent: null, recentGroup: [], recentWorklogsOmitted: 0, dates: [], latestBodies: [] };
|
|
8271
8077
|
const dates = /* @__PURE__ */ new Set();
|
|
8272
8078
|
const consistent = [];
|
|
@@ -8281,7 +8087,7 @@ async function scanWorklog(dataDir) {
|
|
|
8281
8087
|
for (const e of entries) {
|
|
8282
8088
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
8283
8089
|
if (e.isDirectory()) {
|
|
8284
|
-
await walk5(
|
|
8090
|
+
await walk5(join26(absDir, e.name), childRel);
|
|
8285
8091
|
} else if (e.isFile()) {
|
|
8286
8092
|
const m2 = e.name.match(/^(\d{4})-(\d{2})-(\d{2})(?:_\d{4})?-.+\.md$/);
|
|
8287
8093
|
if (!m2)
|
|
@@ -8310,7 +8116,7 @@ async function scanWorklog(dataDir) {
|
|
|
8310
8116
|
const recentGroup = [];
|
|
8311
8117
|
const latestBodies = [];
|
|
8312
8118
|
for (const g of group) {
|
|
8313
|
-
const { title, body } = await readWorklogTitleAndBody(
|
|
8119
|
+
const { title, body } = await readWorklogTitleAndBody(join26(root, g.rel));
|
|
8314
8120
|
recentGroup.push({ path: defangReportPath(`worklog/${g.rel}`), title });
|
|
8315
8121
|
latestBodies.push(body);
|
|
8316
8122
|
}
|
|
@@ -8389,11 +8195,11 @@ function isoDate2(d2) {
|
|
|
8389
8195
|
}
|
|
8390
8196
|
|
|
8391
8197
|
// ../plugins/session-rituals/dist/curate-cli.js
|
|
8392
|
-
import { existsSync as
|
|
8198
|
+
import { existsSync as existsSync14 } from "fs";
|
|
8393
8199
|
import { createHash as createHash3 } from "crypto";
|
|
8394
8200
|
import { readFile as readFile23, readdir as readdir18 } from "fs/promises";
|
|
8395
|
-
import { join as
|
|
8396
|
-
var
|
|
8201
|
+
import { join as join27 } from "path";
|
|
8202
|
+
var SYSTEM_META_DIRS2 = /* @__PURE__ */ new Set([
|
|
8397
8203
|
"worklog",
|
|
8398
8204
|
"decision-log",
|
|
8399
8205
|
"runbooks",
|
|
@@ -8416,7 +8222,7 @@ function firstSegment(rel) {
|
|
|
8416
8222
|
}
|
|
8417
8223
|
function isSystemMetaRel(rel) {
|
|
8418
8224
|
const first = firstSegment(rel);
|
|
8419
|
-
return
|
|
8225
|
+
return SYSTEM_META_DIRS2.has(first) || first.startsWith("_");
|
|
8420
8226
|
}
|
|
8421
8227
|
function validateCuratePayload(payload) {
|
|
8422
8228
|
const errors = [];
|
|
@@ -8472,10 +8278,10 @@ function joinRel(...parts) {
|
|
|
8472
8278
|
}
|
|
8473
8279
|
async function runCurateCandidates(repoRoot, options) {
|
|
8474
8280
|
const maxEntries = options?.maxEntries ?? 200;
|
|
8475
|
-
const dataDir =
|
|
8281
|
+
const dataDir = join27(repoRoot, "data");
|
|
8476
8282
|
const candidates = [];
|
|
8477
8283
|
let truncated = false;
|
|
8478
|
-
if (
|
|
8284
|
+
if (existsSync14(dataDir)) {
|
|
8479
8285
|
async function visit(absDir, relDir) {
|
|
8480
8286
|
if (candidates.length >= maxEntries) {
|
|
8481
8287
|
truncated = true;
|
|
@@ -8496,9 +8302,9 @@ async function runCurateCandidates(repoRoot, options) {
|
|
|
8496
8302
|
const atRoot = relDir === "";
|
|
8497
8303
|
if (e.name.startsWith("."))
|
|
8498
8304
|
continue;
|
|
8499
|
-
if (atRoot && (
|
|
8305
|
+
if (atRoot && (SYSTEM_META_DIRS2.has(e.name) || e.name.startsWith("_")))
|
|
8500
8306
|
continue;
|
|
8501
|
-
await visit(
|
|
8307
|
+
await visit(join27(absDir, e.name), joinRel(relDir, e.name));
|
|
8502
8308
|
} else if (e.isFile() && e.name.endsWith(".md")) {
|
|
8503
8309
|
if (NON_DOC_FILES.has(e.name))
|
|
8504
8310
|
continue;
|
|
@@ -8507,7 +8313,7 @@ async function runCurateCandidates(repoRoot, options) {
|
|
|
8507
8313
|
let topic = null;
|
|
8508
8314
|
let tags = [];
|
|
8509
8315
|
try {
|
|
8510
|
-
const raw = await readFile23(
|
|
8316
|
+
const raw = await readFile23(join27(absDir, e.name), "utf8");
|
|
8511
8317
|
const parsed = parseFrontmatter(raw);
|
|
8512
8318
|
if (typeof parsed.frontmatter.topic === "string") {
|
|
8513
8319
|
topic = parsed.frontmatter.topic.trim().toLowerCase();
|
|
@@ -8545,7 +8351,7 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
|
|
|
8545
8351
|
};
|
|
8546
8352
|
}
|
|
8547
8353
|
try {
|
|
8548
|
-
validateDataRelativePath(
|
|
8354
|
+
validateDataRelativePath(join27(repoRoot, "data"), v2.effectiveRelPath);
|
|
8549
8355
|
} catch (e) {
|
|
8550
8356
|
return {
|
|
8551
8357
|
subcommand: "curate-preview",
|
|
@@ -8562,10 +8368,10 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
|
|
|
8562
8368
|
let targetExists;
|
|
8563
8369
|
let wouldDo;
|
|
8564
8370
|
if (payload.action === "create-file") {
|
|
8565
|
-
targetExists =
|
|
8371
|
+
targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
|
|
8566
8372
|
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
8373
|
} else {
|
|
8568
|
-
targetExists =
|
|
8374
|
+
targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
|
|
8569
8375
|
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
8376
|
}
|
|
8571
8377
|
const nextActions = [];
|
|
@@ -8710,13 +8516,13 @@ function readCuratePayload(args) {
|
|
|
8710
8516
|
break;
|
|
8711
8517
|
}
|
|
8712
8518
|
if (t === "--payload-file" && i + 1 < args.length) {
|
|
8713
|
-
raw =
|
|
8519
|
+
raw = readFileSync3(args[++i], "utf8");
|
|
8714
8520
|
break;
|
|
8715
8521
|
}
|
|
8716
8522
|
}
|
|
8717
8523
|
if (raw === null) {
|
|
8718
8524
|
try {
|
|
8719
|
-
raw =
|
|
8525
|
+
raw = readFileSync3(0, "utf8");
|
|
8720
8526
|
} catch {
|
|
8721
8527
|
raw = "";
|
|
8722
8528
|
}
|
|
@@ -8740,11 +8546,22 @@ async function runVortexCli(argv, io) {
|
|
|
8740
8546
|
const err = io?.stderr ?? ((s) => process.stderr.write(s));
|
|
8741
8547
|
try {
|
|
8742
8548
|
if (argv[0] === "statusline") {
|
|
8743
|
-
const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-
|
|
8549
|
+
const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-JTSL5CCH.js");
|
|
8744
8550
|
const statuslineRoot = process.env.VORTEX_REPO_ROOT?.trim() || process.cwd();
|
|
8745
8551
|
return runStatuslineCli2(argv.slice(1), statuslineRoot, out, err);
|
|
8746
8552
|
}
|
|
8553
|
+
if (argv[0] === "guard") {
|
|
8554
|
+
const { runGuardCli: runGuardCli2 } = await import("./guard-IMJR6ET7.js");
|
|
8555
|
+
return runGuardCli2(argv.slice(1), out, err);
|
|
8556
|
+
}
|
|
8747
8557
|
const repoRoot = resolveRepoRoot();
|
|
8558
|
+
if (argv[0] === "failure") {
|
|
8559
|
+
const { runFailureCli: runFailureCli2 } = await import("./failures-PMURLMVB.js");
|
|
8560
|
+
const { resolveInstanceRoot: resolveInstanceRoot2 } = await import("./guard-IMJR6ET7.js");
|
|
8561
|
+
const root = resolveInstanceRoot2(process.cwd()) ?? repoRoot;
|
|
8562
|
+
const ctx = makeContext(root);
|
|
8563
|
+
return runFailureCli2(argv.slice(1), ctx.dataDir, out, err);
|
|
8564
|
+
}
|
|
8748
8565
|
if (argv[0] === "session-start") {
|
|
8749
8566
|
await runSessionStart(repoRoot, out);
|
|
8750
8567
|
return 0;
|
|
@@ -8784,6 +8601,8 @@ ${names}
|
|
|
8784
8601
|
session-end \u2014 no-op (kept for hook compatibility; worklog gap handling is at session-start)
|
|
8785
8602
|
check-updates \u2014 check the npm registry for a newer @vortex-os/base (read-only; prints the exact update command)
|
|
8786
8603
|
statusline \u2014 render the Claude Code status bar from stdin JSON (\`lite\` for 1-line; \`install [--lite]\` wires .claude/settings.json)
|
|
8604
|
+
failure \u2014 failure ledger (\`record\` an occurrence by recurrence key / \`list\` open groups with their escalation stage)
|
|
8605
|
+
guard \u2014 deterministic write-time guards (\`write\` = PreToolUse hook body; wired by \`vortex init\`)
|
|
8787
8606
|
|
|
8788
8607
|
Instance shortcuts (also available as \`/vortex <sub>\`):
|
|
8789
8608
|
init \u2014 first-time setup: routers + data/ + hooks + slash-commands
|
|
@@ -8850,12 +8669,12 @@ function memoryExtendedPresent() {
|
|
|
8850
8669
|
}
|
|
8851
8670
|
var VECTORIZE_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
8852
8671
|
function vectorizeLockPath(ctx) {
|
|
8853
|
-
return
|
|
8672
|
+
return join28(ctx.dataDir, "_indexes", ".vectorize.lock");
|
|
8854
8673
|
}
|
|
8855
8674
|
function vectorizeSetupInProgress(ctx) {
|
|
8856
8675
|
const lock = vectorizeLockPath(ctx);
|
|
8857
8676
|
try {
|
|
8858
|
-
if (!
|
|
8677
|
+
if (!existsSync15(lock))
|
|
8859
8678
|
return false;
|
|
8860
8679
|
return Date.now() - statSync(lock).mtimeMs < VECTORIZE_LOCK_TTL_MS;
|
|
8861
8680
|
} catch {
|
|
@@ -8876,9 +8695,9 @@ function spawnVectorizeSetup(repoRoot) {
|
|
|
8876
8695
|
}
|
|
8877
8696
|
async function runVectorizeSetup(repoRoot, out, err) {
|
|
8878
8697
|
const ctx = makeContext(repoRoot);
|
|
8879
|
-
const indexDir =
|
|
8880
|
-
const finalDb =
|
|
8881
|
-
if (
|
|
8698
|
+
const indexDir = join28(ctx.dataDir, "_indexes");
|
|
8699
|
+
const finalDb = join28(indexDir, "memory.sqlite");
|
|
8700
|
+
if (existsSync15(finalDb)) {
|
|
8882
8701
|
out("recall index already present \u2014 nothing to do\n");
|
|
8883
8702
|
return;
|
|
8884
8703
|
}
|
|
@@ -8909,7 +8728,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8909
8728
|
return;
|
|
8910
8729
|
}
|
|
8911
8730
|
}
|
|
8912
|
-
const tmpDb =
|
|
8731
|
+
const tmpDb = join28(indexDir, `memory.sqlite.building-${process.pid}`);
|
|
8913
8732
|
const tmpSidecars = [tmpDb + "-wal", tmpDb + "-shm", tmpDb + "-journal"];
|
|
8914
8733
|
const cleanTmp = () => {
|
|
8915
8734
|
rmSync(tmpDb, { force: true });
|
|
@@ -8919,7 +8738,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8919
8738
|
let tokenWritten = false;
|
|
8920
8739
|
const releaseLock = () => {
|
|
8921
8740
|
try {
|
|
8922
|
-
const cur =
|
|
8741
|
+
const cur = existsSync15(lockPath) ? readFileSync3(lockPath, "utf8").trim() : "";
|
|
8923
8742
|
if (cur === token || cur === "" && !tokenWritten)
|
|
8924
8743
|
rmSync(lockPath, { force: true });
|
|
8925
8744
|
} catch {
|
|
@@ -8932,7 +8751,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8932
8751
|
} finally {
|
|
8933
8752
|
closeSync(lockFd);
|
|
8934
8753
|
}
|
|
8935
|
-
if (
|
|
8754
|
+
if (existsSync15(finalDb)) {
|
|
8936
8755
|
out("recall index already present \u2014 nothing to do\n");
|
|
8937
8756
|
return;
|
|
8938
8757
|
}
|
|
@@ -8948,7 +8767,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8948
8767
|
} finally {
|
|
8949
8768
|
db.close();
|
|
8950
8769
|
}
|
|
8951
|
-
if (
|
|
8770
|
+
if (existsSync15(tmpDb + "-wal")) {
|
|
8952
8771
|
throw new Error("temp index retained a WAL sidecar after consolidation; refusing to publish");
|
|
8953
8772
|
}
|
|
8954
8773
|
try {
|
|
@@ -9032,7 +8851,7 @@ async function runSessionStart(repoRoot, out) {
|
|
|
9032
8851
|
let vectorized = null;
|
|
9033
8852
|
let vectorizeSetupStarted = false;
|
|
9034
8853
|
if (config.autoRecord.vectorize) {
|
|
9035
|
-
const dbExists =
|
|
8854
|
+
const dbExists = existsSync15(join28(ctx.dataDir, "_indexes", "memory.sqlite"));
|
|
9036
8855
|
const action = decideVectorizeAction({
|
|
9037
8856
|
vectorizeOn: true,
|
|
9038
8857
|
dbExists,
|
|
@@ -9055,6 +8874,16 @@ async function runSessionStart(repoRoot, out) {
|
|
|
9055
8874
|
}
|
|
9056
8875
|
}
|
|
9057
8876
|
}
|
|
8877
|
+
let failures = null;
|
|
8878
|
+
if (config.autoRecord.failures) {
|
|
8879
|
+
try {
|
|
8880
|
+
const { scanFailures: scanFailures2, failureReportSlice: failureReportSlice2 } = await import("./failures-PMURLMVB.js");
|
|
8881
|
+
const slice = failureReportSlice2(await scanFailures2(ctx.dataDir));
|
|
8882
|
+
if (slice.warnings.length > 0)
|
|
8883
|
+
failures = slice;
|
|
8884
|
+
} catch {
|
|
8885
|
+
}
|
|
8886
|
+
}
|
|
9058
8887
|
let templateUpdate = null;
|
|
9059
8888
|
try {
|
|
9060
8889
|
const td = resolveTemplatesDir();
|
|
@@ -9094,7 +8923,8 @@ async function runSessionStart(repoRoot, out) {
|
|
|
9094
8923
|
updateCheck: updateCheck ?? void 0,
|
|
9095
8924
|
globalSetupOffer: globalSetupOffer || void 0,
|
|
9096
8925
|
carryover: carryover ?? void 0,
|
|
9097
|
-
handoffPrune: handoffPrune ?? void 0
|
|
8926
|
+
handoffPrune: handoffPrune ?? void 0,
|
|
8927
|
+
failures: failures ?? void 0
|
|
9098
8928
|
}));
|
|
9099
8929
|
}
|
|
9100
8930
|
async function runSessionEnd(_repoRoot, _out) {
|
|
@@ -9121,7 +8951,7 @@ function detectInterruptedGitOp(repoRoot) {
|
|
|
9121
8951
|
const resolved = gitOut(repoRoot, args).split(/\r?\n/).map((s) => s.trim());
|
|
9122
8952
|
for (let i = 0; i < markers.length; i++) {
|
|
9123
8953
|
const p = resolved[i];
|
|
9124
|
-
if (p &&
|
|
8954
|
+
if (p && existsSync15(isAbsolute4(p) ? p : join28(repoRoot, p)))
|
|
9125
8955
|
return markers[i];
|
|
9126
8956
|
}
|
|
9127
8957
|
} catch {
|
|
@@ -9141,23 +8971,23 @@ function resolveSessionEnvironment(ctx, config) {
|
|
|
9141
8971
|
let environment = resolveEnvironment(config, {
|
|
9142
8972
|
hostname: hostname(),
|
|
9143
8973
|
env: process.env,
|
|
9144
|
-
pathExists:
|
|
8974
|
+
pathExists: existsSync15
|
|
9145
8975
|
});
|
|
9146
8976
|
if (!environment)
|
|
9147
8977
|
environment = process.env.VORTEX_ENV?.trim() || null;
|
|
9148
8978
|
if (!environment) {
|
|
9149
|
-
const envFile =
|
|
9150
|
-
if (
|
|
9151
|
-
environment =
|
|
8979
|
+
const envFile = join28(ctx.repoRoot, ".agent", "environment");
|
|
8980
|
+
if (existsSync15(envFile)) {
|
|
8981
|
+
environment = readFileSync3(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
|
|
9152
8982
|
}
|
|
9153
8983
|
}
|
|
9154
8984
|
return environment;
|
|
9155
8985
|
}
|
|
9156
8986
|
|
|
9157
8987
|
// ../plugins/session-rituals/dist/ambient-recall.js
|
|
9158
|
-
import { join as
|
|
8988
|
+
import { join as join29 } from "path";
|
|
9159
8989
|
function defaultDbPath2(ctx) {
|
|
9160
|
-
return
|
|
8990
|
+
return join29(ctx.dataDir, "_indexes", "memory.sqlite");
|
|
9161
8991
|
}
|
|
9162
8992
|
function createAmbientRecaller(ctx, options) {
|
|
9163
8993
|
const resolveDb = options.dbPath ?? defaultDbPath2;
|
|
@@ -9194,14 +9024,14 @@ function createAmbientRecaller(ctx, options) {
|
|
|
9194
9024
|
}
|
|
9195
9025
|
|
|
9196
9026
|
// ../plugins/session-rituals/dist/worklog-write.js
|
|
9197
|
-
import { mkdir as mkdir10, writeFile as
|
|
9198
|
-
import { dirname as dirname6, join as
|
|
9027
|
+
import { mkdir as mkdir10, writeFile as writeFile11 } from "fs/promises";
|
|
9028
|
+
import { dirname as dirname6, join as join30 } from "path";
|
|
9199
9029
|
async function ensureWorklogEntry(ctx, opts) {
|
|
9200
9030
|
const now = opts?.now ?? /* @__PURE__ */ new Date();
|
|
9201
9031
|
const date = isoDate3(now);
|
|
9202
9032
|
const time = isoTime2(now);
|
|
9203
9033
|
const keyword = (opts?.keyword ?? "worklog").trim() || "worklog";
|
|
9204
|
-
const store = new WorklogStore(
|
|
9034
|
+
const store = new WorklogStore(join30(ctx.dataDir, "worklog"));
|
|
9205
9035
|
const existing = await store.get(date);
|
|
9206
9036
|
if (existing) {
|
|
9207
9037
|
return { path: existing.path, date: existing.date, keyword: existing.keyword, created: false };
|
|
@@ -9209,7 +9039,7 @@ async function ensureWorklogEntry(ctx, opts) {
|
|
|
9209
9039
|
const path = store.pathFor(date, keyword, time);
|
|
9210
9040
|
const title = opts?.title ?? `${date} worklog`;
|
|
9211
9041
|
await mkdir10(dirname6(path), { recursive: true });
|
|
9212
|
-
await
|
|
9042
|
+
await writeFile11(path, renderWorklogFile(date, title, opts?.body ?? ""), "utf8");
|
|
9213
9043
|
return { path, date, keyword, created: true };
|
|
9214
9044
|
}
|
|
9215
9045
|
function renderWorklogFile(date, title, body) {
|