@vortex-os/base 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +23 -2
- package/dist/index.js +107 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/manifest.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,21 @@ interface AutoRecordConfig {
|
|
|
131
131
|
* `vectorize` is off, nothing runs regardless.
|
|
132
132
|
*/
|
|
133
133
|
readonly vectorizeAutoDownload: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Auto-commit framework bookkeeping. When `vortex update` refreshes
|
|
136
|
+
* framework-owned files it also rewrites the ownership manifest
|
|
137
|
+
* (`data/.vortex/ownership.json`); on its own that leaves an uncommitted
|
|
138
|
+
* "trail" that the next session reports as carried-over work, even though it
|
|
139
|
+
* is plumbing the user never touched. With this on, `vortex update` commits
|
|
140
|
+
* exactly the framework files it changed (the manifest + the templates it
|
|
141
|
+
* refreshed) — and nothing else in the working tree — so an update leaves a
|
|
142
|
+
* clean tree. Best-effort: a non-git folder, or any git failure, is a silent
|
|
143
|
+
* no-op (the command still succeeds). On by default; set `false` to keep the
|
|
144
|
+
* commit manual (e.g. you prefer to review and commit framework changes
|
|
145
|
+
* yourself). Conflicts (`<file>.new`) are never auto-committed — those still
|
|
146
|
+
* wait for you to merge.
|
|
147
|
+
*/
|
|
148
|
+
readonly commitFrameworkChanges: boolean;
|
|
134
149
|
}
|
|
135
150
|
/**
|
|
136
151
|
* One environment label plus the signal that selects it. Rules are evaluated
|
|
@@ -2653,7 +2668,7 @@ declare function detectInterruptedGitOp(repoRoot: string): string | null;
|
|
|
2653
2668
|
* null when there is nothing to report (clean tree / not a git repo). Exported
|
|
2654
2669
|
* for tests. (decision-log 2026-06-04-session-recovery-two-tier.)
|
|
2655
2670
|
*/
|
|
2656
|
-
declare function collectCarryover(repoRoot: string): {
|
|
2671
|
+
declare function collectCarryover(repoRoot: string, ignore?: (repoRelPosixPath: string) => boolean): {
|
|
2657
2672
|
uncommitted: number;
|
|
2658
2673
|
interrupted: string | null;
|
|
2659
2674
|
} | null;
|
|
@@ -3084,8 +3099,14 @@ declare function detectWorklogGaps(commitDays: readonly string[], presentDates:
|
|
|
3084
3099
|
* non-empty line. Pure: the hook runs git; this turns its stdout into the
|
|
3085
3100
|
* Tier-1 carryover count. (`--porcelain` emits exactly one line per changed
|
|
3086
3101
|
* path, including untracked, so a line count is the change count.)
|
|
3102
|
+
*
|
|
3103
|
+
* `ignore`, when given, drops paths it returns true for from the count — used to
|
|
3104
|
+
* exclude framework-generated bookkeeping (the ownership manifest under
|
|
3105
|
+
* `data/.vortex/`), which is auto-maintained plumbing the user never edits, so
|
|
3106
|
+
* it must not be reported as carried-over WIP. A line whose path can't be parsed
|
|
3107
|
+
* is counted (fail toward surfacing, not hiding).
|
|
3087
3108
|
*/
|
|
3088
|
-
declare function countUncommitted(porcelain: string): number;
|
|
3109
|
+
declare function countUncommitted(porcelain: string, ignore?: (repoRelPosixPath: string) => boolean): number;
|
|
3089
3110
|
/**
|
|
3090
3111
|
* Render a session-start report as a compact markdown block for a host hook
|
|
3091
3112
|
* to inject as session context. A pull conflict and any worklog gaps are
|
package/dist/index.js
CHANGED
|
@@ -105,7 +105,7 @@ function moduleDir(ctx, moduleName) {
|
|
|
105
105
|
import { existsSync, readFileSync } from "fs";
|
|
106
106
|
import { join as join2 } from "path";
|
|
107
107
|
var DEFAULT_CONFIG = {
|
|
108
|
-
autoRecord: { sessionStart: true, worklog: true, decision: true, ambientRecall: true, archive: true, vectorize: true, vectorizeAutoDownload: true },
|
|
108
|
+
autoRecord: { sessionStart: true, worklog: true, decision: true, ambientRecall: true, archive: true, vectorize: true, vectorizeAutoDownload: true, commitFrameworkChanges: true },
|
|
109
109
|
updates: { check: "session" },
|
|
110
110
|
environments: []
|
|
111
111
|
};
|
|
@@ -147,11 +147,13 @@ function loadVortexConfig(ctx) {
|
|
|
147
147
|
const check = rawCheck === void 0 ? "session" : typeof rawCheck === "string" && rawCheck.trim().toLowerCase() === "session" ? "session" : "off";
|
|
148
148
|
const rawAuto = raw.autoRecord && typeof raw.autoRecord === "object" && !Array.isArray(raw.autoRecord) ? raw.autoRecord : {};
|
|
149
149
|
const vectorizeAutoDownload = rawAuto.vectorizeAutoDownload === void 0 ? true : rawAuto.vectorizeAutoDownload === true;
|
|
150
|
+
const commitFrameworkChanges = rawAuto.commitFrameworkChanges === void 0 ? true : rawAuto.commitFrameworkChanges === true;
|
|
150
151
|
return {
|
|
151
152
|
autoRecord: {
|
|
152
153
|
...DEFAULT_CONFIG.autoRecord,
|
|
153
154
|
...raw.autoRecord ?? {},
|
|
154
|
-
vectorizeAutoDownload
|
|
155
|
+
vectorizeAutoDownload,
|
|
156
|
+
commitFrameworkChanges
|
|
155
157
|
},
|
|
156
158
|
updates: { check },
|
|
157
159
|
environments
|
|
@@ -5005,6 +5007,21 @@ var MANIFEST_NAME = "manifest.json";
|
|
|
5005
5007
|
function ownershipManifestPath(ctx) {
|
|
5006
5008
|
return join24(ctx.dataDir, ".vortex", "ownership.json");
|
|
5007
5009
|
}
|
|
5010
|
+
function frameworkBookkeepingPrefix(ctx) {
|
|
5011
|
+
return toPosix(relative4(ctx.repoRoot, join24(ctx.dataDir, ".vortex"))) + "/";
|
|
5012
|
+
}
|
|
5013
|
+
function committableUpdatePaths(ctx, result) {
|
|
5014
|
+
const out = /* @__PURE__ */ new Set();
|
|
5015
|
+
for (const a of result.actions) {
|
|
5016
|
+
if (a.error)
|
|
5017
|
+
continue;
|
|
5018
|
+
if (a.action === "replace" || a.action === "restore" || a.action === "install" || a.action === "adopt") {
|
|
5019
|
+
out.add(a.path);
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
out.add(toPosix(relative4(ctx.repoRoot, ownershipManifestPath(ctx))));
|
|
5023
|
+
return [...out];
|
|
5024
|
+
}
|
|
5008
5025
|
function toPosix(p) {
|
|
5009
5026
|
return p.split(sep4).join("/");
|
|
5010
5027
|
}
|
|
@@ -5030,6 +5047,8 @@ function templateDestRelPath(templateRelPath) {
|
|
|
5030
5047
|
const parts = templateRelPath.split("/");
|
|
5031
5048
|
if (parts.length < 2)
|
|
5032
5049
|
return null;
|
|
5050
|
+
if (parts.some((p) => p === ".." || p === "."))
|
|
5051
|
+
return null;
|
|
5033
5052
|
const [top, ...rest] = parts;
|
|
5034
5053
|
const tail = rest.join("/");
|
|
5035
5054
|
if (top === "routers")
|
|
@@ -5608,6 +5627,41 @@ function buildNextActions(status, summary, actions, dryRun, fromVersion, toVersi
|
|
|
5608
5627
|
return out;
|
|
5609
5628
|
}
|
|
5610
5629
|
|
|
5630
|
+
// ../plugins/session-rituals/dist/git-commit.js
|
|
5631
|
+
import { execFileSync } from "child_process";
|
|
5632
|
+
function git(repoRoot, args) {
|
|
5633
|
+
return execFileSync("git", [...args], {
|
|
5634
|
+
cwd: repoRoot,
|
|
5635
|
+
encoding: "utf8",
|
|
5636
|
+
// GIT_LITERAL_PATHSPECS=1 makes every `-- <path>` a LITERAL filename, not a
|
|
5637
|
+
// pathspec: it disables glob magic (`*` `?` `[…]`) and `:(…)` prefixes. So
|
|
5638
|
+
// even a path carrying those bytes (e.g. from a malformed template index)
|
|
5639
|
+
// can only ever match the exact file named — never a wider set.
|
|
5640
|
+
env: { ...process.env, GIT_LITERAL_PATHSPECS: "1" },
|
|
5641
|
+
// Suppress git's own stderr; the caller treats a non-zero exit as "no commit".
|
|
5642
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
5643
|
+
});
|
|
5644
|
+
}
|
|
5645
|
+
function commitFrameworkPaths(repoRoot, paths, message) {
|
|
5646
|
+
if (paths.length === 0)
|
|
5647
|
+
return { committed: false, reason: "no-paths" };
|
|
5648
|
+
try {
|
|
5649
|
+
git(repoRoot, ["rev-parse", "--git-dir"]);
|
|
5650
|
+
} catch {
|
|
5651
|
+
return { committed: false, reason: "not-a-git-repo" };
|
|
5652
|
+
}
|
|
5653
|
+
try {
|
|
5654
|
+
const status = git(repoRoot, ["status", "--porcelain", "--", ...paths]).trim();
|
|
5655
|
+
if (!status)
|
|
5656
|
+
return { committed: false, reason: "nothing-to-commit" };
|
|
5657
|
+
git(repoRoot, ["add", "--", ...paths]);
|
|
5658
|
+
git(repoRoot, ["commit", "-m", message, "--", ...paths]);
|
|
5659
|
+
return { committed: true };
|
|
5660
|
+
} catch (e) {
|
|
5661
|
+
return { committed: false, reason: "git-error", error: e?.message ?? String(e) };
|
|
5662
|
+
}
|
|
5663
|
+
}
|
|
5664
|
+
|
|
5611
5665
|
// ../plugins/session-rituals/dist/commands/vortex.js
|
|
5612
5666
|
var PLANNED_SUBS = [];
|
|
5613
5667
|
var vortexCommand = {
|
|
@@ -6033,10 +6087,25 @@ async function runUpdate(input, tokens) {
|
|
|
6033
6087
|
const dryRun = tokens.includes("--dry-run");
|
|
6034
6088
|
const adopt = parseAdoptArgs(tokens);
|
|
6035
6089
|
const templatesDir = resolveTemplatesDir();
|
|
6036
|
-
|
|
6090
|
+
const result = await runTemplatesUpdate(input.context, templatesDir, {
|
|
6037
6091
|
dryRun,
|
|
6038
6092
|
adopt: adopt.size > 0 ? adopt : void 0
|
|
6039
6093
|
});
|
|
6094
|
+
if (dryRun || result.status === "no-manifest" || result.status === "no-templates")
|
|
6095
|
+
return result;
|
|
6096
|
+
if (!loadVortexConfig(input.context).autoRecord.commitFrameworkChanges)
|
|
6097
|
+
return result;
|
|
6098
|
+
const paths = committableUpdatePaths(input.context, result);
|
|
6099
|
+
const commit = commitFrameworkPaths(input.context.repoRoot, paths, `chore(vortex): sync framework templates to base ${result.toVersion ?? "?"}`);
|
|
6100
|
+
if (!commit.committed)
|
|
6101
|
+
return result;
|
|
6102
|
+
return {
|
|
6103
|
+
...result,
|
|
6104
|
+
nextActions: [
|
|
6105
|
+
...result.nextActions,
|
|
6106
|
+
`Committed the framework changes so nothing is left uncommitted (autoRecord.commitFrameworkChanges; set false to commit these yourself).`
|
|
6107
|
+
]
|
|
6108
|
+
};
|
|
6040
6109
|
}
|
|
6041
6110
|
function parseAdoptArgs(tokens) {
|
|
6042
6111
|
const adopt = /* @__PURE__ */ new Set();
|
|
@@ -7505,7 +7574,7 @@ function createRitualRegistry(options) {
|
|
|
7505
7574
|
}
|
|
7506
7575
|
|
|
7507
7576
|
// ../plugins/session-rituals/dist/cli-dispatch.js
|
|
7508
|
-
import { execFileSync, spawn as spawn2 } from "child_process";
|
|
7577
|
+
import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
|
|
7509
7578
|
import { existsSync as existsSync15, readFileSync as readFileSync4, mkdirSync, openSync, writeSync, closeSync, linkSync, rmSync, statSync } from "fs";
|
|
7510
7579
|
import { createRequire } from "module";
|
|
7511
7580
|
import { hostname } from "os";
|
|
@@ -7767,8 +7836,28 @@ function detectWorklogGaps(commitDays, presentDates) {
|
|
|
7767
7836
|
const present = new Set(presentDates);
|
|
7768
7837
|
return [...new Set(commitDays)].filter((d2) => d2 && !present.has(d2)).sort();
|
|
7769
7838
|
}
|
|
7770
|
-
function
|
|
7771
|
-
|
|
7839
|
+
function porcelainPath(line) {
|
|
7840
|
+
const body = line.slice(3);
|
|
7841
|
+
if (!body)
|
|
7842
|
+
return null;
|
|
7843
|
+
const arrow = body.indexOf(" -> ");
|
|
7844
|
+
const raw = (arrow >= 0 ? body.slice(arrow + 4) : body).trim();
|
|
7845
|
+
if (raw.length >= 2 && raw.startsWith('"') && raw.endsWith('"'))
|
|
7846
|
+
return raw.slice(1, -1);
|
|
7847
|
+
return raw;
|
|
7848
|
+
}
|
|
7849
|
+
function countUncommitted(porcelain, ignore) {
|
|
7850
|
+
const lines = porcelain.split(/\r?\n/).filter((l3) => l3.trim().length > 0);
|
|
7851
|
+
if (!ignore)
|
|
7852
|
+
return lines.length;
|
|
7853
|
+
let n = 0;
|
|
7854
|
+
for (const l3 of lines) {
|
|
7855
|
+
const p = porcelainPath(l3);
|
|
7856
|
+
if (p && ignore(p))
|
|
7857
|
+
continue;
|
|
7858
|
+
n++;
|
|
7859
|
+
}
|
|
7860
|
+
return n;
|
|
7772
7861
|
}
|
|
7773
7862
|
function renderSessionStartReport(report, extras) {
|
|
7774
7863
|
const lines = [
|
|
@@ -7779,9 +7868,9 @@ function renderSessionStartReport(report, extras) {
|
|
|
7779
7868
|
];
|
|
7780
7869
|
const env = report.environment ? ` \xB7 env: ${envLabel(report.environment)}` : "";
|
|
7781
7870
|
lines.push(`- time: ${report.localTime ?? report.time}${env}`);
|
|
7782
|
-
const
|
|
7783
|
-
if (
|
|
7784
|
-
lines.push(
|
|
7871
|
+
const git2 = extras?.git;
|
|
7872
|
+
if (git2?.ran) {
|
|
7873
|
+
lines.push(git2.conflict ? `- git: \u26A0\uFE0F ${git2.summary} \u2014 resolve manually (not auto-resolved)` : `- git: ${git2.summary}`);
|
|
7785
7874
|
}
|
|
7786
7875
|
const countStr = COUNTED_DIRS2.map((d2) => `${d2} ${report.counts[d2] ?? 0}`).join(" \xB7 ");
|
|
7787
7876
|
const miss = report.missing.length ? ` (missing: ${report.missing.join(", ")})` : "";
|
|
@@ -8599,16 +8688,16 @@ async function runSessionStart(repoRoot, out) {
|
|
|
8599
8688
|
if (!config.autoRecord.sessionStart)
|
|
8600
8689
|
return;
|
|
8601
8690
|
const environment = resolveSessionEnvironment(ctx, config);
|
|
8602
|
-
let
|
|
8691
|
+
let git2 = null;
|
|
8603
8692
|
try {
|
|
8604
8693
|
const remotes = gitOut(repoRoot, ["remote"]).trim();
|
|
8605
8694
|
if (remotes) {
|
|
8606
8695
|
try {
|
|
8607
8696
|
const pulled = gitOut(repoRoot, ["pull", "--ff-only"]);
|
|
8608
8697
|
const lastLine = pulled.trim().split(/\r?\n/).pop() || "up to date";
|
|
8609
|
-
|
|
8698
|
+
git2 = { ran: true, summary: lastLine, conflict: false };
|
|
8610
8699
|
} catch {
|
|
8611
|
-
|
|
8700
|
+
git2 = {
|
|
8612
8701
|
ran: true,
|
|
8613
8702
|
summary: "fast-forward pull failed (diverged or dirty tree)",
|
|
8614
8703
|
conflict: true
|
|
@@ -8617,7 +8706,8 @@ async function runSessionStart(repoRoot, out) {
|
|
|
8617
8706
|
}
|
|
8618
8707
|
} catch {
|
|
8619
8708
|
}
|
|
8620
|
-
const
|
|
8709
|
+
const bookkeepingPrefix = frameworkBookkeepingPrefix(ctx);
|
|
8710
|
+
const carryover = collectCarryover(repoRoot, (p) => p.startsWith(bookkeepingPrefix));
|
|
8621
8711
|
const report = await collectSessionStartReport(ctx, { environment });
|
|
8622
8712
|
let missingWorklogDays = [];
|
|
8623
8713
|
try {
|
|
@@ -8688,7 +8778,7 @@ async function runSessionStart(repoRoot, out) {
|
|
|
8688
8778
|
} catch {
|
|
8689
8779
|
}
|
|
8690
8780
|
out(renderSessionStartReport(report, {
|
|
8691
|
-
git,
|
|
8781
|
+
git: git2,
|
|
8692
8782
|
missingWorklogDays,
|
|
8693
8783
|
catchUp: catchUp ?? void 0,
|
|
8694
8784
|
vectorized: vectorized ?? void 0,
|
|
@@ -8712,7 +8802,7 @@ async function runSessionEnd(repoRoot, out) {
|
|
|
8712
8802
|
}
|
|
8713
8803
|
}
|
|
8714
8804
|
function gitOut(cwd, gitArgs) {
|
|
8715
|
-
return
|
|
8805
|
+
return execFileSync2("git", [...gitArgs], {
|
|
8716
8806
|
cwd,
|
|
8717
8807
|
encoding: "utf8",
|
|
8718
8808
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -8740,11 +8830,11 @@ function detectInterruptedGitOp(repoRoot) {
|
|
|
8740
8830
|
}
|
|
8741
8831
|
return null;
|
|
8742
8832
|
}
|
|
8743
|
-
function collectCarryover(repoRoot) {
|
|
8833
|
+
function collectCarryover(repoRoot, ignore) {
|
|
8744
8834
|
const interrupted = detectInterruptedGitOp(repoRoot);
|
|
8745
8835
|
let uncommitted = 0;
|
|
8746
8836
|
try {
|
|
8747
|
-
uncommitted = countUncommitted(gitOut(repoRoot, ["status", "--porcelain"]));
|
|
8837
|
+
uncommitted = countUncommitted(gitOut(repoRoot, ["status", "--porcelain"]), ignore);
|
|
8748
8838
|
} catch {
|
|
8749
8839
|
}
|
|
8750
8840
|
return uncommitted > 0 || interrupted ? { uncommitted, interrupted } : null;
|