@vortex-os/base 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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-EAKDR5B2.js} +40 -9
- package/dist/chunk-EAKDR5B2.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 +289 -6
- package/dist/index.js +432 -628
- package/dist/index.js.map +1 -1
- package/dist/{statusline-NQKJ3NWD.js → statusline-6KSHISXO.js} +8 -2
- package/dist/statusline-6KSHISXO.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-EAKDR5B2.js";
|
|
31
|
+
import {
|
|
32
|
+
GUARD_WRITE_COMMAND,
|
|
33
|
+
GUARD_WRITE_MATCHER,
|
|
34
|
+
buildDenyDecision,
|
|
35
|
+
findControlChar,
|
|
36
|
+
guardWriteDecision,
|
|
37
|
+
resolveInstanceRoot,
|
|
38
|
+
runGuardCli,
|
|
39
|
+
scanToolInput
|
|
40
|
+
} from "./chunk-2FVNWW77.js";
|
|
41
|
+
import {
|
|
42
|
+
atomicWriteFile,
|
|
43
|
+
dist_exports,
|
|
44
|
+
exclusiveCreateFile,
|
|
45
|
+
isVisibleAt,
|
|
46
|
+
loadVortexConfig,
|
|
47
|
+
makeContext,
|
|
48
|
+
normalizePrivacy,
|
|
49
|
+
parseFrontmatter,
|
|
50
|
+
resolveEnvironment,
|
|
51
|
+
serializeFrontmatter,
|
|
52
|
+
validateDataRelativePath
|
|
53
|
+
} from "./chunk-T53UWSTR.js";
|
|
20
54
|
import {
|
|
21
55
|
catchUpSessions
|
|
22
56
|
} from "./chunk-3L5DLEGP.js";
|
|
@@ -24,287 +58,6 @@ import {
|
|
|
24
58
|
__export
|
|
25
59
|
} from "./chunk-PZ5AY32C.js";
|
|
26
60
|
|
|
27
|
-
// ../core/dist/index.js
|
|
28
|
-
var dist_exports = {};
|
|
29
|
-
__export(dist_exports, {
|
|
30
|
-
Privacy: () => Privacy,
|
|
31
|
-
atomicWriteFile: () => atomicWriteFile,
|
|
32
|
-
exclusiveCreateFile: () => exclusiveCreateFile,
|
|
33
|
-
isVisibleAt: () => isVisibleAt,
|
|
34
|
-
loadVortexConfig: () => loadVortexConfig,
|
|
35
|
-
makeContext: () => makeContext,
|
|
36
|
-
maxPrivacy: () => maxPrivacy,
|
|
37
|
-
moduleDir: () => moduleDir,
|
|
38
|
-
normalizePrivacy: () => normalizePrivacy,
|
|
39
|
-
parseFrontmatter: () => parseFrontmatter,
|
|
40
|
-
resolveEnvironment: () => resolveEnvironment,
|
|
41
|
-
serializeFrontmatter: () => serializeFrontmatter,
|
|
42
|
-
validateDataRelativePath: () => validateDataRelativePath,
|
|
43
|
-
vortexConfigPath: () => vortexConfigPath
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// ../core/dist/types.js
|
|
47
|
-
var Privacy = {
|
|
48
|
-
Public: "public",
|
|
49
|
-
Internal: "internal",
|
|
50
|
-
Personal: "personal"
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// ../core/dist/frontmatter.js
|
|
54
|
-
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
55
|
-
var FENCE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
56
|
-
var BOM = "\uFEFF";
|
|
57
|
-
function parseFrontmatter(source) {
|
|
58
|
-
const cleaned = source.startsWith(BOM) ? source.slice(1) : source;
|
|
59
|
-
const match = cleaned.match(FENCE);
|
|
60
|
-
if (!match) {
|
|
61
|
-
return {
|
|
62
|
-
frontmatter: {},
|
|
63
|
-
body: cleaned
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
const yaml = match[1] ?? "";
|
|
67
|
-
const body = cleaned.slice(match[0].length);
|
|
68
|
-
let parsed;
|
|
69
|
-
try {
|
|
70
|
-
const value = parseYaml(yaml);
|
|
71
|
-
parsed = typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
72
|
-
} catch {
|
|
73
|
-
parsed = {};
|
|
74
|
-
}
|
|
75
|
-
return { frontmatter: parsed, body };
|
|
76
|
-
}
|
|
77
|
-
function serializeFrontmatter(doc) {
|
|
78
|
-
const keys = Object.keys(doc.frontmatter ?? {});
|
|
79
|
-
if (keys.length === 0)
|
|
80
|
-
return doc.body;
|
|
81
|
-
const yaml = stringifyYaml(doc.frontmatter).trimEnd();
|
|
82
|
-
return `---
|
|
83
|
-
${yaml}
|
|
84
|
-
---
|
|
85
|
-
${doc.body}`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// ../core/dist/privacy.js
|
|
89
|
-
var ORDER = {
|
|
90
|
-
public: 0,
|
|
91
|
-
internal: 1,
|
|
92
|
-
personal: 2
|
|
93
|
-
};
|
|
94
|
-
function isVisibleAt(docPrivacy, viewerPrivacy) {
|
|
95
|
-
return ORDER[docPrivacy] <= ORDER[viewerPrivacy];
|
|
96
|
-
}
|
|
97
|
-
function maxPrivacy(a, b2) {
|
|
98
|
-
return ORDER[a] >= ORDER[b2] ? a : b2;
|
|
99
|
-
}
|
|
100
|
-
function normalizePrivacy(value, fallback = "internal") {
|
|
101
|
-
if (value === "public" || value === "internal" || value === "personal") {
|
|
102
|
-
return value;
|
|
103
|
-
}
|
|
104
|
-
return fallback;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// ../core/dist/paths.js
|
|
108
|
-
import { resolve, join } from "path";
|
|
109
|
-
function makeContext(repoRoot) {
|
|
110
|
-
const root = resolve(repoRoot);
|
|
111
|
-
return {
|
|
112
|
-
repoRoot: root,
|
|
113
|
-
agentDir: join(root, ".agent"),
|
|
114
|
-
dataDir: join(root, "data"),
|
|
115
|
-
modulesDir: join(root, "modules"),
|
|
116
|
-
pluginsDir: join(root, "plugins")
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function moduleDir(ctx, moduleName) {
|
|
120
|
-
return join(ctx.modulesDir, moduleName);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ../core/dist/config.js
|
|
124
|
-
import { existsSync, readFileSync } from "fs";
|
|
125
|
-
import { join as join2 } from "path";
|
|
126
|
-
var DEFAULT_CONFIG = {
|
|
127
|
-
autoRecord: { sessionStart: true, worklog: true, decision: true, ambientRecall: true, archive: true, vectorize: true, vectorizeAutoDownload: true, commitFrameworkChanges: true, handoff: true, handoffRetentionDays: 7, reindex: true, backfill: true },
|
|
128
|
-
updates: { check: "session" },
|
|
129
|
-
environments: []
|
|
130
|
-
};
|
|
131
|
-
function vortexConfigPath(ctx) {
|
|
132
|
-
return join2(ctx.agentDir, "vortex.json");
|
|
133
|
-
}
|
|
134
|
-
function parseEnvironmentRule(raw) {
|
|
135
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
136
|
-
return null;
|
|
137
|
-
const candidate = raw;
|
|
138
|
-
if (typeof candidate.label !== "string")
|
|
139
|
-
return null;
|
|
140
|
-
const rule = {
|
|
141
|
-
label: candidate.label
|
|
142
|
-
};
|
|
143
|
-
if (typeof candidate.pathExists === "string")
|
|
144
|
-
rule.pathExists = candidate.pathExists;
|
|
145
|
-
if (typeof candidate.hostname === "string")
|
|
146
|
-
rule.hostname = candidate.hostname;
|
|
147
|
-
if (typeof candidate.envVar === "string") {
|
|
148
|
-
rule.envVar = candidate.envVar;
|
|
149
|
-
} else if (typeof candidate.envVar === "object" && candidate.envVar !== null) {
|
|
150
|
-
const ev = candidate.envVar;
|
|
151
|
-
if (typeof ev.name === "string") {
|
|
152
|
-
rule.envVar = typeof ev.equals === "string" ? { name: ev.name, equals: ev.equals } : { name: ev.name };
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return rule;
|
|
156
|
-
}
|
|
157
|
-
function loadVortexConfig(ctx) {
|
|
158
|
-
const path = vortexConfigPath(ctx);
|
|
159
|
-
if (!existsSync(path))
|
|
160
|
-
return DEFAULT_CONFIG;
|
|
161
|
-
try {
|
|
162
|
-
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
163
|
-
const environments = Array.isArray(raw.environments) ? raw.environments.map(parseEnvironmentRule).filter((rule) => rule !== null) : [];
|
|
164
|
-
const rawUpdates = raw.updates && typeof raw.updates === "object" && !Array.isArray(raw.updates) ? raw.updates : {};
|
|
165
|
-
const rawCheck = rawUpdates.check;
|
|
166
|
-
const check = rawCheck === void 0 ? "session" : typeof rawCheck === "string" && rawCheck.trim().toLowerCase() === "session" ? "session" : "off";
|
|
167
|
-
const rawAuto = raw.autoRecord && typeof raw.autoRecord === "object" && !Array.isArray(raw.autoRecord) ? raw.autoRecord : {};
|
|
168
|
-
const vectorizeAutoDownload = rawAuto.vectorizeAutoDownload === void 0 ? true : rawAuto.vectorizeAutoDownload === true;
|
|
169
|
-
const commitFrameworkChanges = rawAuto.commitFrameworkChanges === void 0 ? true : rawAuto.commitFrameworkChanges === true;
|
|
170
|
-
const handoff = rawAuto.handoff === void 0 ? true : rawAuto.handoff === true;
|
|
171
|
-
const reindex = rawAuto.reindex === void 0 ? true : rawAuto.reindex === true;
|
|
172
|
-
const backfill = rawAuto.backfill === void 0 ? true : rawAuto.backfill === true;
|
|
173
|
-
const rawDays = rawAuto.handoffRetentionDays;
|
|
174
|
-
const handoffRetentionDays = typeof rawDays === "number" && Number.isFinite(rawDays) && rawDays > 0 ? Math.floor(rawDays) : DEFAULT_CONFIG.autoRecord.handoffRetentionDays;
|
|
175
|
-
return {
|
|
176
|
-
autoRecord: {
|
|
177
|
-
...DEFAULT_CONFIG.autoRecord,
|
|
178
|
-
...raw.autoRecord ?? {},
|
|
179
|
-
vectorizeAutoDownload,
|
|
180
|
-
commitFrameworkChanges,
|
|
181
|
-
handoff,
|
|
182
|
-
handoffRetentionDays,
|
|
183
|
-
reindex,
|
|
184
|
-
backfill
|
|
185
|
-
},
|
|
186
|
-
updates: { check },
|
|
187
|
-
environments
|
|
188
|
-
};
|
|
189
|
-
} catch {
|
|
190
|
-
return DEFAULT_CONFIG;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
function resolveEnvironment(config, signals) {
|
|
194
|
-
const host = signals.hostname?.toLowerCase();
|
|
195
|
-
const env = signals.env ?? {};
|
|
196
|
-
const pathExists = signals.pathExists ?? (() => false);
|
|
197
|
-
for (const rule of config.environments) {
|
|
198
|
-
if (rule.pathExists && pathExists(rule.pathExists))
|
|
199
|
-
return rule.label;
|
|
200
|
-
if (rule.hostname && host && rule.hostname.toLowerCase() === host)
|
|
201
|
-
return rule.label;
|
|
202
|
-
if (rule.envVar) {
|
|
203
|
-
if (typeof rule.envVar === "string") {
|
|
204
|
-
if (env[rule.envVar] !== void 0)
|
|
205
|
-
return rule.label;
|
|
206
|
-
} else {
|
|
207
|
-
const v2 = env[rule.envVar.name];
|
|
208
|
-
if (v2 !== void 0 && (rule.envVar.equals === void 0 || v2 === rule.envVar.equals)) {
|
|
209
|
-
return rule.label;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return null;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// ../core/dist/safe-fs.js
|
|
218
|
-
import { rename, writeFile } from "fs/promises";
|
|
219
|
-
import { isAbsolute, relative, resolve as resolve2, sep } from "path";
|
|
220
|
-
var SYSTEM_META_DIRS = /* @__PURE__ */ new Set([
|
|
221
|
-
"worklog",
|
|
222
|
-
"decision-log",
|
|
223
|
-
"runbooks",
|
|
224
|
-
"hubs",
|
|
225
|
-
"_memory",
|
|
226
|
-
"_templates",
|
|
227
|
-
"_proactive-curator",
|
|
228
|
-
// Framework metadata carve-out: `data/.vortex/` holds the update-lifecycle
|
|
229
|
-
// ownership manifest and template backups. It is NOT user space — the curate
|
|
230
|
-
// value loop (and any LLM-chosen write path) must never target it, even
|
|
231
|
-
// though it does not start with `_`. (The leading-`_` rule below does not
|
|
232
|
-
// cover a leading-dot dir, so it is listed explicitly.)
|
|
233
|
-
".vortex"
|
|
234
|
-
]);
|
|
235
|
-
var DRIVE_QUALIFIED = /^[a-zA-Z]:/;
|
|
236
|
-
var CONTROL_CHARS = /[\u0000-\u001F]/;
|
|
237
|
-
function validateDataRelativePath(dataDir, rel, _options = {}) {
|
|
238
|
-
if (typeof rel !== "string" || rel.length === 0) {
|
|
239
|
-
throw new Error("Invalid data-relative path: must be a non-empty string.");
|
|
240
|
-
}
|
|
241
|
-
if (CONTROL_CHARS.test(rel)) {
|
|
242
|
-
throw new Error("Invalid data-relative path: contains control characters.");
|
|
243
|
-
}
|
|
244
|
-
const normalized = rel.replace(/\\/g, "/");
|
|
245
|
-
if (normalized === "" || normalized === ".") {
|
|
246
|
-
throw new Error(`Invalid data-relative path: "${rel}" is empty or '.'.`);
|
|
247
|
-
}
|
|
248
|
-
if (DRIVE_QUALIFIED.test(normalized)) {
|
|
249
|
-
throw new Error(`Invalid data-relative path: "${rel}" is drive-qualified (must be data-relative).`);
|
|
250
|
-
}
|
|
251
|
-
if (isAbsolute(normalized) || normalized.startsWith("/")) {
|
|
252
|
-
throw new Error(`Invalid data-relative path: "${rel}" is absolute (must be data-relative).`);
|
|
253
|
-
}
|
|
254
|
-
const segments = normalized.split("/");
|
|
255
|
-
for (const segment of segments) {
|
|
256
|
-
if (segment === "" || segment === "." || segment === "..") {
|
|
257
|
-
throw new Error(`Invalid data-relative path: "${rel}" contains an empty, '.', or '..' segment (path traversal).`);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
const filename = segments[segments.length - 1];
|
|
261
|
-
if (filename.length === 0 || filename.includes("/") || filename.includes("\\")) {
|
|
262
|
-
throw new Error(`Invalid data-relative path: "${rel}" has an invalid filename.`);
|
|
263
|
-
}
|
|
264
|
-
const first = segments[0];
|
|
265
|
-
if (SYSTEM_META_DIRS.has(first) || first.startsWith("_")) {
|
|
266
|
-
throw new Error(`Invalid data-relative path: "${rel}" targets a reserved system/meta directory ("${first}"). The curate value loop writes user documents only \u2014 not worklog/decision-log/runbooks/hubs or any _* directory.`);
|
|
267
|
-
}
|
|
268
|
-
const absPath = resolve2(dataDir, normalized);
|
|
269
|
-
const rootResolved = resolve2(dataDir);
|
|
270
|
-
let relToData = relative(rootResolved, absPath);
|
|
271
|
-
let relCompare = relToData;
|
|
272
|
-
let upPrefix = ".." + sep;
|
|
273
|
-
if (sep === "\\") {
|
|
274
|
-
relCompare = relToData.toLowerCase();
|
|
275
|
-
upPrefix = upPrefix.toLowerCase();
|
|
276
|
-
}
|
|
277
|
-
if (relCompare === ".." || relCompare.startsWith(upPrefix) || isAbsolute(relToData)) {
|
|
278
|
-
throw new Error(`Invalid data-relative path: "${rel}" resolves outside the data directory.`);
|
|
279
|
-
}
|
|
280
|
-
return absPath;
|
|
281
|
-
}
|
|
282
|
-
async function exclusiveCreateFile(absPath, body) {
|
|
283
|
-
try {
|
|
284
|
-
await writeFile(absPath, body, { encoding: "utf8", flag: "wx" });
|
|
285
|
-
} catch (e) {
|
|
286
|
-
if (e.code === "EEXIST") {
|
|
287
|
-
throw new Error(`Refusing to overwrite existing file: ${absPath}. create-file is an exclusive create; to add to an existing document use append-section instead.`);
|
|
288
|
-
}
|
|
289
|
-
throw e;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
var atomicWriteCounter = 0;
|
|
293
|
-
async function atomicWriteFile(absPath, body) {
|
|
294
|
-
const tmp = `${absPath}.tmp-${process.pid}-${atomicWriteCounter++}`;
|
|
295
|
-
try {
|
|
296
|
-
await writeFile(tmp, body, { encoding: "utf8" });
|
|
297
|
-
await rename(tmp, absPath);
|
|
298
|
-
} catch (e) {
|
|
299
|
-
try {
|
|
300
|
-
const { rm } = await import("fs/promises");
|
|
301
|
-
await rm(tmp, { force: true });
|
|
302
|
-
} catch {
|
|
303
|
-
}
|
|
304
|
-
throw e;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
61
|
// ../modules/slash-commands/dist/index.js
|
|
309
62
|
var dist_exports2 = {};
|
|
310
63
|
__export(dist_exports2, {
|
|
@@ -418,8 +171,8 @@ var MemoryType = {
|
|
|
418
171
|
};
|
|
419
172
|
|
|
420
173
|
// ../modules/memory-system/dist/store.js
|
|
421
|
-
import { readdir, readFile, writeFile
|
|
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
|
}
|
|
@@ -6619,18 +6389,18 @@ var COUNT_KEY_TO_DIR = {
|
|
|
6619
6389
|
};
|
|
6620
6390
|
async function runStatus(input) {
|
|
6621
6391
|
const { dataDir } = input.context;
|
|
6622
|
-
const profilePath =
|
|
6623
|
-
const initialized =
|
|
6392
|
+
const profilePath = join24(dataDir, "_memory", "user_profile.md");
|
|
6393
|
+
const initialized = existsSync11(profilePath);
|
|
6624
6394
|
const counts = {
|
|
6625
|
-
memory: await safeCount(
|
|
6626
|
-
worklog: await safeCount(
|
|
6627
|
-
decisionLog: await safeCount(
|
|
6628
|
-
runbooks: await safeCount(
|
|
6629
|
-
hubs: await safeCount(
|
|
6395
|
+
memory: await safeCount(join24(dataDir, "_memory"), false),
|
|
6396
|
+
worklog: await safeCount(join24(dataDir, "worklog"), true),
|
|
6397
|
+
decisionLog: await safeCount(join24(dataDir, "decision-log"), false),
|
|
6398
|
+
runbooks: await safeCount(join24(dataDir, "runbooks"), false),
|
|
6399
|
+
hubs: await safeCount(join24(dataDir, "hubs"), false)
|
|
6630
6400
|
};
|
|
6631
6401
|
let latestWorklog;
|
|
6632
6402
|
try {
|
|
6633
|
-
const store = new WorklogStore(
|
|
6403
|
+
const store = new WorklogStore(join24(dataDir, "worklog"));
|
|
6634
6404
|
const latest = await store.getLatest();
|
|
6635
6405
|
if (latest) {
|
|
6636
6406
|
latestWorklog = {
|
|
@@ -6657,8 +6427,8 @@ async function runStatus(input) {
|
|
|
6657
6427
|
for (const [key, count] of Object.entries(counts)) {
|
|
6658
6428
|
if (count === 0) {
|
|
6659
6429
|
const dirName = COUNT_KEY_TO_DIR[key];
|
|
6660
|
-
const dirPath =
|
|
6661
|
-
missing.push(
|
|
6430
|
+
const dirPath = join24(dataDir, dirName);
|
|
6431
|
+
missing.push(existsSync11(dirPath) ? `${dirName}/ is empty` : `${dirName}/ does not exist`);
|
|
6662
6432
|
}
|
|
6663
6433
|
}
|
|
6664
6434
|
const nextActions = [];
|
|
@@ -6693,7 +6463,7 @@ function extractProfile(body) {
|
|
|
6693
6463
|
return out;
|
|
6694
6464
|
}
|
|
6695
6465
|
async function safeCount(dir, recursive) {
|
|
6696
|
-
if (!
|
|
6466
|
+
if (!existsSync11(dir))
|
|
6697
6467
|
return 0;
|
|
6698
6468
|
try {
|
|
6699
6469
|
return await countMarkdown2(dir, recursive);
|
|
@@ -6717,7 +6487,7 @@ async function countMarkdown2(dir, recursive) {
|
|
|
6717
6487
|
} else if (e.isDirectory() && recursive) {
|
|
6718
6488
|
if (e.name.startsWith(".") || e.name.startsWith("_"))
|
|
6719
6489
|
continue;
|
|
6720
|
-
total += await countMarkdown2(
|
|
6490
|
+
total += await countMarkdown2(join24(dir, e.name), recursive);
|
|
6721
6491
|
}
|
|
6722
6492
|
}
|
|
6723
6493
|
return total;
|
|
@@ -6852,7 +6622,7 @@ async function runImport(input, tokens) {
|
|
|
6852
6622
|
]
|
|
6853
6623
|
};
|
|
6854
6624
|
}
|
|
6855
|
-
if (!
|
|
6625
|
+
if (!existsSync11(args.from)) {
|
|
6856
6626
|
return {
|
|
6857
6627
|
subcommand: "import",
|
|
6858
6628
|
status: "source-missing",
|
|
@@ -6886,8 +6656,8 @@ async function runImport(input, tokens) {
|
|
|
6886
6656
|
const systemDirsCreated = [];
|
|
6887
6657
|
if (!args.dryRun) {
|
|
6888
6658
|
for (const d2 of systemDirs) {
|
|
6889
|
-
const p =
|
|
6890
|
-
if (!
|
|
6659
|
+
const p = join24(dataDir, d2);
|
|
6660
|
+
if (!existsSync11(p)) {
|
|
6891
6661
|
await mkdir9(p, { recursive: true });
|
|
6892
6662
|
systemDirsCreated.push(d2);
|
|
6893
6663
|
}
|
|
@@ -6983,7 +6753,7 @@ async function runImport(input, tokens) {
|
|
|
6983
6753
|
async function walkAndImport(rootSource, currentDir, dataDir, dryRun, stats) {
|
|
6984
6754
|
const entries = await readdir16(currentDir, { withFileTypes: true });
|
|
6985
6755
|
for (const e of entries) {
|
|
6986
|
-
const sourcePath =
|
|
6756
|
+
const sourcePath = join24(currentDir, e.name);
|
|
6987
6757
|
if (e.isDirectory()) {
|
|
6988
6758
|
if (IMPORT_SKIP_DIRS.has(e.name.toLowerCase()))
|
|
6989
6759
|
continue;
|
|
@@ -7024,7 +6794,7 @@ async function walkAndImport(rootSource, currentDir, dataDir, dryRun, stats) {
|
|
|
7024
6794
|
body: parsed.body
|
|
7025
6795
|
});
|
|
7026
6796
|
try {
|
|
7027
|
-
await
|
|
6797
|
+
await writeFile10(targetPath, out, { encoding: "utf8", flag: "wx" });
|
|
7028
6798
|
stats.copied++;
|
|
7029
6799
|
} catch (e2) {
|
|
7030
6800
|
if (e2.code === "EEXIST") {
|
|
@@ -7057,7 +6827,7 @@ async function importAttachment(sourcePath, relPath, filename, dataDir, dryRun,
|
|
|
7057
6827
|
stats.importedExtensions.add(ext);
|
|
7058
6828
|
if (dryRun)
|
|
7059
6829
|
return;
|
|
7060
|
-
const targetPath =
|
|
6830
|
+
const targetPath = join24(dataDir, relPath);
|
|
7061
6831
|
await mkdir9(dirname5(targetPath), { recursive: true });
|
|
7062
6832
|
try {
|
|
7063
6833
|
await copyFile2(sourcePath, targetPath, constants.COPYFILE_EXCL);
|
|
@@ -7121,27 +6891,27 @@ function computeTargetPath(category, sourcePath, rootSource, dataDir, filename)
|
|
|
7121
6891
|
const mdName = withMdExtension(filename);
|
|
7122
6892
|
if (category === "preserved") {
|
|
7123
6893
|
const relPath = withMdExtension(sourcePath.substring(rootSource.length).replace(/^[/\\]/, ""));
|
|
7124
|
-
return
|
|
6894
|
+
return join24(dataDir, relPath);
|
|
7125
6895
|
}
|
|
7126
6896
|
if (category === "worklog") {
|
|
7127
6897
|
const match = mdName.match(/^(\d{4})-(\d{2})-/);
|
|
7128
6898
|
if (match) {
|
|
7129
|
-
return
|
|
6899
|
+
return join24(dataDir, "worklog", match[1], match[2], mdName);
|
|
7130
6900
|
}
|
|
7131
6901
|
const d2 = /* @__PURE__ */ new Date();
|
|
7132
6902
|
const y2 = String(d2.getFullYear());
|
|
7133
6903
|
const m2 = String(d2.getMonth() + 1).padStart(2, "0");
|
|
7134
|
-
return
|
|
6904
|
+
return join24(dataDir, "worklog", y2, m2, mdName);
|
|
7135
6905
|
}
|
|
7136
6906
|
if (category === "decisionLog")
|
|
7137
|
-
return
|
|
6907
|
+
return join24(dataDir, "decision-log", mdName);
|
|
7138
6908
|
if (category === "runbooks")
|
|
7139
|
-
return
|
|
6909
|
+
return join24(dataDir, "runbooks", mdName);
|
|
7140
6910
|
if (category === "hubs")
|
|
7141
|
-
return
|
|
6911
|
+
return join24(dataDir, "hubs", mdName);
|
|
7142
6912
|
if (category === "memory")
|
|
7143
|
-
return
|
|
7144
|
-
return
|
|
6913
|
+
return join24(dataDir, "_memory", mdName);
|
|
6914
|
+
return join24(dataDir, mdName);
|
|
7145
6915
|
}
|
|
7146
6916
|
function withMdExtension(name) {
|
|
7147
6917
|
const ext = extname11(name);
|
|
@@ -7288,7 +7058,7 @@ async function checkControlBytes(dataDir) {
|
|
|
7288
7058
|
return;
|
|
7289
7059
|
}
|
|
7290
7060
|
for (const e of entries) {
|
|
7291
|
-
const p =
|
|
7061
|
+
const p = join24(dir, e.name);
|
|
7292
7062
|
if (e.isDirectory()) {
|
|
7293
7063
|
if (SKIP_DIRS.has(e.name))
|
|
7294
7064
|
continue;
|
|
@@ -7299,7 +7069,7 @@ async function checkControlBytes(dataDir) {
|
|
|
7299
7069
|
for (let i = 0; i < buf.length; i++) {
|
|
7300
7070
|
const x2 = buf[i];
|
|
7301
7071
|
if (x2 < 32 && x2 !== 9 && x2 !== 10 && x2 !== 13) {
|
|
7302
|
-
offenders.push(`${
|
|
7072
|
+
offenders.push(`${relative4(dataDir, p).replace(/\\/g, "/")} @ byte ${i}`);
|
|
7303
7073
|
break;
|
|
7304
7074
|
}
|
|
7305
7075
|
}
|
|
@@ -7322,7 +7092,7 @@ async function checkControlBytes(dataDir) {
|
|
|
7322
7092
|
};
|
|
7323
7093
|
}
|
|
7324
7094
|
function checkSystemDirs(dataDir) {
|
|
7325
|
-
const missing = DOCTOR_SYSTEM_DIRS.filter((d2) => !
|
|
7095
|
+
const missing = DOCTOR_SYSTEM_DIRS.filter((d2) => !existsSync11(join24(dataDir, d2)));
|
|
7326
7096
|
if (missing.length === 0) {
|
|
7327
7097
|
return {
|
|
7328
7098
|
id: "system-dirs",
|
|
@@ -7338,8 +7108,8 @@ function checkSystemDirs(dataDir) {
|
|
|
7338
7108
|
};
|
|
7339
7109
|
}
|
|
7340
7110
|
function checkUserProfile(dataDir) {
|
|
7341
|
-
const profilePath =
|
|
7342
|
-
if (
|
|
7111
|
+
const profilePath = join24(dataDir, "_memory", "user_profile.md");
|
|
7112
|
+
if (existsSync11(profilePath)) {
|
|
7343
7113
|
return {
|
|
7344
7114
|
id: "user-profile",
|
|
7345
7115
|
label: "user_profile.md exists",
|
|
@@ -7356,11 +7126,11 @@ function checkUserProfile(dataDir) {
|
|
|
7356
7126
|
async function checkIndexes(dataDir) {
|
|
7357
7127
|
const missing = [];
|
|
7358
7128
|
for (const d2 of DOCTOR_SYSTEM_DIRS) {
|
|
7359
|
-
const dirPath =
|
|
7360
|
-
if (!
|
|
7129
|
+
const dirPath = join24(dataDir, d2);
|
|
7130
|
+
if (!existsSync11(dirPath))
|
|
7361
7131
|
continue;
|
|
7362
|
-
const indexPath =
|
|
7363
|
-
if (!
|
|
7132
|
+
const indexPath = join24(dirPath, "_INDEX.md");
|
|
7133
|
+
if (!existsSync11(indexPath))
|
|
7364
7134
|
missing.push(`${d2}/_INDEX.md`);
|
|
7365
7135
|
}
|
|
7366
7136
|
if (missing.length === 0) {
|
|
@@ -7393,7 +7163,7 @@ async function collectAttachmentExtensions(dataDir) {
|
|
|
7393
7163
|
if (e.name.startsWith(".") || e.name === "_session-archive" || e.name === "node_modules") {
|
|
7394
7164
|
continue;
|
|
7395
7165
|
}
|
|
7396
|
-
stack.push(
|
|
7166
|
+
stack.push(join24(current, e.name));
|
|
7397
7167
|
} else if (e.isFile()) {
|
|
7398
7168
|
const ext = extname11(e.name);
|
|
7399
7169
|
if (ext && ext.toLowerCase() !== ".md")
|
|
@@ -7490,8 +7260,8 @@ async function checkFrontmatterLint(dataDir, additionalExtensions = []) {
|
|
|
7490
7260
|
}
|
|
7491
7261
|
}
|
|
7492
7262
|
async function checkRunbookAging(dataDir) {
|
|
7493
|
-
const runbooksDir =
|
|
7494
|
-
if (!
|
|
7263
|
+
const runbooksDir = join24(dataDir, "runbooks");
|
|
7264
|
+
if (!existsSync11(runbooksDir)) {
|
|
7495
7265
|
return {
|
|
7496
7266
|
id: "runbook-aging",
|
|
7497
7267
|
label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,
|
|
@@ -7511,7 +7281,7 @@ async function checkRunbookAging(dataDir) {
|
|
|
7511
7281
|
continue;
|
|
7512
7282
|
}
|
|
7513
7283
|
total++;
|
|
7514
|
-
const filePath =
|
|
7284
|
+
const filePath = join24(runbooksDir, e.name);
|
|
7515
7285
|
const raw = await readFile21(filePath, "utf8");
|
|
7516
7286
|
const { frontmatter } = parseFrontmatter(raw);
|
|
7517
7287
|
if (!frontmatter.last_tested) {
|
|
@@ -7574,8 +7344,8 @@ function checkNodeVersion() {
|
|
|
7574
7344
|
};
|
|
7575
7345
|
}
|
|
7576
7346
|
async function checkGitRemote(repoRoot) {
|
|
7577
|
-
const gitConfig =
|
|
7578
|
-
if (!
|
|
7347
|
+
const gitConfig = join24(repoRoot, ".git", "config");
|
|
7348
|
+
if (!existsSync11(gitConfig)) {
|
|
7579
7349
|
return {
|
|
7580
7350
|
id: "git-remote",
|
|
7581
7351
|
label: "git remote for sync",
|
|
@@ -7614,11 +7384,11 @@ async function detectExternalFolders(excludePath) {
|
|
|
7614
7384
|
if (!home)
|
|
7615
7385
|
return void 0;
|
|
7616
7386
|
const candidates = [
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7387
|
+
join24(home, "Documents", "obsidian-vault"),
|
|
7388
|
+
join24(home, "Documents", "notes"),
|
|
7389
|
+
join24(home, "Documents", "Notebook"),
|
|
7390
|
+
join24(home, "notes"),
|
|
7391
|
+
join24(home, "Notes")
|
|
7622
7392
|
];
|
|
7623
7393
|
const excludeNorm = excludePath.replace(/[/\\]+$/, "");
|
|
7624
7394
|
const found = [];
|
|
@@ -7627,7 +7397,7 @@ async function detectExternalFolders(excludePath) {
|
|
|
7627
7397
|
if (candNorm === excludeNorm || candNorm.startsWith(excludeNorm + "/") || candNorm.startsWith(excludeNorm + "\\") || excludeNorm.startsWith(candNorm + "/") || excludeNorm.startsWith(candNorm + "\\")) {
|
|
7628
7398
|
continue;
|
|
7629
7399
|
}
|
|
7630
|
-
if (!
|
|
7400
|
+
if (!existsSync11(candidate))
|
|
7631
7401
|
continue;
|
|
7632
7402
|
let mdCount = 0;
|
|
7633
7403
|
try {
|
|
@@ -7751,7 +7521,7 @@ async function runSync(input, tokens) {
|
|
|
7751
7521
|
var SYNC_TAIL_LENGTH = 1e3;
|
|
7752
7522
|
async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
7753
7523
|
const start = Date.now();
|
|
7754
|
-
return new Promise((
|
|
7524
|
+
return new Promise((resolve3) => {
|
|
7755
7525
|
let stdout = "";
|
|
7756
7526
|
let stderr = "";
|
|
7757
7527
|
const child = spawn(cmd, [...cmdArgs], { cwd, shell: true });
|
|
@@ -7762,7 +7532,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
|
7762
7532
|
stderr += chunk.toString("utf8");
|
|
7763
7533
|
});
|
|
7764
7534
|
child.on("close", (code) => {
|
|
7765
|
-
|
|
7535
|
+
resolve3({
|
|
7766
7536
|
exitCode: code ?? -1,
|
|
7767
7537
|
durationMs: Date.now() - start,
|
|
7768
7538
|
stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
|
|
@@ -7770,7 +7540,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
|
7770
7540
|
});
|
|
7771
7541
|
});
|
|
7772
7542
|
child.on("error", (err) => {
|
|
7773
|
-
|
|
7543
|
+
resolve3({
|
|
7774
7544
|
exitCode: -1,
|
|
7775
7545
|
durationMs: Date.now() - start,
|
|
7776
7546
|
stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
|
|
@@ -7816,22 +7586,22 @@ function createRitualRegistry(options) {
|
|
|
7816
7586
|
|
|
7817
7587
|
// ../plugins/session-rituals/dist/cli-dispatch.js
|
|
7818
7588
|
import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
|
|
7819
|
-
import { existsSync as
|
|
7589
|
+
import { existsSync as existsSync15, readFileSync as readFileSync3, mkdirSync, openSync, writeSync, closeSync, linkSync, rmSync, statSync } from "fs";
|
|
7820
7590
|
import { createRequire } from "module";
|
|
7821
7591
|
import { hostname } from "os";
|
|
7822
|
-
import { isAbsolute as
|
|
7592
|
+
import { isAbsolute as isAbsolute4, join as join28 } from "path";
|
|
7823
7593
|
|
|
7824
7594
|
// ../plugins/session-rituals/dist/update-check.js
|
|
7825
7595
|
import { execSync } from "child_process";
|
|
7826
|
-
import { existsSync as
|
|
7827
|
-
import { join as
|
|
7596
|
+
import { existsSync as existsSync12, readFileSync as readFileSync2 } from "fs";
|
|
7597
|
+
import { join as join25 } from "path";
|
|
7828
7598
|
var PKG = "@vortex-os/base";
|
|
7829
7599
|
var NPM_TIMEOUT_MS = 4e3;
|
|
7830
7600
|
function readInstalledBaseVersion(templatesDir = resolveTemplatesDir()) {
|
|
7831
7601
|
if (!templatesDir)
|
|
7832
7602
|
return null;
|
|
7833
7603
|
try {
|
|
7834
|
-
const m2 = JSON.parse(
|
|
7604
|
+
const m2 = JSON.parse(readFileSync2(join25(templatesDir, "manifest.json"), "utf8"));
|
|
7835
7605
|
return typeof m2.baseVersion === "string" && parseCore(m2.baseVersion) ? m2.baseVersion.trim() : null;
|
|
7836
7606
|
} catch {
|
|
7837
7607
|
return null;
|
|
@@ -7903,8 +7673,8 @@ function isStableUpdate(latest, installed) {
|
|
|
7903
7673
|
return compareSemver(latest, installed) === 1;
|
|
7904
7674
|
}
|
|
7905
7675
|
function buildInstallCommand(repoRoot) {
|
|
7906
|
-
const has = (f) =>
|
|
7907
|
-
const local =
|
|
7676
|
+
const has = (f) => existsSync12(join25(repoRoot, f));
|
|
7677
|
+
const local = existsSync12(join25(repoRoot, "node_modules", "@vortex-os", "base"));
|
|
7908
7678
|
let installPart;
|
|
7909
7679
|
if (!local) {
|
|
7910
7680
|
installPart = `npm i -g ${PKG}@latest`;
|
|
@@ -7932,9 +7702,9 @@ function checkBaseUpdate(ctx) {
|
|
|
7932
7702
|
}
|
|
7933
7703
|
|
|
7934
7704
|
// ../plugins/session-rituals/dist/session-start-report.js
|
|
7935
|
-
import { existsSync as
|
|
7705
|
+
import { existsSync as existsSync13 } from "fs";
|
|
7936
7706
|
import { readdir as readdir17, readFile as readFile22, stat as stat9 } from "fs/promises";
|
|
7937
|
-
import { join as
|
|
7707
|
+
import { join as join26 } from "path";
|
|
7938
7708
|
var COUNTED_DIRS2 = ["_memory", "worklog", "decision-log"];
|
|
7939
7709
|
var DEFAULT_GAP_WINDOW_DAYS = 30;
|
|
7940
7710
|
function gapWindowSinceArg() {
|
|
@@ -7951,8 +7721,8 @@ async function collectSessionStartReport(ctx, opts) {
|
|
|
7951
7721
|
const counts = {};
|
|
7952
7722
|
const missing = [];
|
|
7953
7723
|
for (const name of COUNTED_DIRS2) {
|
|
7954
|
-
const dir =
|
|
7955
|
-
if (!
|
|
7724
|
+
const dir = join26(ctx.dataDir, name);
|
|
7725
|
+
if (!existsSync13(dir)) {
|
|
7956
7726
|
missing.push(name);
|
|
7957
7727
|
counts[name] = 0;
|
|
7958
7728
|
continue;
|
|
@@ -7962,7 +7732,7 @@ async function collectSessionStartReport(ctx, opts) {
|
|
|
7962
7732
|
const { recent, recentGroup, recentWorklogsOmitted, dates, latestBodies } = await scanWorklog(ctx.dataDir);
|
|
7963
7733
|
const cutoff = isoDate2(addDays2(now, -(opts?.gapWindowDays ?? DEFAULT_GAP_WINDOW_DAYS)));
|
|
7964
7734
|
const recentWorklogDates = dates.filter((d2) => d2 >= cutoff);
|
|
7965
|
-
const mem = await scanMemoryTiers(
|
|
7735
|
+
const mem = await scanMemoryTiers(join26(ctx.dataDir, "_memory"));
|
|
7966
7736
|
const ho = await scanHandoffs(ctx.dataDir);
|
|
7967
7737
|
const handoffs = ho.active.map((h) => ({
|
|
7968
7738
|
date: h.date,
|
|
@@ -8029,7 +7799,7 @@ async function scanMemoryTiers(memoryDir) {
|
|
|
8029
7799
|
for (const e of entries) {
|
|
8030
7800
|
if (!e.isFile() || !e.name.endsWith(".md"))
|
|
8031
7801
|
continue;
|
|
8032
|
-
const full =
|
|
7802
|
+
const full = join26(memoryDir, e.name);
|
|
8033
7803
|
if (e.name === "_INDEX.md") {
|
|
8034
7804
|
indexExists = true;
|
|
8035
7805
|
try {
|
|
@@ -8189,6 +7959,16 @@ function renderSessionStartReport(report, extras) {
|
|
|
8189
7959
|
if (carry && carry.uncommitted > 0) {
|
|
8190
7960
|
lines.push(`- \u21A9\uFE0F ${carry.uncommitted} uncommitted change(s) carried over from a prior session \u2014 likely normal work in progress.`);
|
|
8191
7961
|
}
|
|
7962
|
+
const fl = extras?.failures;
|
|
7963
|
+
if (fl && fl.warnings.length > 0) {
|
|
7964
|
+
lines.push(`- \u{1F501} recurring failures (open ledger entries: ${fl.totalOpen}):`);
|
|
7965
|
+
for (const w2 of fl.warnings) {
|
|
7966
|
+
const stageText = w2.stage === "promote" ? "3rd+ occurrence \u2014 PROPOSE a deterministic guard to the user (ladder: promote; never self-install)" : `2nd occurrence \u2014 the covering rule's write-time gate is MANDATORY this session${w2.rule ? ` (rule: ${w2.rule})` : ""}`;
|
|
7967
|
+
lines.push(` - ${w2.key} \xD7${w2.count} (last ${w2.lastDate}) \u2014 ${stageText}`);
|
|
7968
|
+
}
|
|
7969
|
+
if (fl.omitted > 0)
|
|
7970
|
+
lines.push(` - \u2026(+${fl.omitted} more \u2014 \`vortex failure list\`)`);
|
|
7971
|
+
}
|
|
8192
7972
|
const cu = extras?.catchUp;
|
|
8193
7973
|
if (cu && (cu.ingestedLocal > 0 || cu.indexedPulled > 0 || cu.errors > 0)) {
|
|
8194
7974
|
const parts = [];
|
|
@@ -8258,15 +8038,15 @@ async function countMarkdown3(dir, recursive) {
|
|
|
8258
8038
|
} else if (e.isDirectory() && recursive) {
|
|
8259
8039
|
if (e.name.startsWith(".") || e.name.startsWith("_"))
|
|
8260
8040
|
continue;
|
|
8261
|
-
total += await countMarkdown3(
|
|
8041
|
+
total += await countMarkdown3(join26(dir, e.name), recursive);
|
|
8262
8042
|
}
|
|
8263
8043
|
}
|
|
8264
8044
|
return total;
|
|
8265
8045
|
}
|
|
8266
8046
|
var MAX_GROUP_READ = 20;
|
|
8267
8047
|
async function scanWorklog(dataDir) {
|
|
8268
|
-
const root =
|
|
8269
|
-
if (!
|
|
8048
|
+
const root = join26(dataDir, "worklog");
|
|
8049
|
+
if (!existsSync13(root))
|
|
8270
8050
|
return { recent: null, recentGroup: [], recentWorklogsOmitted: 0, dates: [], latestBodies: [] };
|
|
8271
8051
|
const dates = /* @__PURE__ */ new Set();
|
|
8272
8052
|
const consistent = [];
|
|
@@ -8281,7 +8061,7 @@ async function scanWorklog(dataDir) {
|
|
|
8281
8061
|
for (const e of entries) {
|
|
8282
8062
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
8283
8063
|
if (e.isDirectory()) {
|
|
8284
|
-
await walk5(
|
|
8064
|
+
await walk5(join26(absDir, e.name), childRel);
|
|
8285
8065
|
} else if (e.isFile()) {
|
|
8286
8066
|
const m2 = e.name.match(/^(\d{4})-(\d{2})-(\d{2})(?:_\d{4})?-.+\.md$/);
|
|
8287
8067
|
if (!m2)
|
|
@@ -8310,7 +8090,7 @@ async function scanWorklog(dataDir) {
|
|
|
8310
8090
|
const recentGroup = [];
|
|
8311
8091
|
const latestBodies = [];
|
|
8312
8092
|
for (const g of group) {
|
|
8313
|
-
const { title, body } = await readWorklogTitleAndBody(
|
|
8093
|
+
const { title, body } = await readWorklogTitleAndBody(join26(root, g.rel));
|
|
8314
8094
|
recentGroup.push({ path: defangReportPath(`worklog/${g.rel}`), title });
|
|
8315
8095
|
latestBodies.push(body);
|
|
8316
8096
|
}
|
|
@@ -8389,11 +8169,11 @@ function isoDate2(d2) {
|
|
|
8389
8169
|
}
|
|
8390
8170
|
|
|
8391
8171
|
// ../plugins/session-rituals/dist/curate-cli.js
|
|
8392
|
-
import { existsSync as
|
|
8172
|
+
import { existsSync as existsSync14 } from "fs";
|
|
8393
8173
|
import { createHash as createHash3 } from "crypto";
|
|
8394
8174
|
import { readFile as readFile23, readdir as readdir18 } from "fs/promises";
|
|
8395
|
-
import { join as
|
|
8396
|
-
var
|
|
8175
|
+
import { join as join27 } from "path";
|
|
8176
|
+
var SYSTEM_META_DIRS2 = /* @__PURE__ */ new Set([
|
|
8397
8177
|
"worklog",
|
|
8398
8178
|
"decision-log",
|
|
8399
8179
|
"runbooks",
|
|
@@ -8416,7 +8196,7 @@ function firstSegment(rel) {
|
|
|
8416
8196
|
}
|
|
8417
8197
|
function isSystemMetaRel(rel) {
|
|
8418
8198
|
const first = firstSegment(rel);
|
|
8419
|
-
return
|
|
8199
|
+
return SYSTEM_META_DIRS2.has(first) || first.startsWith("_");
|
|
8420
8200
|
}
|
|
8421
8201
|
function validateCuratePayload(payload) {
|
|
8422
8202
|
const errors = [];
|
|
@@ -8472,10 +8252,10 @@ function joinRel(...parts) {
|
|
|
8472
8252
|
}
|
|
8473
8253
|
async function runCurateCandidates(repoRoot, options) {
|
|
8474
8254
|
const maxEntries = options?.maxEntries ?? 200;
|
|
8475
|
-
const dataDir =
|
|
8255
|
+
const dataDir = join27(repoRoot, "data");
|
|
8476
8256
|
const candidates = [];
|
|
8477
8257
|
let truncated = false;
|
|
8478
|
-
if (
|
|
8258
|
+
if (existsSync14(dataDir)) {
|
|
8479
8259
|
async function visit(absDir, relDir) {
|
|
8480
8260
|
if (candidates.length >= maxEntries) {
|
|
8481
8261
|
truncated = true;
|
|
@@ -8496,9 +8276,9 @@ async function runCurateCandidates(repoRoot, options) {
|
|
|
8496
8276
|
const atRoot = relDir === "";
|
|
8497
8277
|
if (e.name.startsWith("."))
|
|
8498
8278
|
continue;
|
|
8499
|
-
if (atRoot && (
|
|
8279
|
+
if (atRoot && (SYSTEM_META_DIRS2.has(e.name) || e.name.startsWith("_")))
|
|
8500
8280
|
continue;
|
|
8501
|
-
await visit(
|
|
8281
|
+
await visit(join27(absDir, e.name), joinRel(relDir, e.name));
|
|
8502
8282
|
} else if (e.isFile() && e.name.endsWith(".md")) {
|
|
8503
8283
|
if (NON_DOC_FILES.has(e.name))
|
|
8504
8284
|
continue;
|
|
@@ -8507,7 +8287,7 @@ async function runCurateCandidates(repoRoot, options) {
|
|
|
8507
8287
|
let topic = null;
|
|
8508
8288
|
let tags = [];
|
|
8509
8289
|
try {
|
|
8510
|
-
const raw = await readFile23(
|
|
8290
|
+
const raw = await readFile23(join27(absDir, e.name), "utf8");
|
|
8511
8291
|
const parsed = parseFrontmatter(raw);
|
|
8512
8292
|
if (typeof parsed.frontmatter.topic === "string") {
|
|
8513
8293
|
topic = parsed.frontmatter.topic.trim().toLowerCase();
|
|
@@ -8545,7 +8325,7 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
|
|
|
8545
8325
|
};
|
|
8546
8326
|
}
|
|
8547
8327
|
try {
|
|
8548
|
-
validateDataRelativePath(
|
|
8328
|
+
validateDataRelativePath(join27(repoRoot, "data"), v2.effectiveRelPath);
|
|
8549
8329
|
} catch (e) {
|
|
8550
8330
|
return {
|
|
8551
8331
|
subcommand: "curate-preview",
|
|
@@ -8562,10 +8342,10 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
|
|
|
8562
8342
|
let targetExists;
|
|
8563
8343
|
let wouldDo;
|
|
8564
8344
|
if (payload.action === "create-file") {
|
|
8565
|
-
targetExists =
|
|
8345
|
+
targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
|
|
8566
8346
|
wouldDo = targetExists ? `create-file at ${v2.effectiveRelPath} \u2014 but the file already EXISTS, so accept would REFUSE (no overwrite).` : `create a new document at data/${v2.effectiveRelPath}.`;
|
|
8567
8347
|
} else {
|
|
8568
|
-
targetExists =
|
|
8348
|
+
targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
|
|
8569
8349
|
wouldDo = targetExists ? `append a "## ${payload.sectionHeader}" section to data/${v2.effectiveRelPath}.` : `append-section to data/${v2.effectiveRelPath} \u2014 but the file does NOT exist, so accept would FAIL (append-section never creates).`;
|
|
8570
8350
|
}
|
|
8571
8351
|
const nextActions = [];
|
|
@@ -8710,13 +8490,13 @@ function readCuratePayload(args) {
|
|
|
8710
8490
|
break;
|
|
8711
8491
|
}
|
|
8712
8492
|
if (t === "--payload-file" && i + 1 < args.length) {
|
|
8713
|
-
raw =
|
|
8493
|
+
raw = readFileSync3(args[++i], "utf8");
|
|
8714
8494
|
break;
|
|
8715
8495
|
}
|
|
8716
8496
|
}
|
|
8717
8497
|
if (raw === null) {
|
|
8718
8498
|
try {
|
|
8719
|
-
raw =
|
|
8499
|
+
raw = readFileSync3(0, "utf8");
|
|
8720
8500
|
} catch {
|
|
8721
8501
|
raw = "";
|
|
8722
8502
|
}
|
|
@@ -8740,11 +8520,22 @@ async function runVortexCli(argv, io) {
|
|
|
8740
8520
|
const err = io?.stderr ?? ((s) => process.stderr.write(s));
|
|
8741
8521
|
try {
|
|
8742
8522
|
if (argv[0] === "statusline") {
|
|
8743
|
-
const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-
|
|
8523
|
+
const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-6KSHISXO.js");
|
|
8744
8524
|
const statuslineRoot = process.env.VORTEX_REPO_ROOT?.trim() || process.cwd();
|
|
8745
8525
|
return runStatuslineCli2(argv.slice(1), statuslineRoot, out, err);
|
|
8746
8526
|
}
|
|
8527
|
+
if (argv[0] === "guard") {
|
|
8528
|
+
const { runGuardCli: runGuardCli2 } = await import("./guard-IMJR6ET7.js");
|
|
8529
|
+
return runGuardCli2(argv.slice(1), out, err);
|
|
8530
|
+
}
|
|
8747
8531
|
const repoRoot = resolveRepoRoot();
|
|
8532
|
+
if (argv[0] === "failure") {
|
|
8533
|
+
const { runFailureCli: runFailureCli2 } = await import("./failures-PMURLMVB.js");
|
|
8534
|
+
const { resolveInstanceRoot: resolveInstanceRoot2 } = await import("./guard-IMJR6ET7.js");
|
|
8535
|
+
const root = resolveInstanceRoot2(process.cwd()) ?? repoRoot;
|
|
8536
|
+
const ctx = makeContext(root);
|
|
8537
|
+
return runFailureCli2(argv.slice(1), ctx.dataDir, out, err);
|
|
8538
|
+
}
|
|
8748
8539
|
if (argv[0] === "session-start") {
|
|
8749
8540
|
await runSessionStart(repoRoot, out);
|
|
8750
8541
|
return 0;
|
|
@@ -8784,6 +8575,8 @@ ${names}
|
|
|
8784
8575
|
session-end \u2014 no-op (kept for hook compatibility; worklog gap handling is at session-start)
|
|
8785
8576
|
check-updates \u2014 check the npm registry for a newer @vortex-os/base (read-only; prints the exact update command)
|
|
8786
8577
|
statusline \u2014 render the Claude Code status bar from stdin JSON (\`lite\` for 1-line; \`install [--lite]\` wires .claude/settings.json)
|
|
8578
|
+
failure \u2014 failure ledger (\`record\` an occurrence by recurrence key / \`list\` open groups with their escalation stage)
|
|
8579
|
+
guard \u2014 deterministic write-time guards (\`write\` = PreToolUse hook body; wired by \`vortex init\`)
|
|
8787
8580
|
|
|
8788
8581
|
Instance shortcuts (also available as \`/vortex <sub>\`):
|
|
8789
8582
|
init \u2014 first-time setup: routers + data/ + hooks + slash-commands
|
|
@@ -8850,12 +8643,12 @@ function memoryExtendedPresent() {
|
|
|
8850
8643
|
}
|
|
8851
8644
|
var VECTORIZE_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
8852
8645
|
function vectorizeLockPath(ctx) {
|
|
8853
|
-
return
|
|
8646
|
+
return join28(ctx.dataDir, "_indexes", ".vectorize.lock");
|
|
8854
8647
|
}
|
|
8855
8648
|
function vectorizeSetupInProgress(ctx) {
|
|
8856
8649
|
const lock = vectorizeLockPath(ctx);
|
|
8857
8650
|
try {
|
|
8858
|
-
if (!
|
|
8651
|
+
if (!existsSync15(lock))
|
|
8859
8652
|
return false;
|
|
8860
8653
|
return Date.now() - statSync(lock).mtimeMs < VECTORIZE_LOCK_TTL_MS;
|
|
8861
8654
|
} catch {
|
|
@@ -8876,9 +8669,9 @@ function spawnVectorizeSetup(repoRoot) {
|
|
|
8876
8669
|
}
|
|
8877
8670
|
async function runVectorizeSetup(repoRoot, out, err) {
|
|
8878
8671
|
const ctx = makeContext(repoRoot);
|
|
8879
|
-
const indexDir =
|
|
8880
|
-
const finalDb =
|
|
8881
|
-
if (
|
|
8672
|
+
const indexDir = join28(ctx.dataDir, "_indexes");
|
|
8673
|
+
const finalDb = join28(indexDir, "memory.sqlite");
|
|
8674
|
+
if (existsSync15(finalDb)) {
|
|
8882
8675
|
out("recall index already present \u2014 nothing to do\n");
|
|
8883
8676
|
return;
|
|
8884
8677
|
}
|
|
@@ -8909,7 +8702,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8909
8702
|
return;
|
|
8910
8703
|
}
|
|
8911
8704
|
}
|
|
8912
|
-
const tmpDb =
|
|
8705
|
+
const tmpDb = join28(indexDir, `memory.sqlite.building-${process.pid}`);
|
|
8913
8706
|
const tmpSidecars = [tmpDb + "-wal", tmpDb + "-shm", tmpDb + "-journal"];
|
|
8914
8707
|
const cleanTmp = () => {
|
|
8915
8708
|
rmSync(tmpDb, { force: true });
|
|
@@ -8919,7 +8712,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8919
8712
|
let tokenWritten = false;
|
|
8920
8713
|
const releaseLock = () => {
|
|
8921
8714
|
try {
|
|
8922
|
-
const cur =
|
|
8715
|
+
const cur = existsSync15(lockPath) ? readFileSync3(lockPath, "utf8").trim() : "";
|
|
8923
8716
|
if (cur === token || cur === "" && !tokenWritten)
|
|
8924
8717
|
rmSync(lockPath, { force: true });
|
|
8925
8718
|
} catch {
|
|
@@ -8932,7 +8725,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8932
8725
|
} finally {
|
|
8933
8726
|
closeSync(lockFd);
|
|
8934
8727
|
}
|
|
8935
|
-
if (
|
|
8728
|
+
if (existsSync15(finalDb)) {
|
|
8936
8729
|
out("recall index already present \u2014 nothing to do\n");
|
|
8937
8730
|
return;
|
|
8938
8731
|
}
|
|
@@ -8948,7 +8741,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
|
|
|
8948
8741
|
} finally {
|
|
8949
8742
|
db.close();
|
|
8950
8743
|
}
|
|
8951
|
-
if (
|
|
8744
|
+
if (existsSync15(tmpDb + "-wal")) {
|
|
8952
8745
|
throw new Error("temp index retained a WAL sidecar after consolidation; refusing to publish");
|
|
8953
8746
|
}
|
|
8954
8747
|
try {
|
|
@@ -9032,7 +8825,7 @@ async function runSessionStart(repoRoot, out) {
|
|
|
9032
8825
|
let vectorized = null;
|
|
9033
8826
|
let vectorizeSetupStarted = false;
|
|
9034
8827
|
if (config.autoRecord.vectorize) {
|
|
9035
|
-
const dbExists =
|
|
8828
|
+
const dbExists = existsSync15(join28(ctx.dataDir, "_indexes", "memory.sqlite"));
|
|
9036
8829
|
const action = decideVectorizeAction({
|
|
9037
8830
|
vectorizeOn: true,
|
|
9038
8831
|
dbExists,
|
|
@@ -9055,6 +8848,16 @@ async function runSessionStart(repoRoot, out) {
|
|
|
9055
8848
|
}
|
|
9056
8849
|
}
|
|
9057
8850
|
}
|
|
8851
|
+
let failures = null;
|
|
8852
|
+
if (config.autoRecord.failures) {
|
|
8853
|
+
try {
|
|
8854
|
+
const { scanFailures: scanFailures2, failureReportSlice: failureReportSlice2 } = await import("./failures-PMURLMVB.js");
|
|
8855
|
+
const slice = failureReportSlice2(await scanFailures2(ctx.dataDir));
|
|
8856
|
+
if (slice.warnings.length > 0)
|
|
8857
|
+
failures = slice;
|
|
8858
|
+
} catch {
|
|
8859
|
+
}
|
|
8860
|
+
}
|
|
9058
8861
|
let templateUpdate = null;
|
|
9059
8862
|
try {
|
|
9060
8863
|
const td = resolveTemplatesDir();
|
|
@@ -9094,7 +8897,8 @@ async function runSessionStart(repoRoot, out) {
|
|
|
9094
8897
|
updateCheck: updateCheck ?? void 0,
|
|
9095
8898
|
globalSetupOffer: globalSetupOffer || void 0,
|
|
9096
8899
|
carryover: carryover ?? void 0,
|
|
9097
|
-
handoffPrune: handoffPrune ?? void 0
|
|
8900
|
+
handoffPrune: handoffPrune ?? void 0,
|
|
8901
|
+
failures: failures ?? void 0
|
|
9098
8902
|
}));
|
|
9099
8903
|
}
|
|
9100
8904
|
async function runSessionEnd(_repoRoot, _out) {
|
|
@@ -9121,7 +8925,7 @@ function detectInterruptedGitOp(repoRoot) {
|
|
|
9121
8925
|
const resolved = gitOut(repoRoot, args).split(/\r?\n/).map((s) => s.trim());
|
|
9122
8926
|
for (let i = 0; i < markers.length; i++) {
|
|
9123
8927
|
const p = resolved[i];
|
|
9124
|
-
if (p &&
|
|
8928
|
+
if (p && existsSync15(isAbsolute4(p) ? p : join28(repoRoot, p)))
|
|
9125
8929
|
return markers[i];
|
|
9126
8930
|
}
|
|
9127
8931
|
} catch {
|
|
@@ -9141,23 +8945,23 @@ function resolveSessionEnvironment(ctx, config) {
|
|
|
9141
8945
|
let environment = resolveEnvironment(config, {
|
|
9142
8946
|
hostname: hostname(),
|
|
9143
8947
|
env: process.env,
|
|
9144
|
-
pathExists:
|
|
8948
|
+
pathExists: existsSync15
|
|
9145
8949
|
});
|
|
9146
8950
|
if (!environment)
|
|
9147
8951
|
environment = process.env.VORTEX_ENV?.trim() || null;
|
|
9148
8952
|
if (!environment) {
|
|
9149
|
-
const envFile =
|
|
9150
|
-
if (
|
|
9151
|
-
environment =
|
|
8953
|
+
const envFile = join28(ctx.repoRoot, ".agent", "environment");
|
|
8954
|
+
if (existsSync15(envFile)) {
|
|
8955
|
+
environment = readFileSync3(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
|
|
9152
8956
|
}
|
|
9153
8957
|
}
|
|
9154
8958
|
return environment;
|
|
9155
8959
|
}
|
|
9156
8960
|
|
|
9157
8961
|
// ../plugins/session-rituals/dist/ambient-recall.js
|
|
9158
|
-
import { join as
|
|
8962
|
+
import { join as join29 } from "path";
|
|
9159
8963
|
function defaultDbPath2(ctx) {
|
|
9160
|
-
return
|
|
8964
|
+
return join29(ctx.dataDir, "_indexes", "memory.sqlite");
|
|
9161
8965
|
}
|
|
9162
8966
|
function createAmbientRecaller(ctx, options) {
|
|
9163
8967
|
const resolveDb = options.dbPath ?? defaultDbPath2;
|
|
@@ -9194,14 +8998,14 @@ function createAmbientRecaller(ctx, options) {
|
|
|
9194
8998
|
}
|
|
9195
8999
|
|
|
9196
9000
|
// ../plugins/session-rituals/dist/worklog-write.js
|
|
9197
|
-
import { mkdir as mkdir10, writeFile as
|
|
9198
|
-
import { dirname as dirname6, join as
|
|
9001
|
+
import { mkdir as mkdir10, writeFile as writeFile11 } from "fs/promises";
|
|
9002
|
+
import { dirname as dirname6, join as join30 } from "path";
|
|
9199
9003
|
async function ensureWorklogEntry(ctx, opts) {
|
|
9200
9004
|
const now = opts?.now ?? /* @__PURE__ */ new Date();
|
|
9201
9005
|
const date = isoDate3(now);
|
|
9202
9006
|
const time = isoTime2(now);
|
|
9203
9007
|
const keyword = (opts?.keyword ?? "worklog").trim() || "worklog";
|
|
9204
|
-
const store = new WorklogStore(
|
|
9008
|
+
const store = new WorklogStore(join30(ctx.dataDir, "worklog"));
|
|
9205
9009
|
const existing = await store.get(date);
|
|
9206
9010
|
if (existing) {
|
|
9207
9011
|
return { path: existing.path, date: existing.date, keyword: existing.keyword, created: false };
|
|
@@ -9209,7 +9013,7 @@ async function ensureWorklogEntry(ctx, opts) {
|
|
|
9209
9013
|
const path = store.pathFor(date, keyword, time);
|
|
9210
9014
|
const title = opts?.title ?? `${date} worklog`;
|
|
9211
9015
|
await mkdir10(dirname6(path), { recursive: true });
|
|
9212
|
-
await
|
|
9016
|
+
await writeFile11(path, renderWorklogFile(date, title, opts?.body ?? ""), "utf8");
|
|
9213
9017
|
return { path, date, keyword, created: true };
|
|
9214
9018
|
}
|
|
9215
9019
|
function renderWorklogFile(date, title, body) {
|