project-librarian 0.2.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/LICENSE +21 -0
- package/README.ja.md +227 -0
- package/README.ko.md +229 -0
- package/README.md +280 -0
- package/README.zh.md +227 -0
- package/SKILL.md +335 -0
- package/agents/openai.yaml +3 -0
- package/dist/args.js +235 -0
- package/dist/code-index-db.js +34 -0
- package/dist/code-index-file-policy.js +120 -0
- package/dist/code-index-sql.js +9 -0
- package/dist/code-index.js +1856 -0
- package/dist/hooks.js +321 -0
- package/dist/init-project-wiki.js +246 -0
- package/dist/install-skill.js +142 -0
- package/dist/migration.js +356 -0
- package/dist/modes.js +823 -0
- package/dist/templates.js +552 -0
- package/dist/types.js +2 -0
- package/dist/wiki-files.js +289 -0
- package/dist/workspace.js +212 -0
- package/package.json +71 -0
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.gitWikiCommitTrailersScript = exports.gitPrepareCommitMsgHook = exports.hookScript = void 0;
|
|
37
|
+
exports.upsertGitHooksPath = upsertGitHooksPath;
|
|
38
|
+
exports.upsertHookConfig = upsertHookConfig;
|
|
39
|
+
exports.upsertClaudeHookConfig = upsertClaudeHookConfig;
|
|
40
|
+
const childProcess = __importStar(require("node:child_process"));
|
|
41
|
+
const args_1 = require("./args");
|
|
42
|
+
const workspace_1 = require("./workspace");
|
|
43
|
+
function upsertGitHooksPath() {
|
|
44
|
+
if (args_1.noGitConfigMode)
|
|
45
|
+
return "skipped-no-git-config";
|
|
46
|
+
if (!(0, workspace_1.isGitRepository)())
|
|
47
|
+
return "skipped-no-git";
|
|
48
|
+
let previous = "";
|
|
49
|
+
try {
|
|
50
|
+
previous = childProcess.execFileSync("git", ["config", "--get", "core.hooksPath"], {
|
|
51
|
+
cwd: workspace_1.root,
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
54
|
+
}).trim();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
previous = "";
|
|
58
|
+
}
|
|
59
|
+
if (previous === ".githooks")
|
|
60
|
+
return "exists";
|
|
61
|
+
if (previous)
|
|
62
|
+
return `skipped-existing-hooksPath ${previous}`;
|
|
63
|
+
childProcess.execFileSync("git", ["config", "core.hooksPath", ".githooks"], {
|
|
64
|
+
cwd: workspace_1.root,
|
|
65
|
+
stdio: "ignore",
|
|
66
|
+
});
|
|
67
|
+
return previous ? `updated from ${previous}` : "configured";
|
|
68
|
+
}
|
|
69
|
+
function buildHookCommand(command, timeout) {
|
|
70
|
+
const hook = { type: "command", command };
|
|
71
|
+
if (typeof timeout === "number")
|
|
72
|
+
hook.timeout = timeout;
|
|
73
|
+
return hook;
|
|
74
|
+
}
|
|
75
|
+
function upsertSessionStartHookConfig(relativePath, command, matchers, timeout) {
|
|
76
|
+
const config = (0, workspace_1.parseJson)(relativePath, { hooks: {} });
|
|
77
|
+
if (!config.hooks || typeof config.hooks !== "object" || Array.isArray(config.hooks)) {
|
|
78
|
+
config.hooks = {};
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(config.hooks.SessionStart))
|
|
81
|
+
config.hooks.SessionStart = [];
|
|
82
|
+
const sessionStart = config.hooks.SessionStart.flatMap((entry) => {
|
|
83
|
+
if (!Array.isArray(entry?.hooks))
|
|
84
|
+
return [entry];
|
|
85
|
+
const hooks = entry.hooks.filter((hook) => hook?.command !== command);
|
|
86
|
+
return hooks.length > 0 ? [{ ...entry, hooks }] : [];
|
|
87
|
+
});
|
|
88
|
+
for (const matcher of matchers) {
|
|
89
|
+
const existing = sessionStart.find((entry) => entry?.matcher === matcher && Array.isArray(entry.hooks));
|
|
90
|
+
if (existing) {
|
|
91
|
+
existing.hooks = [...existing.hooks, buildHookCommand(command, timeout)];
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
sessionStart.push({
|
|
95
|
+
matcher,
|
|
96
|
+
hooks: [buildHookCommand(command, timeout)],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
config.hooks.SessionStart = sessionStart;
|
|
101
|
+
const next = `${JSON.stringify(config, null, 2)}\n`;
|
|
102
|
+
const previous = (0, workspace_1.exists)(relativePath) ? (0, workspace_1.read)(relativePath) : "";
|
|
103
|
+
(0, workspace_1.write)(relativePath, next);
|
|
104
|
+
return previous === next ? "exists" : previous ? "updated" : "created";
|
|
105
|
+
}
|
|
106
|
+
function upsertHookConfig() {
|
|
107
|
+
return upsertSessionStartHookConfig(".codex/hooks.json", "node .codex/hooks/wiki-session-start.js", ["startup|resume|clear"], 10);
|
|
108
|
+
}
|
|
109
|
+
function upsertClaudeHookConfig() {
|
|
110
|
+
return upsertSessionStartHookConfig(".claude/settings.json", "node .claude/hooks/wiki-session-start.js", ["startup", "resume", "clear", "compact"]);
|
|
111
|
+
}
|
|
112
|
+
exports.hookScript = `#!/usr/bin/env node
|
|
113
|
+
|
|
114
|
+
const fs = require("fs");
|
|
115
|
+
const path = require("path");
|
|
116
|
+
|
|
117
|
+
function readHookInput() {
|
|
118
|
+
try {
|
|
119
|
+
const stat = fs.fstatSync(0);
|
|
120
|
+
if (!stat.isFIFO() && !stat.isFile()) return {};
|
|
121
|
+
const raw = fs.readFileSync(0, "utf8").trim();
|
|
122
|
+
if (!raw) return {};
|
|
123
|
+
return JSON.parse(raw);
|
|
124
|
+
} catch {
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const hookInput = readHookInput();
|
|
130
|
+
const cwd = process.env.CODEX_WORKSPACE_DIR || hookInput.cwd || process.cwd();
|
|
131
|
+
|
|
132
|
+
function readIfExists(relativePath, maxChars) {
|
|
133
|
+
const filePath = path.join(cwd, relativePath);
|
|
134
|
+
try {
|
|
135
|
+
const text = fs.readFileSync(filePath, "utf8").trim();
|
|
136
|
+
if (text.length <= maxChars) return text;
|
|
137
|
+
return \`\${text.slice(0, maxChars)}\\n\\n[truncated: \${relativePath}]\`;
|
|
138
|
+
} catch {
|
|
139
|
+
return "";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const files = [
|
|
144
|
+
["wiki/startup.md", 3500],
|
|
145
|
+
["wiki/index.md", 4500],
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
const sections = files
|
|
149
|
+
.map(([relativePath, maxChars]) => {
|
|
150
|
+
const text = readIfExists(relativePath, maxChars);
|
|
151
|
+
if (!text) return "";
|
|
152
|
+
return \`## \${relativePath}\\n\\n\${text}\`;
|
|
153
|
+
})
|
|
154
|
+
.filter(Boolean);
|
|
155
|
+
|
|
156
|
+
const additionalContext = [
|
|
157
|
+
"[Project wiki startup review]",
|
|
158
|
+
"Use ./wiki as the project-planning source of truth only. Start with compact routing context; read detailed project canonical, decision, or meta files on demand.",
|
|
159
|
+
"Project canonical content language is selected from user/project context; do not assume a fixed default language.",
|
|
160
|
+
"When project planning content is added, changed, or removed, update ./wiki in the same turn.",
|
|
161
|
+
"Do not put non-project LLM memory or collaboration instructions in project canonical/decision docs; use AGENTS.md, wiki/AGENTS.md, hooks, or skills.",
|
|
162
|
+
"",
|
|
163
|
+
...sections,
|
|
164
|
+
].join("\\n");
|
|
165
|
+
|
|
166
|
+
process.stdout.write(JSON.stringify({
|
|
167
|
+
continue: true,
|
|
168
|
+
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext },
|
|
169
|
+
}));
|
|
170
|
+
`;
|
|
171
|
+
exports.gitPrepareCommitMsgHook = `#!/bin/sh
|
|
172
|
+
MSG_FILE="$1"
|
|
173
|
+
SOURCE="$2"
|
|
174
|
+
|
|
175
|
+
case "$SOURCE" in
|
|
176
|
+
merge|squash|commit)
|
|
177
|
+
exit 0
|
|
178
|
+
;;
|
|
179
|
+
esac
|
|
180
|
+
|
|
181
|
+
if command -v node >/dev/null 2>&1 && [ -f ".githooks/wiki-commit-trailers.js" ]; then
|
|
182
|
+
node .githooks/wiki-commit-trailers.js "$MSG_FILE"
|
|
183
|
+
fi
|
|
184
|
+
`;
|
|
185
|
+
exports.gitWikiCommitTrailersScript = `#!/usr/bin/env node
|
|
186
|
+
|
|
187
|
+
const fs = require("fs");
|
|
188
|
+
const path = require("path");
|
|
189
|
+
const childProcess = require("child_process");
|
|
190
|
+
|
|
191
|
+
const messagePath = process.argv[2];
|
|
192
|
+
if (!messagePath) process.exit(0);
|
|
193
|
+
|
|
194
|
+
function runGit(args) {
|
|
195
|
+
try {
|
|
196
|
+
return childProcess.execFileSync("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
197
|
+
} catch {
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function commandOk(command, args) {
|
|
203
|
+
try {
|
|
204
|
+
childProcess.execFileSync(command, args, { stdio: "ignore" });
|
|
205
|
+
return true;
|
|
206
|
+
} catch {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function existingFile(relativePath) {
|
|
212
|
+
try {
|
|
213
|
+
return fs.readFileSync(relativePath, "utf8");
|
|
214
|
+
} catch {
|
|
215
|
+
return "";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function truncateList(items) {
|
|
220
|
+
if (items.length === 0) return "none";
|
|
221
|
+
if (items.length <= 3) return items.join(", ");
|
|
222
|
+
return items.slice(0, 3).join(", ") + ", +" + String(items.length - 3);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function metadataLine(text, label) {
|
|
226
|
+
const match = text.match(new RegExp("^- " + label + ":\\\\s*(.+)$", "m"));
|
|
227
|
+
return match ? match[1].trim() : "";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function migrationStatus(files) {
|
|
231
|
+
const hasMigration = files.some((file) => file.startsWith("wiki/migration/") || file.endsWith("/migration-inbox.md"));
|
|
232
|
+
if (!hasMigration) return "n/a";
|
|
233
|
+
const text = existingFile("wiki/migration/verification.md") + "\\n" + existingFile("wiki/migration/review.md");
|
|
234
|
+
const coverage = metadataLine(text, "coverage") || "unknown";
|
|
235
|
+
const semantic = metadataLine(text, "semantic migration complete") || "unknown";
|
|
236
|
+
const pending = metadataLine(text, "pending") || "unknown";
|
|
237
|
+
const needsHuman = metadataLine(text, "needs-human-review") || "unknown";
|
|
238
|
+
return "coverage " + coverage + "; semantic complete " + semantic + "; pending " + pending + "; needs-human-review " + needsHuman;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function wikiScope(files) {
|
|
242
|
+
const scopes = [];
|
|
243
|
+
const add = (name) => {
|
|
244
|
+
if (!scopes.includes(name)) scopes.push(name);
|
|
245
|
+
};
|
|
246
|
+
for (const file of files) {
|
|
247
|
+
if (file.startsWith("wiki/canonical/")) add("canonical");
|
|
248
|
+
else if (file.startsWith("wiki/decisions/")) add("decisions");
|
|
249
|
+
else if (file.startsWith("wiki/meta/")) add("meta");
|
|
250
|
+
else if (file.startsWith("wiki/sources/")) add("sources");
|
|
251
|
+
else if (file.startsWith("wiki/migration/") || file.endsWith("/migration-inbox.md")) add("migration");
|
|
252
|
+
else if (file === "wiki/startup.md") add("startup");
|
|
253
|
+
else if (file === "wiki/index.md") add("index");
|
|
254
|
+
else if (file.startsWith(".codex/hooks/") || file === ".codex/hooks.json") add("codex-hooks");
|
|
255
|
+
else if (file.startsWith(".claude/hooks/") || file === ".claude/settings.json") add("claude-hooks");
|
|
256
|
+
else if (file === "AGENTS.md" || file === "CLAUDE.md") add("agents");
|
|
257
|
+
else if (file.startsWith(".githooks/")) add("git-hooks");
|
|
258
|
+
else if (file.startsWith("tools/project-librarian/")) add("skill");
|
|
259
|
+
}
|
|
260
|
+
return scopes.length === 0 ? "none" : scopes.join(", ");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function validationTrailers() {
|
|
264
|
+
const home = process.env.HOME || "";
|
|
265
|
+
const lintScript = [
|
|
266
|
+
"tools/project-librarian/dist/init-project-wiki.js",
|
|
267
|
+
path.join(home, ".codex/skills/project-librarian/dist/init-project-wiki.js"),
|
|
268
|
+
path.join(home, ".claude/skills/project-librarian/dist/init-project-wiki.js"),
|
|
269
|
+
].find((candidate) => fs.existsSync(candidate));
|
|
270
|
+
const lintOk = Boolean(lintScript) && commandOk("node", [lintScript, "--lint"]);
|
|
271
|
+
const codexSessionHookOk = fs.existsSync(".codex/hooks/wiki-session-start.js") && commandOk("node", [".codex/hooks/wiki-session-start.js"]);
|
|
272
|
+
const claudeSessionHookOk = fs.existsSync(".claude/hooks/wiki-session-start.js") && commandOk("node", [".claude/hooks/wiki-session-start.js"]);
|
|
273
|
+
if (lintOk && codexSessionHookOk && claudeSessionHookOk) return { tested: "project wiki lint; Codex and Claude wiki session-start hooks", notTested: "none" };
|
|
274
|
+
const gaps = [];
|
|
275
|
+
if (!lintOk) gaps.push("project wiki lint");
|
|
276
|
+
if (!codexSessionHookOk) gaps.push("Codex wiki session-start hook");
|
|
277
|
+
if (!claudeSessionHookOk) gaps.push("Claude wiki session-start hook");
|
|
278
|
+
return { tested: "prepare-commit-msg generated wiki trailers", notTested: gaps.join("; ") || "unknown" };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const staged = runGit(["diff", "--cached", "--name-only", "--diff-filter=ACMR"])
|
|
282
|
+
.split(/\\r?\\n/)
|
|
283
|
+
.map((line) => line.trim())
|
|
284
|
+
.filter(Boolean);
|
|
285
|
+
|
|
286
|
+
const wikiFiles = staged.filter((file) => {
|
|
287
|
+
return file.startsWith("wiki/")
|
|
288
|
+
|| file === "AGENTS.md"
|
|
289
|
+
|| file === "CLAUDE.md"
|
|
290
|
+
|| file === ".codex/hooks.json"
|
|
291
|
+
|| file.startsWith(".codex/hooks/")
|
|
292
|
+
|| file === ".claude/settings.json"
|
|
293
|
+
|| file.startsWith(".claude/hooks/")
|
|
294
|
+
|| file.startsWith(".githooks/")
|
|
295
|
+
|| file.startsWith("tools/project-librarian/");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
if (wikiFiles.length === 0) process.exit(0);
|
|
299
|
+
|
|
300
|
+
let message = fs.readFileSync(messagePath, "utf8");
|
|
301
|
+
if (/^Wiki-scope:/m.test(message)) process.exit(0);
|
|
302
|
+
|
|
303
|
+
const decisionRefs = wikiFiles.filter((file) => file.startsWith("wiki/decisions/") || file === "wiki/meta/wiki-ops-v1-decisions.md");
|
|
304
|
+
const validation = validationTrailers();
|
|
305
|
+
const trailers = [
|
|
306
|
+
["Wiki-scope", wikiScope(wikiFiles)],
|
|
307
|
+
["Canonical-updated", truncateList(wikiFiles.filter((file) => file.startsWith("wiki/canonical/") && !file.endsWith("/migration-inbox.md")))],
|
|
308
|
+
["Decision-ref", truncateList(decisionRefs)],
|
|
309
|
+
["Startup-updated", wikiFiles.includes("wiki/startup.md") ? "yes" : "no"],
|
|
310
|
+
["Index-updated", wikiFiles.includes("wiki/index.md") ? "yes" : "no"],
|
|
311
|
+
["Migration-status", migrationStatus(wikiFiles)],
|
|
312
|
+
["Tested", validation.tested],
|
|
313
|
+
["Not-tested", validation.notTested],
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
const lines = [];
|
|
317
|
+
for (const [key, value] of trailers) {
|
|
318
|
+
if (!new RegExp("^" + key + ":", "m").test(message)) lines.push(key + ": " + value);
|
|
319
|
+
}
|
|
320
|
+
if (lines.length > 0) fs.writeFileSync(messagePath, message.replace(/\\s*$/, "") + "\\n\\n" + lines.join("\\n") + "\\n");
|
|
321
|
+
`;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const args_1 = require("./args");
|
|
5
|
+
const hooks_1 = require("./hooks");
|
|
6
|
+
const install_skill_1 = require("./install-skill");
|
|
7
|
+
const modes_1 = require("./modes");
|
|
8
|
+
const migration_1 = require("./migration");
|
|
9
|
+
const templates_1 = require("./templates");
|
|
10
|
+
const workspace_1 = require("./workspace");
|
|
11
|
+
const wiki_files_1 = require("./wiki-files");
|
|
12
|
+
function codeIndex() {
|
|
13
|
+
return require("./code-index");
|
|
14
|
+
}
|
|
15
|
+
function printUsage() {
|
|
16
|
+
console.log(`Usage:
|
|
17
|
+
project-librarian [init] [options]
|
|
18
|
+
project-librarian install-skill [--scope user|project] [--agents codex|claude|both]
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--migrate, --adopt-existing Preserve an existing wiki as wiki_legacy and create migration inboxes.
|
|
22
|
+
--lint Validate the generated project wiki setup without editing files.
|
|
23
|
+
--link-check Report broken wiki links, duplicate routes, and orphan pages.
|
|
24
|
+
--quality-check Report stale, conflicting, and low-quality wiki document signals.
|
|
25
|
+
--doctor Run lint, link-check, and quality-check together.
|
|
26
|
+
--fix With --doctor, safely refresh generated index routing.
|
|
27
|
+
--issue-create Create a GitHub issue with gh issue create after explicit user approval.
|
|
28
|
+
--issue-draft Print a problem/side-effect GitHub issue body draft.
|
|
29
|
+
--issue-body-file <path> With --issue-create, use an existing Markdown body file.
|
|
30
|
+
--issue-title <title> Override the generated issue draft title.
|
|
31
|
+
--query <terms> Search wiki paths, metadata, titles, and bodies.
|
|
32
|
+
--refresh-index Update the managed auto-discovered wiki index block.
|
|
33
|
+
--capture-inbox Append a candidate note with --title, --content, and optional --category.
|
|
34
|
+
--glossary-init Create and route the optional glossary page.
|
|
35
|
+
--prune-check Report active pages with stale or unresolved signals.
|
|
36
|
+
--review-migration Sync migration inbox statuses into migration review files.
|
|
37
|
+
--no-git-config Install hook files without changing git core.hooksPath.
|
|
38
|
+
--code-index Build the disposable .project-wiki code evidence index.
|
|
39
|
+
--incremental With --code-index, require an existing compatible index and update only changes.
|
|
40
|
+
--code-index-full With --code-index, force a full rebuild even when incremental update is possible.
|
|
41
|
+
--code-parser <mode> With --code-index, use parser mode default or tree-sitter.
|
|
42
|
+
--code-query <sql> Run conservative read-only SQL over the code evidence index.
|
|
43
|
+
--code-status, --code-files Inspect the code evidence index.
|
|
44
|
+
--code-report Print architecture and ownership summaries from the code evidence index.
|
|
45
|
+
--code-report-section <section> With --code-report, print one section: coverage, ownership, languages, parsers, workspaces, workspace-graph, routes, hotspots, configs, or edges.
|
|
46
|
+
--code-impact <term> Show file, symbol, route, import, and edge impact evidence for a term.
|
|
47
|
+
--code-search-symbol <term> Search indexed symbols.
|
|
48
|
+
--help Show this help.`);
|
|
49
|
+
}
|
|
50
|
+
if (args_1.helpMode) {
|
|
51
|
+
printUsage();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
if (args_1.unknownCommand) {
|
|
55
|
+
console.error(`unknown command: ${args_1.unknownCommand}`);
|
|
56
|
+
printUsage();
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
if (args_1.unknownOptions.length > 0) {
|
|
60
|
+
console.error(`unknown option${args_1.unknownOptions.length === 1 ? "" : "s"}: ${args_1.unknownOptions.join(", ")}`);
|
|
61
|
+
printUsage();
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (args_1.unexpectedValueOptions.length > 0) {
|
|
65
|
+
console.error(`option${args_1.unexpectedValueOptions.length === 1 ? "" : "s"} do${args_1.unexpectedValueOptions.length === 1 ? "es" : ""} not take a value: ${args_1.unexpectedValueOptions.join(", ")}`);
|
|
66
|
+
printUsage();
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
if (args_1.missingValueOptions.length > 0) {
|
|
70
|
+
console.error(`missing value for option${args_1.missingValueOptions.length === 1 ? "" : "s"}: ${args_1.missingValueOptions.join(", ")}`);
|
|
71
|
+
printUsage();
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
if (args_1.fixMode && !args_1.doctorMode) {
|
|
75
|
+
console.error("--fix is only supported with --doctor.");
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
if (args_1.issueCreateMode && args_1.issueDraftMode) {
|
|
79
|
+
console.error("Use one issue mode at a time: --issue-draft or --issue-create.");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
if (args_1.codeReportSection && !args_1.codeReportMode) {
|
|
83
|
+
console.error("--code-report-section is only supported with --code-report.");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
if (args_1.codeIndexIncrementalMode && !args_1.codeIndexMode) {
|
|
87
|
+
console.error("--incremental is only supported with --code-index.");
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
if (args_1.codeIndexFullMode && !args_1.codeIndexMode) {
|
|
91
|
+
console.error("--code-index-full is only supported with --code-index.");
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
if (args_1.codeParserMode && !args_1.codeIndexMode) {
|
|
95
|
+
console.error("--code-parser is only supported with --code-index.");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
if (args_1.codeIndexIncrementalMode && args_1.codeIndexFullMode) {
|
|
99
|
+
console.error("Use one code index update mode at a time: --incremental or --code-index-full.");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
if (args_1.command === "install-skill") {
|
|
103
|
+
(0, install_skill_1.runInstallSkillMode)();
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
const activeCodeModes = [args_1.codeQueryMode, args_1.codeReportMode, args_1.codeStatusMode, args_1.codeFilesMode, args_1.codeImpactMode, args_1.codeSearchSymbolMode, args_1.codeIndexMode].filter(Boolean).length;
|
|
107
|
+
if (activeCodeModes > 1) {
|
|
108
|
+
console.error("Use one code evidence mode at a time: --code-index, --code-query, --code-report, --code-status, --code-files, --code-impact, or --code-search-symbol.");
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
if (args_1.codeQueryMode) {
|
|
112
|
+
codeIndex().runCodeQueryMode();
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
if (args_1.codeReportMode) {
|
|
116
|
+
codeIndex().runCodeReportMode();
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
if (args_1.codeStatusMode) {
|
|
120
|
+
codeIndex().runCodeStatusMode();
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
if (args_1.codeFilesMode) {
|
|
124
|
+
codeIndex().runCodeFilesMode();
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
if (args_1.codeImpactMode) {
|
|
128
|
+
codeIndex().runCodeImpactMode();
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
if (args_1.codeSearchSymbolMode) {
|
|
132
|
+
codeIndex().runCodeSearchSymbolMode();
|
|
133
|
+
process.exit(0);
|
|
134
|
+
}
|
|
135
|
+
if (args_1.codeIndexMode) {
|
|
136
|
+
codeIndex().runCodeIndexMode();
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
if (args_1.queryTerm) {
|
|
140
|
+
(0, modes_1.runQueryMode)();
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
if (args_1.issueCreateMode) {
|
|
144
|
+
(0, modes_1.runIssueCreateMode)();
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|
|
147
|
+
if (args_1.issueDraftMode) {
|
|
148
|
+
(0, modes_1.runIssueDraftMode)();
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
if (args_1.pruneCheckMode) {
|
|
152
|
+
(0, modes_1.runPruneCheckMode)();
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}
|
|
155
|
+
if (args_1.reviewMigrationMode) {
|
|
156
|
+
(0, migration_1.runReviewMigrationMode)();
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
159
|
+
if (args_1.doctorMode) {
|
|
160
|
+
(0, modes_1.runDoctorMode)(args_1.fixMode);
|
|
161
|
+
process.exit(0);
|
|
162
|
+
}
|
|
163
|
+
if (args_1.linkCheckMode) {
|
|
164
|
+
(0, modes_1.runLinkCheckMode)();
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
if (args_1.qualityCheckMode) {
|
|
168
|
+
(0, modes_1.runQualityCheckMode)();
|
|
169
|
+
process.exit(0);
|
|
170
|
+
}
|
|
171
|
+
if (args_1.lintMode) {
|
|
172
|
+
(0, modes_1.runLintMode)();
|
|
173
|
+
process.exit(0);
|
|
174
|
+
}
|
|
175
|
+
const migrationState = args_1.migrateMode ? (0, migration_1.prepareMigrationMode)() : null;
|
|
176
|
+
const results = [];
|
|
177
|
+
if (migrationState)
|
|
178
|
+
results.push(["migration prepare", migrationState.note]);
|
|
179
|
+
(0, workspace_1.mkdirp)("wiki/canonical");
|
|
180
|
+
(0, workspace_1.mkdirp)("wiki/decisions");
|
|
181
|
+
(0, workspace_1.mkdirp)("wiki/inbox");
|
|
182
|
+
(0, workspace_1.mkdirp)("wiki/meta");
|
|
183
|
+
(0, workspace_1.mkdirp)("wiki/sources");
|
|
184
|
+
(0, workspace_1.mkdirp)(".codex/hooks");
|
|
185
|
+
(0, workspace_1.mkdirp)(".claude/hooks");
|
|
186
|
+
(0, workspace_1.mkdirp)(".githooks");
|
|
187
|
+
results.push(["AGENTS.md", (0, workspace_1.upsertMarkedSection)("AGENTS.md", "<!-- PROJECT-WIKI-FIRST:START -->", "<!-- PROJECT-WIKI-FIRST:END -->", templates_1.agentsSection)]);
|
|
188
|
+
results.push(["CLAUDE.md", (0, workspace_1.upsertMarkedSection)("CLAUDE.md", "<!-- PROJECT-WIKI-CLAUDE:START -->", "<!-- PROJECT-WIKI-CLAUDE:END -->", templates_1.claudeSection)]);
|
|
189
|
+
results.push(["wiki/AGENTS.md", (0, workspace_1.upsertMarkedSection)("wiki/AGENTS.md", "<!-- PROJECT-WIKI-INTERNAL:START -->", "<!-- PROJECT-WIKI-INTERNAL:END -->", templates_1.wikiAgentsSection)]);
|
|
190
|
+
results.push([".githooks/prepare-commit-msg", (0, workspace_1.writeManaged)(".githooks/prepare-commit-msg", hooks_1.gitPrepareCommitMsgHook)]);
|
|
191
|
+
(0, workspace_1.makeExecutable)(".githooks/prepare-commit-msg");
|
|
192
|
+
results.push([".githooks/wiki-commit-trailers.js", (0, workspace_1.writeManaged)(".githooks/wiki-commit-trailers.js", hooks_1.gitWikiCommitTrailersScript)]);
|
|
193
|
+
(0, workspace_1.makeExecutable)(".githooks/wiki-commit-trailers.js");
|
|
194
|
+
results.push(["git core.hooksPath", (0, hooks_1.upsertGitHooksPath)()]);
|
|
195
|
+
results.push([".codex/hooks.json", (0, hooks_1.upsertHookConfig)()]);
|
|
196
|
+
results.push([".codex/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".codex/hooks/wiki-session-start.js", hooks_1.hookScript)]);
|
|
197
|
+
results.push([".claude/settings.json", (0, hooks_1.upsertClaudeHookConfig)()]);
|
|
198
|
+
results.push([".claude/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".claude/hooks/wiki-session-start.js", hooks_1.hookScript)]);
|
|
199
|
+
results.push(["wiki/startup.md", (0, workspace_1.writeManaged)("wiki/startup.md", (0, wiki_files_1.withPreservedMarkedSections)("wiki/startup.md", templates_1.startup, [["<!-- PROJECT-WIKI-MIGRATION:START -->", "<!-- PROJECT-WIKI-MIGRATION:END -->"]]))]);
|
|
200
|
+
results.push(["wiki/index.md", (0, workspace_1.writeManaged)("wiki/index.md", (0, wiki_files_1.withPreservedMarkedSections)("wiki/index.md", templates_1.index, [
|
|
201
|
+
["<!-- PROJECT-WIKI-MIGRATION:START -->", "<!-- PROJECT-WIKI-MIGRATION:END -->"],
|
|
202
|
+
["<!-- PROJECT-WIKI-GLOSSARY:START -->", "<!-- PROJECT-WIKI-GLOSSARY:END -->"],
|
|
203
|
+
["<!-- PROJECT-WIKI-INBOX:START -->", "<!-- PROJECT-WIKI-INBOX:END -->"],
|
|
204
|
+
["<!-- PROJECT-WIKI-AUTO-INDEX:START -->", "<!-- PROJECT-WIKI-AUTO-INDEX:END -->"],
|
|
205
|
+
]))]);
|
|
206
|
+
results.push(["wiki/meta/operating-model.md", (0, workspace_1.writeManaged)("wiki/meta/operating-model.md", templates_1.wikiOperatingModel)]);
|
|
207
|
+
results.push(["wiki/meta/decision-policy.md", (0, workspace_1.writeManaged)("wiki/meta/decision-policy.md", templates_1.decisionPolicy)]);
|
|
208
|
+
results.push(["wiki/canonical/wiki-operating-model.md", (0, workspace_1.deleteIfGenerated)("wiki/canonical/wiki-operating-model.md", ["# Wiki Operating Model"])]);
|
|
209
|
+
results.push(["wiki/canonical/decision-policy.md", (0, workspace_1.deleteIfGenerated)("wiki/canonical/decision-policy.md", ["# Decision Policy"])]);
|
|
210
|
+
results.push(["wiki/decisions/wiki-v1-decisions.md", (0, workspace_1.deleteIfGenerated)("wiki/decisions/wiki-v1-decisions.md", ["# Wiki v1 Decisions", "# Wiki Operations v1 Decisions"])]);
|
|
211
|
+
for (const [relativePath, content] of Object.entries(templates_1.starterFiles)) {
|
|
212
|
+
results.push([relativePath, (0, workspace_1.writeStarter)(relativePath, content)]);
|
|
213
|
+
}
|
|
214
|
+
results.push(["wiki/meta/wiki-ops-v1-decisions.md", (0, workspace_1.writeManaged)("wiki/meta/wiki-ops-v1-decisions.md", templates_1.starterFiles["wiki/meta/wiki-ops-v1-decisions.md"])]);
|
|
215
|
+
if (args_1.glossaryMode) {
|
|
216
|
+
results.push(["wiki/canonical/glossary.md", (0, workspace_1.writeStarter)("wiki/canonical/glossary.md", templates_1.glossary)]);
|
|
217
|
+
results.push(["wiki/index.md glossary router", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-GLOSSARY:START -->", "<!-- PROJECT-WIKI-GLOSSARY:END -->", templates_1.glossaryIndexBlock)]);
|
|
218
|
+
}
|
|
219
|
+
if (args_1.captureInboxMode) {
|
|
220
|
+
results.push(["wiki/inbox/project-candidates.md", (0, modes_1.appendCaptureInbox)()]);
|
|
221
|
+
results.push(["wiki/index.md inbox router", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-INBOX:START -->", "<!-- PROJECT-WIKI-INBOX:END -->", templates_1.inboxIndexBlock)]);
|
|
222
|
+
}
|
|
223
|
+
if (args_1.refreshIndexMode) {
|
|
224
|
+
results.push(["wiki/index.md auto-discovered pages", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-AUTO-INDEX:START -->", "<!-- PROJECT-WIKI-AUTO-INDEX:END -->", (0, modes_1.buildRefreshIndexBlock)())]);
|
|
225
|
+
}
|
|
226
|
+
if (args_1.migrateMode && migrationState) {
|
|
227
|
+
const migration = (0, migration_1.runMigrationMode)(migrationState);
|
|
228
|
+
for (const result of migration.results)
|
|
229
|
+
results.push(result);
|
|
230
|
+
results.push(["migration summary", `${migration.total} files from ${migration.legacyPath || "no legacy"}`]);
|
|
231
|
+
}
|
|
232
|
+
const modes = [];
|
|
233
|
+
if (args_1.migrateMode)
|
|
234
|
+
modes.push("migration");
|
|
235
|
+
if (args_1.glossaryMode)
|
|
236
|
+
modes.push("glossary");
|
|
237
|
+
if (args_1.captureInboxMode)
|
|
238
|
+
modes.push("capture-inbox");
|
|
239
|
+
if (args_1.refreshIndexMode)
|
|
240
|
+
modes.push("refresh-index");
|
|
241
|
+
if (args_1.noGitConfigMode)
|
|
242
|
+
modes.push("no-git-config");
|
|
243
|
+
console.log(modes.length > 0 ? `Project Librarian + ${modes.join(" + ")} complete.` : "Project Librarian complete.");
|
|
244
|
+
for (const [relativePath, status] of results) {
|
|
245
|
+
console.log(`${String(status).padEnd(7)} ${relativePath}`);
|
|
246
|
+
}
|