@vortex-os/base 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,10 @@ import {
8
8
  recordGuardDenial,
9
9
  runFailureCli,
10
10
  scanFailures
11
- } from "./chunk-UV76ZEDC.js";
11
+ } from "./chunk-T4TJZUPP.js";
12
+ import {
13
+ catchUpSessions
14
+ } from "./chunk-3L5DLEGP.js";
12
15
  import {
13
16
  SESSION_END_COMMAND,
14
17
  SESSION_START_COMMAND,
@@ -27,7 +30,7 @@ import {
27
30
  serializeSettings,
28
31
  sniffEffortFromTranscript,
29
32
  statuslineCommand
30
- } from "./chunk-EAKDR5B2.js";
33
+ } from "./chunk-OFID33QA.js";
31
34
  import {
32
35
  GUARD_WRITE_COMMAND,
33
36
  GUARD_WRITE_MATCHER,
@@ -37,7 +40,7 @@ import {
37
40
  resolveInstanceRoot,
38
41
  runGuardCli,
39
42
  scanToolInput
40
- } from "./chunk-2FVNWW77.js";
43
+ } from "./chunk-JKQAB5OK.js";
41
44
  import {
42
45
  atomicWriteFile,
43
46
  dist_exports,
@@ -50,10 +53,7 @@ import {
50
53
  resolveEnvironment,
51
54
  serializeFrontmatter,
52
55
  validateDataRelativePath
53
- } from "./chunk-T53UWSTR.js";
54
- import {
55
- catchUpSessions
56
- } from "./chunk-3L5DLEGP.js";
56
+ } from "./chunk-IZIAMK3L.js";
57
57
  import {
58
58
  __export
59
59
  } from "./chunk-PZ5AY32C.js";
@@ -4024,6 +4024,7 @@ __export(dist_exports14, {
4024
4024
  agendaCommand: () => agendaCommand,
4025
4025
  aggregateHandoff: () => aggregateHandoff,
4026
4026
  applyGlobalSetup: () => applyGlobalSetup,
4027
+ archiveRelPath: () => archiveRelPath,
4027
4028
  argvToSlash: () => argvToSlash,
4028
4029
  autoReindexMemory: () => autoReindexMemory,
4029
4030
  buildDenyDecision: () => buildDenyDecision,
@@ -4057,6 +4058,7 @@ __export(dist_exports14, {
4057
4058
  formatTokens: () => formatTokens,
4058
4059
  formatWindow: () => formatWindow,
4059
4060
  gapWindowSinceArg: () => gapWindowSinceArg,
4061
+ gitOut: () => gitOut,
4060
4062
  globalMemoryPath: () => globalMemoryPath,
4061
4063
  globalSettingsHasHook: () => globalSettingsHasHook,
4062
4064
  globalSettingsPath: () => globalSettingsPath,
@@ -4092,6 +4094,7 @@ __export(dist_exports14, {
4092
4094
  repairOwnershipManifest: () => repairOwnershipManifest,
4093
4095
  resolveInstanceRoot: () => resolveInstanceRoot,
4094
4096
  resolveRepoRoot: () => resolveRepoRoot,
4097
+ runArchiveSync: () => runArchiveSync,
4095
4098
  runCurateAccept: () => runCurateAccept,
4096
4099
  runCurateCandidates: () => runCurateCandidates,
4097
4100
  runCurateDecline: () => runCurateDecline,
@@ -4109,6 +4112,8 @@ __export(dist_exports14, {
4109
4112
  sessionStartCommand: () => sessionStartCommand,
4110
4113
  sniffEffortFromTranscript: () => sniffEffortFromTranscript,
4111
4114
  statuslineCommand: () => statuslineCommand,
4115
+ sweepOrphanTempFiles: () => sweepOrphanTempFiles,
4116
+ sweepRawArchive: () => sweepRawArchive,
4112
4117
  templateDestRelPath: () => templateDestRelPath,
4113
4118
  upsertGlobalBlock: () => upsertGlobalBlock,
4114
4119
  validateCuratePayload: () => validateCuratePayload,
@@ -6009,9 +6014,13 @@ async function seedInstanceConfig(repoRoot, templatesDir) {
6009
6014
  decision: true,
6010
6015
  ambientRecall: true,
6011
6016
  archive: true,
6017
+ archiveCommit: true,
6018
+ archiveAtEnd: true,
6019
+ archiveRawRetentionDays: 30,
6012
6020
  vectorize: true
6013
6021
  },
6014
6022
  updates: { check: "session" },
6023
+ sync: { autoPush: false },
6015
6024
  environments: []
6016
6025
  }, null, 2) + "\n", "utf8");
6017
6026
  }
@@ -6246,10 +6255,36 @@ async function runUpdate(input, tokens) {
6246
6255
  const dryRun = tokens.includes("--dry-run");
6247
6256
  const adopt = parseAdoptArgs(tokens);
6248
6257
  const templatesDir = resolveTemplatesDir();
6249
- const result = await runTemplatesUpdate(input.context, templatesDir, {
6258
+ let result = await runTemplatesUpdate(input.context, templatesDir, {
6250
6259
  dryRun,
6251
6260
  adopt: adopt.size > 0 ? adopt : void 0
6252
6261
  });
6262
+ if (!dryRun) {
6263
+ try {
6264
+ const settingsPath = join24(input.context.repoRoot, ".claude", "settings.json");
6265
+ const existingText = existsSync11(settingsPath) ? await readFile21(settingsPath, "utf8") : null;
6266
+ const { settings, added, alreadyWired } = ensureVortexHooks(parseSettings(existingText), { guard: true });
6267
+ if (!alreadyWired) {
6268
+ await mkdir9(join24(input.context.repoRoot, ".claude"), { recursive: true });
6269
+ await writeFile10(settingsPath, serializeSettings(settings), "utf8");
6270
+ result = {
6271
+ ...result,
6272
+ nextActions: [
6273
+ ...result.nextActions,
6274
+ `Wired missing ${added.join(" + ")} hook(s) into .claude/settings.json` + (added.includes("PreToolUse") ? " \u2014 the write guard now denies literal control bytes in file writes (remove the PreToolUse group to opt out)." : ".")
6275
+ ]
6276
+ };
6277
+ }
6278
+ } catch (e) {
6279
+ result = {
6280
+ ...result,
6281
+ nextActions: [
6282
+ ...result.nextActions,
6283
+ `\u26A0\uFE0F Could not verify/wire session hooks: ${e.message}`
6284
+ ]
6285
+ };
6286
+ }
6287
+ }
6253
6288
  if (dryRun || result.status === "no-manifest" || result.status === "no-templates")
6254
6289
  return result;
6255
6290
  if (!loadVortexConfig(input.context).autoRecord.commitFrameworkChanges)
@@ -7585,23 +7620,280 @@ function createRitualRegistry(options) {
7585
7620
  }
7586
7621
 
7587
7622
  // ../plugins/session-rituals/dist/cli-dispatch.js
7588
- import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
7589
- import { existsSync as existsSync15, readFileSync as readFileSync3, mkdirSync, openSync, writeSync, closeSync, linkSync, rmSync, statSync } from "fs";
7623
+ import { spawn as spawn2 } from "child_process";
7624
+ import { existsSync as existsSync16, readFileSync as readFileSync4, mkdirSync as mkdirSync2, openSync as openSync2, writeSync as writeSync2, closeSync as closeSync2, linkSync, rmSync as rmSync2, statSync as statSync2 } from "fs";
7590
7625
  import { createRequire } from "module";
7591
7626
  import { hostname } from "os";
7592
- import { isAbsolute as isAbsolute4, join as join28 } from "path";
7627
+ import { join as join29 } from "path";
7628
+
7629
+ // ../plugins/session-rituals/dist/archive-sync.js
7630
+ import { closeSync, existsSync as existsSync12, mkdirSync, openSync, readdirSync, readFileSync as readFileSync2, renameSync, rmSync, statSync, writeSync } from "fs";
7631
+ import { execFileSync as execFileSync2 } from "child_process";
7632
+ import { isAbsolute as isAbsolute4, join as join25, relative as relative5, sep as sep4 } from "path";
7633
+ function gitOut(cwd, gitArgs) {
7634
+ return execFileSync2("git", [...gitArgs], {
7635
+ cwd,
7636
+ encoding: "utf8",
7637
+ stdio: ["ignore", "pipe", "ignore"]
7638
+ });
7639
+ }
7640
+ function detectInterruptedGitOp(repoRoot) {
7641
+ const markers = [
7642
+ "MERGE_HEAD",
7643
+ "rebase-merge",
7644
+ "rebase-apply",
7645
+ "CHERRY_PICK_HEAD",
7646
+ "REVERT_HEAD",
7647
+ "BISECT_LOG",
7648
+ "index.lock"
7649
+ ];
7650
+ try {
7651
+ const args = ["rev-parse", ...markers.flatMap((m2) => ["--git-path", m2])];
7652
+ const resolved = gitOut(repoRoot, args).split(/\r?\n/).map((s) => s.trim());
7653
+ for (let i = 0; i < markers.length; i++) {
7654
+ const p = resolved[i];
7655
+ if (p && existsSync12(isAbsolute4(p) ? p : join25(repoRoot, p)))
7656
+ return markers[i];
7657
+ }
7658
+ } catch {
7659
+ }
7660
+ return null;
7661
+ }
7662
+ var NOTHING = {
7663
+ ran: false,
7664
+ lockSkipped: false,
7665
+ catchUp: null,
7666
+ rawPruned: 0,
7667
+ retentionDays: 0,
7668
+ committed: false,
7669
+ pushed: false
7670
+ };
7671
+ var ARCHIVE_SYNC_LOCK_TTL_MS = 10 * 60 * 1e3;
7672
+ function lockPath(dataDir) {
7673
+ return join25(dataDir, "_session-archive", ".sync.lock");
7674
+ }
7675
+ function archiveRelPath(ctx) {
7676
+ return relative5(ctx.repoRoot, join25(ctx.dataDir, "_session-archive")).split(sep4).join("/");
7677
+ }
7678
+ function sweepRawArchive(dataDir, retentionDays, nowMs = Date.now()) {
7679
+ if (!(retentionDays > 0))
7680
+ return 0;
7681
+ const rawDir = join25(dataDir, "_session-archive", "raw");
7682
+ const cutoff = nowMs - retentionDays * 864e5;
7683
+ let pruned = 0;
7684
+ const walk5 = (dir) => {
7685
+ let entries;
7686
+ try {
7687
+ entries = readdirSync(dir, { withFileTypes: true });
7688
+ } catch {
7689
+ return;
7690
+ }
7691
+ for (const e of entries) {
7692
+ const p = join25(dir, e.name);
7693
+ if (e.isDirectory()) {
7694
+ walk5(p);
7695
+ } else if (e.isFile()) {
7696
+ try {
7697
+ if (statSync(p).mtimeMs < cutoff) {
7698
+ rmSync(p, { force: true });
7699
+ pruned++;
7700
+ }
7701
+ } catch {
7702
+ }
7703
+ }
7704
+ }
7705
+ };
7706
+ walk5(rawDir);
7707
+ return pruned;
7708
+ }
7709
+ function sweepOrphanTempFiles(dataDir, nowMs = Date.now()) {
7710
+ let removed = 0;
7711
+ const sweep = (dir, recurse, minAgeMs) => {
7712
+ let entries;
7713
+ try {
7714
+ entries = readdirSync(dir, { withFileTypes: true });
7715
+ } catch {
7716
+ return;
7717
+ }
7718
+ for (const e of entries) {
7719
+ const p = join25(dir, e.name);
7720
+ if (e.isDirectory()) {
7721
+ if (recurse)
7722
+ sweep(p, recurse, minAgeMs);
7723
+ } else if (e.isFile() && /\.tmp-\d+$/.test(e.name)) {
7724
+ try {
7725
+ if (minAgeMs === 0 || nowMs - statSync(p).mtimeMs >= minAgeMs) {
7726
+ rmSync(p, { force: true });
7727
+ removed++;
7728
+ }
7729
+ } catch {
7730
+ }
7731
+ }
7732
+ }
7733
+ };
7734
+ sweep(join25(dataDir, "_session-archive", "raw"), true, 0);
7735
+ sweep(join25(dataDir, "_session-archive", "normalized"), true, 0);
7736
+ sweep(join25(dataDir, "_session-archive", ".tmp"), false, ARCHIVE_SYNC_LOCK_TTL_MS);
7737
+ return removed;
7738
+ }
7739
+ function isDetachedHead(repoRoot) {
7740
+ try {
7741
+ gitOut(repoRoot, ["symbolic-ref", "-q", "HEAD"]);
7742
+ return false;
7743
+ } catch {
7744
+ return true;
7745
+ }
7746
+ }
7747
+ function pushCurrentBranch(repoRoot) {
7748
+ try {
7749
+ if (!gitOut(repoRoot, ["remote"]).trim())
7750
+ return { pushed: false, skip: "no-remote" };
7751
+ } catch {
7752
+ return { pushed: false, skip: "git-error" };
7753
+ }
7754
+ try {
7755
+ gitOut(repoRoot, ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"]);
7756
+ } catch {
7757
+ return { pushed: false, skip: "no-upstream" };
7758
+ }
7759
+ const counts = () => {
7760
+ const [a, b2] = gitOut(repoRoot, ["rev-list", "--left-right", "--count", "HEAD...@{upstream}"]).trim().split(/\s+/);
7761
+ return { ahead: Number(a ?? 0) || 0, behind: Number(b2 ?? 0) || 0 };
7762
+ };
7763
+ try {
7764
+ let { ahead, behind } = counts();
7765
+ if (behind > 0) {
7766
+ try {
7767
+ gitOut(repoRoot, ["pull", "--ff-only"]);
7768
+ } catch {
7769
+ return { pushed: false, skip: "diverged" };
7770
+ }
7771
+ ({ ahead, behind } = counts());
7772
+ }
7773
+ if (ahead === 0)
7774
+ return { pushed: false, skip: "no-commit" };
7775
+ gitOut(repoRoot, ["push"]);
7776
+ return { pushed: true };
7777
+ } catch {
7778
+ return { pushed: false, skip: "git-error" };
7779
+ }
7780
+ }
7781
+ async function runArchiveSync(ctx, config, _phase, opts) {
7782
+ const lock = lockPath(ctx.dataDir);
7783
+ const token = `${process.pid}-${process.hrtime.bigint()}`;
7784
+ let lockFd;
7785
+ try {
7786
+ mkdirSync(join25(ctx.dataDir, "_session-archive"), { recursive: true });
7787
+ lockFd = openSync(lock, "wx");
7788
+ } catch (e) {
7789
+ if (e.code !== "EEXIST") {
7790
+ return { ...NOTHING, lockSkipped: true };
7791
+ }
7792
+ let stale = true;
7793
+ try {
7794
+ stale = Date.now() - statSync(lock).mtimeMs >= ARCHIVE_SYNC_LOCK_TTL_MS;
7795
+ } catch {
7796
+ stale = true;
7797
+ }
7798
+ if (!stale)
7799
+ return { ...NOTHING, lockSkipped: true };
7800
+ const claimed = `${lock}.stale-${process.pid}`;
7801
+ try {
7802
+ renameSync(lock, claimed);
7803
+ rmSync(claimed, { force: true });
7804
+ } catch {
7805
+ return { ...NOTHING, lockSkipped: true };
7806
+ }
7807
+ try {
7808
+ lockFd = openSync(lock, "wx");
7809
+ } catch {
7810
+ return { ...NOTHING, lockSkipped: true };
7811
+ }
7812
+ }
7813
+ let tokenWritten = false;
7814
+ const releaseLock = () => {
7815
+ try {
7816
+ const cur = existsSync12(lock) ? readFileSync2(lock, "utf8").trim() : "";
7817
+ if (cur === token || cur === "" && !tokenWritten)
7818
+ rmSync(lock, { force: true });
7819
+ } catch {
7820
+ }
7821
+ };
7822
+ try {
7823
+ try {
7824
+ writeSync(lockFd, token + "\n");
7825
+ tokenWritten = true;
7826
+ } finally {
7827
+ closeSync(lockFd);
7828
+ }
7829
+ let catchUp = null;
7830
+ try {
7831
+ const { catchUpSessions: catchUpSessions2 } = await import("./catch-up-GDDKPZHJ.js");
7832
+ catchUp = await catchUpSessions2(ctx, opts?.catchUp);
7833
+ } catch {
7834
+ }
7835
+ const retentionDays = config.autoRecord.archiveRawRetentionDays;
7836
+ let rawPruned = 0;
7837
+ try {
7838
+ rawPruned = sweepRawArchive(ctx.dataDir, retentionDays);
7839
+ } catch {
7840
+ }
7841
+ try {
7842
+ sweepOrphanTempFiles(ctx.dataDir);
7843
+ } catch {
7844
+ }
7845
+ let committed = false;
7846
+ let commitSkipped;
7847
+ if (!config.autoRecord.archiveCommit) {
7848
+ commitSkipped = "off";
7849
+ } else if (detectInterruptedGitOp(ctx.repoRoot)) {
7850
+ commitSkipped = "git-busy";
7851
+ } else if (isDetachedHead(ctx.repoRoot)) {
7852
+ commitSkipped = "detached-head";
7853
+ } else {
7854
+ const rel = archiveRelPath(ctx);
7855
+ const paths = [`${rel}/raw`, `${rel}/normalized`].filter((p) => existsSync12(join25(ctx.repoRoot, ...p.split("/"))));
7856
+ const ingested = catchUp?.ingestedLocal ?? 0;
7857
+ const result = commitFrameworkPaths(ctx.repoRoot, paths, `chore(vortex): session archive sync (${ingested} ingested, ${rawPruned} raw pruned)`);
7858
+ committed = result.committed;
7859
+ if (!result.committed) {
7860
+ commitSkipped = result.reason === "nothing-to-commit" || result.reason === "no-paths" ? "nothing-to-commit" : result.reason === "not-a-git-repo" ? "not-a-git-repo" : "git-error";
7861
+ }
7862
+ }
7863
+ let pushed = false;
7864
+ let pushSkipped;
7865
+ if (!config.sync.autoPush) {
7866
+ pushSkipped = "off";
7867
+ } else {
7868
+ ({ pushed, skip: pushSkipped } = pushCurrentBranch(ctx.repoRoot));
7869
+ }
7870
+ return {
7871
+ ran: true,
7872
+ lockSkipped: false,
7873
+ catchUp,
7874
+ rawPruned,
7875
+ retentionDays,
7876
+ committed,
7877
+ ...commitSkipped !== void 0 ? { commitSkipped } : {},
7878
+ pushed,
7879
+ ...pushSkipped !== void 0 ? { pushSkipped } : {}
7880
+ };
7881
+ } finally {
7882
+ releaseLock();
7883
+ }
7884
+ }
7593
7885
 
7594
7886
  // ../plugins/session-rituals/dist/update-check.js
7595
7887
  import { execSync } from "child_process";
7596
- import { existsSync as existsSync12, readFileSync as readFileSync2 } from "fs";
7597
- import { join as join25 } from "path";
7888
+ import { existsSync as existsSync13, readFileSync as readFileSync3 } from "fs";
7889
+ import { join as join26 } from "path";
7598
7890
  var PKG = "@vortex-os/base";
7599
7891
  var NPM_TIMEOUT_MS = 4e3;
7600
7892
  function readInstalledBaseVersion(templatesDir = resolveTemplatesDir()) {
7601
7893
  if (!templatesDir)
7602
7894
  return null;
7603
7895
  try {
7604
- const m2 = JSON.parse(readFileSync2(join25(templatesDir, "manifest.json"), "utf8"));
7896
+ const m2 = JSON.parse(readFileSync3(join26(templatesDir, "manifest.json"), "utf8"));
7605
7897
  return typeof m2.baseVersion === "string" && parseCore(m2.baseVersion) ? m2.baseVersion.trim() : null;
7606
7898
  } catch {
7607
7899
  return null;
@@ -7673,8 +7965,8 @@ function isStableUpdate(latest, installed) {
7673
7965
  return compareSemver(latest, installed) === 1;
7674
7966
  }
7675
7967
  function buildInstallCommand(repoRoot) {
7676
- const has = (f) => existsSync12(join25(repoRoot, f));
7677
- const local = existsSync12(join25(repoRoot, "node_modules", "@vortex-os", "base"));
7968
+ const has = (f) => existsSync13(join26(repoRoot, f));
7969
+ const local = existsSync13(join26(repoRoot, "node_modules", "@vortex-os", "base"));
7678
7970
  let installPart;
7679
7971
  if (!local) {
7680
7972
  installPart = `npm i -g ${PKG}@latest`;
@@ -7702,9 +7994,9 @@ function checkBaseUpdate(ctx) {
7702
7994
  }
7703
7995
 
7704
7996
  // ../plugins/session-rituals/dist/session-start-report.js
7705
- import { existsSync as existsSync13 } from "fs";
7997
+ import { existsSync as existsSync14 } from "fs";
7706
7998
  import { readdir as readdir17, readFile as readFile22, stat as stat9 } from "fs/promises";
7707
- import { join as join26 } from "path";
7999
+ import { join as join27 } from "path";
7708
8000
  var COUNTED_DIRS2 = ["_memory", "worklog", "decision-log"];
7709
8001
  var DEFAULT_GAP_WINDOW_DAYS = 30;
7710
8002
  function gapWindowSinceArg() {
@@ -7721,8 +8013,8 @@ async function collectSessionStartReport(ctx, opts) {
7721
8013
  const counts = {};
7722
8014
  const missing = [];
7723
8015
  for (const name of COUNTED_DIRS2) {
7724
- const dir = join26(ctx.dataDir, name);
7725
- if (!existsSync13(dir)) {
8016
+ const dir = join27(ctx.dataDir, name);
8017
+ if (!existsSync14(dir)) {
7726
8018
  missing.push(name);
7727
8019
  counts[name] = 0;
7728
8020
  continue;
@@ -7732,7 +8024,7 @@ async function collectSessionStartReport(ctx, opts) {
7732
8024
  const { recent, recentGroup, recentWorklogsOmitted, dates, latestBodies } = await scanWorklog(ctx.dataDir);
7733
8025
  const cutoff = isoDate2(addDays2(now, -(opts?.gapWindowDays ?? DEFAULT_GAP_WINDOW_DAYS)));
7734
8026
  const recentWorklogDates = dates.filter((d2) => d2 >= cutoff);
7735
- const mem = await scanMemoryTiers(join26(ctx.dataDir, "_memory"));
8027
+ const mem = await scanMemoryTiers(join27(ctx.dataDir, "_memory"));
7736
8028
  const ho = await scanHandoffs(ctx.dataDir);
7737
8029
  const handoffs = ho.active.map((h) => ({
7738
8030
  date: h.date,
@@ -7799,7 +8091,7 @@ async function scanMemoryTiers(memoryDir) {
7799
8091
  for (const e of entries) {
7800
8092
  if (!e.isFile() || !e.name.endsWith(".md"))
7801
8093
  continue;
7802
- const full = join26(memoryDir, e.name);
8094
+ const full = join27(memoryDir, e.name);
7803
8095
  if (e.name === "_INDEX.md") {
7804
8096
  indexExists = true;
7805
8097
  try {
@@ -7970,6 +8262,7 @@ function renderSessionStartReport(report, extras) {
7970
8262
  lines.push(` - \u2026(+${fl.omitted} more \u2014 \`vortex failure list\`)`);
7971
8263
  }
7972
8264
  const cu = extras?.catchUp;
8265
+ const as = extras?.archiveSync;
7973
8266
  if (cu && (cu.ingestedLocal > 0 || cu.indexedPulled > 0 || cu.errors > 0)) {
7974
8267
  const parts = [];
7975
8268
  if (cu.ingestedLocal > 0)
@@ -7978,9 +8271,19 @@ function renderSessionStartReport(report, extras) {
7978
8271
  parts.push(`${cu.indexedPulled} pulled`);
7979
8272
  const n = cu.ingestedLocal + cu.indexedPulled;
7980
8273
  let line = `- caught up: archived ${parts.join(" + ")} conversation${n === 1 ? "" : "s"}`;
8274
+ if (as?.committed)
8275
+ line += as.pushed ? " \xB7 committed & pushed" : " \xB7 committed";
7981
8276
  if (cu.errors > 0)
7982
8277
  line += ` (${cu.errors} error${cu.errors === 1 ? "" : "s"})`;
7983
8278
  lines.push(line);
8279
+ } else if (as?.committed) {
8280
+ lines.push(`- archive: changes committed${as.pushed ? " & pushed" : ""}`);
8281
+ }
8282
+ if (as && as.rawPruned > 0) {
8283
+ lines.push(`- \u{1F9F9} archive: removed ${as.rawPruned} raw transcript cop${as.rawPruned === 1 ? "y" : "ies"} older than ${as.retentionDays}d (local duplicates; the normalized archive keeps everything)`);
8284
+ }
8285
+ if (as && !as.pushed && as.pushSkipped && as.pushSkipped !== "off" && as.pushSkipped !== "no-commit") {
8286
+ lines.push(`- \u26A0\uFE0F auto-push is on but could not push (${as.pushSkipped}) \u2014 push manually or check the remote.`);
7984
8287
  }
7985
8288
  const vec = extras?.vectorized;
7986
8289
  if (vec && vec.sessionChunks > 0) {
@@ -8038,15 +8341,15 @@ async function countMarkdown3(dir, recursive) {
8038
8341
  } else if (e.isDirectory() && recursive) {
8039
8342
  if (e.name.startsWith(".") || e.name.startsWith("_"))
8040
8343
  continue;
8041
- total += await countMarkdown3(join26(dir, e.name), recursive);
8344
+ total += await countMarkdown3(join27(dir, e.name), recursive);
8042
8345
  }
8043
8346
  }
8044
8347
  return total;
8045
8348
  }
8046
8349
  var MAX_GROUP_READ = 20;
8047
8350
  async function scanWorklog(dataDir) {
8048
- const root = join26(dataDir, "worklog");
8049
- if (!existsSync13(root))
8351
+ const root = join27(dataDir, "worklog");
8352
+ if (!existsSync14(root))
8050
8353
  return { recent: null, recentGroup: [], recentWorklogsOmitted: 0, dates: [], latestBodies: [] };
8051
8354
  const dates = /* @__PURE__ */ new Set();
8052
8355
  const consistent = [];
@@ -8061,7 +8364,7 @@ async function scanWorklog(dataDir) {
8061
8364
  for (const e of entries) {
8062
8365
  const childRel = rel ? `${rel}/${e.name}` : e.name;
8063
8366
  if (e.isDirectory()) {
8064
- await walk5(join26(absDir, e.name), childRel);
8367
+ await walk5(join27(absDir, e.name), childRel);
8065
8368
  } else if (e.isFile()) {
8066
8369
  const m2 = e.name.match(/^(\d{4})-(\d{2})-(\d{2})(?:_\d{4})?-.+\.md$/);
8067
8370
  if (!m2)
@@ -8090,7 +8393,7 @@ async function scanWorklog(dataDir) {
8090
8393
  const recentGroup = [];
8091
8394
  const latestBodies = [];
8092
8395
  for (const g of group) {
8093
- const { title, body } = await readWorklogTitleAndBody(join26(root, g.rel));
8396
+ const { title, body } = await readWorklogTitleAndBody(join27(root, g.rel));
8094
8397
  recentGroup.push({ path: defangReportPath(`worklog/${g.rel}`), title });
8095
8398
  latestBodies.push(body);
8096
8399
  }
@@ -8169,10 +8472,10 @@ function isoDate2(d2) {
8169
8472
  }
8170
8473
 
8171
8474
  // ../plugins/session-rituals/dist/curate-cli.js
8172
- import { existsSync as existsSync14 } from "fs";
8475
+ import { existsSync as existsSync15 } from "fs";
8173
8476
  import { createHash as createHash3 } from "crypto";
8174
8477
  import { readFile as readFile23, readdir as readdir18 } from "fs/promises";
8175
- import { join as join27 } from "path";
8478
+ import { join as join28 } from "path";
8176
8479
  var SYSTEM_META_DIRS2 = /* @__PURE__ */ new Set([
8177
8480
  "worklog",
8178
8481
  "decision-log",
@@ -8252,10 +8555,10 @@ function joinRel(...parts) {
8252
8555
  }
8253
8556
  async function runCurateCandidates(repoRoot, options) {
8254
8557
  const maxEntries = options?.maxEntries ?? 200;
8255
- const dataDir = join27(repoRoot, "data");
8558
+ const dataDir = join28(repoRoot, "data");
8256
8559
  const candidates = [];
8257
8560
  let truncated = false;
8258
- if (existsSync14(dataDir)) {
8561
+ if (existsSync15(dataDir)) {
8259
8562
  async function visit(absDir, relDir) {
8260
8563
  if (candidates.length >= maxEntries) {
8261
8564
  truncated = true;
@@ -8278,7 +8581,7 @@ async function runCurateCandidates(repoRoot, options) {
8278
8581
  continue;
8279
8582
  if (atRoot && (SYSTEM_META_DIRS2.has(e.name) || e.name.startsWith("_")))
8280
8583
  continue;
8281
- await visit(join27(absDir, e.name), joinRel(relDir, e.name));
8584
+ await visit(join28(absDir, e.name), joinRel(relDir, e.name));
8282
8585
  } else if (e.isFile() && e.name.endsWith(".md")) {
8283
8586
  if (NON_DOC_FILES.has(e.name))
8284
8587
  continue;
@@ -8287,7 +8590,7 @@ async function runCurateCandidates(repoRoot, options) {
8287
8590
  let topic = null;
8288
8591
  let tags = [];
8289
8592
  try {
8290
- const raw = await readFile23(join27(absDir, e.name), "utf8");
8593
+ const raw = await readFile23(join28(absDir, e.name), "utf8");
8291
8594
  const parsed = parseFrontmatter(raw);
8292
8595
  if (typeof parsed.frontmatter.topic === "string") {
8293
8596
  topic = parsed.frontmatter.topic.trim().toLowerCase();
@@ -8325,7 +8628,7 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
8325
8628
  };
8326
8629
  }
8327
8630
  try {
8328
- validateDataRelativePath(join27(repoRoot, "data"), v2.effectiveRelPath);
8631
+ validateDataRelativePath(join28(repoRoot, "data"), v2.effectiveRelPath);
8329
8632
  } catch (e) {
8330
8633
  return {
8331
8634
  subcommand: "curate-preview",
@@ -8342,10 +8645,10 @@ async function runCuratePreview(repoRoot, payload, now = /* @__PURE__ */ new Dat
8342
8645
  let targetExists;
8343
8646
  let wouldDo;
8344
8647
  if (payload.action === "create-file") {
8345
- targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
8648
+ targetExists = existsSync15(join28(repoRoot, "data", v2.effectiveRelPath));
8346
8649
  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}.`;
8347
8650
  } else {
8348
- targetExists = existsSync14(join27(repoRoot, "data", v2.effectiveRelPath));
8651
+ targetExists = existsSync15(join28(repoRoot, "data", v2.effectiveRelPath));
8349
8652
  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).`;
8350
8653
  }
8351
8654
  const nextActions = [];
@@ -8490,13 +8793,13 @@ function readCuratePayload(args) {
8490
8793
  break;
8491
8794
  }
8492
8795
  if (t === "--payload-file" && i + 1 < args.length) {
8493
- raw = readFileSync3(args[++i], "utf8");
8796
+ raw = readFileSync4(args[++i], "utf8");
8494
8797
  break;
8495
8798
  }
8496
8799
  }
8497
8800
  if (raw === null) {
8498
8801
  try {
8499
- raw = readFileSync3(0, "utf8");
8802
+ raw = readFileSync4(0, "utf8");
8500
8803
  } catch {
8501
8804
  raw = "";
8502
8805
  }
@@ -8520,18 +8823,18 @@ async function runVortexCli(argv, io) {
8520
8823
  const err = io?.stderr ?? ((s) => process.stderr.write(s));
8521
8824
  try {
8522
8825
  if (argv[0] === "statusline") {
8523
- const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-6KSHISXO.js");
8826
+ const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-6BGWOOLA.js");
8524
8827
  const statuslineRoot = process.env.VORTEX_REPO_ROOT?.trim() || process.cwd();
8525
8828
  return runStatuslineCli2(argv.slice(1), statuslineRoot, out, err);
8526
8829
  }
8527
8830
  if (argv[0] === "guard") {
8528
- const { runGuardCli: runGuardCli2 } = await import("./guard-IMJR6ET7.js");
8831
+ const { runGuardCli: runGuardCli2 } = await import("./guard-S6NGMDXR.js");
8529
8832
  return runGuardCli2(argv.slice(1), out, err);
8530
8833
  }
8531
8834
  const repoRoot = resolveRepoRoot();
8532
8835
  if (argv[0] === "failure") {
8533
- const { runFailureCli: runFailureCli2 } = await import("./failures-PMURLMVB.js");
8534
- const { resolveInstanceRoot: resolveInstanceRoot2 } = await import("./guard-IMJR6ET7.js");
8836
+ const { runFailureCli: runFailureCli2 } = await import("./failures-DBXJKFYX.js");
8837
+ const { resolveInstanceRoot: resolveInstanceRoot2 } = await import("./guard-S6NGMDXR.js");
8535
8838
  const root = resolveInstanceRoot2(process.cwd()) ?? repoRoot;
8536
8839
  const ctx = makeContext(root);
8537
8840
  return runFailureCli2(argv.slice(1), ctx.dataDir, out, err);
@@ -8544,6 +8847,10 @@ async function runVortexCli(argv, io) {
8544
8847
  await runSessionEnd(repoRoot, out);
8545
8848
  return 0;
8546
8849
  }
8850
+ if (argv[0] === "catch-up") {
8851
+ await runCatchUpCli(repoRoot, out);
8852
+ return 0;
8853
+ }
8547
8854
  if (argv[0] === "check-updates") {
8548
8855
  const result2 = checkBaseUpdate(makeContext(repoRoot));
8549
8856
  out(JSON.stringify(result2, null, 2) + "\n");
@@ -8571,8 +8878,9 @@ async function runVortexCli(argv, io) {
8571
8878
 
8572
8879
  Commands:
8573
8880
  ${names}
8574
- session-start \u2014 emit the start-of-session boot report (git pull + data counts + catch-up)
8575
- session-end \u2014 no-op (kept for hook compatibility; worklog gap handling is at session-start)
8881
+ session-start \u2014 emit the start-of-session boot report (git pull + data counts + archive sync)
8882
+ session-end \u2014 best-effort archive sync at wind-down (ingest closed sessions + auto-commit; crash-safe \u2014 session-start repeats it)
8883
+ catch-up \u2014 explicit archive sync now (ingest closed sessions, sweep raw copies, auto-commit, opt-in push); run before a manual sync
8576
8884
  check-updates \u2014 check the npm registry for a newer @vortex-os/base (read-only; prints the exact update command)
8577
8885
  statusline \u2014 render the Claude Code status bar from stdin JSON (\`lite\` for 1-line; \`install [--lite]\` wires .claude/settings.json)
8578
8886
  failure \u2014 failure ledger (\`record\` an occurrence by recurrence key / \`list\` open groups with their escalation stage)
@@ -8643,14 +8951,14 @@ function memoryExtendedPresent() {
8643
8951
  }
8644
8952
  var VECTORIZE_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
8645
8953
  function vectorizeLockPath(ctx) {
8646
- return join28(ctx.dataDir, "_indexes", ".vectorize.lock");
8954
+ return join29(ctx.dataDir, "_indexes", ".vectorize.lock");
8647
8955
  }
8648
8956
  function vectorizeSetupInProgress(ctx) {
8649
8957
  const lock = vectorizeLockPath(ctx);
8650
8958
  try {
8651
- if (!existsSync15(lock))
8959
+ if (!existsSync16(lock))
8652
8960
  return false;
8653
- return Date.now() - statSync(lock).mtimeMs < VECTORIZE_LOCK_TTL_MS;
8961
+ return Date.now() - statSync2(lock).mtimeMs < VECTORIZE_LOCK_TTL_MS;
8654
8962
  } catch {
8655
8963
  return false;
8656
8964
  }
@@ -8669,24 +8977,24 @@ function spawnVectorizeSetup(repoRoot) {
8669
8977
  }
8670
8978
  async function runVectorizeSetup(repoRoot, out, err) {
8671
8979
  const ctx = makeContext(repoRoot);
8672
- const indexDir = join28(ctx.dataDir, "_indexes");
8673
- const finalDb = join28(indexDir, "memory.sqlite");
8674
- if (existsSync15(finalDb)) {
8980
+ const indexDir = join29(ctx.dataDir, "_indexes");
8981
+ const finalDb = join29(indexDir, "memory.sqlite");
8982
+ if (existsSync16(finalDb)) {
8675
8983
  out("recall index already present \u2014 nothing to do\n");
8676
8984
  return;
8677
8985
  }
8678
- mkdirSync(indexDir, { recursive: true });
8679
- const lockPath = vectorizeLockPath(ctx);
8986
+ mkdirSync2(indexDir, { recursive: true });
8987
+ const lockPath2 = vectorizeLockPath(ctx);
8680
8988
  const token = `${process.pid}-${process.hrtime.bigint()}`;
8681
8989
  let lockFd;
8682
8990
  try {
8683
- lockFd = openSync(lockPath, "wx");
8991
+ lockFd = openSync2(lockPath2, "wx");
8684
8992
  } catch (e) {
8685
8993
  if (e.code !== "EEXIST")
8686
8994
  throw e;
8687
8995
  let stale = true;
8688
8996
  try {
8689
- stale = Date.now() - statSync(lockPath).mtimeMs >= VECTORIZE_LOCK_TTL_MS;
8997
+ stale = Date.now() - statSync2(lockPath2).mtimeMs >= VECTORIZE_LOCK_TTL_MS;
8690
8998
  } catch {
8691
8999
  stale = true;
8692
9000
  }
@@ -8694,38 +9002,38 @@ async function runVectorizeSetup(repoRoot, out, err) {
8694
9002
  out("another recall setup is already in progress \u2014 skipping\n");
8695
9003
  return;
8696
9004
  }
8697
- rmSync(lockPath, { force: true });
9005
+ rmSync2(lockPath2, { force: true });
8698
9006
  try {
8699
- lockFd = openSync(lockPath, "wx");
9007
+ lockFd = openSync2(lockPath2, "wx");
8700
9008
  } catch {
8701
9009
  out("another recall setup just started \u2014 skipping\n");
8702
9010
  return;
8703
9011
  }
8704
9012
  }
8705
- const tmpDb = join28(indexDir, `memory.sqlite.building-${process.pid}`);
9013
+ const tmpDb = join29(indexDir, `memory.sqlite.building-${process.pid}`);
8706
9014
  const tmpSidecars = [tmpDb + "-wal", tmpDb + "-shm", tmpDb + "-journal"];
8707
9015
  const cleanTmp = () => {
8708
- rmSync(tmpDb, { force: true });
9016
+ rmSync2(tmpDb, { force: true });
8709
9017
  for (const s of tmpSidecars)
8710
- rmSync(s, { force: true });
9018
+ rmSync2(s, { force: true });
8711
9019
  };
8712
9020
  let tokenWritten = false;
8713
9021
  const releaseLock = () => {
8714
9022
  try {
8715
- const cur = existsSync15(lockPath) ? readFileSync3(lockPath, "utf8").trim() : "";
9023
+ const cur = existsSync16(lockPath2) ? readFileSync4(lockPath2, "utf8").trim() : "";
8716
9024
  if (cur === token || cur === "" && !tokenWritten)
8717
- rmSync(lockPath, { force: true });
9025
+ rmSync2(lockPath2, { force: true });
8718
9026
  } catch {
8719
9027
  }
8720
9028
  };
8721
9029
  try {
8722
9030
  try {
8723
- writeSync(lockFd, token + "\n");
9031
+ writeSync2(lockFd, token + "\n");
8724
9032
  tokenWritten = true;
8725
9033
  } finally {
8726
- closeSync(lockFd);
9034
+ closeSync2(lockFd);
8727
9035
  }
8728
- if (existsSync15(finalDb)) {
9036
+ if (existsSync16(finalDb)) {
8729
9037
  out("recall index already present \u2014 nothing to do\n");
8730
9038
  return;
8731
9039
  }
@@ -8741,7 +9049,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8741
9049
  } finally {
8742
9050
  db.close();
8743
9051
  }
8744
- if (existsSync15(tmpDb + "-wal")) {
9052
+ if (existsSync16(tmpDb + "-wal")) {
8745
9053
  throw new Error("temp index retained a WAL sidecar after consolidation; refusing to publish");
8746
9054
  }
8747
9055
  try {
@@ -8754,7 +9062,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8754
9062
  }
8755
9063
  throw e;
8756
9064
  }
8757
- rmSync(tmpDb, { force: true });
9065
+ rmSync2(tmpDb, { force: true });
8758
9066
  out(`recall index built \u2014 semantic search ready (memories: ${result.memories}, conversation chunks: ${result.sessionChunks})
8759
9067
  `);
8760
9068
  } catch (e) {
@@ -8790,7 +9098,8 @@ async function runSessionStart(repoRoot, out) {
8790
9098
  } catch {
8791
9099
  }
8792
9100
  const bookkeepingPrefix = frameworkBookkeepingPrefix(ctx);
8793
- const carryover = collectCarryover(repoRoot, (p) => p.startsWith(bookkeepingPrefix));
9101
+ const archivePrefix = archiveRelPath(ctx) + "/";
9102
+ const carryover = collectCarryover(repoRoot, (p) => p.startsWith(bookkeepingPrefix) || p.startsWith(archivePrefix));
8794
9103
  if (config.autoRecord.reindex && !git2?.conflict) {
8795
9104
  await autoReindexMemory(ctx);
8796
9105
  }
@@ -8804,14 +9113,14 @@ async function runSessionStart(repoRoot, out) {
8804
9113
  } catch {
8805
9114
  }
8806
9115
  }
8807
- let catchUp = null;
9116
+ let archiveSync = null;
8808
9117
  if (config.autoRecord.archive) {
8809
9118
  try {
8810
- const { catchUpSessions: catchUpSessions2 } = await import("./catch-up-GDDKPZHJ.js");
8811
- catchUp = await catchUpSessions2(ctx);
9119
+ archiveSync = await runArchiveSync(ctx, config, "start");
8812
9120
  } catch {
8813
9121
  }
8814
9122
  }
9123
+ const catchUp = archiveSync?.catchUp ?? null;
8815
9124
  let handoffPrune = null;
8816
9125
  if (config.autoRecord.handoff) {
8817
9126
  try {
@@ -8825,7 +9134,7 @@ async function runSessionStart(repoRoot, out) {
8825
9134
  let vectorized = null;
8826
9135
  let vectorizeSetupStarted = false;
8827
9136
  if (config.autoRecord.vectorize) {
8828
- const dbExists = existsSync15(join28(ctx.dataDir, "_indexes", "memory.sqlite"));
9137
+ const dbExists = existsSync16(join29(ctx.dataDir, "_indexes", "memory.sqlite"));
8829
9138
  const action = decideVectorizeAction({
8830
9139
  vectorizeOn: true,
8831
9140
  dbExists,
@@ -8851,7 +9160,7 @@ async function runSessionStart(repoRoot, out) {
8851
9160
  let failures = null;
8852
9161
  if (config.autoRecord.failures) {
8853
9162
  try {
8854
- const { scanFailures: scanFailures2, failureReportSlice: failureReportSlice2 } = await import("./failures-PMURLMVB.js");
9163
+ const { scanFailures: scanFailures2, failureReportSlice: failureReportSlice2 } = await import("./failures-DBXJKFYX.js");
8855
9164
  const slice = failureReportSlice2(await scanFailures2(ctx.dataDir));
8856
9165
  if (slice.warnings.length > 0)
8857
9166
  failures = slice;
@@ -8891,6 +9200,13 @@ async function runSessionStart(repoRoot, out) {
8891
9200
  baseVersion,
8892
9201
  missingWorklogDays,
8893
9202
  catchUp: catchUp ?? void 0,
9203
+ archiveSync: archiveSync ? {
9204
+ committed: archiveSync.committed,
9205
+ pushed: archiveSync.pushed,
9206
+ pushSkipped: archiveSync.pushSkipped,
9207
+ rawPruned: archiveSync.rawPruned,
9208
+ retentionDays: archiveSync.retentionDays
9209
+ } : void 0,
8894
9210
  vectorized: vectorized ?? void 0,
8895
9211
  vectorizeSetup: vectorizeSetupStarted || void 0,
8896
9212
  templateUpdate: templateUpdate ?? void 0,
@@ -8901,36 +9217,48 @@ async function runSessionStart(repoRoot, out) {
8901
9217
  failures: failures ?? void 0
8902
9218
  }));
8903
9219
  }
8904
- async function runSessionEnd(_repoRoot, _out) {
8905
- }
8906
- function gitOut(cwd, gitArgs) {
8907
- return execFileSync2("git", [...gitArgs], {
8908
- cwd,
8909
- encoding: "utf8",
8910
- stdio: ["ignore", "pipe", "ignore"]
8911
- });
8912
- }
8913
- function detectInterruptedGitOp(repoRoot) {
8914
- const markers = [
8915
- "MERGE_HEAD",
8916
- "rebase-merge",
8917
- "rebase-apply",
8918
- "CHERRY_PICK_HEAD",
8919
- "REVERT_HEAD",
8920
- "BISECT_LOG",
8921
- "index.lock"
8922
- ];
9220
+ async function runSessionEnd(repoRoot, out) {
8923
9221
  try {
8924
- const args = ["rev-parse", ...markers.flatMap((m2) => ["--git-path", m2])];
8925
- const resolved = gitOut(repoRoot, args).split(/\r?\n/).map((s) => s.trim());
8926
- for (let i = 0; i < markers.length; i++) {
8927
- const p = resolved[i];
8928
- if (p && existsSync15(isAbsolute4(p) ? p : join28(repoRoot, p)))
8929
- return markers[i];
9222
+ const ctx = makeContext(repoRoot);
9223
+ const config = loadVortexConfig(ctx);
9224
+ if (!config.autoRecord.archive || !config.autoRecord.archiveAtEnd)
9225
+ return;
9226
+ const r = await runArchiveSync(ctx, config, "end");
9227
+ if (r.lockSkipped) {
9228
+ out("archive sync skipped (another session is syncing)\n");
9229
+ return;
8930
9230
  }
9231
+ const parts = [];
9232
+ if (r.catchUp)
9233
+ parts.push(`${r.catchUp.ingestedLocal} archived`);
9234
+ if (r.rawPruned > 0)
9235
+ parts.push(`${r.rawPruned} raw pruned`);
9236
+ if (r.committed)
9237
+ parts.push("committed");
9238
+ if (r.pushed)
9239
+ parts.push("pushed");
9240
+ out(`session-end archive sync: ${parts.length ? parts.join(", ") : "nothing to do"}
9241
+ `);
8931
9242
  } catch {
8932
9243
  }
8933
- return null;
9244
+ }
9245
+ async function runCatchUpCli(repoRoot, out) {
9246
+ const ctx = makeContext(repoRoot);
9247
+ const config = loadVortexConfig(ctx);
9248
+ const r = await runArchiveSync(ctx, config, "manual");
9249
+ out(JSON.stringify({
9250
+ ran: r.ran,
9251
+ lockSkipped: r.lockSkipped,
9252
+ ingested: r.catchUp?.ingestedLocal ?? 0,
9253
+ indexedPulled: r.catchUp?.indexedPulled ?? 0,
9254
+ ingestErrors: r.catchUp?.errors ?? 0,
9255
+ rawPruned: r.rawPruned,
9256
+ rawRetentionDays: r.retentionDays,
9257
+ committed: r.committed,
9258
+ ...r.commitSkipped ? { commitSkipped: r.commitSkipped } : {},
9259
+ pushed: r.pushed,
9260
+ ...r.pushSkipped ? { pushSkipped: r.pushSkipped } : {}
9261
+ }, null, 2) + "\n");
8934
9262
  }
8935
9263
  function collectCarryover(repoRoot, ignore) {
8936
9264
  const interrupted = detectInterruptedGitOp(repoRoot);
@@ -8945,23 +9273,23 @@ function resolveSessionEnvironment(ctx, config) {
8945
9273
  let environment = resolveEnvironment(config, {
8946
9274
  hostname: hostname(),
8947
9275
  env: process.env,
8948
- pathExists: existsSync15
9276
+ pathExists: existsSync16
8949
9277
  });
8950
9278
  if (!environment)
8951
9279
  environment = process.env.VORTEX_ENV?.trim() || null;
8952
9280
  if (!environment) {
8953
- const envFile = join28(ctx.repoRoot, ".agent", "environment");
8954
- if (existsSync15(envFile)) {
8955
- environment = readFileSync3(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
9281
+ const envFile = join29(ctx.repoRoot, ".agent", "environment");
9282
+ if (existsSync16(envFile)) {
9283
+ environment = readFileSync4(envFile, "utf8").split(/\r?\n/)[0]?.trim() || null;
8956
9284
  }
8957
9285
  }
8958
9286
  return environment;
8959
9287
  }
8960
9288
 
8961
9289
  // ../plugins/session-rituals/dist/ambient-recall.js
8962
- import { join as join29 } from "path";
9290
+ import { join as join30 } from "path";
8963
9291
  function defaultDbPath2(ctx) {
8964
- return join29(ctx.dataDir, "_indexes", "memory.sqlite");
9292
+ return join30(ctx.dataDir, "_indexes", "memory.sqlite");
8965
9293
  }
8966
9294
  function createAmbientRecaller(ctx, options) {
8967
9295
  const resolveDb = options.dbPath ?? defaultDbPath2;
@@ -8999,13 +9327,13 @@ function createAmbientRecaller(ctx, options) {
8999
9327
 
9000
9328
  // ../plugins/session-rituals/dist/worklog-write.js
9001
9329
  import { mkdir as mkdir10, writeFile as writeFile11 } from "fs/promises";
9002
- import { dirname as dirname6, join as join30 } from "path";
9330
+ import { dirname as dirname6, join as join31 } from "path";
9003
9331
  async function ensureWorklogEntry(ctx, opts) {
9004
9332
  const now = opts?.now ?? /* @__PURE__ */ new Date();
9005
9333
  const date = isoDate3(now);
9006
9334
  const time = isoTime2(now);
9007
9335
  const keyword = (opts?.keyword ?? "worklog").trim() || "worklog";
9008
- const store = new WorklogStore(join30(ctx.dataDir, "worklog"));
9336
+ const store = new WorklogStore(join31(ctx.dataDir, "worklog"));
9009
9337
  const existing = await store.get(date);
9010
9338
  if (existing) {
9011
9339
  return { path: existing.path, date: existing.date, keyword: existing.keyword, created: false };