@vortex-os/base 0.2.3 → 0.3.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 +39 -1
- package/bin/vortex.mjs +17 -0
- package/dist/catch-up-ZQN7HMMN.js +7 -0
- package/dist/catch-up-ZQN7HMMN.js.map +1 -0
- package/dist/chunk-6SO4DAWJ.js +32 -0
- package/dist/chunk-6SO4DAWJ.js.map +1 -0
- package/dist/index.d.ts +33 -3
- package/dist/index.js +384 -84
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/templates/commands/agenda.md +15 -0
- package/templates/commands/recall.md +17 -0
- package/templates/config/vortex.json +10 -0
- package/templates/routers/.cursorrules +14 -0
- package/templates/routers/AGENT.md +91 -0
- package/templates/routers/CLAUDE.md +16 -0
- package/templates/routers/CODEX.md +14 -0
- package/templates/routers/GEMINI.md +14 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
__export,
|
|
3
|
+
catchUpSessions
|
|
4
|
+
} from "./chunk-6SO4DAWJ.js";
|
|
6
5
|
|
|
7
6
|
// ../core/dist/index.js
|
|
8
7
|
var dist_exports = {};
|
|
@@ -1873,7 +1872,7 @@ __export(dist_exports8, {
|
|
|
1873
1872
|
|
|
1874
1873
|
// ../modules/worklog/dist/store.js
|
|
1875
1874
|
import { readdir as readdir6, readFile as readFile6, stat as stat2 } from "fs/promises";
|
|
1876
|
-
import { join as join9 } from "path";
|
|
1875
|
+
import { join as join9, resolve as resolve2, sep } from "path";
|
|
1877
1876
|
var FILENAME_PATTERN = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
|
|
1878
1877
|
var MONTH_PATTERN = /^\d{2}$/;
|
|
1879
1878
|
var YEAR_PATTERN = /^\d{4}$/;
|
|
@@ -1923,11 +1922,14 @@ var WorklogStore = class {
|
|
|
1923
1922
|
}
|
|
1924
1923
|
/** Resolve the file path for a given (date, keyword), without creating it. */
|
|
1925
1924
|
pathFor(date, keyword) {
|
|
1926
|
-
|
|
1927
|
-
if (!year || !month) {
|
|
1925
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
1928
1926
|
throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);
|
|
1929
1927
|
}
|
|
1930
|
-
|
|
1928
|
+
const [year, month] = date.split("-");
|
|
1929
|
+
validateSegment("keyword", keyword);
|
|
1930
|
+
const abs = join9(this.rootDir, year, month, `${date}-${keyword}.md`);
|
|
1931
|
+
assertContained(abs, this.rootDir);
|
|
1932
|
+
return abs;
|
|
1931
1933
|
}
|
|
1932
1934
|
async listSubdirs(dir, pattern) {
|
|
1933
1935
|
try {
|
|
@@ -1970,6 +1972,26 @@ var WorklogStore = class {
|
|
|
1970
1972
|
return out;
|
|
1971
1973
|
}
|
|
1972
1974
|
};
|
|
1975
|
+
function validateSegment(label, value) {
|
|
1976
|
+
const v2 = (value ?? "").trim();
|
|
1977
|
+
if (v2.length === 0)
|
|
1978
|
+
throw new Error(`${label} is required`);
|
|
1979
|
+
if (v2.includes("/") || v2.includes("\\"))
|
|
1980
|
+
throw new Error(`${label} must not contain path separators: ${value}`);
|
|
1981
|
+
if (/(^|[\\/])\.\.([\\/]|$)/.test(v2) || v2 === "..")
|
|
1982
|
+
throw new Error(`${label} must not contain '..': ${value}`);
|
|
1983
|
+
if (v2.startsWith("/") || v2.startsWith("\\") || /^[a-zA-Z]:/.test(v2))
|
|
1984
|
+
throw new Error(`${label} must be a relative name, not an absolute path: ${value}`);
|
|
1985
|
+
if (/[\u0000-\u001f\u007f]/.test(v2))
|
|
1986
|
+
throw new Error(`${label} must not contain NUL or control characters: ${value}`);
|
|
1987
|
+
}
|
|
1988
|
+
function assertContained(abs, rootDir) {
|
|
1989
|
+
const root = resolve2(rootDir);
|
|
1990
|
+
const target = resolve2(abs);
|
|
1991
|
+
if (target !== root && !(target + sep).startsWith(root + sep)) {
|
|
1992
|
+
throw new Error(`Refusing to write outside the store directory: ${abs}`);
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1973
1995
|
|
|
1974
1996
|
// ../modules/worklog/dist/append.js
|
|
1975
1997
|
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
@@ -1996,7 +2018,7 @@ __export(dist_exports9, {
|
|
|
1996
2018
|
|
|
1997
2019
|
// ../modules/decision-log/dist/store.js
|
|
1998
2020
|
import { readdir as readdir7, readFile as readFile8, stat as stat3 } from "fs/promises";
|
|
1999
|
-
import { join as join10 } from "path";
|
|
2021
|
+
import { join as join10, resolve as resolve3, sep as sep2 } from "path";
|
|
2000
2022
|
var FILENAME_PATTERN2 = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
|
|
2001
2023
|
var DecisionStore = class {
|
|
2002
2024
|
rootDir;
|
|
@@ -2089,9 +2111,32 @@ var DecisionStore = class {
|
|
|
2089
2111
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
2090
2112
|
throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);
|
|
2091
2113
|
}
|
|
2092
|
-
|
|
2114
|
+
validateSegment2("slug", slug);
|
|
2115
|
+
const abs = join10(this.rootDir, `${date}-${slug}.md`);
|
|
2116
|
+
assertContained2(abs, this.rootDir);
|
|
2117
|
+
return abs;
|
|
2093
2118
|
}
|
|
2094
2119
|
};
|
|
2120
|
+
function validateSegment2(label, value) {
|
|
2121
|
+
const v2 = (value ?? "").trim();
|
|
2122
|
+
if (v2.length === 0)
|
|
2123
|
+
throw new Error(`${label} is required`);
|
|
2124
|
+
if (v2.includes("/") || v2.includes("\\"))
|
|
2125
|
+
throw new Error(`${label} must not contain path separators: ${value}`);
|
|
2126
|
+
if (/(^|[\\/])\.\.([\\/]|$)/.test(v2) || v2 === "..")
|
|
2127
|
+
throw new Error(`${label} must not contain '..': ${value}`);
|
|
2128
|
+
if (v2.startsWith("/") || v2.startsWith("\\") || /^[a-zA-Z]:/.test(v2))
|
|
2129
|
+
throw new Error(`${label} must be a relative name, not an absolute path: ${value}`);
|
|
2130
|
+
if (/[\u0000-\u001f\u007f]/.test(v2))
|
|
2131
|
+
throw new Error(`${label} must not contain NUL or control characters: ${value}`);
|
|
2132
|
+
}
|
|
2133
|
+
function assertContained2(abs, rootDir) {
|
|
2134
|
+
const root = resolve3(rootDir);
|
|
2135
|
+
const target = resolve3(abs);
|
|
2136
|
+
if (target !== root && !(target + sep2).startsWith(root + sep2)) {
|
|
2137
|
+
throw new Error(`Refusing to write outside the store directory: ${abs}`);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2095
2140
|
|
|
2096
2141
|
// ../modules/decision-log/dist/template.js
|
|
2097
2142
|
function renderTemplate(input) {
|
|
@@ -2838,12 +2883,15 @@ function isActive(entry, nowMs) {
|
|
|
2838
2883
|
const expiresMs = new Date(entry.expiresAt).getTime();
|
|
2839
2884
|
return Number.isFinite(expiresMs) && expiresMs > nowMs;
|
|
2840
2885
|
}
|
|
2886
|
+
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2841
2887
|
function purgeExpired(entries, now) {
|
|
2842
2888
|
if (!entries)
|
|
2843
2889
|
return {};
|
|
2844
|
-
const out =
|
|
2890
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
2845
2891
|
const nowMs = now.getTime();
|
|
2846
2892
|
for (const [fp, entry] of Object.entries(entries)) {
|
|
2893
|
+
if (DANGEROUS_KEYS.has(fp))
|
|
2894
|
+
continue;
|
|
2847
2895
|
if (isActive(entry, nowMs))
|
|
2848
2896
|
out[fp] = entry;
|
|
2849
2897
|
}
|
|
@@ -3898,6 +3946,7 @@ __export(dist_exports14, {
|
|
|
3898
3946
|
SESSION_END_COMMAND: () => SESSION_END_COMMAND,
|
|
3899
3947
|
SESSION_START_COMMAND: () => SESSION_START_COMMAND,
|
|
3900
3948
|
agendaCommand: () => agendaCommand,
|
|
3949
|
+
buildRegistry: () => buildRegistry,
|
|
3901
3950
|
catchUpSessions: () => catchUpSessions,
|
|
3902
3951
|
collectAgenda: () => collectAgenda,
|
|
3903
3952
|
collectSessionStartReport: () => collectSessionStartReport,
|
|
@@ -3916,6 +3965,8 @@ __export(dist_exports14, {
|
|
|
3916
3965
|
reindexCommand: () => reindexCommand,
|
|
3917
3966
|
renderAgenda: () => renderAgenda,
|
|
3918
3967
|
renderSessionStartReport: () => renderSessionStartReport,
|
|
3968
|
+
resolveRepoRoot: () => resolveRepoRoot,
|
|
3969
|
+
runVortexCli: () => runVortexCli,
|
|
3919
3970
|
serializeSettings: () => serializeSettings,
|
|
3920
3971
|
sessionStartCommand: () => sessionStartCommand,
|
|
3921
3972
|
vortexCommand: () => vortexCommand
|
|
@@ -4399,8 +4450,8 @@ import { basename as basename7, dirname as dirname4, join as join22 } from "path
|
|
|
4399
4450
|
import { fileURLToPath } from "url";
|
|
4400
4451
|
|
|
4401
4452
|
// ../plugins/session-rituals/dist/ensure-hooks.js
|
|
4402
|
-
var SESSION_START_COMMAND = "
|
|
4403
|
-
var SESSION_END_COMMAND = "
|
|
4453
|
+
var SESSION_START_COMMAND = "npx --no-install -p @vortex-os/base vortex session-start";
|
|
4454
|
+
var SESSION_END_COMMAND = "npx --no-install -p @vortex-os/base vortex session-end";
|
|
4404
4455
|
function parseSettings(text) {
|
|
4405
4456
|
const trimmed = (text ?? "").trim();
|
|
4406
4457
|
if (trimmed.length === 0)
|
|
@@ -4536,43 +4587,133 @@ function runHelp() {
|
|
|
4536
4587
|
]
|
|
4537
4588
|
};
|
|
4538
4589
|
}
|
|
4539
|
-
|
|
4590
|
+
function resolveTemplatesDir() {
|
|
4540
4591
|
const here = dirname4(fileURLToPath(import.meta.url));
|
|
4541
|
-
const
|
|
4542
|
-
|
|
4592
|
+
const candidates = [
|
|
4593
|
+
join22(here, "..", "..", "templates"),
|
|
4594
|
+
// session-rituals: dist/commands -> templates
|
|
4595
|
+
join22(here, "..", "templates"),
|
|
4596
|
+
// base aggregate: dist -> templates
|
|
4597
|
+
join22(here, "templates")
|
|
4598
|
+
// defensive: alongside the bundle
|
|
4599
|
+
];
|
|
4600
|
+
for (const c of candidates) {
|
|
4601
|
+
if (existsSync8(join22(c, "commands")) || existsSync8(join22(c, "routers")))
|
|
4602
|
+
return c;
|
|
4603
|
+
}
|
|
4604
|
+
return null;
|
|
4605
|
+
}
|
|
4606
|
+
async function installCommandTemplates(repoRoot, templatesDir) {
|
|
4607
|
+
if (!templatesDir)
|
|
4608
|
+
return [];
|
|
4609
|
+
const commandsDir = join22(templatesDir, "commands");
|
|
4610
|
+
if (!existsSync8(commandsDir))
|
|
4543
4611
|
return [];
|
|
4544
4612
|
const destDir = join22(repoRoot, ".claude", "commands");
|
|
4545
4613
|
await mkdir5(destDir, { recursive: true });
|
|
4546
4614
|
const written = [];
|
|
4547
|
-
for (const name of await readdir15(
|
|
4615
|
+
for (const name of await readdir15(commandsDir)) {
|
|
4548
4616
|
if (!name.endsWith(".md"))
|
|
4549
4617
|
continue;
|
|
4550
4618
|
const dest = join22(destDir, name);
|
|
4551
4619
|
if (existsSync8(dest))
|
|
4552
4620
|
continue;
|
|
4553
|
-
await copyFile(join22(
|
|
4621
|
+
await copyFile(join22(commandsDir, name), dest);
|
|
4622
|
+
written.push(dest);
|
|
4623
|
+
}
|
|
4624
|
+
return written;
|
|
4625
|
+
}
|
|
4626
|
+
var ROUTER_FILES = [
|
|
4627
|
+
"AGENT.md",
|
|
4628
|
+
"CLAUDE.md",
|
|
4629
|
+
"CODEX.md",
|
|
4630
|
+
"GEMINI.md",
|
|
4631
|
+
".cursorrules"
|
|
4632
|
+
];
|
|
4633
|
+
async function installRouterTemplates(repoRoot, templatesDir) {
|
|
4634
|
+
if (!templatesDir)
|
|
4635
|
+
return [];
|
|
4636
|
+
const routersDir = join22(templatesDir, "routers");
|
|
4637
|
+
if (!existsSync8(routersDir))
|
|
4638
|
+
return [];
|
|
4639
|
+
const written = [];
|
|
4640
|
+
for (const name of ROUTER_FILES) {
|
|
4641
|
+
const src = join22(routersDir, name);
|
|
4642
|
+
if (!existsSync8(src))
|
|
4643
|
+
continue;
|
|
4644
|
+
const dest = join22(repoRoot, name);
|
|
4645
|
+
if (existsSync8(dest))
|
|
4646
|
+
continue;
|
|
4647
|
+
await copyFile(src, dest);
|
|
4554
4648
|
written.push(dest);
|
|
4555
4649
|
}
|
|
4556
4650
|
return written;
|
|
4557
4651
|
}
|
|
4652
|
+
async function seedInstanceConfig(repoRoot, templatesDir) {
|
|
4653
|
+
const written = [];
|
|
4654
|
+
const agentDir = join22(repoRoot, ".agent");
|
|
4655
|
+
const vortexJson = join22(agentDir, "vortex.json");
|
|
4656
|
+
if (!existsSync8(vortexJson)) {
|
|
4657
|
+
await mkdir5(agentDir, { recursive: true });
|
|
4658
|
+
const tmpl = templatesDir ? join22(templatesDir, "config", "vortex.json") : null;
|
|
4659
|
+
if (tmpl && existsSync8(tmpl)) {
|
|
4660
|
+
await copyFile(tmpl, vortexJson);
|
|
4661
|
+
} else {
|
|
4662
|
+
await writeFile10(vortexJson, JSON.stringify({
|
|
4663
|
+
autoRecord: {
|
|
4664
|
+
sessionStart: true,
|
|
4665
|
+
worklog: true,
|
|
4666
|
+
decision: true,
|
|
4667
|
+
ambientRecall: true,
|
|
4668
|
+
archive: true
|
|
4669
|
+
},
|
|
4670
|
+
environments: []
|
|
4671
|
+
}, null, 2) + "\n", "utf8");
|
|
4672
|
+
}
|
|
4673
|
+
written.push(vortexJson);
|
|
4674
|
+
}
|
|
4675
|
+
const pkgPath = join22(repoRoot, "package.json");
|
|
4676
|
+
if (!existsSync8(pkgPath)) {
|
|
4677
|
+
await writeFile10(pkgPath, JSON.stringify({
|
|
4678
|
+
name: "vortex-instance",
|
|
4679
|
+
version: "0.0.0",
|
|
4680
|
+
private: true,
|
|
4681
|
+
type: "module",
|
|
4682
|
+
description: "A VortEX instance (created by `vortex init`)."
|
|
4683
|
+
}, null, 2) + "\n", "utf8");
|
|
4684
|
+
written.push(pkgPath);
|
|
4685
|
+
}
|
|
4686
|
+
return written;
|
|
4687
|
+
}
|
|
4558
4688
|
async function runInit(input, tokens) {
|
|
4559
4689
|
const args = parseInitArgs(tokens);
|
|
4560
|
-
const { dataDir } = input.context;
|
|
4690
|
+
const { dataDir, repoRoot } = input.context;
|
|
4691
|
+
const templatesDir = resolveTemplatesDir();
|
|
4561
4692
|
const requiredDirs = ["_memory", "worklog", "decision-log", "hubs", "inbox", "runbooks"];
|
|
4562
4693
|
for (const d2 of requiredDirs) {
|
|
4563
4694
|
const p = join22(dataDir, d2);
|
|
4564
4695
|
if (!existsSync8(p))
|
|
4565
4696
|
await mkdir5(p, { recursive: true });
|
|
4566
4697
|
}
|
|
4698
|
+
const scaffolded = [];
|
|
4699
|
+
try {
|
|
4700
|
+
scaffolded.push(...await installRouterTemplates(repoRoot, templatesDir));
|
|
4701
|
+
} catch {
|
|
4702
|
+
}
|
|
4703
|
+
try {
|
|
4704
|
+
scaffolded.push(...await seedInstanceConfig(repoRoot, templatesDir));
|
|
4705
|
+
} catch {
|
|
4706
|
+
}
|
|
4567
4707
|
const profilePath = join22(dataDir, "_memory", "user_profile.md");
|
|
4568
4708
|
if (existsSync8(profilePath) && !args.force) {
|
|
4569
4709
|
return {
|
|
4570
4710
|
subcommand: "init",
|
|
4571
4711
|
status: "already-initialized",
|
|
4572
|
-
created:
|
|
4712
|
+
created: scaffolded,
|
|
4573
4713
|
nextActions: [
|
|
4574
4714
|
`VortEX instance is already initialized (${profilePath} exists).`,
|
|
4575
|
-
|
|
4715
|
+
scaffolded.length > 0 ? `Seeded ${scaffolded.length} missing scaffolding file(s): ${scaffolded.map((p) => p.replace(repoRoot, ".")).join(", ")}.` : "All scaffolding (routers, .agent/vortex.json, package.json) already present.",
|
|
4716
|
+
"To re-run, pass `--force` (existing user_profile / first worklog will be overwritten).",
|
|
4576
4717
|
"To check current state, try `/session-start`."
|
|
4577
4718
|
]
|
|
4578
4719
|
};
|
|
@@ -4610,7 +4751,12 @@ async function runInit(input, tokens) {
|
|
|
4610
4751
|
};
|
|
4611
4752
|
}
|
|
4612
4753
|
const today2 = todayIso3();
|
|
4613
|
-
const created = [];
|
|
4754
|
+
const created = [...scaffolded];
|
|
4755
|
+
const scaffoldNotes = [];
|
|
4756
|
+
if (scaffolded.length > 0) {
|
|
4757
|
+
const names = scaffolded.map((p) => p.replace(repoRoot, ".").replace(/\\/g, "/"));
|
|
4758
|
+
scaffoldNotes.push(`Seeded instance scaffolding: ${names.join(", ")}.`);
|
|
4759
|
+
}
|
|
4614
4760
|
await writeFile10(profilePath, renderUserProfile(args.name, args.role, args.task, today2), "utf8");
|
|
4615
4761
|
created.push(profilePath);
|
|
4616
4762
|
const [year, month] = today2.split("-");
|
|
@@ -4636,7 +4782,7 @@ async function runInit(input, tokens) {
|
|
|
4636
4782
|
hookNotes.push(`\u26A0\uFE0F Could not wire session hooks automatically: ${e.message} Copy .claude/settings.example.json to .claude/settings.json by hand to enable the boot report.`);
|
|
4637
4783
|
}
|
|
4638
4784
|
try {
|
|
4639
|
-
const cmds = await installCommandTemplates(input.context.repoRoot);
|
|
4785
|
+
const cmds = await installCommandTemplates(input.context.repoRoot, templatesDir);
|
|
4640
4786
|
created.push(...cmds);
|
|
4641
4787
|
if (cmds.length > 0) {
|
|
4642
4788
|
hookNotes.push(`Installed ${cmds.length} slash command(s) into .claude/commands/ (${cmds.map((c) => "/" + basename7(c, ".md")).join(", ")}).`);
|
|
@@ -4647,6 +4793,7 @@ async function runInit(input, tokens) {
|
|
|
4647
4793
|
const externalFolders = await detectExternalFolders(input.context.repoRoot);
|
|
4648
4794
|
const baseNext = [
|
|
4649
4795
|
`Done. Created ${created.length} files.`,
|
|
4796
|
+
...scaffoldNotes,
|
|
4650
4797
|
...hookNotes,
|
|
4651
4798
|
"Next 3 things you can try right now:",
|
|
4652
4799
|
" /log <one-line update> \u2014 append a section to today's worklog",
|
|
@@ -5653,7 +5800,7 @@ async function runSync(input, tokens) {
|
|
|
5653
5800
|
var SYNC_TAIL_LENGTH = 1e3;
|
|
5654
5801
|
async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
5655
5802
|
const start = Date.now();
|
|
5656
|
-
return new Promise((
|
|
5803
|
+
return new Promise((resolve4) => {
|
|
5657
5804
|
let stdout = "";
|
|
5658
5805
|
let stderr = "";
|
|
5659
5806
|
const child = spawn(cmd, [...cmdArgs], { cwd, shell: true });
|
|
@@ -5664,7 +5811,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
|
5664
5811
|
stderr += chunk.toString("utf8");
|
|
5665
5812
|
});
|
|
5666
5813
|
child.on("close", (code) => {
|
|
5667
|
-
|
|
5814
|
+
resolve4({
|
|
5668
5815
|
exitCode: code ?? -1,
|
|
5669
5816
|
durationMs: Date.now() - start,
|
|
5670
5817
|
stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
|
|
@@ -5672,7 +5819,7 @@ async function runShellCommand(cmd, cmdArgs, cwd) {
|
|
|
5672
5819
|
});
|
|
5673
5820
|
});
|
|
5674
5821
|
child.on("error", (err) => {
|
|
5675
|
-
|
|
5822
|
+
resolve4({
|
|
5676
5823
|
exitCode: -1,
|
|
5677
5824
|
durationMs: Date.now() - start,
|
|
5678
5825
|
stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),
|
|
@@ -5864,43 +6011,16 @@ function createRitualRegistry(options) {
|
|
|
5864
6011
|
return registry;
|
|
5865
6012
|
}
|
|
5866
6013
|
|
|
5867
|
-
// ../plugins/session-rituals/dist/
|
|
5868
|
-
import {
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
}
|
|
5872
|
-
function createAmbientRecaller(ctx, options) {
|
|
5873
|
-
const resolveDb = options.dbPath ?? defaultDbPath2;
|
|
5874
|
-
const dbPath = resolveDb(ctx);
|
|
5875
|
-
return new AmbientRecaller({
|
|
5876
|
-
...options.minScore !== void 0 ? { minScore: options.minScore } : {},
|
|
5877
|
-
...options.maxSuggestions !== void 0 ? { maxSuggestions: options.maxSuggestions } : {},
|
|
5878
|
-
...options.minQueryChars !== void 0 ? { minQueryChars: options.minQueryChars } : {},
|
|
5879
|
-
recall: async (query, opts) => {
|
|
5880
|
-
const { sqlite, vector, recall: recallEngine } = await import("@vortex-os/memory-extended");
|
|
5881
|
-
const sqlStore = new sqlite.MemorySqliteStore(dbPath);
|
|
5882
|
-
const vecStore = new vector.MemoryVectorStore({ db: dbPath });
|
|
5883
|
-
const chunkStore = new vector.SessionChunkStore(dbPath);
|
|
5884
|
-
try {
|
|
5885
|
-
const result = await recallEngine.recall({
|
|
5886
|
-
query,
|
|
5887
|
-
...opts?.k !== void 0 ? { k: opts.k } : {},
|
|
5888
|
-
...options.source !== void 0 ? { source: options.source } : {}
|
|
5889
|
-
}, { sqlite: sqlStore, vector: vecStore, embed: options.embed, sessionChunks: chunkStore });
|
|
5890
|
-
return { hits: result.hits };
|
|
5891
|
-
} finally {
|
|
5892
|
-
chunkStore.close();
|
|
5893
|
-
vecStore.close();
|
|
5894
|
-
sqlStore.close();
|
|
5895
|
-
}
|
|
5896
|
-
}
|
|
5897
|
-
});
|
|
5898
|
-
}
|
|
6014
|
+
// ../plugins/session-rituals/dist/cli-dispatch.js
|
|
6015
|
+
import { execFileSync } from "child_process";
|
|
6016
|
+
import { existsSync as existsSync10, readFileSync as readFileSync2 } from "fs";
|
|
6017
|
+
import { hostname } from "os";
|
|
6018
|
+
import { join as join25 } from "path";
|
|
5899
6019
|
|
|
5900
6020
|
// ../plugins/session-rituals/dist/session-start-report.js
|
|
5901
6021
|
import { existsSync as existsSync9 } from "fs";
|
|
5902
6022
|
import { readdir as readdir16, readFile as readFile18 } from "fs/promises";
|
|
5903
|
-
import { join as
|
|
6023
|
+
import { join as join23 } from "path";
|
|
5904
6024
|
var COUNTED_DIRS2 = ["_memory", "worklog", "decision-log"];
|
|
5905
6025
|
var DEFAULT_GAP_WINDOW_DAYS = 30;
|
|
5906
6026
|
var BOOT_BANNER = String.raw`
|
|
@@ -5914,7 +6034,7 @@ async function collectSessionStartReport(ctx, opts) {
|
|
|
5914
6034
|
const counts = {};
|
|
5915
6035
|
const missing = [];
|
|
5916
6036
|
for (const name of COUNTED_DIRS2) {
|
|
5917
|
-
const dir =
|
|
6037
|
+
const dir = join23(ctx.dataDir, name);
|
|
5918
6038
|
if (!existsSync9(dir)) {
|
|
5919
6039
|
missing.push(name);
|
|
5920
6040
|
counts[name] = 0;
|
|
@@ -5986,13 +6106,13 @@ async function countMarkdown3(dir, recursive) {
|
|
|
5986
6106
|
} else if (e.isDirectory() && recursive) {
|
|
5987
6107
|
if (e.name.startsWith(".") || e.name.startsWith("_"))
|
|
5988
6108
|
continue;
|
|
5989
|
-
total += await countMarkdown3(
|
|
6109
|
+
total += await countMarkdown3(join23(dir, e.name), recursive);
|
|
5990
6110
|
}
|
|
5991
6111
|
}
|
|
5992
6112
|
return total;
|
|
5993
6113
|
}
|
|
5994
6114
|
async function scanWorklog(dataDir) {
|
|
5995
|
-
const root =
|
|
6115
|
+
const root = join23(dataDir, "worklog");
|
|
5996
6116
|
if (!existsSync9(root))
|
|
5997
6117
|
return { recent: null, dates: [] };
|
|
5998
6118
|
let bestRel = null;
|
|
@@ -6007,7 +6127,7 @@ async function scanWorklog(dataDir) {
|
|
|
6007
6127
|
for (const e of entries) {
|
|
6008
6128
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
6009
6129
|
if (e.isDirectory()) {
|
|
6010
|
-
await walk5(
|
|
6130
|
+
await walk5(join23(absDir, e.name), childRel);
|
|
6011
6131
|
} else if (e.isFile()) {
|
|
6012
6132
|
const m2 = e.name.match(/^(\d{4}-\d{2}-\d{2})-.+\.md$/);
|
|
6013
6133
|
if (!m2)
|
|
@@ -6019,7 +6139,7 @@ async function scanWorklog(dataDir) {
|
|
|
6019
6139
|
}
|
|
6020
6140
|
}
|
|
6021
6141
|
await walk5(root, "");
|
|
6022
|
-
const recent = bestRel === null ? null : { path: `worklog/${bestRel}`, title: await readTitle(
|
|
6142
|
+
const recent = bestRel === null ? null : { path: `worklog/${bestRel}`, title: await readTitle(join23(root, bestRel)) };
|
|
6023
6143
|
return { recent, dates: [...dates] };
|
|
6024
6144
|
}
|
|
6025
6145
|
async function readTitle(absPath) {
|
|
@@ -6047,11 +6167,11 @@ function isoDate(d2) {
|
|
|
6047
6167
|
|
|
6048
6168
|
// ../plugins/session-rituals/dist/worklog-write.js
|
|
6049
6169
|
import { mkdir as mkdir6, writeFile as writeFile11 } from "fs/promises";
|
|
6050
|
-
import { dirname as dirname5, join as
|
|
6170
|
+
import { dirname as dirname5, join as join24 } from "path";
|
|
6051
6171
|
async function ensureWorklogEntry(ctx, opts) {
|
|
6052
6172
|
const date = isoDate2(opts?.now ?? /* @__PURE__ */ new Date());
|
|
6053
6173
|
const keyword = (opts?.keyword ?? "worklog").trim() || "worklog";
|
|
6054
|
-
const store = new WorklogStore(
|
|
6174
|
+
const store = new WorklogStore(join24(ctx.dataDir, "worklog"));
|
|
6055
6175
|
const existing = await store.get(date);
|
|
6056
6176
|
if (existing) {
|
|
6057
6177
|
return { path: existing.path, date: existing.date, keyword: existing.keyword, created: false };
|
|
@@ -6083,25 +6203,205 @@ function isoDate2(d2) {
|
|
|
6083
6203
|
return `${y2}-${m2}-${day}`;
|
|
6084
6204
|
}
|
|
6085
6205
|
|
|
6086
|
-
// ../plugins/session-rituals/dist/
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
const dataDir = ctx.dataDir;
|
|
6090
|
-
const cwd = opts?.cwd ?? ctx.repoRoot;
|
|
6091
|
-
const adapters = opts?.adapters ?? [sessionArchive.claudeCodeAdapter];
|
|
6092
|
-
const ingestResult = await sessionArchive.ingest({ adapters, dataDir, cwd, env: opts?.env });
|
|
6093
|
-
const store = new sessionArchive.SessionArchiveStore(dataDir);
|
|
6094
|
-
let indexedPulled = 0;
|
|
6206
|
+
// ../plugins/session-rituals/dist/cli-dispatch.js
|
|
6207
|
+
var VORTEX_SUBCOMMANDS = ["init", "status", "import", "doctor", "sync"];
|
|
6208
|
+
async function buildRegistry() {
|
|
6095
6209
|
try {
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6210
|
+
const { vector } = await import("@vortex-os/memory-extended");
|
|
6211
|
+
return createRitualRegistry({ recall: { embed: vector.createLocalEmbedder() } });
|
|
6212
|
+
} catch {
|
|
6213
|
+
return createRitualRegistry();
|
|
6099
6214
|
}
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6215
|
+
}
|
|
6216
|
+
function resolveRepoRoot() {
|
|
6217
|
+
return process.env.VORTEX_REPO_ROOT?.trim() || process.cwd();
|
|
6218
|
+
}
|
|
6219
|
+
function requote(token) {
|
|
6220
|
+
if (!/\s/.test(token))
|
|
6221
|
+
return token;
|
|
6222
|
+
if (token.includes('"') && !token.includes("'"))
|
|
6223
|
+
return `'${token}'`;
|
|
6224
|
+
return `"${token.replace(/"/g, "")}"`;
|
|
6225
|
+
}
|
|
6226
|
+
async function runVortexCli(argv, io) {
|
|
6227
|
+
const out = io?.stdout ?? ((s) => process.stdout.write(s));
|
|
6228
|
+
const err = io?.stderr ?? ((s) => process.stderr.write(s));
|
|
6229
|
+
const repoRoot = resolveRepoRoot();
|
|
6230
|
+
try {
|
|
6231
|
+
if (argv[0] === "session-start") {
|
|
6232
|
+
await runSessionStart(repoRoot, out);
|
|
6233
|
+
return 0;
|
|
6234
|
+
}
|
|
6235
|
+
if (argv[0] === "session-end") {
|
|
6236
|
+
await runSessionEnd(repoRoot, out);
|
|
6237
|
+
return 0;
|
|
6238
|
+
}
|
|
6239
|
+
const registry = await buildRegistry();
|
|
6240
|
+
if (argv.length === 0 || argv[0] === "--list" || argv[0] === "--help") {
|
|
6241
|
+
const names = registry.list().map((c) => ` ${c.name} \u2014 ${c.description}`).join("\n");
|
|
6242
|
+
err(`vortex \u2014 headless ritual runner
|
|
6243
|
+
|
|
6244
|
+
Commands:
|
|
6245
|
+
${names}
|
|
6246
|
+
session-start \u2014 emit the start-of-session boot report (git pull + data counts + catch-up)
|
|
6247
|
+
session-end \u2014 worklog safety net (create today's worklog if work happened and none exists)
|
|
6248
|
+
|
|
6249
|
+
Instance shortcuts (also available as \`/vortex <sub>\`):
|
|
6250
|
+
init \u2014 first-time setup: routers + data/ + hooks + slash-commands
|
|
6251
|
+
status \u2014 instance state report
|
|
6252
|
+
import \u2014 bring an existing notes folder into data/
|
|
6253
|
+
doctor \u2014 health diagnosis
|
|
6254
|
+
|
|
6255
|
+
Usage: vortex <command> [args...]
|
|
6256
|
+
`);
|
|
6257
|
+
return 0;
|
|
6258
|
+
}
|
|
6259
|
+
const name = argv[0];
|
|
6260
|
+
const isVortexSub = VORTEX_SUBCOMMANDS.includes(name);
|
|
6261
|
+
const body = (isVortexSub ? argv : argv.slice(1)).map(requote).join(" ");
|
|
6262
|
+
const slash = isVortexSub ? `/vortex ${body}` : `/${name} ${body}`;
|
|
6263
|
+
const context = makeContext(repoRoot);
|
|
6264
|
+
const result = await runSlash(slash.trim(), { registry, context });
|
|
6265
|
+
out(JSON.stringify(result, null, 2) + "\n");
|
|
6266
|
+
return 0;
|
|
6267
|
+
} catch (e) {
|
|
6268
|
+
if (e instanceof CommandNotFoundError) {
|
|
6269
|
+
err(`[vortex] unknown command: ${e.message}
|
|
6270
|
+
Run \`vortex --list\` to see available commands.
|
|
6271
|
+
`);
|
|
6272
|
+
} else {
|
|
6273
|
+
err(`[vortex] error: ${e?.message ?? e}
|
|
6274
|
+
`);
|
|
6275
|
+
}
|
|
6276
|
+
return 1;
|
|
6277
|
+
}
|
|
6278
|
+
}
|
|
6279
|
+
async function runSessionStart(repoRoot, out) {
|
|
6280
|
+
const ctx = makeContext(repoRoot);
|
|
6281
|
+
const config = loadVortexConfig(ctx);
|
|
6282
|
+
if (!config.autoRecord.sessionStart)
|
|
6283
|
+
return;
|
|
6284
|
+
const environment = resolveSessionEnvironment(ctx, config);
|
|
6285
|
+
let git = null;
|
|
6286
|
+
try {
|
|
6287
|
+
const remotes = gitOut(repoRoot, ["remote"]).trim();
|
|
6288
|
+
if (remotes) {
|
|
6289
|
+
try {
|
|
6290
|
+
const pulled = gitOut(repoRoot, ["pull", "--ff-only"]);
|
|
6291
|
+
const lastLine = pulled.trim().split(/\r?\n/).pop() || "up to date";
|
|
6292
|
+
git = { ran: true, summary: lastLine, conflict: false };
|
|
6293
|
+
} catch {
|
|
6294
|
+
git = {
|
|
6295
|
+
ran: true,
|
|
6296
|
+
summary: "fast-forward pull failed (diverged or dirty tree)",
|
|
6297
|
+
conflict: true
|
|
6298
|
+
};
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
} catch {
|
|
6302
|
+
}
|
|
6303
|
+
const report = await collectSessionStartReport(ctx, { environment });
|
|
6304
|
+
let missingWorklogDays = [];
|
|
6305
|
+
try {
|
|
6306
|
+
const log = gitOut(repoRoot, ["log", "--since=7 days ago", "--pretty=%cd", "--date=short"]);
|
|
6307
|
+
const commitDays = log.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
6308
|
+
missingWorklogDays = detectWorklogGaps(commitDays, report.recentWorklogDates);
|
|
6309
|
+
} catch {
|
|
6310
|
+
}
|
|
6311
|
+
let catchUp = null;
|
|
6312
|
+
if (config.autoRecord.archive) {
|
|
6313
|
+
try {
|
|
6314
|
+
const { catchUpSessions: catchUpSessions2 } = await import("./catch-up-ZQN7HMMN.js");
|
|
6315
|
+
catchUp = await catchUpSessions2(ctx);
|
|
6316
|
+
} catch {
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6319
|
+
out(renderSessionStartReport(report, {
|
|
6320
|
+
git,
|
|
6321
|
+
missingWorklogDays,
|
|
6322
|
+
catchUp: catchUp ?? void 0
|
|
6323
|
+
}));
|
|
6324
|
+
}
|
|
6325
|
+
async function runSessionEnd(repoRoot, out) {
|
|
6326
|
+
const ctx = makeContext(repoRoot);
|
|
6327
|
+
const config = loadVortexConfig(ctx);
|
|
6328
|
+
if (config.autoRecord.worklog && hadActivityToday(repoRoot)) {
|
|
6329
|
+
const res = await ensureWorklogEntry(ctx, {
|
|
6330
|
+
body: "_Auto-created at session end (work detected but no worklog written). Enrich with the session's work, or remove if there is nothing to log._"
|
|
6331
|
+
});
|
|
6332
|
+
if (res.created)
|
|
6333
|
+
out(`VortEX: created worklog ${res.path}
|
|
6334
|
+
`);
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
function gitOut(cwd, gitArgs) {
|
|
6338
|
+
return execFileSync("git", [...gitArgs], {
|
|
6339
|
+
cwd,
|
|
6340
|
+
encoding: "utf8",
|
|
6341
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
6342
|
+
});
|
|
6343
|
+
}
|
|
6344
|
+
function hadActivityToday(repoRoot) {
|
|
6345
|
+
try {
|
|
6346
|
+
const dirty = gitOut(repoRoot, ["status", "--porcelain"]).trim();
|
|
6347
|
+
if (dirty)
|
|
6348
|
+
return true;
|
|
6349
|
+
const since = /* @__PURE__ */ new Date();
|
|
6350
|
+
since.setHours(0, 0, 0, 0);
|
|
6351
|
+
const commits = gitOut(repoRoot, ["log", "--oneline", `--since=${since.toISOString()}`]).trim();
|
|
6352
|
+
return commits.length > 0;
|
|
6353
|
+
} catch {
|
|
6354
|
+
return false;
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
function resolveSessionEnvironment(ctx, config) {
|
|
6358
|
+
let environment = resolveEnvironment(config, {
|
|
6359
|
+
hostname: hostname(),
|
|
6360
|
+
env: process.env,
|
|
6361
|
+
pathExists: existsSync10
|
|
6362
|
+
});
|
|
6363
|
+
if (!environment)
|
|
6364
|
+
environment = process.env.VORTEX_ENV?.trim() || null;
|
|
6365
|
+
if (!environment) {
|
|
6366
|
+
const envFile = join25(ctx.repoRoot, ".agent", "environment");
|
|
6367
|
+
if (existsSync10(envFile)) {
|
|
6368
|
+
environment = readFileSync2(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
|
|
6369
|
+
}
|
|
6370
|
+
}
|
|
6371
|
+
return environment;
|
|
6372
|
+
}
|
|
6373
|
+
|
|
6374
|
+
// ../plugins/session-rituals/dist/ambient-recall.js
|
|
6375
|
+
import { join as join26 } from "path";
|
|
6376
|
+
function defaultDbPath2(ctx) {
|
|
6377
|
+
return join26(ctx.dataDir, "_indexes", "memory.sqlite");
|
|
6378
|
+
}
|
|
6379
|
+
function createAmbientRecaller(ctx, options) {
|
|
6380
|
+
const resolveDb = options.dbPath ?? defaultDbPath2;
|
|
6381
|
+
const dbPath = resolveDb(ctx);
|
|
6382
|
+
return new AmbientRecaller({
|
|
6383
|
+
...options.minScore !== void 0 ? { minScore: options.minScore } : {},
|
|
6384
|
+
...options.maxSuggestions !== void 0 ? { maxSuggestions: options.maxSuggestions } : {},
|
|
6385
|
+
...options.minQueryChars !== void 0 ? { minQueryChars: options.minQueryChars } : {},
|
|
6386
|
+
recall: async (query, opts) => {
|
|
6387
|
+
const { sqlite, vector, recall: recallEngine } = await import("@vortex-os/memory-extended");
|
|
6388
|
+
const sqlStore = new sqlite.MemorySqliteStore(dbPath);
|
|
6389
|
+
const vecStore = new vector.MemoryVectorStore({ db: dbPath });
|
|
6390
|
+
const chunkStore = new vector.SessionChunkStore(dbPath);
|
|
6391
|
+
try {
|
|
6392
|
+
const result = await recallEngine.recall({
|
|
6393
|
+
query,
|
|
6394
|
+
...opts?.k !== void 0 ? { k: opts.k } : {},
|
|
6395
|
+
...options.source !== void 0 ? { source: options.source } : {}
|
|
6396
|
+
}, { sqlite: sqlStore, vector: vecStore, embed: options.embed, sessionChunks: chunkStore });
|
|
6397
|
+
return { hits: result.hits };
|
|
6398
|
+
} finally {
|
|
6399
|
+
chunkStore.close();
|
|
6400
|
+
vecStore.close();
|
|
6401
|
+
sqlStore.close();
|
|
6402
|
+
}
|
|
6403
|
+
}
|
|
6404
|
+
});
|
|
6105
6405
|
}
|
|
6106
6406
|
export {
|
|
6107
6407
|
dist_exports5 as aiCodingPitfalls,
|