projectstore-codex 0.0.1 → 0.28.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 (185) hide show
  1. package/.codex-plugin/plugin.json +48 -0
  2. package/README.md +15 -7
  3. package/bin/projectstore-codex.mjs +88 -0
  4. package/hooks/hooks.json +59 -0
  5. package/node_modules/projectstore/.claude-plugin/marketplace.json +40 -0
  6. package/node_modules/projectstore/.claude-plugin/plugin.json +23 -0
  7. package/node_modules/projectstore/.mcp.json +14 -0
  8. package/node_modules/projectstore/AGENTS.md +26 -0
  9. package/node_modules/projectstore/LICENSE +21 -0
  10. package/node_modules/projectstore/README.md +284 -0
  11. package/node_modules/projectstore/agents/archaeologist.md +76 -0
  12. package/node_modules/projectstore/agents/clerk.md +93 -0
  13. package/node_modules/projectstore/agents/critic.md +94 -0
  14. package/node_modules/projectstore/agents/librarian.md +81 -0
  15. package/node_modules/projectstore/agents/planner.md +80 -0
  16. package/node_modules/projectstore/agents/reviewer.md +98 -0
  17. package/node_modules/projectstore/bin/projectstore.mjs +7 -0
  18. package/node_modules/projectstore/commands/adr.md +57 -0
  19. package/node_modules/projectstore/commands/agents.md +180 -0
  20. package/node_modules/projectstore/commands/bind.md +128 -0
  21. package/node_modules/projectstore/commands/codemap.md +50 -0
  22. package/node_modules/projectstore/commands/concept.md +17 -0
  23. package/node_modules/projectstore/commands/doctor.md +166 -0
  24. package/node_modules/projectstore/commands/epic.md +40 -0
  25. package/node_modules/projectstore/commands/graph.md +56 -0
  26. package/node_modules/projectstore/commands/kanban.md +40 -0
  27. package/node_modules/projectstore/commands/meeting.md +17 -0
  28. package/node_modules/projectstore/commands/reconcile.md +73 -0
  29. package/node_modules/projectstore/commands/research.md +17 -0
  30. package/node_modules/projectstore/commands/review.md +89 -0
  31. package/node_modules/projectstore/commands/runbook.md +17 -0
  32. package/node_modules/projectstore/commands/scaffold.md +23 -0
  33. package/node_modules/projectstore/commands/search.md +22 -0
  34. package/node_modules/projectstore/commands/spec.md +91 -0
  35. package/node_modules/projectstore/commands/status.md +27 -0
  36. package/node_modules/projectstore/commands/statusline.md +46 -0
  37. package/node_modules/projectstore/commands/story.md +113 -0
  38. package/node_modules/projectstore/docs/extending.md +172 -0
  39. package/node_modules/projectstore/docs/getting-started.md +133 -0
  40. package/node_modules/projectstore/docs/harnesses.md +163 -0
  41. package/node_modules/projectstore/docs/how-it-works.md +263 -0
  42. package/node_modules/projectstore/docs/images/loop-light.svg +94 -0
  43. package/node_modules/projectstore/docs/images/loop.svg +93 -0
  44. package/node_modules/projectstore/docs/images/statusline-hud.png +0 -0
  45. package/node_modules/projectstore/docs/images/team-light.svg +79 -0
  46. package/node_modules/projectstore/docs/images/team.svg +79 -0
  47. package/node_modules/projectstore/harnesses/claude-code.json +483 -0
  48. package/node_modules/projectstore/harnesses/codex.json +332 -0
  49. package/node_modules/projectstore/hooks/hooks.json +59 -0
  50. package/node_modules/projectstore/hooks/pre-compact.mjs +121 -0
  51. package/node_modules/projectstore/hooks/session-rules.mjs +63 -0
  52. package/node_modules/projectstore/hooks/session-start.mjs +301 -0
  53. package/node_modules/projectstore/hooks/session-stop.mjs +84 -0
  54. package/node_modules/projectstore/package.json +70 -0
  55. package/node_modules/projectstore/scaffold/checklists.json +88 -0
  56. package/node_modules/projectstore/scaffold/headings.json +171 -0
  57. package/node_modules/projectstore/scaffold/layouts/engineering.json +85 -0
  58. package/node_modules/projectstore/scripts/binding.mjs +165 -0
  59. package/node_modules/projectstore/scripts/build-adapters.mjs +264 -0
  60. package/node_modules/projectstore/scripts/cli.mjs +595 -0
  61. package/node_modules/projectstore/scripts/codemap.mjs +99 -0
  62. package/node_modules/projectstore/scripts/diff-refs.mjs +127 -0
  63. package/node_modules/projectstore/scripts/doctor.mjs +2127 -0
  64. package/node_modules/projectstore/scripts/draft.mjs +261 -0
  65. package/node_modules/projectstore/scripts/graph.mjs +219 -0
  66. package/node_modules/projectstore/scripts/harness.mjs +608 -0
  67. package/node_modules/projectstore/scripts/install-harness.mjs +1387 -0
  68. package/node_modules/projectstore/scripts/kanban.mjs +174 -0
  69. package/node_modules/projectstore/scripts/lib.mjs +3085 -0
  70. package/node_modules/projectstore/scripts/mcp.mjs +391 -0
  71. package/node_modules/projectstore/scripts/portable-registration.mjs +198 -0
  72. package/node_modules/projectstore/scripts/provenance.mjs +375 -0
  73. package/node_modules/projectstore/scripts/query.mjs +490 -0
  74. package/node_modules/projectstore/scripts/reconcile.mjs +422 -0
  75. package/node_modules/projectstore/scripts/statusline-launcher.mjs +141 -0
  76. package/node_modules/projectstore/scripts/statusline.mjs +253 -0
  77. package/node_modules/projectstore/scripts/story-section.mjs +209 -0
  78. package/node_modules/projectstore/scripts/surfaces.mjs +421 -0
  79. package/node_modules/projectstore/scripts/tokens.mjs +449 -0
  80. package/node_modules/projectstore/scripts/touch-session.mjs +336 -0
  81. package/node_modules/projectstore/scripts/version-guard.mjs +255 -0
  82. package/node_modules/projectstore/scripts/worktree.mjs +109 -0
  83. package/node_modules/projectstore/skills/projectstore-decision-detector/SKILL.md +40 -0
  84. package/node_modules/projectstore/skills/projectstore-peer-reviewer/SKILL.md +38 -0
  85. package/node_modules/projectstore/skills/projectstore-story-completion/SKILL.md +50 -0
  86. package/node_modules/projectstore/skills/projectstore-vault-communication/SKILL.md +96 -0
  87. package/node_modules/projectstore/templates/claude-md-block.md.tmpl +26 -0
  88. package/node_modules/projectstore/templates/de/adr.md.tmpl +67 -0
  89. package/node_modules/projectstore/templates/de/concept.md.tmpl +43 -0
  90. package/node_modules/projectstore/templates/de/epic.md.tmpl +59 -0
  91. package/node_modules/projectstore/templates/de/folder-readme.md.tmpl +14 -0
  92. package/node_modules/projectstore/templates/de/kanban.md.tmpl +36 -0
  93. package/node_modules/projectstore/templates/de/meeting.md.tmpl +38 -0
  94. package/node_modules/projectstore/templates/de/research.md.tmpl +47 -0
  95. package/node_modules/projectstore/templates/de/runbook.md.tmpl +53 -0
  96. package/node_modules/projectstore/templates/de/spec.md.tmpl +64 -0
  97. package/node_modules/projectstore/templates/de/story.md.tmpl +76 -0
  98. package/node_modules/projectstore/templates/de/strings.json +6 -0
  99. package/node_modules/projectstore/templates/en/adr.md.tmpl +67 -0
  100. package/node_modules/projectstore/templates/en/concept.md.tmpl +43 -0
  101. package/node_modules/projectstore/templates/en/epic.md.tmpl +59 -0
  102. package/node_modules/projectstore/templates/en/folder-readme.md.tmpl +14 -0
  103. package/node_modules/projectstore/templates/en/kanban.md.tmpl +36 -0
  104. package/node_modules/projectstore/templates/en/meeting.md.tmpl +38 -0
  105. package/node_modules/projectstore/templates/en/research.md.tmpl +47 -0
  106. package/node_modules/projectstore/templates/en/runbook.md.tmpl +53 -0
  107. package/node_modules/projectstore/templates/en/spec.md.tmpl +64 -0
  108. package/node_modules/projectstore/templates/en/story.md.tmpl +76 -0
  109. package/node_modules/projectstore/templates/en/strings.json +6 -0
  110. package/node_modules/projectstore/templates/es/adr.md.tmpl +67 -0
  111. package/node_modules/projectstore/templates/es/concept.md.tmpl +43 -0
  112. package/node_modules/projectstore/templates/es/epic.md.tmpl +59 -0
  113. package/node_modules/projectstore/templates/es/folder-readme.md.tmpl +14 -0
  114. package/node_modules/projectstore/templates/es/kanban.md.tmpl +36 -0
  115. package/node_modules/projectstore/templates/es/meeting.md.tmpl +38 -0
  116. package/node_modules/projectstore/templates/es/research.md.tmpl +47 -0
  117. package/node_modules/projectstore/templates/es/runbook.md.tmpl +53 -0
  118. package/node_modules/projectstore/templates/es/spec.md.tmpl +64 -0
  119. package/node_modules/projectstore/templates/es/story.md.tmpl +76 -0
  120. package/node_modules/projectstore/templates/es/strings.json +6 -0
  121. package/node_modules/projectstore/templates/fr/adr.md.tmpl +67 -0
  122. package/node_modules/projectstore/templates/fr/concept.md.tmpl +43 -0
  123. package/node_modules/projectstore/templates/fr/epic.md.tmpl +59 -0
  124. package/node_modules/projectstore/templates/fr/folder-readme.md.tmpl +14 -0
  125. package/node_modules/projectstore/templates/fr/kanban.md.tmpl +36 -0
  126. package/node_modules/projectstore/templates/fr/meeting.md.tmpl +38 -0
  127. package/node_modules/projectstore/templates/fr/research.md.tmpl +47 -0
  128. package/node_modules/projectstore/templates/fr/runbook.md.tmpl +53 -0
  129. package/node_modules/projectstore/templates/fr/spec.md.tmpl +64 -0
  130. package/node_modules/projectstore/templates/fr/story.md.tmpl +76 -0
  131. package/node_modules/projectstore/templates/fr/strings.json +6 -0
  132. package/node_modules/projectstore/templates/ru/adr.md.tmpl +67 -0
  133. package/node_modules/projectstore/templates/ru/concept.md.tmpl +43 -0
  134. package/node_modules/projectstore/templates/ru/epic.md.tmpl +59 -0
  135. package/node_modules/projectstore/templates/ru/folder-readme.md.tmpl +14 -0
  136. package/node_modules/projectstore/templates/ru/kanban.md.tmpl +36 -0
  137. package/node_modules/projectstore/templates/ru/meeting.md.tmpl +38 -0
  138. package/node_modules/projectstore/templates/ru/research.md.tmpl +47 -0
  139. package/node_modules/projectstore/templates/ru/runbook.md.tmpl +53 -0
  140. package/node_modules/projectstore/templates/ru/spec.md.tmpl +64 -0
  141. package/node_modules/projectstore/templates/ru/story.md.tmpl +76 -0
  142. package/node_modules/projectstore/templates/ru/strings.json +6 -0
  143. package/node_modules/projectstore/templates/zh/adr.md.tmpl +67 -0
  144. package/node_modules/projectstore/templates/zh/concept.md.tmpl +43 -0
  145. package/node_modules/projectstore/templates/zh/epic.md.tmpl +59 -0
  146. package/node_modules/projectstore/templates/zh/folder-readme.md.tmpl +14 -0
  147. package/node_modules/projectstore/templates/zh/kanban.md.tmpl +36 -0
  148. package/node_modules/projectstore/templates/zh/meeting.md.tmpl +38 -0
  149. package/node_modules/projectstore/templates/zh/research.md.tmpl +47 -0
  150. package/node_modules/projectstore/templates/zh/runbook.md.tmpl +53 -0
  151. package/node_modules/projectstore/templates/zh/spec.md.tmpl +64 -0
  152. package/node_modules/projectstore/templates/zh/story.md.tmpl +76 -0
  153. package/node_modules/projectstore/templates/zh/strings.json +6 -0
  154. package/package.json +36 -14
  155. package/plugin.json +53 -0
  156. package/skills/projectstore-adr/SKILL.md +76 -0
  157. package/skills/projectstore-agents/SKILL.md +50 -0
  158. package/skills/projectstore-archaeologist/SKILL.md +109 -0
  159. package/skills/projectstore-bind/SKILL.md +44 -0
  160. package/skills/projectstore-clerk/SKILL.md +126 -0
  161. package/skills/projectstore-codemap/SKILL.md +69 -0
  162. package/skills/projectstore-concept/SKILL.md +36 -0
  163. package/skills/projectstore-critic/SKILL.md +127 -0
  164. package/skills/projectstore-decision-detector/SKILL.md +59 -0
  165. package/skills/projectstore-doctor/SKILL.md +33 -0
  166. package/skills/projectstore-epic/SKILL.md +59 -0
  167. package/skills/projectstore-graph/SKILL.md +75 -0
  168. package/skills/projectstore-kanban/SKILL.md +60 -0
  169. package/skills/projectstore-librarian/SKILL.md +114 -0
  170. package/skills/projectstore-meeting/SKILL.md +36 -0
  171. package/skills/projectstore-peer-reviewer/SKILL.md +57 -0
  172. package/skills/projectstore-planner/SKILL.md +113 -0
  173. package/skills/projectstore-reconcile/SKILL.md +92 -0
  174. package/skills/projectstore-research/SKILL.md +36 -0
  175. package/skills/projectstore-review/SKILL.md +108 -0
  176. package/skills/projectstore-reviewer/SKILL.md +131 -0
  177. package/skills/projectstore-runbook/SKILL.md +36 -0
  178. package/skills/projectstore-scaffold/SKILL.md +42 -0
  179. package/skills/projectstore-search/SKILL.md +41 -0
  180. package/skills/projectstore-spec/SKILL.md +110 -0
  181. package/skills/projectstore-status/SKILL.md +47 -0
  182. package/skills/projectstore-statusline/SKILL.md +29 -0
  183. package/skills/projectstore-story/SKILL.md +132 -0
  184. package/skills/projectstore-story-completion/SKILL.md +69 -0
  185. package/skills/projectstore-vault-communication/SKILL.md +115 -0
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ // projectstore — codemap.mjs
3
+ // Derives code-map.md — the epic↔code overview — from epic/story frontmatter
4
+ // `code_refs` (ADR-004). Same one-way pattern as kanban.mjs: frontmatter is
5
+ // the source of truth, this file is a regenerated view.
6
+ //
7
+ // Output: JSON { path, content, stats } — compute only. The applier is
8
+ // reconcile.mjs --write (atomic replace, recompute-at-write), not the
9
+ // harness: no Write-tool step remains in the derived-view flows.
10
+
11
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { readConfig, loadLayout, folderByKind, parseFrontmatter, nowIso, isMain } from "./lib.mjs";
14
+
15
+ function die(msg) {
16
+ process.stderr.write(`projectstore/codemap: ${msg}\n`);
17
+ process.exit(1);
18
+ }
19
+
20
+ function parseRefs(raw) {
21
+ if (!raw || raw === "[]") return [];
22
+ try {
23
+ const v = JSON.parse(raw);
24
+ return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
25
+ } catch {
26
+ return [];
27
+ }
28
+ }
29
+
30
+ function main() {
31
+ const cfg = readConfig();
32
+ if (!cfg) die("No projectstore config. Run /projectstore:bind first.");
33
+ const layout = loadLayout(cfg.layout);
34
+ const folder = folderByKind(layout, "epic");
35
+ if (!folder) die("Layout has no epic folder — nothing to map.");
36
+
37
+ const root = join(cfg.vault_path, folder.path);
38
+ const epics = [];
39
+ const storyRows = [];
40
+ if (existsSync(root)) {
41
+ for (const id of readdirSync(root).sort()) {
42
+ const epicMd = join(root, id, "epic.md");
43
+ if (!existsSync(epicMd)) continue;
44
+ const fm = parseFrontmatter(readFileSync(epicMd, "utf8")).data;
45
+ epics.push({ id, title: fm.title || id, status: fm.status || "planned", refs: parseRefs(fm.code_refs) });
46
+ const storiesDir = join(root, id, "stories");
47
+ if (!existsSync(storiesDir)) continue;
48
+ for (const f of readdirSync(storiesDir).sort()) {
49
+ if (!f.endsWith(".md")) continue;
50
+ const sfm = parseFrontmatter(readFileSync(join(storiesDir, f), "utf8")).data;
51
+ const refs = parseRefs(sfm.code_refs);
52
+ if (refs.length) {
53
+ storyRows.push({ epic: id, story: f.replace(/\.md$/, ""), title: sfm.title || f, refs });
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ const lines = [
60
+ "---",
61
+ "",
62
+ "projectstore: derived",
63
+ // Full ISO, not date-only: freshness comparison on an active day is
64
+ // ill-defined otherwise (spec contract 6). Normalizers strip the line.
65
+ `generated_at: ${nowIso()}`,
66
+ "",
67
+ "---",
68
+ "",
69
+ "# Code map",
70
+ "",
71
+ "Epic ↔ code mapping, derived from frontmatter `code_refs` (source of truth).",
72
+ "Regenerate via `/projectstore:codemap`; edit refs via `/projectstore:codemap set`.",
73
+ "",
74
+ "| Epic | Title | Status | code_refs |",
75
+ "|------|-------|--------|-----------|",
76
+ ];
77
+ for (const e of epics) {
78
+ const refs = e.refs.length ? e.refs.map((r) => `\`${r}\``).join(", ") : "—";
79
+ lines.push(`| [[${folder.path}/${e.id}/epic\\|${e.id}]] | ${e.title} | ${e.status} | ${refs} |`);
80
+ }
81
+ if (storyRows.length) {
82
+ lines.push("", "## Story-level refs (files each story touched)", "",
83
+ "| Epic | Story | code_refs |", "|------|-------|-----------|");
84
+ for (const s of storyRows) {
85
+ lines.push(`| ${s.epic} | ${s.title} | ${s.refs.map((r) => `\`${r}\``).join(", ")} |`);
86
+ }
87
+ }
88
+ lines.push("");
89
+
90
+ process.stdout.write(JSON.stringify({
91
+ path: join(cfg.vault_path, "code-map.md"),
92
+ content: lines.join("\n"),
93
+ stats: { epics: epics.length, epics_with_refs: epics.filter((e) => e.refs.length).length, story_rows: storyRows.length },
94
+ }, null, 2) + "\n");
95
+ }
96
+
97
+ if (isMain(import.meta.url)) {
98
+ main();
99
+ }
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ // projectstore — diff-refs.mjs (PS-SPEC story-009)
3
+ // Computes the files a story touched, for the reviewer's proposed code_refs.
4
+ // Our own extension: neither Backlog.md nor projectstore derived code mapping
5
+ // from git before this. Pure compute — the write path stays
6
+ // /projectstore:codemap set, approval-gated.
7
+ //
8
+ // node diff-refs.mjs --since <iso-timestamp> [--range <git-range>]
9
+ //
10
+ // Range derivation is STORY-SCOPED: `--since` is the story's started_at (set
11
+ // by /projectstore:story plan). Branch-wide ranges (merge-base..HEAD) are
12
+ // deliberately not the default — shared feature branches over-attribute and
13
+ // direct-to-main work yields an empty diff (research note, adoption item 3).
14
+ // Output: { since, range, files, uncommitted, fallback } — fallback=true
15
+ // means the caller must ask the user for an explicit range instead of
16
+ // guessing.
17
+ //
18
+ // Git runs in the PROJECT (the directory the harness hands us), never the vault — the vault
19
+ // is typically not a git repository.
20
+
21
+ import { spawnSync } from "node:child_process";
22
+ import { resolve } from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+ import { projectRoot, SOURCE_IGNORE } from "./lib.mjs";
25
+
26
+ // One definition, in lib.mjs, shared with the entry-rule hook and doctor —
27
+ // three consumers of "is this a source file" that must not drift apart.
28
+ const IGNORE = SOURCE_IGNORE;
29
+
30
+ // The default 15 s is a batch budget — diff-refs runs off the hot path. A caller
31
+ // on a user-facing path must pass its own: SessionStart's gather budget is 200 ms,
32
+ // so a stalled git there would hold session start for fifteen seconds.
33
+ export function gitIn(cwd, args, { timeout = 15000 } = {}) {
34
+ const r = spawnSync("git", args, {
35
+ cwd,
36
+ encoding: "utf8",
37
+ timeout,
38
+ });
39
+ return r.status === 0 ? r.stdout : null;
40
+ }
41
+
42
+ const git = (args) => gitIn(projectRoot(), args);
43
+
44
+ // Doctor's only route to git. Kept here rather than in lib.mjs, whose header
45
+ // pins it as dependency-free with no subprocess anywhere.
46
+ export function uncommittedProjectFiles(cwd = projectRoot(), ignore = IGNORE) {
47
+ // A non-repository, a shallow clone with no HEAD, or a detached worktree with
48
+ // no commits all make these fail — null means "cannot tell", which is not the
49
+ // same as "nothing uncommitted" and must not be reported as a finding.
50
+ const tracked = gitIn(cwd, ["diff", "--name-only", "HEAD"]);
51
+ const untracked = gitIn(cwd, ["ls-files", "--others", "--exclude-standard"]);
52
+ if (tracked === null && untracked === null) return null;
53
+ return [...new Set([...(tracked || "").split("\n"), ...(untracked || "").split("\n")])]
54
+ .map((f) => f.trim())
55
+ .filter((f) => f && !ignore.some((rx) => rx.test(f)))
56
+ .sort();
57
+ }
58
+
59
+ // Newest commit timestamp, ms, or null when git cannot answer.
60
+ export function lastCommitMs(cwd = projectRoot()) {
61
+ const out = gitIn(cwd, ["log", "-1", "--format=%cI"]);
62
+ if (!out) return null;
63
+ const t = Date.parse(out.trim());
64
+ return Number.isFinite(t) ? t : null;
65
+ }
66
+
67
+ function filterFiles(list) {
68
+ return [...new Set(list)]
69
+ .map((f) => f.trim())
70
+ .filter((f) => f && !IGNORE.some((rx) => rx.test(f)))
71
+ .sort();
72
+ }
73
+
74
+ function main() {
75
+ const args = process.argv.slice(2);
76
+ const since = args.includes("--since") ? args[args.indexOf("--since") + 1] : null;
77
+ const range = args.includes("--range") ? args[args.indexOf("--range") + 1] : null;
78
+
79
+ let committed = [];
80
+ let usedRange = null;
81
+ if (range) {
82
+ const out = git(["diff", "--name-only", range]);
83
+ if (out === null) {
84
+ process.stdout.write(JSON.stringify({ error: `git diff ${range} failed`, fallback: true }) + "\n");
85
+ return;
86
+ }
87
+ committed = out.split("\n");
88
+ usedRange = range;
89
+ } else if (since) {
90
+ // committer-date window; work committed before the story went in-progress
91
+ // is invisible by design (story-scoped attribution).
92
+ //
93
+ // A bare YYYY-MM-DD gets midnight appended, and it is not cosmetic. Git's
94
+ // approxidate reads a date with no time as THAT DATE AT THE CURRENT TIME OF
95
+ // DAY, so `--since=2026-09-08` run at 17:46 silently excludes everything
96
+ // committed earlier the same day. `started_at` is written as a bare date,
97
+ // so a story started and finished in one day proposed `files: []` and the
98
+ // caller had no way to tell that from "nothing was committed" (measured
99
+ // 2026-09-08: --since=2026-09-08 returned nothing while
100
+ // --since="2026-09-08 00:00" returned the day's commit).
101
+ const window = /^\d{4}-\d{2}-\d{2}$/.test(since) ? `${since} 00:00:00` : since;
102
+ const out = git(["log", `--since=${window}`, "--name-only", "--pretty=format:"]);
103
+ committed = out ? out.split("\n") : [];
104
+ usedRange = `--since=${window}`;
105
+ }
106
+
107
+ // ls-files --others expands untracked DIRECTORIES to individual files
108
+ // (porcelain would collapse them to "tests/") and needs no column slicing.
109
+ const uncommitted = filterFiles([
110
+ ...(git(["diff", "--name-only", "HEAD"]) || "").split("\n"),
111
+ ...(git(["ls-files", "--others", "--exclude-standard"]) || "").split("\n"),
112
+ ]);
113
+ const files = filterFiles(committed);
114
+
115
+ const fallback = !range && !since || (files.length === 0 && uncommitted.length === 0);
116
+ process.stdout.write(JSON.stringify({
117
+ since: since || null,
118
+ range: usedRange,
119
+ files,
120
+ uncommitted,
121
+ fallback,
122
+ }, null, 2) + "\n");
123
+ }
124
+
125
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
126
+ main();
127
+ }