@djolex999/vir-cli 0.25.3 → 0.26.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.
Files changed (66) hide show
  1. package/README.md +90 -17
  2. package/dist/audit/run.js +2 -2
  3. package/dist/audit/run.js.map +1 -1
  4. package/dist/claude/updater.js +22 -11
  5. package/dist/claude/updater.js.map +1 -1
  6. package/dist/cli/connect.js +5 -3
  7. package/dist/cli/connect.js.map +1 -1
  8. package/dist/cli/costLabel.js +2 -1
  9. package/dist/cli/costLabel.js.map +1 -1
  10. package/dist/cli/dedupe.js +2 -1
  11. package/dist/cli/dedupe.js.map +1 -1
  12. package/dist/cli/init.js +69 -31
  13. package/dist/cli/init.js.map +1 -1
  14. package/dist/cli/initConfig.js +30 -5
  15. package/dist/cli/initConfig.js.map +1 -1
  16. package/dist/cli/projectSelect.js +1 -1
  17. package/dist/cli/projectSelect.js.map +1 -1
  18. package/dist/cli/projects.js +3 -2
  19. package/dist/cli/projects.js.map +1 -1
  20. package/dist/cli/reconcile.js +12 -9
  21. package/dist/cli/reconcile.js.map +1 -1
  22. package/dist/cli/syncClaude.js +10 -3
  23. package/dist/cli/syncClaude.js.map +1 -1
  24. package/dist/cli.js +40 -12
  25. package/dist/cli.js.map +1 -1
  26. package/dist/config.js +22 -4
  27. package/dist/config.js.map +1 -1
  28. package/dist/cost/pricing.js.map +1 -1
  29. package/dist/cost/report.js +2 -1
  30. package/dist/cost/report.js.map +1 -1
  31. package/dist/daemon/systemd.js +1 -1
  32. package/dist/diagnostics/distillFailures.js +1 -1
  33. package/dist/diagnostics/distillFailures.js.map +1 -1
  34. package/dist/diagnostics/doctor.js +68 -17
  35. package/dist/diagnostics/doctor.js.map +1 -1
  36. package/dist/diagnostics/preflightFailure.js +14 -12
  37. package/dist/diagnostics/preflightFailure.js.map +1 -1
  38. package/dist/mcp/install.js +18 -0
  39. package/dist/mcp/install.js.map +1 -1
  40. package/dist/mcp/server.js +4 -4
  41. package/dist/mcp/server.js.map +1 -1
  42. package/dist/pipeline/claudeCli.js +22 -83
  43. package/dist/pipeline/claudeCli.js.map +1 -1
  44. package/dist/pipeline/codexCli.js +167 -0
  45. package/dist/pipeline/codexCli.js.map +1 -0
  46. package/dist/pipeline/distiller.js +16 -9
  47. package/dist/pipeline/distiller.js.map +1 -1
  48. package/dist/pipeline/projects.js +2 -1
  49. package/dist/pipeline/projects.js.map +1 -1
  50. package/dist/pipeline/run.js +16 -15
  51. package/dist/pipeline/run.js.map +1 -1
  52. package/dist/pipeline/slug.js +7 -2
  53. package/dist/pipeline/slug.js.map +1 -1
  54. package/dist/pipeline/subscription.js +91 -0
  55. package/dist/pipeline/subscription.js.map +1 -0
  56. package/dist/prune/classify.js +2 -1
  57. package/dist/prune/classify.js.map +1 -1
  58. package/dist/sources/codex/inject.js +84 -0
  59. package/dist/sources/codex/inject.js.map +1 -0
  60. package/dist/sources/codex/parser.js +141 -0
  61. package/dist/sources/codex/parser.js.map +1 -0
  62. package/dist/sources/codex/source.js +108 -0
  63. package/dist/sources/codex/source.js.map +1 -0
  64. package/dist/sources/registry.js +7 -0
  65. package/dist/sources/registry.js.map +1 -1
  66. package/package.json +2 -1
@@ -0,0 +1,141 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename } from "node:path";
3
+ import { buildRawSummary, extractToolResultContent } from "../../pipeline/parser.js";
4
+ import { renderToolResult, renderToolUse } from "../../pipeline/toolCallFilter.js";
5
+ import { stripCodexInjected } from "./inject.js";
6
+ const PATCH_FILE = /^\*\*\* (?:Add|Update|Delete) File: (.+)$/gm;
7
+ // Same text/[type] flattening the Claude parser uses for tool results.
8
+ function messageText(content) {
9
+ return extractToolResultContent(Array.isArray(content)
10
+ ? content.map((c) => {
11
+ const b = (c ?? {});
12
+ return typeof b.text === "string" ? { type: "text", text: b.text } : b;
13
+ })
14
+ : content);
15
+ }
16
+ // renderToolUse needs single-line JSON (TOOL_USE_RE in toolCallFilter).
17
+ function toolInputJson(p) {
18
+ if (typeof p.arguments === "string") {
19
+ try {
20
+ return JSON.stringify(JSON.parse(p.arguments));
21
+ }
22
+ catch {
23
+ return JSON.stringify({ arguments: p.arguments });
24
+ }
25
+ }
26
+ return JSON.stringify({ input: typeof p.input === "string" ? p.input : (p.input ?? null) });
27
+ }
28
+ // Codex rollout → ParsedSession. Reads response_item lines only: event_msg,
29
+ // turn_context, token/world-state records and `compacted` (whose
30
+ // replacement_history would double-count prose) are skipped on purpose.
31
+ export function parseCodexSession(path, hash, projectSlug) {
32
+ const lines = readFileSync(path, "utf8").split("\n").filter((l) => l.trim().length > 0);
33
+ let startedAt = null;
34
+ let endedAt = null;
35
+ let entrypoint = null;
36
+ let isSidechain = false;
37
+ let metaSeen = false;
38
+ let cwd = "";
39
+ let lineCount = 0;
40
+ let toolCallCount = 0;
41
+ const branches = [];
42
+ const files = new Set();
43
+ const userBlocks = [];
44
+ const assistantBlocks = [];
45
+ const parts = [];
46
+ const toolNameById = new Map();
47
+ for (const raw of lines) {
48
+ let evt;
49
+ try {
50
+ evt = JSON.parse(raw);
51
+ }
52
+ catch {
53
+ continue;
54
+ }
55
+ if (typeof evt.timestamp === "string") {
56
+ startedAt ??= evt.timestamp;
57
+ endedAt = evt.timestamp;
58
+ }
59
+ const p = evt.payload ?? {};
60
+ if (evt.type === "session_meta") {
61
+ if (metaSeen)
62
+ continue; // a rollout can repeat session_meta; first wins
63
+ metaSeen = true;
64
+ if (typeof p.cwd === "string")
65
+ cwd = p.cwd;
66
+ if (typeof p.originator === "string")
67
+ entrypoint = p.originator;
68
+ if (p.source !== null && typeof p.source === "object")
69
+ isSidechain = true;
70
+ const branch = p.git?.branch;
71
+ if (typeof branch === "string" && branch.length > 0 && branch !== "HEAD")
72
+ branches.push(branch);
73
+ continue;
74
+ }
75
+ if (evt.type !== "response_item")
76
+ continue;
77
+ lineCount += 1; // the heuristic filter (filter.ts) is calibrated on content lines, not telemetry
78
+ switch (p.type) {
79
+ case "message": {
80
+ const text = messageText(p.content);
81
+ if (p.role === "user") {
82
+ const kept = stripCodexInjected(text);
83
+ if (kept !== null && kept.length > 0) {
84
+ userBlocks.push(kept);
85
+ parts.push(kept);
86
+ }
87
+ }
88
+ else if (p.role === "assistant" && text.length > 0) {
89
+ assistantBlocks.push(text);
90
+ parts.push(text);
91
+ }
92
+ break; // "developer" = harness instructions, never user knowledge
93
+ }
94
+ case "function_call":
95
+ case "custom_tool_call": {
96
+ const name = typeof p.name === "string" ? p.name : "tool";
97
+ toolCallCount += 1;
98
+ if (typeof p.call_id === "string")
99
+ toolNameById.set(p.call_id, name);
100
+ const rawInput = typeof p.input === "string" ? p.input : typeof p.arguments === "string" ? p.arguments : "";
101
+ for (const m of rawInput.matchAll(PATCH_FILE))
102
+ if (m[1])
103
+ files.add(m[1].trim());
104
+ parts.push(renderToolUse(name, toolInputJson(p)));
105
+ break;
106
+ }
107
+ case "function_call_output":
108
+ case "custom_tool_call_output": {
109
+ const name = (typeof p.call_id === "string" ? toolNameById.get(p.call_id) : undefined) ?? "tool";
110
+ const out = typeof p.output === "string" ? p.output : extractToolResultContent(p.output);
111
+ parts.push(renderToolResult(name, out, false));
112
+ break;
113
+ }
114
+ default:
115
+ break; // reasoning (encrypted), agent_message, …
116
+ }
117
+ }
118
+ const userText = userBlocks.join("\n\n");
119
+ const assistantText = assistantBlocks.join("\n\n");
120
+ const filesTouched = [...files];
121
+ return {
122
+ path,
123
+ hash,
124
+ sessionId: basename(path, ".jsonl"),
125
+ projectSlug: projectSlug ?? (cwd ? basename(cwd) : basename(path)),
126
+ startedAt,
127
+ endedAt,
128
+ lineCount,
129
+ toolCallCount,
130
+ filesTouched,
131
+ assistantText,
132
+ userText,
133
+ rawSummary: buildRawSummary({ userText, assistantText, toolCallCount, filesTouched }),
134
+ transcriptText: parts.join("\n\n"),
135
+ isSidechain,
136
+ entrypoint,
137
+ branches,
138
+ agentLabel: "Codex",
139
+ };
140
+ }
141
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/sources/codex/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { closeSync, openSync, readSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { basename, dirname, join, relative, sep } from "node:path";
4
+ import { scanSessions } from "../../pipeline/scanner.js";
5
+ import { parseCodexSession } from "./parser.js";
6
+ const CHUNK = 64 * 1024;
7
+ // session_meta carries the base instructions and runs to tens of KB.
8
+ const META_CAP = 1024 * 1024;
9
+ // First line only. readTranscriptHead doesn't fit: it waits for a
10
+ // type:"user" line Codex never writes.
11
+ export function readCodexMeta(path) {
12
+ let fd;
13
+ try {
14
+ fd = openSync(path, "r");
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ try {
20
+ const chunks = [];
21
+ let total = 0;
22
+ for (;;) {
23
+ const buf = Buffer.alloc(CHUNK);
24
+ const n = readSync(fd, buf, 0, CHUNK, total);
25
+ if (n === 0)
26
+ break;
27
+ const nl = buf.subarray(0, n).indexOf(0x0a);
28
+ chunks.push(buf.subarray(0, nl === -1 ? n : nl));
29
+ total += nl === -1 ? n : nl;
30
+ if (nl !== -1)
31
+ break;
32
+ if (total > META_CAP)
33
+ return null;
34
+ }
35
+ if (total === 0 || total > META_CAP)
36
+ return null;
37
+ const evt = JSON.parse(Buffer.concat(chunks).toString("utf8"));
38
+ const p = evt.payload;
39
+ if (evt.type !== "session_meta" || !p || typeof p.cwd !== "string")
40
+ return null;
41
+ return {
42
+ cwd: p.cwd,
43
+ originator: typeof p.originator === "string" ? p.originator : null,
44
+ source: p.source ?? null,
45
+ };
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ finally {
51
+ closeSync(fd);
52
+ }
53
+ }
54
+ const WORKTREE_SEGMENT = `${sep}.claude${sep}worktrees${sep}`;
55
+ // Leaf rule, same as Claude's decodeProjectName, so a directory used from
56
+ // either agent lands in one project. Holds only while the directory exists:
57
+ // once it's deleted Claude falls back to the raw encoded dir name, while
58
+ // Codex still says the leaf. Accepted.
59
+ function codexProjectName(cwd, home) {
60
+ const scratch = join(home, "Documents", "Codex");
61
+ const rel = relative(scratch, cwd);
62
+ // rel === "" is a chat started in the scratch root itself.
63
+ if (!rel.startsWith("..") && !rel.startsWith(sep))
64
+ return "codex-scratch";
65
+ const wt = cwd.indexOf(WORKTREE_SEGMENT);
66
+ if (wt !== -1)
67
+ return basename(cwd.slice(0, wt));
68
+ return basename(cwd);
69
+ }
70
+ export function createCodexSource(root, deps = {}) {
71
+ const home = deps.home ?? homedir();
72
+ const metaByPath = new Map();
73
+ const meta = (path) => {
74
+ if (!metaByPath.has(path))
75
+ metaByPath.set(path, readCodexMeta(path));
76
+ return metaByPath.get(path) ?? null;
77
+ };
78
+ return {
79
+ id: "codex",
80
+ label: "Codex",
81
+ // ~/.codex/archived_sessions is a sibling of root and never scanned:
82
+ // archiving a thread hides it from vir.
83
+ root,
84
+ retentionDays: null,
85
+ owns: (path) => {
86
+ const rel = relative(root, path);
87
+ return rel.length > 0 && !rel.startsWith("..");
88
+ },
89
+ scan: () => scanSessions(root).map((s) => ({ ...s, source: "codex" })),
90
+ // Subagent/guardian threads carry an object `source`; humans a string.
91
+ category: (path) => {
92
+ const m = meta(path);
93
+ return m !== null && m.source !== null && typeof m.source === "object" ? "sidechain" : "session";
94
+ },
95
+ // Verified 2026-10-07 (codex-cli 0.160.1): `codex exec` writes
96
+ // source "exec", originator "codex_exec".
97
+ agentEntrypoint: (path) => {
98
+ const m = meta(path);
99
+ return m !== null && m.source === "exec" ? m.originator : null;
100
+ },
101
+ projectName: (path) => {
102
+ const m = meta(path);
103
+ return m === null ? basename(dirname(path)) : codexProjectName(m.cwd, home);
104
+ },
105
+ parse: (path, hash, slug) => parseCodexSession(path, hash, slug),
106
+ };
107
+ }
108
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/sources/codex/source.ts"],"names":[],"mappings":"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"}
@@ -2,11 +2,15 @@ import { basename, dirname } from "node:path";
2
2
  import { parseSession } from "../pipeline/parser.js";
3
3
  import { decodeProjectName, readTranscriptHead, sniffAgentEntrypoint, } from "../pipeline/projects.js";
4
4
  import { createClaudeCodeSource } from "./claudeCode.js";
5
+ import { createCodexSource } from "./codex/source.js";
5
6
  export function buildSources(cfg) {
6
7
  const sources = [];
7
8
  if (cfg.claudeProjectsDir) {
8
9
  sources.push(createClaudeCodeSource(cfg.claudeProjectsDir));
9
10
  }
11
+ if (cfg.codexSessionsDir) {
12
+ sources.push(createCodexSource(cfg.codexSessionsDir));
13
+ }
10
14
  return sources;
11
15
  }
12
16
  // A path no configured source owns (a moved root, a test fixture) keeps the
@@ -27,6 +31,9 @@ export const FALLBACK_SOURCE = {
27
31
  export function resolveSource(sources, path) {
28
32
  return sources.find((s) => s.owns(path)) ?? FALLBACK_SOURCE;
29
33
  }
34
+ export function scanLabel(sources) {
35
+ return `scanning ${sources.map((s) => s.label).join(" + ")}`;
36
+ }
30
37
  export function scanAll(sources) {
31
38
  return sources.flatMap((s) => s.scan());
32
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/sources/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,GAErB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAKzD,MAAM,UAAU,YAAY,CAAC,GAAiB;IAC5C,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,4EAA4E;AAC5E,8EAA8E;AAC9E,2DAA2D;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAkB;IAC5C,EAAE,EAAE,SAAS;IACb,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,EAAE;IACR,aAAa,EAAE,IAAI;IACnB,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI;IAChB,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;IACd,QAAQ,EAAE,GAAG,EAAE,CAAC,SAAS;IACzB,eAAe,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;IACrE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,UAAU,aAAa,CAC3B,OAAwB,EACxB,IAAY;IAEZ,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,eAAe,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAwB;IAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,+EAA+E;AAC/E,gEAAgE;AAChE,MAAM,UAAU,aAAa,CAC3B,QAA6D,EAC7D,OAAwB;IAExB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChE,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACtB,CAAC;QACD,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/sources/registry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djolex999/vir-cli",
3
- "version": "0.25.3",
3
+ "version": "0.26.1",
4
4
  "description": "An LLM Wiki for Claude Code, in your Obsidian vault.",
5
5
  "author": "Djordje Marković <djordje@growthq.rs>",
6
6
  "license": "MIT",
@@ -37,6 +37,7 @@
37
37
  ],
38
38
  "scripts": {
39
39
  "build": "tsc",
40
+ "fixture:codex": "npm run build --silent && node scripts/codex-fixture.mjs",
40
41
  "build:notifier": "native/notifier/build.sh",
41
42
  "prepublishOnly": "npm run build && npm test",
42
43
  "dev": "tsc --watch",