project-librarian 0.5.9 → 0.6.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/README.ko.md +3 -2
- package/README.md +3 -2
- package/SKILL.md +1 -0
- package/dist/agent-surfaces.js +1 -0
- package/dist/args.js +7 -8
- package/dist/hooks.js +5 -2
- package/dist/init-project-wiki.js +10 -17
- package/dist/install-skill.js +17 -0
- package/dist/modes.js +13 -2
- package/dist/native/linux-arm64/project-librarian-indexer +0 -0
- package/dist/native/linux-arm64-musl/project-librarian-indexer +0 -0
- package/dist/native/linux-x64/project-librarian-indexer +0 -0
- package/dist/native/linux-x64-musl/project-librarian-indexer +0 -0
- package/dist/native/project-librarian-indexer-manifest.json +10 -10
- package/dist/native/win32-arm64/project-librarian-indexer.exe +0 -0
- package/dist/native/win32-x64/project-librarian-indexer.exe +0 -0
- package/dist/wiki-diagnostics.js +111 -1
- package/dist/wiki-graph.js +123 -0
- package/docs/cli-reference.md +14 -4
- package/docs/ko/cli-reference.md +14 -4
- package/docs/ko/usage.md +5 -6
- package/docs/usage.md +5 -6
- package/package.json +2 -2
- package/dist/wiki-concepts.js +0 -49
- package/dist/wiki-visualizer.js +0 -558
package/README.ko.md
CHANGED
|
@@ -41,7 +41,7 @@ npx project-librarian@latest install --scope project --agents all
|
|
|
41
41
|
npx project-librarian@latest update
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
이 명령은 관리 설정 파일, 에이전트 훅, 위키 운영/메타 파일, 기존 프로젝트 범위 스킬 복사본을 갱신합니다. 현재 `wiki/`는 보존하고 migration flag는 거부하므로 위키를 `wiki_legacy*`로 바꾸지 않습니다.
|
|
44
|
+
이 명령은 관리 설정 파일, 에이전트 훅, 위키 운영/메타 파일, 기존 프로젝트 범위 스킬 복사본을 갱신합니다. 기존 공유 `.agents/skills/project-librarian/` 복사본도 특정 에이전트 설정 표면을 암묵적으로 추가하지 않고 갱신합니다. 현재 `wiki/`는 보존하고 migration flag는 거부하므로 위키를 `wiki_legacy*`로 바꾸지 않습니다.
|
|
45
45
|
|
|
46
46
|
특정 프로젝트 표면을 의도적으로 추가하거나 갱신할 때는 `--agents`를 명시합니다.
|
|
47
47
|
|
|
@@ -77,9 +77,9 @@ Project Librarian은 작은 첫 읽기와 더 깊은 정본으로 가는 경로
|
|
|
77
77
|
- **첫 읽기를 작게.** 시작 훅은 `wiki/startup.md`와 `wiki/index.md`만 주입하고, 에이전트는 필요할 때 더 깊은 페이지로 이동합니다.
|
|
78
78
|
- **한 번 설정, 네 에이전트.** Codex, Claude Code, Cursor, Gemini CLI가 같은 저장소 로컬 기억 계약을 공유합니다.
|
|
79
79
|
- **구조적인 위키 작성.** 새 프로젝트 내용은 작성하거나 취합하기 전에 분류하므로 PRD, 정책, UX, 데이터, API, QA, 릴리즈, 운영 메모가 하나의 잡다한 페이지로 합쳐지지 않습니다.
|
|
80
|
-
- **검토 가능한 위키 그래프.** `--wiki-visualize`는 시작 컨텍스트를 늘리지 않고 `.project-wiki/` 아래에 정적 HTML 그래프를 작성합니다.
|
|
81
80
|
- **측정된 주장.** 벤치마크에서 이긴 경우와 손해를 본 경우를 주장 경계와 함께 공개합니다.
|
|
82
81
|
- **로컬 세션 핸드오프.** `--handoff-save`는 `.project-wiki/session/` 아래에 생성형 재개 메모를 저장하되 실행 기억을 프로젝트 정본으로 바꾸지 않습니다.
|
|
82
|
+
- **답변형 위키 토폴로지.** `--wiki-impact`, `--wiki-neighborhood`, topology diagnostics가 graph visualizer 없이 backlinks, decision 근거, router depth, 가까운 읽기 순서를 노출합니다.
|
|
83
83
|
- **선택적 코드 근거.** SQLite 인덱스와 답변 형태 MCP 도구가 큰 저장소의 비싼 탐색 질문에 답하며, MCP SDK 의존성은 추가하지 않습니다.
|
|
84
84
|
- **다시 실행해도 안전.** 부트스트랩은 멱등하고 기존 내용 보존을 우선합니다.
|
|
85
85
|
|
|
@@ -94,6 +94,7 @@ Project Librarian은 작은 첫 읽기와 더 깊은 정본으로 가는 경로
|
|
|
94
94
|
| 기존 문서/위키 마이그레이션 | "Project Librarian으로 기존 docs/wiki 내용을 마이그레이션해줘." |
|
|
95
95
|
| 진단 실행 | "Project Librarian 진단을 실행해줘." |
|
|
96
96
|
| 프로젝트 기억 검색 | "Project Librarian 위키에서 authentication decisions를 찾아줘." |
|
|
97
|
+
| 가까운 위키 맥락 찾기 | "canonical/project-brief의 Project Librarian wiki neighborhood를 보여줘." |
|
|
97
98
|
| 코드 근거 구축 | "Project Librarian 코드 근거를 `src`에 대해 구축해줘." |
|
|
98
99
|
| 코드 영향 확인 | "`healthHandler`에 대한 Project Librarian 영향 근거를 보여줘." |
|
|
99
100
|
| 세션 핸드오프 저장 | "현재 작업에 대한 Project Librarian 세션 핸드오프를 저장해줘." |
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ To refresh an existing setup without migrating the wiki, run:
|
|
|
41
41
|
npx project-librarian@latest update
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
That updates managed setup files, agent hooks, wiki operating/meta files, and existing project-scoped skill copies. It preserves the current `wiki/` and rejects migration flags, so it will not rename the wiki to `wiki_legacy*`.
|
|
44
|
+
That updates managed setup files, agent hooks, wiki operating/meta files, and existing project-scoped skill copies. Existing shared `.agents/skills/project-librarian/` copies are refreshed without implying any agent-specific setup surface. It preserves the current `wiki/` and rejects migration flags, so it will not rename the wiki to `wiki_legacy*`.
|
|
45
45
|
|
|
46
46
|
Use `--agents` when you intentionally want to add or refresh a specific project surface:
|
|
47
47
|
|
|
@@ -77,9 +77,9 @@ The core idea is not "write more docs." It is "keep the first agent read small,
|
|
|
77
77
|
- **Small first read.** Startup hooks inject only `wiki/startup.md` and `wiki/index.md`; agents route to deeper pages on demand.
|
|
78
78
|
- **One setup, four agents.** Codex, Claude Code, Cursor, and Gemini CLI share the same repo-local memory contract.
|
|
79
79
|
- **Structured wiki writing.** New project content is classified before it is written or consolidated, so PRDs, policies, UX, data, APIs, QA, release, and operations notes do not collapse into one catch-all page.
|
|
80
|
-
- **Inspectable wiki graph.** `--wiki-visualize` writes a static HTML graph under `.project-wiki/` without adding to startup context.
|
|
81
80
|
- **Measured claims.** Benchmark wins and losses are published together, with claim boundaries attached.
|
|
82
81
|
- **Local session handoff.** `--handoff-save` stores generated resume notes under `.project-wiki/session/` without turning execution memory into canonical project truth.
|
|
82
|
+
- **Answer-shaped wiki topology.** `--wiki-impact`, `--wiki-neighborhood`, and topology diagnostics expose backlinks, decision evidence, router depth, and nearby read order without a graph visualizer.
|
|
83
83
|
- **Optional code evidence.** A SQLite index plus answer-shaped MCP tools answer expensive traversal questions on large repositories without adding an MCP SDK dependency.
|
|
84
84
|
- **Safe to re-run.** Bootstrap is idempotent and preservation-first.
|
|
85
85
|
|
|
@@ -94,6 +94,7 @@ Ask your agent for the outcome you want; the installed skill maps the request to
|
|
|
94
94
|
| Migrate existing docs/wiki content | "Use Project Librarian to migrate the existing docs/wiki content." |
|
|
95
95
|
| Run diagnostics | "Run Project Librarian diagnostics." |
|
|
96
96
|
| Search project memory | "Search the Project Librarian wiki for authentication decisions." |
|
|
97
|
+
| Find nearby wiki context | "Show Project Librarian wiki neighborhood for canonical/project-brief." |
|
|
97
98
|
| Build code evidence | "Build Project Librarian code evidence for `src`." |
|
|
98
99
|
| Inspect code impact | "Show Project Librarian impact evidence for `healthHandler`." |
|
|
99
100
|
| Save a handoff | "Save a Project Librarian session handoff for the current work." |
|
package/SKILL.md
CHANGED
|
@@ -37,6 +37,7 @@ Supported actions:
|
|
|
37
37
|
Prefer an already installed local runner over network package execution:
|
|
38
38
|
|
|
39
39
|
- In the project-librarian source repository, use `node dist/init-project-wiki.js` when `dist/init-project-wiki.js` exists.
|
|
40
|
+
- In a target repository with a shared project-scoped skill install, use `node .agents/skills/project-librarian/dist/init-project-wiki.js`.
|
|
40
41
|
- In a target repository with a project-scoped Codex skill install, use `node .codex/skills/project-librarian/dist/init-project-wiki.js`.
|
|
41
42
|
- In a target repository with a project-scoped Claude skill install, use `node .claude/skills/project-librarian/dist/init-project-wiki.js`.
|
|
42
43
|
- In a target repository with a project-scoped Cursor skill install, use `node .cursor/skills/project-librarian/dist/init-project-wiki.js`.
|
package/dist/agent-surfaces.js
CHANGED
|
@@ -20,6 +20,7 @@ const agentSurfaceProjectSkillFiles = {
|
|
|
20
20
|
gemini: [".gemini/skills/project-librarian/SKILL.md"],
|
|
21
21
|
};
|
|
22
22
|
const projectLibrarianCommonInstallFiles = [
|
|
23
|
+
".agents/skills/project-librarian/SKILL.md",
|
|
23
24
|
"wiki/startup.md",
|
|
24
25
|
"wiki/index.md",
|
|
25
26
|
"wiki/AGENTS.md",
|
package/dist/args.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.codeIndexMode = exports.acknowledgeSmallRepoMode = exports.noGitConfigMode = exports.reviewMigrationMode = exports.pruneCheckStrictMode = exports.pruneCheckMode = exports.captureInboxMode = exports.refreshIndexMode = exports.issueDraftMode = exports.issueCreateMode = exports.handoffVerification = exports.handoffStatusMode = exports.handoffState = exports.handoffShowMode = exports.handoffSaveMode = exports.handoffPromoteInboxMode = exports.handoffInjectionStatusMode = exports.handoffInjectionEnableMode = exports.handoffInjectionDisableMode = exports.handoffOpenQuestions = exports.handoffNextActions = exports.handoffLastSuccessCommand = exports.handoffLastFailureCommand = exports.handoffInputMode = exports.handoffGoal = exports.handoffDecisions = exports.handoffClearMode = exports.handoffBlocked = exports.glossaryMode = exports.fixMode = exports.doctorMode = exports.qualityCheckMode = exports.linkCheckMode = exports.migrationQualityCheckMode = exports.migrationLintMode = exports.migrationDoctorMode = exports.lintMode = exports.migrateMode = exports.invalidAgentTargets = exports.missingValueOptions = exports.unexpectedValueOptions = exports.unknownOptions = exports.args = exports.commandArgs = exports.command = exports.unknownCommand = exports.helpMode = exports.agentTargets = exports.parsedArgs = exports.rawArgs = void 0;
|
|
4
|
-
exports.issueDraftTitle = exports.issueBodyFile = exports.captureCategory = exports.captureContent = exports.captureTitle = exports.codeIndexScopes = exports.codeParser = exports.codeIndexOutput = exports.codeSearchSymbol = exports.codeReportSection = exports.codeQuerySql = exports.codeImpactTarget = exports.codeContextPackTarget = exports.
|
|
4
|
+
exports.issueDraftTitle = exports.issueBodyFile = exports.captureCategory = exports.captureContent = exports.captureTitle = exports.codeIndexScopes = exports.codeParser = exports.codeIndexOutput = exports.codeSearchSymbol = exports.codeReportSection = exports.codeQuerySql = exports.codeImpactTarget = exports.codeContextPackTarget = exports.wikiNeighborhoodTarget = exports.wikiNeighborhoodMode = exports.wikiImpactTarget = exports.wikiImpactMode = exports.queryTerm = exports.codeSearchSymbolMode = exports.codeQueryMode = exports.codeImpactMode = exports.codeParserMode = exports.codeContextPackMode = exports.codeFilesMode = exports.codeStatusMode = exports.codeReportMode = exports.codeIndexHealthMode = exports.codeIndexFullMode = exports.codeIndexMigrateMode = exports.codeIndexIncrementalMode = exports.codeIndexEngineMode = exports.codeIndexEngine = void 0;
|
|
5
5
|
exports.parseArgs = parseArgs;
|
|
6
6
|
exports.argValue = argValue;
|
|
7
7
|
exports.argValues = argValues;
|
|
@@ -72,10 +72,8 @@ const flagDefinitions = [
|
|
|
72
72
|
{ name: "--review-migration", value: "none", aliases: ["--semantic-migrate"] },
|
|
73
73
|
{ name: "--scope", value: "value" },
|
|
74
74
|
{ name: "--title", value: "value" },
|
|
75
|
-
{ name: "--wiki-graph-html", value: "none" },
|
|
76
75
|
{ name: "--wiki-impact", value: "value" },
|
|
77
|
-
{ name: "--wiki-
|
|
78
|
-
{ name: "--wiki-visualize-out", value: "value" },
|
|
76
|
+
{ name: "--wiki-neighborhood", value: "value" },
|
|
79
77
|
];
|
|
80
78
|
function definitionNames(definition) {
|
|
81
79
|
return [definition.name, ...(definition.aliases ?? [])];
|
|
@@ -156,6 +154,7 @@ function parseArgs(argv) {
|
|
|
156
154
|
const codeContextPackTarget = argValueFromAny("--code-context-pack");
|
|
157
155
|
const codeQuerySql = argValueFromAny("--code-query");
|
|
158
156
|
const codeSearchSymbol = argValueFromAny("--code-search-symbol");
|
|
157
|
+
const wikiNeighborhoodTarget = argValue("--wiki-neighborhood");
|
|
159
158
|
const parsedAgentTargets = (0, agent_surfaces_1.parseAgentSurfaceValues)(argValues("--agents"));
|
|
160
159
|
const handoffInputMode = [
|
|
161
160
|
"--blocked",
|
|
@@ -254,8 +253,8 @@ function parseArgs(argv) {
|
|
|
254
253
|
.filter((arg) => !knownFlags.has(arg)))),
|
|
255
254
|
wikiImpactMode: hasFlag("--wiki-impact"),
|
|
256
255
|
wikiImpactTarget: argValue("--wiki-impact"),
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
wikiNeighborhoodMode: hasFlag("--wiki-neighborhood"),
|
|
257
|
+
wikiNeighborhoodTarget,
|
|
259
258
|
};
|
|
260
259
|
}
|
|
261
260
|
exports.parsedArgs = parseArgs(exports.rawArgs);
|
|
@@ -330,8 +329,8 @@ function argValues(name) {
|
|
|
330
329
|
exports.queryTerm = exports.parsedArgs.queryTerm;
|
|
331
330
|
exports.wikiImpactMode = exports.parsedArgs.wikiImpactMode;
|
|
332
331
|
exports.wikiImpactTarget = exports.parsedArgs.wikiImpactTarget;
|
|
333
|
-
exports.
|
|
334
|
-
exports.
|
|
332
|
+
exports.wikiNeighborhoodMode = exports.parsedArgs.wikiNeighborhoodMode;
|
|
333
|
+
exports.wikiNeighborhoodTarget = exports.parsedArgs.wikiNeighborhoodTarget;
|
|
335
334
|
exports.codeContextPackTarget = exports.parsedArgs.codeContextPackTarget;
|
|
336
335
|
exports.codeImpactTarget = exports.parsedArgs.codeImpactTarget;
|
|
337
336
|
exports.codeQuerySql = exports.parsedArgs.codeQuerySql;
|
package/dist/hooks.js
CHANGED
|
@@ -149,6 +149,7 @@ const mcpServerName = "project-librarian";
|
|
|
149
149
|
// runner wins; absent any local install we register the published binary.
|
|
150
150
|
const localRunnerCandidates = [
|
|
151
151
|
"tools/project-librarian/dist/init-project-wiki.js",
|
|
152
|
+
".agents/skills/project-librarian/dist/init-project-wiki.js",
|
|
152
153
|
".codex/skills/project-librarian/dist/init-project-wiki.js",
|
|
153
154
|
".claude/skills/project-librarian/dist/init-project-wiki.js",
|
|
154
155
|
".cursor/skills/project-librarian/dist/init-project-wiki.js",
|
|
@@ -458,7 +459,7 @@ function wikiScope(files) {
|
|
|
458
459
|
else if (file.startsWith(".gemini/hooks/") || file === ".gemini/settings.json") add("gemini-hooks");
|
|
459
460
|
else if (file === "AGENTS.md" || file === "CLAUDE.md" || file === "GEMINI.md") add("agents");
|
|
460
461
|
else if (file.startsWith(".githooks/")) add("git-hooks");
|
|
461
|
-
else if (file.startsWith("tools/project-librarian/")) add("skill");
|
|
462
|
+
else if (file.startsWith("tools/project-librarian/") || file.startsWith(".agents/skills/project-librarian/")) add("skill");
|
|
462
463
|
}
|
|
463
464
|
return scopes.length === 0 ? "none" : scopes.join(", ");
|
|
464
465
|
}
|
|
@@ -467,6 +468,7 @@ function validationTrailers() {
|
|
|
467
468
|
const home = process.env.HOME || "";
|
|
468
469
|
const lintScript = [
|
|
469
470
|
"tools/project-librarian/dist/init-project-wiki.js",
|
|
471
|
+
".agents/skills/project-librarian/dist/init-project-wiki.js",
|
|
470
472
|
path.join(home, ".codex/skills/project-librarian/dist/init-project-wiki.js"),
|
|
471
473
|
path.join(home, ".claude/skills/project-librarian/dist/init-project-wiki.js"),
|
|
472
474
|
path.join(home, ".cursor/skills/project-librarian/dist/init-project-wiki.js"),
|
|
@@ -517,7 +519,8 @@ const wikiFiles = staged.filter((file) => {
|
|
|
517
519
|
|| file === ".gemini/settings.json"
|
|
518
520
|
|| file.startsWith(".gemini/hooks/")
|
|
519
521
|
|| file.startsWith(".githooks/")
|
|
520
|
-
|| file.startsWith("tools/project-librarian/")
|
|
522
|
+
|| file.startsWith("tools/project-librarian/")
|
|
523
|
+
|| file.startsWith(".agents/skills/project-librarian/");
|
|
521
524
|
});
|
|
522
525
|
|
|
523
526
|
if (wikiFiles.length === 0) process.exit(0);
|
|
@@ -9,7 +9,6 @@ const modes_1 = require("./modes");
|
|
|
9
9
|
const migration_1 = require("./migration");
|
|
10
10
|
const session_handoff_1 = require("./session-handoff");
|
|
11
11
|
const templates_1 = require("./templates");
|
|
12
|
-
const wiki_visualizer_1 = require("./wiki-visualizer");
|
|
13
12
|
const workspace_1 = require("./workspace");
|
|
14
13
|
function codeIndex() {
|
|
15
14
|
return require("./code-index");
|
|
@@ -37,8 +36,8 @@ Options:
|
|
|
37
36
|
--dry-run With install, preview copied skill files without writing them.
|
|
38
37
|
--query <terms> Search wiki paths, metadata, titles, and bodies (answer-shaped, capped output).
|
|
39
38
|
--wiki-impact <page-or-term> Show wiki backlinks, decision_ref citations, and router depth for matching pages.
|
|
40
|
-
--wiki-
|
|
41
|
-
|
|
39
|
+
--wiki-neighborhood <page-or-term>
|
|
40
|
+
Show a bounded read order for nearby wiki pages.
|
|
42
41
|
--refresh-index Update the managed auto-discovered wiki index block.
|
|
43
42
|
--capture-inbox Append a candidate note with --title, --content, and optional --category.
|
|
44
43
|
--handoff-save Save local generated session handoff state under .project-wiki/session/.
|
|
@@ -147,10 +146,6 @@ if (args_1.codeReportSection && !args_1.codeReportMode) {
|
|
|
147
146
|
console.error("--code-report-section is only supported with --code-report.");
|
|
148
147
|
process.exit(1);
|
|
149
148
|
}
|
|
150
|
-
if (args_1.wikiVisualizeOutput && !args_1.wikiVisualizeMode) {
|
|
151
|
-
console.error("--wiki-visualize-out is only supported with --wiki-visualize.");
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
149
|
if (args_1.pruneCheckStrictMode && !args_1.pruneCheckMode) {
|
|
155
150
|
console.error("--prune-check-strict is only supported with --prune-check.");
|
|
156
151
|
process.exit(1);
|
|
@@ -266,16 +261,9 @@ function runInitCommand() {
|
|
|
266
261
|
exitAfterStdoutDrain(0);
|
|
267
262
|
return;
|
|
268
263
|
}
|
|
269
|
-
if (args_1.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
console.log(`Project wiki visualizer written: ${output}`);
|
|
273
|
-
exitAfterStdoutDrain(0);
|
|
274
|
-
}
|
|
275
|
-
catch (error) {
|
|
276
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
277
|
-
process.exit(1);
|
|
278
|
-
}
|
|
264
|
+
if (args_1.wikiNeighborhoodMode) {
|
|
265
|
+
(0, modes_1.runWikiNeighborhoodMode)();
|
|
266
|
+
exitAfterStdoutDrain(0);
|
|
279
267
|
return;
|
|
280
268
|
}
|
|
281
269
|
if (args_1.queryTerm) {
|
|
@@ -340,6 +328,7 @@ function runInitCommand() {
|
|
|
340
328
|
const projectSkillSyncSurfaces = args_1.command === "update"
|
|
341
329
|
? (0, install_skill_1.installedProjectSkillSurfaces)().filter((surface) => (0, agent_surfaces_1.includesAgentSurface)(selectedAgentSurfaces, surface))
|
|
342
330
|
: [];
|
|
331
|
+
const syncSharedProjectSkill = args_1.command === "update" && (0, install_skill_1.hasSharedProjectSkillInstall)();
|
|
343
332
|
const shouldWriteSurface = (surface) => (0, agent_surfaces_1.includesAgentSurface)(selectedAgentSurfaces, surface);
|
|
344
333
|
const writeCodexSurface = shouldWriteSurface("codex");
|
|
345
334
|
const writeClaudeSurface = shouldWriteSurface("claude");
|
|
@@ -369,6 +358,10 @@ function runInitCommand() {
|
|
|
369
358
|
for (const result of (0, install_skill_1.syncProjectSkillInstall)(surface))
|
|
370
359
|
results.push(result);
|
|
371
360
|
}
|
|
361
|
+
if (syncSharedProjectSkill) {
|
|
362
|
+
for (const result of (0, install_skill_1.syncSharedProjectSkillInstall)())
|
|
363
|
+
results.push(result);
|
|
364
|
+
}
|
|
372
365
|
// B1 fallback: sync the CURRENT startup.md TL;DR into the managed AGENTS.md block
|
|
373
366
|
// so non-interactive `codex exec` (which does not run SessionStart hooks) still
|
|
374
367
|
// gets compact startup context. Routers are starter files written later in this
|
package/dist/install-skill.js
CHANGED
|
@@ -34,8 +34,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.projectSkillTarget = projectSkillTarget;
|
|
37
|
+
exports.sharedProjectSkillTarget = sharedProjectSkillTarget;
|
|
37
38
|
exports.installedProjectSkillSurfaces = installedProjectSkillSurfaces;
|
|
39
|
+
exports.hasSharedProjectSkillInstall = hasSharedProjectSkillInstall;
|
|
38
40
|
exports.syncProjectSkillInstall = syncProjectSkillInstall;
|
|
41
|
+
exports.syncSharedProjectSkillInstall = syncSharedProjectSkillInstall;
|
|
39
42
|
exports.runInstallSkillMode = runInstallSkillMode;
|
|
40
43
|
const fs = __importStar(require("node:fs"));
|
|
41
44
|
const os = __importStar(require("node:os"));
|
|
@@ -43,6 +46,7 @@ const path = __importStar(require("node:path"));
|
|
|
43
46
|
const agent_surfaces_1 = require("./agent-surfaces");
|
|
44
47
|
const args_1 = require("./args");
|
|
45
48
|
const skillName = "project-librarian";
|
|
49
|
+
const sharedProjectSkillRelativeRoot = path.join(".agents", "skills", skillName);
|
|
46
50
|
const packageFiles = [
|
|
47
51
|
"SKILL.md",
|
|
48
52
|
"dist",
|
|
@@ -121,6 +125,9 @@ function projectSkillRelativeRoot(agent) {
|
|
|
121
125
|
function projectSkillTarget(agent) {
|
|
122
126
|
return path.join(process.cwd(), projectSkillRelativeRoot(agent));
|
|
123
127
|
}
|
|
128
|
+
function sharedProjectSkillTarget() {
|
|
129
|
+
return path.join(process.cwd(), sharedProjectSkillRelativeRoot);
|
|
130
|
+
}
|
|
124
131
|
function installTarget(agent, scope) {
|
|
125
132
|
const base = scope === "user" ? userAgentRoot(agent) : path.join(process.cwd(), projectAgentRoot(agent));
|
|
126
133
|
return path.join(base, "skills", skillName);
|
|
@@ -247,6 +254,9 @@ function copyPath(source, target, targetRoot, dryRun) {
|
|
|
247
254
|
function installedProjectSkillSurfaces() {
|
|
248
255
|
return agent_surfaces_1.allAgentSurfaces.filter((agent) => fs.existsSync(path.join(projectSkillTarget(agent), "SKILL.md")));
|
|
249
256
|
}
|
|
257
|
+
function hasSharedProjectSkillInstall() {
|
|
258
|
+
return fs.existsSync(path.join(sharedProjectSkillTarget(), "SKILL.md"));
|
|
259
|
+
}
|
|
250
260
|
function copyPackageFiles(targetRoot, dryRun, labelRoot = targetRoot) {
|
|
251
261
|
const root = packageRoot();
|
|
252
262
|
const packageRows = packageFiles.map((relativePath) => {
|
|
@@ -269,6 +279,13 @@ function syncProjectSkillInstall(agent) {
|
|
|
269
279
|
return [label, status];
|
|
270
280
|
});
|
|
271
281
|
}
|
|
282
|
+
function syncSharedProjectSkillInstall() {
|
|
283
|
+
return copyPackageFiles(sharedProjectSkillTarget(), false, sharedProjectSkillRelativeRoot).map(([label, status]) => {
|
|
284
|
+
if (status === "dry-run")
|
|
285
|
+
throw new Error("shared project skill sync does not support dry-run status");
|
|
286
|
+
return [label, status];
|
|
287
|
+
});
|
|
288
|
+
}
|
|
272
289
|
function runInstallSkillMode() {
|
|
273
290
|
const scope = installScope();
|
|
274
291
|
const agents = installAgents();
|
package/dist/modes.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.buildRefreshIndexBlock = buildRefreshIndexBlock;
|
|
37
37
|
exports.runQueryMode = runQueryMode;
|
|
38
38
|
exports.runWikiImpactMode = runWikiImpactMode;
|
|
39
|
+
exports.runWikiNeighborhoodMode = runWikiNeighborhoodMode;
|
|
39
40
|
exports.projectCandidatesContent = projectCandidatesContent;
|
|
40
41
|
exports.appendProjectCandidate = appendProjectCandidate;
|
|
41
42
|
exports.appendCaptureInbox = appendCaptureInbox;
|
|
@@ -325,6 +326,14 @@ function runWikiImpactMode() {
|
|
|
325
326
|
const corpus = (0, wiki_corpus_1.loadWikiCorpus)();
|
|
326
327
|
console.log((0, wiki_graph_1.wikiImpactAnswer)(corpus.pages, args_1.wikiImpactTarget.trim(), (0, wiki_corpus_1.wikiCorpusGraph)(corpus)));
|
|
327
328
|
}
|
|
329
|
+
function runWikiNeighborhoodMode() {
|
|
330
|
+
if (!args_1.wikiNeighborhoodTarget.trim()) {
|
|
331
|
+
console.error("missing wiki neighborhood target: use --wiki-neighborhood \"page-or-term\"");
|
|
332
|
+
process.exit(1);
|
|
333
|
+
}
|
|
334
|
+
const corpus = (0, wiki_corpus_1.loadWikiCorpus)();
|
|
335
|
+
console.log((0, wiki_graph_1.wikiNeighborhoodAnswer)(corpus.pages, args_1.wikiNeighborhoodTarget.trim(), (0, wiki_corpus_1.wikiCorpusGraph)(corpus)));
|
|
336
|
+
}
|
|
328
337
|
function projectCandidatesContent() {
|
|
329
338
|
return `${(0, templates_1.metadata)("inbox", "on-demand", "wiki/meta/wiki-ops-v1-decisions.md", "candidates are adopted, rejected, or stale")}
|
|
330
339
|
# Project Candidates Inbox
|
|
@@ -699,6 +708,7 @@ function collectLinkDiagnostics(corpus = (0, wiki_corpus_1.loadWikiCorpus)()) {
|
|
|
699
708
|
}
|
|
700
709
|
}
|
|
701
710
|
}
|
|
711
|
+
diagnostics.push(...(0, wiki_diagnostics_1.collectTopologyDiagnostics)(corpus));
|
|
702
712
|
return diagnostics.sort((a, b) => a.severity.localeCompare(b.severity) || a.file.localeCompare(b.file) || a.code.localeCompare(b.code));
|
|
703
713
|
}
|
|
704
714
|
function legacyWikiRoots() {
|
|
@@ -725,9 +735,10 @@ function migrationLegacyReferenceDiagnostics(files, corpus) {
|
|
|
725
735
|
message: "new project truth must not link to or cite wiki_legacy*; migrate the meaning or keep unresolved material in migration inboxes",
|
|
726
736
|
}));
|
|
727
737
|
}
|
|
728
|
-
function collectQualityDiagnostics(corpus = (0, wiki_corpus_1.loadWikiCorpus)()) {
|
|
738
|
+
function collectQualityDiagnostics(corpus = (0, wiki_corpus_1.loadWikiCorpus)(), options = {}) {
|
|
729
739
|
const diagnostics = [];
|
|
730
740
|
const files = corpus.files;
|
|
741
|
+
const currentDate = options.today ?? workspace_1.today;
|
|
731
742
|
const titles = new Map();
|
|
732
743
|
for (const file of files) {
|
|
733
744
|
const text = (0, wiki_corpus_1.wikiCorpusText)(corpus, file);
|
|
@@ -742,7 +753,7 @@ function collectQualityDiagnostics(corpus = (0, wiki_corpus_1.loadWikiCorpus)())
|
|
|
742
753
|
if (tldrExpected && !/##\s+TL;DR/.test(body)) {
|
|
743
754
|
diagnostics.push({ code: "missing-tldr", severity: "warn", file, message: "add a compact TL;DR near the top" });
|
|
744
755
|
}
|
|
745
|
-
const reviewAge = updated ? (0, wiki_diagnostics_1.staleReviewAge)(updated,
|
|
756
|
+
const reviewAge = updated ? (0, wiki_diagnostics_1.staleReviewAge)(updated, currentDate) : null;
|
|
746
757
|
if (status === "active" && reviewAge !== null && /project-canonical|project-decisions|source-summary|wiki-meta/.test(scope)) {
|
|
747
758
|
diagnostics.push({ code: "stale-review", severity: "warn", file, message: `updated ${reviewAge} days ago: ${updated}` });
|
|
748
759
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -21,39 +21,39 @@
|
|
|
21
21
|
"architecture": "arm64",
|
|
22
22
|
"format": "elf",
|
|
23
23
|
"path": "dist/native/linux-arm64/project-librarian-indexer",
|
|
24
|
-
"sha256": "
|
|
25
|
-
"size":
|
|
24
|
+
"sha256": "88146d5bbe5b77bb53e2cbe872ad6d2a8a93a58fa1b53671841cc94463443f46",
|
|
25
|
+
"size": 3065568,
|
|
26
26
|
"triple": "linux-arm64"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"architecture": "arm64",
|
|
30
30
|
"format": "elf",
|
|
31
31
|
"path": "dist/native/linux-arm64-musl/project-librarian-indexer",
|
|
32
|
-
"sha256": "
|
|
33
|
-
"size":
|
|
32
|
+
"sha256": "bcb48020ae87fe3e5ebd6a8d986a91f83e67e5d69c4df9357a7c3a6c78c232b0",
|
|
33
|
+
"size": 3101344,
|
|
34
34
|
"triple": "linux-arm64-musl"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"architecture": "x64",
|
|
38
38
|
"format": "elf",
|
|
39
39
|
"path": "dist/native/linux-x64/project-librarian-indexer",
|
|
40
|
-
"sha256": "
|
|
41
|
-
"size":
|
|
40
|
+
"sha256": "22d32884276c23c4597bd611facd5880936b29600c8331bb3d585d2ab370a206",
|
|
41
|
+
"size": 3110688,
|
|
42
42
|
"triple": "linux-x64"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"architecture": "x64",
|
|
46
46
|
"format": "elf",
|
|
47
47
|
"path": "dist/native/linux-x64-musl/project-librarian-indexer",
|
|
48
|
-
"sha256": "
|
|
49
|
-
"size":
|
|
48
|
+
"sha256": "811221a87fe5d8ef9f67f4eafe4386ef7aa03bdc1601e89fa191c0e0d7b0dcd5",
|
|
49
|
+
"size": 3247424,
|
|
50
50
|
"triple": "linux-x64-musl"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"architecture": "arm64",
|
|
54
54
|
"format": "pe",
|
|
55
55
|
"path": "dist/native/win32-arm64/project-librarian-indexer.exe",
|
|
56
|
-
"sha256": "
|
|
56
|
+
"sha256": "69aeecd89d8ec8e7e4e85adfdf15cd682df9eaa14b8e6d0e99f445eeb70e6267",
|
|
57
57
|
"size": 2098688,
|
|
58
58
|
"triple": "win32-arm64"
|
|
59
59
|
},
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"architecture": "x64",
|
|
62
62
|
"format": "pe",
|
|
63
63
|
"path": "dist/native/win32-x64/project-librarian-indexer.exe",
|
|
64
|
-
"sha256": "
|
|
64
|
+
"sha256": "ae493dbea6ddd4cd6831ad9a21db07df0c6e2989602e6048dfbfa9aa1eb80ee5",
|
|
65
65
|
"size": 2375680,
|
|
66
66
|
"triple": "win32-x64"
|
|
67
67
|
}
|
|
Binary file
|
|
Binary file
|
package/dist/wiki-diagnostics.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.staleReviewAgeDays = void 0;
|
|
3
|
+
exports.topologyFanoutThreshold = exports.topologyHubOverloadThreshold = exports.staleReviewAgeDays = void 0;
|
|
4
4
|
exports.staleReviewAge = staleReviewAge;
|
|
5
|
+
exports.collectTopologyDiagnostics = collectTopologyDiagnostics;
|
|
6
|
+
const wiki_corpus_1 = require("./wiki-corpus");
|
|
7
|
+
const wiki_graph_1 = require("./wiki-graph");
|
|
8
|
+
const workspace_1 = require("./workspace");
|
|
5
9
|
exports.staleReviewAgeDays = 30;
|
|
10
|
+
exports.topologyHubOverloadThreshold = 60;
|
|
11
|
+
exports.topologyFanoutThreshold = 8;
|
|
6
12
|
function dateOnlyMillis(value) {
|
|
7
13
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
8
14
|
return null;
|
|
@@ -17,3 +23,107 @@ function staleReviewAge(updated, currentDate) {
|
|
|
17
23
|
const ageDays = Math.floor((currentMillis - updatedMillis) / 86_400_000);
|
|
18
24
|
return ageDays > exports.staleReviewAgeDays ? ageDays : null;
|
|
19
25
|
}
|
|
26
|
+
function uniqueExisting(values, fileSet) {
|
|
27
|
+
return Array.from(new Set(values.filter((value) => fileSet.has(value)))).sort();
|
|
28
|
+
}
|
|
29
|
+
function isGeneratedScopedRouter(file) {
|
|
30
|
+
return /^wiki\/indexes\/auto-[a-z0-9-]+(?:-\d+)?\.md$/.test(file);
|
|
31
|
+
}
|
|
32
|
+
function isCanonicalTruthPage(file, text) {
|
|
33
|
+
return file.startsWith("wiki/canonical/") && (0, workspace_1.metadataValue)(text, "status") === "active";
|
|
34
|
+
}
|
|
35
|
+
function hasEvidenceClaimSignal(body) {
|
|
36
|
+
return /\b(source-backed|source backed|research-backed|external research|paper-backed|evidence-backed)\b/i.test(body);
|
|
37
|
+
}
|
|
38
|
+
function hasDecisionRefSignal(text) {
|
|
39
|
+
const decisionRef = (0, workspace_1.metadataValue)(text, "decision_ref").trim().toLowerCase();
|
|
40
|
+
return decisionRef !== "" && decisionRef !== "none";
|
|
41
|
+
}
|
|
42
|
+
function hasFocusedAuthoritySignal(text, body) {
|
|
43
|
+
return hasDecisionRefSignal(text) || hasEvidenceClaimSignal(body);
|
|
44
|
+
}
|
|
45
|
+
function hasEvidenceLink(file, corpus, graph = (0, wiki_corpus_1.wikiCorpusGraph)(corpus)) {
|
|
46
|
+
const outgoingLinks = graph.outgoingLinks.get(file) ?? [];
|
|
47
|
+
const sourceLink = outgoingLinks.some((link) => link.normalizedTarget.startsWith("wiki/sources/") && corpus.fileSet.has(link.normalizedTarget));
|
|
48
|
+
const decisionRef = graph.outgoingDecisionRef.get(file);
|
|
49
|
+
return sourceLink || Boolean(decisionRef && corpus.fileSet.has(decisionRef));
|
|
50
|
+
}
|
|
51
|
+
function isBroadReviewTrigger(trigger) {
|
|
52
|
+
const normalized = trigger.toLowerCase().trim();
|
|
53
|
+
if (!normalized)
|
|
54
|
+
return false;
|
|
55
|
+
return normalized === "changes"
|
|
56
|
+
|| normalized === "project changes"
|
|
57
|
+
|| normalized === "routine review"
|
|
58
|
+
|| /^any\b.*changes$/.test(normalized)
|
|
59
|
+
|| /^general\b.*changes$/.test(normalized);
|
|
60
|
+
}
|
|
61
|
+
function isTopologyHub(file) {
|
|
62
|
+
return file === "wiki/index.md"
|
|
63
|
+
|| file.startsWith("wiki/meta/")
|
|
64
|
+
|| /^wiki\/indexes\/(?!auto-)[^/]+\.md$/.test(file);
|
|
65
|
+
}
|
|
66
|
+
function collectTopologyDiagnostics(corpus) {
|
|
67
|
+
const diagnostics = [];
|
|
68
|
+
const graph = (0, wiki_corpus_1.wikiCorpusGraph)(corpus);
|
|
69
|
+
for (const file of corpus.files) {
|
|
70
|
+
if (isGeneratedScopedRouter(file))
|
|
71
|
+
continue;
|
|
72
|
+
const outgoing = uniqueExisting((graph.outgoingLinks.get(file) ?? [])
|
|
73
|
+
.map((link) => link.normalizedTarget)
|
|
74
|
+
.filter((target) => target !== file), corpus.fileSet);
|
|
75
|
+
if (isTopologyHub(file) && outgoing.length > exports.topologyHubOverloadThreshold) {
|
|
76
|
+
diagnostics.push({
|
|
77
|
+
code: "hub-overload",
|
|
78
|
+
severity: "warn",
|
|
79
|
+
file,
|
|
80
|
+
message: `${outgoing.length} outgoing wiki links exceed the topology hub threshold ${exports.topologyHubOverloadThreshold}; split or scope the route surface`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const file of corpus.files) {
|
|
85
|
+
const text = (0, wiki_corpus_1.wikiCorpusText)(corpus, file);
|
|
86
|
+
if (isCanonicalTruthPage(file, text)) {
|
|
87
|
+
const body = (0, workspace_1.stripMetadataHeader)(text);
|
|
88
|
+
const incoming = uniqueExisting((graph.incomingLinks.get(file) ?? [])
|
|
89
|
+
.map((link) => link.file)
|
|
90
|
+
.filter((source) => source !== file), corpus.fileSet);
|
|
91
|
+
if (incoming.length > 0 && incoming.every(isGeneratedScopedRouter) && hasFocusedAuthoritySignal(text, body)) {
|
|
92
|
+
diagnostics.push({
|
|
93
|
+
code: "weak-authority-route",
|
|
94
|
+
severity: "warn",
|
|
95
|
+
file,
|
|
96
|
+
message: "active canonical page with authority signals is routed only by generated auto-index pages; add a focused route when this truth is durable",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (hasEvidenceClaimSignal(body) && !hasEvidenceLink(file, corpus, graph)) {
|
|
100
|
+
diagnostics.push({
|
|
101
|
+
code: "missing-evidence-link",
|
|
102
|
+
severity: "warn",
|
|
103
|
+
file,
|
|
104
|
+
message: "canonical page makes a source-backed claim but has no source link or decision_ref evidence link",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const file of corpus.files) {
|
|
110
|
+
if (file === wiki_graph_1.wikiRouterRoot || isGeneratedScopedRouter(file))
|
|
111
|
+
continue;
|
|
112
|
+
const text = (0, wiki_corpus_1.wikiCorpusText)(corpus, file);
|
|
113
|
+
if ((0, workspace_1.metadataValue)(text, "status") !== "active")
|
|
114
|
+
continue;
|
|
115
|
+
const incoming = uniqueExisting((graph.incomingLinks.get(file) ?? [])
|
|
116
|
+
.map((link) => link.file)
|
|
117
|
+
.filter((source) => source !== file), corpus.fileSet);
|
|
118
|
+
const reviewTrigger = (0, workspace_1.metadataValue)(text, "review_trigger");
|
|
119
|
+
if (incoming.length >= exports.topologyFanoutThreshold && isBroadReviewTrigger(reviewTrigger)) {
|
|
120
|
+
diagnostics.push({
|
|
121
|
+
code: "stale-fanout",
|
|
122
|
+
severity: "warn",
|
|
123
|
+
file,
|
|
124
|
+
message: `${incoming.length} incoming links with broad review_trigger "${reviewTrigger}"; tighten review trigger before broad edits`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code));
|
|
129
|
+
}
|