project-librarian 0.2.1 → 0.3.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/README.ko.md +245 -93
- package/README.md +174 -76
- package/SKILL.md +15 -10
- package/dist/args.js +11 -2
- package/dist/code-index-file-policy.js +105 -2
- package/dist/code-index.js +77 -59
- package/dist/hooks.js +78 -0
- package/dist/init-project-wiki.js +234 -166
- package/dist/install-skill.js +2 -9
- package/dist/mcp-server.js +449 -0
- package/dist/migration.js +875 -60
- package/dist/modes.js +205 -59
- package/dist/taxonomy.js +193 -0
- package/dist/templates.js +214 -36
- package/dist/wiki-files.js +15 -27
- package/dist/wiki-graph.js +141 -0
- package/package.json +3 -3
- package/README.ja.md +0 -215
- package/README.zh.md +0 -215
package/dist/templates.js
CHANGED
|
@@ -1,8 +1,67 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.starterFiles = exports.decisionPolicy = exports.wikiOperatingModel = exports.inboxIndexBlock = exports.glossaryIndexBlock = exports.glossary = exports.index = exports.startup = exports.metadata = exports.wikiAgentsSection = exports.cursorRule = exports.geminiSection = exports.claudeSection = exports.
|
|
3
|
+
exports.defaultStarterFilePaths = exports.starterFiles = exports.documentTaxonomy = exports.decisionPolicy = exports.wikiOperatingModel = exports.inboxIndexBlock = exports.glossaryIndexBlock = exports.glossary = exports.index = exports.startup = exports.metadata = exports.wikiAgentsSection = exports.cursorRule = exports.geminiSection = exports.claudeSection = exports.STARTUP_TLDR_MAX_CHARS = exports.startupTldrSyncLabel = exports.codeEvidenceTrustContract = exports.wikiTrustContract = void 0;
|
|
4
|
+
exports.extractStartupTldr = extractStartupTldr;
|
|
5
|
+
exports.agentsSection = agentsSection;
|
|
4
6
|
const workspace_1 = require("./workspace");
|
|
5
|
-
|
|
7
|
+
// B4 (gated on B2, which ships in the same phase): a single-sentence trust
|
|
8
|
+
// contract in the managed AGENTS.md block. It is the substitution mechanism that
|
|
9
|
+
// stops repo-wide re-verification greps; the --doctor router-truth rule (B2)
|
|
10
|
+
// guards against trusting a stale router.
|
|
11
|
+
exports.wikiTrustContract = "Wiki decision documents are authoritative for project decisions: do not re-verify them against the repository unless directly conflicting code evidence appears, since the `--doctor` router-truth rule guards against stale routers.";
|
|
12
|
+
// B4 analogue for code evidence: a single-sentence trust contract making the
|
|
13
|
+
// code-evidence tool/report outputs authoritative for code-structure questions,
|
|
14
|
+
// gated on the same staleness check the tools surface (`--code-status` /
|
|
15
|
+
// `code_status`). Mirrors wikiTrustContract scale; kept budget-conscious. The
|
|
16
|
+
// closing clause is the scale-conditional guidance (2026-06-12 decision, stageR1
|
|
17
|
+
// evidence): on small repos simple lookups measured cheaper via direct reads.
|
|
18
|
+
exports.codeEvidenceTrustContract = "Code-evidence tool and report outputs (`--code-impact`, `--code-report`, and the `project-librarian mcp` tools) are authoritative for code-structure questions: do not re-verify them with repo-wide greps unless `--code-status`/`code_status` reports staleness; on small repos below the measured scale threshold, prefer direct reads over these tools for simple lookups (measured cheaper at small scale).";
|
|
19
|
+
// B1 fallback: label for the auto-synced startup TL;DR sub-block embedded in the
|
|
20
|
+
// managed AGENTS.md marker section. Non-interactive `codex exec` does not run
|
|
21
|
+
// SessionStart hooks (measured 2026-06-10), so AGENTS.md is the only startup
|
|
22
|
+
// context carrier there; the sync stays TL;DR-only per token discipline.
|
|
23
|
+
exports.startupTldrSyncLabel = "Startup TL;DR (auto-synced for non-interactive sessions; source: wiki/startup.md)";
|
|
24
|
+
// Hard cap on the extracted TL;DR text embedded in AGENTS.md. The startup hook
|
|
25
|
+
// budget is 3500 chars for the full wiki/startup.md; the TL;DR sub-section must
|
|
26
|
+
// stay well under that so the managed block remains token-efficient. 2000 chars is
|
|
27
|
+
// a documented hard bound: it leaves headroom for frontmatter, other sections, and
|
|
28
|
+
// the AGENTS.md surrounding content. Per the no-fallback rule, we NEVER truncate —
|
|
29
|
+
// if the extracted bullets exceed this limit the sync fails loudly so the author
|
|
30
|
+
// knows to trim the TL;DR.
|
|
31
|
+
exports.STARTUP_TLDR_MAX_CHARS = 2000;
|
|
32
|
+
// Extract the `## TL;DR` bullet list from a startup.md body (TL;DR section ONLY —
|
|
33
|
+
// never Recent Decisions or Project State). Returns the `- ` bullet lines between
|
|
34
|
+
// the `## TL;DR` heading and the next `## ` heading. Throws loudly when the
|
|
35
|
+
// startup body has no `## TL;DR` section, that section has no bullets, or the
|
|
36
|
+
// extracted text exceeds STARTUP_TLDR_MAX_CHARS (no fallback, no silent truncation).
|
|
37
|
+
function extractStartupTldr(startupMarkdown) {
|
|
38
|
+
const match = startupMarkdown.match(/^##\s+TL;DR[^\n]*\n([\s\S]*?)(?=\n##\s|(?![\s\S]))/m);
|
|
39
|
+
if (!match) {
|
|
40
|
+
throw new Error("cannot sync startup TL;DR into AGENTS.md: wiki/startup.md has no \"## TL;DR\" section");
|
|
41
|
+
}
|
|
42
|
+
const bullets = (match[1] ?? "")
|
|
43
|
+
.split(/\r?\n/)
|
|
44
|
+
.map((line) => line.trimEnd())
|
|
45
|
+
.filter((line) => /^\s*-\s+\S/.test(line));
|
|
46
|
+
if (bullets.length === 0) {
|
|
47
|
+
throw new Error("cannot sync startup TL;DR into AGENTS.md: the wiki/startup.md \"## TL;DR\" section has no bullet items");
|
|
48
|
+
}
|
|
49
|
+
const result = bullets.join("\n");
|
|
50
|
+
if (result.length > exports.STARTUP_TLDR_MAX_CHARS) {
|
|
51
|
+
throw new Error(`cannot sync startup TL;DR into AGENTS.md: extracted TL;DR is ${result.length} chars, which exceeds the ${exports.STARTUP_TLDR_MAX_CHARS}-char limit; trim the ## TL;DR section in wiki/startup.md`);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
// Build the managed AGENTS.md marker section. The startup TL;DR is synced in as a
|
|
56
|
+
// clearly labeled sub-block (B1 fallback) so non-interactive Codex sessions, which
|
|
57
|
+
// never run the SessionStart hook, still receive compact startup context; the
|
|
58
|
+
// trust contract sentence (B4) is appended to the during-conversation rules. Only
|
|
59
|
+
// this marker block changes; user content outside the markers is untouched, and
|
|
60
|
+
// because the section is built deterministically from the current startup TL;DR a
|
|
61
|
+
// re-run with unchanged startup yields the same section ("exists" via
|
|
62
|
+
// upsertMarkedSection).
|
|
63
|
+
function agentsSection(startupTldr) {
|
|
64
|
+
return `<!-- PROJECT-WIKI-FIRST:START -->
|
|
6
65
|
## Wiki-First Planning
|
|
7
66
|
|
|
8
67
|
This project uses \`./wiki\` as the durable project-planning source of truth.
|
|
@@ -13,13 +72,21 @@ At the start of every session:
|
|
|
13
72
|
2. Review \`wiki/index.md\` as the router for which files to read next.
|
|
14
73
|
3. Read detailed \`wiki/canonical/\`, \`wiki/decisions/\`, \`wiki/meta/\`, and \`wiki/sources/\` files on demand only when the current question needs them.
|
|
15
74
|
|
|
75
|
+
### ${exports.startupTldrSyncLabel}
|
|
76
|
+
|
|
77
|
+
${startupTldr}
|
|
78
|
+
|
|
16
79
|
During conversation:
|
|
17
80
|
|
|
18
81
|
- Update \`./wiki\` in the same turn when project planning content is added, changed, or removed.
|
|
82
|
+
- Classify new project-planning content with \`wiki/meta/document-taxonomy.md\` before writing or consolidating it.
|
|
19
83
|
- Do not store non-project LLM memory, assistant preferences, collaboration reminders, or workflow instructions in project wiki canonical or decision docs.
|
|
20
84
|
- Follow \`wiki/AGENTS.md\` for detailed rules when editing files under \`wiki/\`.
|
|
21
85
|
- Let \`.githooks/prepare-commit-msg\` append wiki trailers automatically for staged wiki, hook, AGENTS, or project-librarian files.
|
|
86
|
+
- ${exports.wikiTrustContract}
|
|
87
|
+
- ${exports.codeEvidenceTrustContract}
|
|
22
88
|
<!-- PROJECT-WIKI-FIRST:END -->`;
|
|
89
|
+
}
|
|
23
90
|
exports.claudeSection = `<!-- PROJECT-WIKI-CLAUDE:START -->
|
|
24
91
|
# Claude Code Project Instructions
|
|
25
92
|
|
|
@@ -79,6 +146,14 @@ Storage boundaries:
|
|
|
79
146
|
- Do not store non-project LLM memory, assistant preferences, collaboration reminders, or workflow instructions in \`canonical/\` or \`decisions/\`; use root \`AGENTS.md\`, compatibility instruction files, hooks, rules, or skills instead.
|
|
80
147
|
- During migration review, preserve useful meaning while converting it to the current wiki structure. Legacy files, sections, blocks, and wording may be retained when review confirms they belong in the new topic shape and remain current project truth. Do not link to or cite \`wiki_legacy*\` from the new wiki; cite current-project evidence when possible and keep unresolved or ambiguous material in migration inboxes.
|
|
81
148
|
|
|
149
|
+
Classification rules:
|
|
150
|
+
|
|
151
|
+
- Before adding or consolidating project content, classify it with \`meta/document-taxonomy.md\`.
|
|
152
|
+
- Write current agreement to the narrowest durable canonical document that fits the taxonomy; do not append unrelated material to \`canonical/project-brief.md\`.
|
|
153
|
+
- If one input crosses several lifecycle areas, split it into separate canonical updates and link the related pages.
|
|
154
|
+
- If the input explains why a direction changed, update the relevant decision log or Decision Pack in addition to canonical truth.
|
|
155
|
+
- If an external artifact is the better source of truth (for example Figma, OpenAPI, ERD, issue tracker, or code), keep a concise canonical summary and link the external source as the authoritative location.
|
|
156
|
+
|
|
82
157
|
Update rules:
|
|
83
158
|
|
|
84
159
|
- Every wiki knowledge markdown file should include compact metadata with \`status\`, \`updated\`, \`scope\`, \`read_budget\`, \`decision_ref\`, and \`review_trigger\`. This \`wiki/AGENTS.md\` instruction file is excluded from that wiki-page metadata requirement.
|
|
@@ -117,14 +192,12 @@ exports.startup = `${(0, exports.metadata)("startup-router", "short", "wiki/meta
|
|
|
117
192
|
- At session start, read only this file and \`wiki/index.md\` first; read detailed files on demand.
|
|
118
193
|
- Project canonical content language is not fixed by this bootstrap. The LLM should choose the language that best matches the user and project context.
|
|
119
194
|
- Update the wiki in the same turn when project-planning content changes.
|
|
195
|
+
- Classify new project-planning content with \`wiki/meta/document-taxonomy.md\` before writing or consolidating it.
|
|
120
196
|
|
|
121
197
|
## Read On Demand
|
|
122
198
|
|
|
123
199
|
- [[index]]: document router.
|
|
124
|
-
- [[
|
|
125
|
-
- [[canonical/open-questions]]: read only when unresolved questions or next clarification items matter.
|
|
126
|
-
- [[canonical/assumptions]]: read only when temporary assumptions or unverified premises matter.
|
|
127
|
-
- [[canonical/risks]]: read only when risks, revisit triggers, or uncertainty matter.
|
|
200
|
+
- [[meta/document-taxonomy]]: read only when classifying or reorganizing project wiki content.
|
|
128
201
|
|
|
129
202
|
## Project State
|
|
130
203
|
|
|
@@ -179,22 +252,7 @@ This file is a router, not a file to expand into every answer. Read only the fil
|
|
|
179
252
|
|
|
180
253
|
## Canonical
|
|
181
254
|
|
|
182
|
-
|
|
183
|
-
- Read: product direction, audience, scope, success criteria, core scenarios.
|
|
184
|
-
- Update: product, audience, scope, or success criteria changes.
|
|
185
|
-
- Token budget: medium.
|
|
186
|
-
- [[canonical/open-questions]]
|
|
187
|
-
- Read: unresolved questions or next clarifications.
|
|
188
|
-
- Update: questions are added, answered, or moved.
|
|
189
|
-
- Token budget: short.
|
|
190
|
-
- [[canonical/assumptions]]
|
|
191
|
-
- Read: temporary assumptions or unverified premises.
|
|
192
|
-
- Update: assumptions are added, validated, or retired.
|
|
193
|
-
- Token budget: short.
|
|
194
|
-
- [[canonical/risks]]
|
|
195
|
-
- Read: risks, revisit triggers, uncertainty.
|
|
196
|
-
- Update: risks are added, mitigated, or resolved.
|
|
197
|
-
- Token budget: short.
|
|
255
|
+
No empty canonical starter pages are created by default. Create focused pages under \`wiki/canonical/\` only when durable project truth exists, then route them here or with \`--refresh-index\`.
|
|
198
256
|
|
|
199
257
|
## Project Decisions
|
|
200
258
|
|
|
@@ -202,18 +260,14 @@ This file is a router, not a file to expand into every answer. Read only the fil
|
|
|
202
260
|
- Read: recent important project decisions.
|
|
203
261
|
- Update: a decision belongs in startup context.
|
|
204
262
|
- Token budget: short.
|
|
263
|
+
- [[decisions/README]]
|
|
264
|
+
- Read: decision directory structure or decision routing conventions.
|
|
265
|
+
- Update: decision directory conventions change.
|
|
266
|
+
- Token budget: short.
|
|
205
267
|
- [[decisions/log]]
|
|
206
268
|
- Read: project decision timing matters.
|
|
207
269
|
- Update: a trivial decision needs timestamp tracking.
|
|
208
270
|
- Token budget: on-demand.
|
|
209
|
-
- [[decisions/decision-pack-template]]
|
|
210
|
-
- Read: creating a Decision Pack.
|
|
211
|
-
- Update: Decision Pack format changes.
|
|
212
|
-
- Token budget: short.
|
|
213
|
-
- [[decisions/full-adr-template]]
|
|
214
|
-
- Read: creating a Full ADR.
|
|
215
|
-
- Update: Full ADR format changes.
|
|
216
|
-
- Token budget: short.
|
|
217
271
|
|
|
218
272
|
## Wiki Meta
|
|
219
273
|
|
|
@@ -221,6 +275,10 @@ This file is a router, not a file to expand into every answer. Read only the fil
|
|
|
221
275
|
- Read: wiki operation, hooks, bootstrap, maintenance, language policy.
|
|
222
276
|
- Update: wiki operation or startup behavior changes.
|
|
223
277
|
- Token budget: medium.
|
|
278
|
+
- [[meta/document-taxonomy]]
|
|
279
|
+
- Read: classifying, writing, consolidating, splitting, or reorganizing project wiki content.
|
|
280
|
+
- Update: wiki information architecture or service-documentation categories change.
|
|
281
|
+
- Token budget: medium.
|
|
224
282
|
- [[meta/decision-policy]]
|
|
225
283
|
- Read: decision level, ADR need, canonical/decision split.
|
|
226
284
|
- Update: decision classification or ADR criteria changes.
|
|
@@ -281,6 +339,7 @@ exports.wikiOperatingModel = `${(0, exports.metadata)("wiki-meta", "medium", "wi
|
|
|
281
339
|
- Operating documents generated by bootstrap are English by default.
|
|
282
340
|
- Project canonical content language is selected from user/project context, not hardcoded by this bootstrap.
|
|
283
341
|
- Search, index refresh, inbox capture, and lifecycle checks are explicit script modes.
|
|
342
|
+
- New project content is classified through [[meta/document-taxonomy]] before it is written or consolidated.
|
|
284
343
|
|
|
285
344
|
## Purpose
|
|
286
345
|
|
|
@@ -299,6 +358,18 @@ Karpathy's LLM Wiki pattern favors a continuously maintained markdown wiki over
|
|
|
299
358
|
5. Router: read/update/token-budget guidance in \`wiki/index.md\`.
|
|
300
359
|
6. Wiki meta: operating rules, decision policy, bootstrap, migration, lint, and language policy under \`wiki/meta/\`.
|
|
301
360
|
|
|
361
|
+
## Content Classification Procedure
|
|
362
|
+
|
|
363
|
+
Before writing or reorganizing project-planning content:
|
|
364
|
+
|
|
365
|
+
1. Identify the content's lifecycle area with [[meta/document-taxonomy]].
|
|
366
|
+
2. Decide whether the content is current truth, decision rationale, source evidence, an unresolved candidate, or a wiki operating rule.
|
|
367
|
+
3. Write current truth to the narrowest relevant \`canonical/\` page, decision rationale to \`decisions/\`, source notes to \`sources/\`, candidates to \`inbox/\`, and wiki operating rules to \`meta/\`.
|
|
368
|
+
4. Split multi-area inputs instead of making one catch-all document.
|
|
369
|
+
5. Link upstream and downstream pages when the content derives from another artifact or produces another artifact.
|
|
370
|
+
|
|
371
|
+
Do not treat \`canonical/project-brief.md\` as a default dumping ground. It should summarize direction, audience, scope, and success criteria; detailed product, policy, UX, data, engineering, QA, release, or operations truth should move into focused pages when it grows.
|
|
372
|
+
|
|
302
373
|
## Language Policy
|
|
303
374
|
|
|
304
375
|
- Bootstrap-generated operating documents are English.
|
|
@@ -371,6 +442,106 @@ Use a Full ADR when the decision affects product direction, architecture, public
|
|
|
371
442
|
- Do not inject full canonical or decision bodies into startup context.
|
|
372
443
|
- Read long decision files only when \`wiki/index.md\` routing says they are relevant.
|
|
373
444
|
`;
|
|
445
|
+
exports.documentTaxonomy = `${(0, exports.metadata)("wiki-meta", "medium", "wiki/meta/wiki-ops-v1-decisions.md", "wiki information architecture, documentation categories, or content classification rules change")}
|
|
446
|
+
# Document Taxonomy
|
|
447
|
+
|
|
448
|
+
## TL;DR
|
|
449
|
+
|
|
450
|
+
- Classify new project-planning content before writing it into the wiki.
|
|
451
|
+
- Use this page to classify content into \`canonical/\`, \`decisions/\`, \`sources/\`, \`inbox/\`, or \`meta/\`.
|
|
452
|
+
- Keep \`canonical/project-brief.md\` compact; move detailed truth into focused canonical pages.
|
|
453
|
+
- Preserve derivation links: evidence -> strategy -> requirements -> design/data/engineering -> QA -> release/operations -> feedback.
|
|
454
|
+
|
|
455
|
+
## Top-Level Flow
|
|
456
|
+
|
|
457
|
+
\`\`\`text
|
|
458
|
+
0. Source-of-truth governance
|
|
459
|
+
-> 1. Research and evidence
|
|
460
|
+
-> 2. Strategy and business model
|
|
461
|
+
-> 3. Product scope and requirements
|
|
462
|
+
-> 4. Policies and rules
|
|
463
|
+
-> 5. UX and content
|
|
464
|
+
-> 6. Design
|
|
465
|
+
-> 7. Data and analytics
|
|
466
|
+
-> 8. Engineering
|
|
467
|
+
-> 9. Security, legal, compliance
|
|
468
|
+
-> 10. QA and verification
|
|
469
|
+
-> 11. Release and operations
|
|
470
|
+
-> 12. Business operations
|
|
471
|
+
-> 13. Improvement, migration, and end-of-life
|
|
472
|
+
-> next product scope, policy, or roadmap change
|
|
473
|
+
\`\`\`
|
|
474
|
+
|
|
475
|
+
## Storage Decision
|
|
476
|
+
|
|
477
|
+
| Content Type | Store In | Notes |
|
|
478
|
+
| --- | --- | --- |
|
|
479
|
+
| Current valid project truth | \`wiki/canonical/\` | Split by topic and read frequency. |
|
|
480
|
+
| Why a choice was made | \`wiki/decisions/\` | Use log, Decision Pack, or ADR by impact. |
|
|
481
|
+
| Source material or summarized evidence | \`wiki/sources/\` | Keep links, checked dates, and applicability. |
|
|
482
|
+
| Unreviewed or ambiguous material | \`wiki/inbox/\` | Do not treat as canonical truth. |
|
|
483
|
+
| Wiki operation, taxonomy, hooks, migration, lint, language rules | \`wiki/meta/\` | Keep outside project canonical truth. |
|
|
484
|
+
| Better external source of truth | External artifact plus a concise wiki route | Examples: Figma, OpenAPI, ERD, Jira, code. |
|
|
485
|
+
|
|
486
|
+
## Lifecycle Areas
|
|
487
|
+
|
|
488
|
+
| Area | Put Here | Usually Derives From | Usually Produces |
|
|
489
|
+
| --- | --- | --- | --- |
|
|
490
|
+
| 0. Governance | source-of-truth map, owners, RACI, approval flow, change rules, glossary, state dictionary, assumptions, risk register | team/process constraints | routing, ownership, conflict resolution |
|
|
491
|
+
| 1. Research | market, competitor, user interviews, VOC, analytics, legal/regulatory, technical feasibility, cost, vendor, accessibility research | raw discovery | strategy, risks, sources |
|
|
492
|
+
| 2. Strategy | service overview, vision, problem, target users, personas, jobs-to-be-done, value offer, positioning, business model, KPI/OKR, success/stop criteria, roadmap, MVP, non-goals | research | PRD, roadmap, scope |
|
|
493
|
+
| 3. Product | PRD, user stories, use cases, priorities, backlog rules, acceptance criteria, feature spec, exceptions, state definitions, notification rules, search/filter/sort rules, admin requirements | strategy and policy | UX, API, data, QA |
|
|
494
|
+
| 4. Policy | operations policy, auth/account, permissions, pricing, payment/refund, coupon/credit, content moderation, notifications, retention/deletion, abuse response, support, EOL | business model, law, risks | feature constraints, API rules, CS/ops |
|
|
495
|
+
| 5. UX and Content | IA, sitemap, user flow, task flow, screen list, wireframes, screen specs, content model, UX writing, empty/error states, help/FAQ, localization, SEO, accessibility criteria | product and policy | design, frontend, QA |
|
|
496
|
+
| 6. Design | brand guide, design principles, design system, component spec, responsive rules, interaction spec, prototype, design QA | UX and brand | UI implementation, design QA |
|
|
497
|
+
| 7. Data and Analytics | ERD, data dictionary, classification, ownership/stewardship, event taxonomy, metric definitions, funnels, data quality, lineage, export/import, anonymization, dashboards | product, policy, KPI | schemas, events, reports |
|
|
498
|
+
| 8. Engineering | architecture, technology decisions, API/OpenAPI, integrations, webhooks/idempotency, state machines, jobs/cron, error codes, env vars, secrets, local dev, conventions, branch/release strategy, CI/CD, feature flags, dependencies, migrations, performance, scalability, FinOps | product, UX, data, policy | implementation and verification |
|
|
499
|
+
| 9. Security/Legal | security requirements, threat model, privacy rules, privacy impact, terms, privacy policy, audit logs, permission history, internal access controls, key rotation, vulnerability response, licenses, vendor and DPA documents | data, architecture, law | controls, tests, release gates |
|
|
500
|
+
| 10. QA | test strategy, QA scenarios, test cases, regression checklist, UAT, browser/device matrix, accessibility tests, performance tests, security tests, data quality tests, design QA, quality gates | requirements, design, engineering | release approval |
|
|
501
|
+
| 11. Release/Ops | release plan, deployment procedure, rollback, release notes, operator manual, runbooks, monitoring, observability, SLO/SLA, on-call/escalation, incident response, backup/restore, DR/BCP, recurring checks | QA and infrastructure | stable operation |
|
|
502
|
+
| 12. Business Ops | CS macros, support policy, training, sales/adoption guide, CRM rules, onboarding playbook, churn/offboarding, admin operations, communication templates, revenue recognition, tax/invoice, partner operations | policy, release, sales motion | customer-facing operation |
|
|
503
|
+
| 13. Improvement/EOL | VOC summary, retrospectives, experiments, experiment results, cohort/retention analysis, feature deprecation, migration/data transfer, service end-of-life | operations and analytics | next PRD, policy, roadmap |
|
|
504
|
+
|
|
505
|
+
## Writing Rule
|
|
506
|
+
|
|
507
|
+
When a new note arrives:
|
|
508
|
+
|
|
509
|
+
1. Identify the lifecycle area and storage location.
|
|
510
|
+
2. Update an existing focused page when the topic already has a canonical home.
|
|
511
|
+
3. Create a new focused page only when the topic is durable, likely to be read independently, or too large for its current page.
|
|
512
|
+
4. Add an \`index.md\` route when the page becomes durable.
|
|
513
|
+
5. Add upstream/downstream links in prose or tables when one artifact derives from another.
|
|
514
|
+
6. Record decision rationale separately when the change explains why the project chose one option over another.
|
|
515
|
+
|
|
516
|
+
## Page Shape
|
|
517
|
+
|
|
518
|
+
Use this shape for focused canonical pages unless a domain-specific shape is clearly better:
|
|
519
|
+
|
|
520
|
+
\`\`\`md
|
|
521
|
+
---
|
|
522
|
+
status: active
|
|
523
|
+
updated: YYYY-MM-DD
|
|
524
|
+
scope: project-canonical
|
|
525
|
+
read_budget: short|medium|on-demand
|
|
526
|
+
decision_ref: none|wiki/decisions/...
|
|
527
|
+
review_trigger: what should cause this page to change
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
# <Topic>
|
|
531
|
+
|
|
532
|
+
## TL;DR
|
|
533
|
+
|
|
534
|
+
- Current agreement in one to five bullets.
|
|
535
|
+
|
|
536
|
+
## Current Truth
|
|
537
|
+
|
|
538
|
+
## Upstream Inputs
|
|
539
|
+
|
|
540
|
+
## Downstream Artifacts
|
|
541
|
+
|
|
542
|
+
## Open Questions
|
|
543
|
+
\`\`\`
|
|
544
|
+
`;
|
|
374
545
|
exports.starterFiles = {
|
|
375
546
|
"wiki/README.md": `${(0, exports.metadata)("wiki-entry", "short", "wiki/meta/wiki-ops-v1-decisions.md", "top-level wiki structure changes")}
|
|
376
547
|
# Project Wiki
|
|
@@ -381,10 +552,7 @@ This directory is the durable project-planning source of truth. Keep product dir
|
|
|
381
552
|
|
|
382
553
|
- [[startup]]
|
|
383
554
|
- [[index]]
|
|
384
|
-
- [[
|
|
385
|
-
- [[canonical/open-questions]]
|
|
386
|
-
- [[canonical/assumptions]]
|
|
387
|
-
- [[canonical/risks]]
|
|
555
|
+
- [[meta/document-taxonomy]]
|
|
388
556
|
`,
|
|
389
557
|
"wiki/canonical/project-brief.md": `${(0, exports.metadata)("project-canonical", "medium", "none", "product direction, audience, scope, success criteria, or language choice changes")}
|
|
390
558
|
# Project Brief
|
|
@@ -502,17 +670,18 @@ No project decisions yet.
|
|
|
502
670
|
## TL;DR
|
|
503
671
|
|
|
504
672
|
- This Decision Pack records accepted wiki operating choices for project-librarian.
|
|
505
|
-
- It covers wiki structure, startup hook scope, metadata, language policy, git hook behavior, migration review, and inbox handling.
|
|
673
|
+
- It covers wiki structure, document taxonomy, startup hook scope, metadata, language policy, git hook behavior, migration review, and inbox handling.
|
|
506
674
|
- Project product decisions belong in \`wiki/decisions/\`, while these operating decisions stay in \`wiki/meta/\`.
|
|
507
675
|
|
|
508
676
|
Status: accepted
|
|
509
677
|
Scope: wiki operation
|
|
510
|
-
Canonical: [[meta/operating-model]], [[meta/decision-policy]]
|
|
678
|
+
Canonical: [[meta/operating-model]], [[meta/decision-policy]], [[meta/document-taxonomy]]
|
|
511
679
|
|
|
512
680
|
| Date | Decision | Rationale | Rejected Alternative | Revisit Trigger | Canonical Link |
|
|
513
681
|
| --- | --- | --- | --- | --- | --- |
|
|
514
682
|
| ${workspace_1.today} | Keep the wiki root at \`./wiki\`. | Planning docs live with the project. | External docs only. | Another tool cannot read \`./wiki\` or the team needs another path. | [[meta/operating-model]] |
|
|
515
683
|
| ${workspace_1.today} | Split \`canonical/\` and \`decisions/\`. | Current truth and decision history are easier to scan when separated. | A single mixed docs directory. | The structure proves too heavy for small projects. | [[meta/decision-policy]] |
|
|
684
|
+
| ${workspace_1.today} | Classify new wiki content through a service-lifecycle document taxonomy before writing or consolidating it. | Agents need a structural contract for deciding whether content is strategy, product, policy, UX, design, data, engineering, security/legal, QA, release/ops, business ops, or improvement/EOL truth. | Let agents append new content to whichever existing page is nearby. | The taxonomy becomes too heavy for small projects or repeatedly misroutes content. | [[meta/document-taxonomy]], [[meta/operating-model]] |
|
|
516
685
|
| ${workspace_1.today} | Inject only \`startup.md\` and \`index.md\` through Codex, Claude Code, Cursor, and Gemini CLI startup hooks; route detailed files Read On Demand. | Full canonical and decision bodies waste startup tokens. | Always read detailed canonical and decision files first. | Important context is repeatedly missed at startup. | [[startup]], [[index]] |
|
|
517
686
|
| ${workspace_1.today} | Use metadata headers on wiki knowledge pages. | Agents and humans can quickly judge status, scope, budget, and review triggers. | Body-only conventions. | Header maintenance costs more than it saves. | [[meta/operating-model]] |
|
|
518
687
|
| ${workspace_1.today} | Keep wiki operating docs in \`wiki/meta/\`. | Project truth stays focused on product/project content. | Store operating docs in \`canonical/\` or \`decisions/\`. | Meta docs become hard to discover. | [[meta/operating-model]] |
|
|
@@ -523,6 +692,7 @@ Canonical: [[meta/operating-model]], [[meta/decision-policy]]
|
|
|
523
692
|
| ${workspace_1.today} | Migration may mark rows \`needs-human-review\`. | Ambiguous, risky, or high-impact legacy content should not be closed automatically. | Force every migrated row into adopted/rejected/resolved. | Human review queues become too large. | [[meta/operating-model]] |
|
|
524
693
|
| ${workspace_1.today} | Capture stores candidates in \`wiki/inbox/\`. | Useful ideas are not lost, but unreviewed content does not become canonical truth. | Save all conversation content directly into canonical docs. | Inbox content is frequently abandoned. | [[meta/operating-model]] |
|
|
525
694
|
`,
|
|
695
|
+
"wiki/meta/document-taxonomy.md": exports.documentTaxonomy,
|
|
526
696
|
"wiki/decisions/decision-pack-template.md": `${(0, exports.metadata)("project-decision-template", "short", "wiki/meta/decision-policy.md", "decision pack format changes", "template")}
|
|
527
697
|
# <Topic> v<N> Decisions
|
|
528
698
|
|
|
@@ -571,3 +741,11 @@ Checked: ${workspace_1.today}
|
|
|
571
741
|
- \`wiki/meta/\` stores wiki operating rules and operating decisions.
|
|
572
742
|
`,
|
|
573
743
|
};
|
|
744
|
+
exports.defaultStarterFilePaths = new Set([
|
|
745
|
+
"wiki/README.md",
|
|
746
|
+
"wiki/decisions/README.md",
|
|
747
|
+
"wiki/decisions/log.md",
|
|
748
|
+
"wiki/decisions/recent.md",
|
|
749
|
+
"wiki/meta/document-taxonomy.md",
|
|
750
|
+
"wiki/sources/karpathy-llm-wiki.md",
|
|
751
|
+
]);
|
package/dist/wiki-files.js
CHANGED
|
@@ -46,10 +46,9 @@ exports.extractWikiLinks = extractWikiLinks;
|
|
|
46
46
|
exports.wikiTitleForFile = wikiTitleForFile;
|
|
47
47
|
exports.metadataSummary = metadataSummary;
|
|
48
48
|
exports.stripMarkedSection = stripMarkedSection;
|
|
49
|
-
exports.extractMarkedSection = extractMarkedSection;
|
|
50
|
-
exports.withPreservedMarkedSections = withPreservedMarkedSections;
|
|
51
49
|
exports.hasGlossaryNeedSignal = hasGlossaryNeedSignal;
|
|
52
50
|
exports.hasGlossaryTable = hasGlossaryTable;
|
|
51
|
+
exports.firstTldrBullet = firstTldrBullet;
|
|
53
52
|
exports.canonicalBodyForLint = canonicalBodyForLint;
|
|
54
53
|
const fs = __importStar(require("node:fs"));
|
|
55
54
|
const path = __importStar(require("node:path"));
|
|
@@ -75,24 +74,22 @@ exports.standardWikiFiles = new Set([
|
|
|
75
74
|
"wiki/index.md",
|
|
76
75
|
"wiki/inbox/project-candidates.md",
|
|
77
76
|
"wiki/migration/inventory.md",
|
|
77
|
+
"wiki/migration/unit-map.md",
|
|
78
|
+
"wiki/migration/split-plan.md",
|
|
78
79
|
"wiki/migration/coverage.md",
|
|
79
80
|
"wiki/migration/plan.md",
|
|
80
81
|
"wiki/migration/review.md",
|
|
81
82
|
"wiki/migration/verification.md",
|
|
82
|
-
"wiki/
|
|
83
|
+
"wiki/migration/bulk-review.md",
|
|
83
84
|
"wiki/canonical/glossary.md",
|
|
84
|
-
"wiki/canonical/open-questions.md",
|
|
85
|
-
"wiki/canonical/assumptions.md",
|
|
86
|
-
"wiki/canonical/risks.md",
|
|
87
85
|
"wiki/canonical/migration-inbox.md",
|
|
88
86
|
"wiki/decisions/README.md",
|
|
89
87
|
"wiki/decisions/log.md",
|
|
90
88
|
"wiki/decisions/recent.md",
|
|
91
|
-
"wiki/decisions/decision-pack-template.md",
|
|
92
|
-
"wiki/decisions/full-adr-template.md",
|
|
93
89
|
"wiki/decisions/migration-inbox.md",
|
|
94
90
|
"wiki/meta/operating-model.md",
|
|
95
91
|
"wiki/meta/decision-policy.md",
|
|
92
|
+
"wiki/meta/document-taxonomy.md",
|
|
96
93
|
"wiki/meta/wiki-ops-v1-decisions.md",
|
|
97
94
|
"wiki/sources/karpathy-llm-wiki.md",
|
|
98
95
|
"wiki/sources/migration-inbox.md",
|
|
@@ -264,25 +261,6 @@ function stripMarkedSection(text, startMarker, endMarker) {
|
|
|
264
261
|
return text;
|
|
265
262
|
return `${text.slice(0, start).trimEnd()}\n\n${text.slice(end + endMarker.length).trimStart()}`.trim() + "\n";
|
|
266
263
|
}
|
|
267
|
-
function extractMarkedSection(text, startMarker, endMarker) {
|
|
268
|
-
const start = text.indexOf(startMarker);
|
|
269
|
-
const end = text.indexOf(endMarker);
|
|
270
|
-
if (start < 0 || end <= start)
|
|
271
|
-
return "";
|
|
272
|
-
return text.slice(start, end + endMarker.length).trim();
|
|
273
|
-
}
|
|
274
|
-
function withPreservedMarkedSections(relativePath, base, markerPairs) {
|
|
275
|
-
if (!(0, workspace_1.exists)(relativePath))
|
|
276
|
-
return base;
|
|
277
|
-
const current = (0, workspace_1.read)(relativePath);
|
|
278
|
-
const preserved = markerPairs
|
|
279
|
-
.map(([startMarker, endMarker]) => extractMarkedSection(current, startMarker, endMarker))
|
|
280
|
-
.filter(Boolean)
|
|
281
|
-
.filter((section) => !base.includes(section));
|
|
282
|
-
if (preserved.length === 0)
|
|
283
|
-
return base;
|
|
284
|
-
return `${base.trimEnd()}\n\n${preserved.join("\n\n")}\n`;
|
|
285
|
-
}
|
|
286
264
|
function hasGlossaryNeedSignal(text) {
|
|
287
265
|
return /(^|\n)##\s+(Glossary|Terms|Roles|Entities|Data Model|State Model|Permissions|Events|용어|역할|엔티티|상태 모델|권한|이벤트)(\s|$)|`[^`]+`\s*(term|role|state|permission|event|entity|API|DB|UI|용어|역할|상태|권한|이벤트|엔티티)/i.test(text);
|
|
288
266
|
}
|
|
@@ -290,6 +268,16 @@ function hasGlossaryTable(text) {
|
|
|
290
268
|
const body = (0, workspace_1.stripMetadataHeader)(text);
|
|
291
269
|
return /\|\s*Term\s*\|\s*Definition\s*\|\s*Avoid\s*\|\s*Related Canonical Doc\s*\|\s*Status\s*\|/.test(body);
|
|
292
270
|
}
|
|
271
|
+
// First "## TL;DR" bullet for answer-shaped query envelopes: gives an agent the
|
|
272
|
+
// page's one-line summary without opening the page. Pages without a TL;DR section
|
|
273
|
+
// return "" and the envelope simply omits the line — quality-check separately
|
|
274
|
+
// flags the missing TL;DR, so this is optional enrichment, not a fallback path.
|
|
275
|
+
function firstTldrBullet(text) {
|
|
276
|
+
const body = (0, workspace_1.stripMetadataHeader)(text);
|
|
277
|
+
const match = body.match(/^##\s+TL;DR[^\n]*\n([\s\S]*?)(?=\n##\s|(?![\s\S]))/m);
|
|
278
|
+
const bullet = match?.[1]?.split(/\r?\n/).find((line) => /^\s*-\s+\S/.test(line));
|
|
279
|
+
return bullet ? bullet.replace(/^\s*-\s*/, "").trim().slice(0, 160) : "";
|
|
280
|
+
}
|
|
293
281
|
function canonicalBodyForLint() {
|
|
294
282
|
return (0, workspace_1.walkFilesUnder)("wiki/canonical", (file) => /\.(md|mdx)$/i.test(file) && file !== "wiki/canonical/glossary.md")
|
|
295
283
|
.map((file) => (0, workspace_1.stripMetadataHeader)((0, workspace_1.read)(file)))
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wikiAnswerTruncationNotice = exports.wikiAnswerCharCap = exports.wikiRouterExemptPages = exports.wikiRouterDepthBudget = exports.wikiRouterRoot = void 0;
|
|
4
|
+
exports.finalizeWikiAnswer = finalizeWikiAnswer;
|
|
5
|
+
exports.buildWikiGraph = buildWikiGraph;
|
|
6
|
+
exports.wikiRouterDepths = wikiRouterDepths;
|
|
7
|
+
exports.wikiImpactAnswer = wikiImpactAnswer;
|
|
8
|
+
const wiki_files_1 = require("./wiki-files");
|
|
9
|
+
const workspace_1 = require("./workspace");
|
|
10
|
+
// Router reachability budget. The benchmark fixture A1 assert guarantees
|
|
11
|
+
// startup -> index -> answer page within two hops; real wikis add one hop for
|
|
12
|
+
// generated scoped routers (startup -> index -> wiki/indexes/auto-*.md -> page),
|
|
13
|
+
// so the real-wiki budget is three hops from wiki/startup.md.
|
|
14
|
+
exports.wikiRouterRoot = "wiki/startup.md";
|
|
15
|
+
exports.wikiRouterDepthBudget = 3;
|
|
16
|
+
// startup is the BFS root; README is a human entry document that is deliberately
|
|
17
|
+
// unrouted (the same exemption the orphan-page rule uses).
|
|
18
|
+
exports.wikiRouterExemptPages = new Set([exports.wikiRouterRoot, "wiki/README.md"]);
|
|
19
|
+
// Answer-shape discipline for wiki-side query/impact output: answer-first text,
|
|
20
|
+
// hard char cap, explicit truncation notice (never silent). Mirrors the MCP
|
|
21
|
+
// server constants (src/mcp-server.ts MAX_RESPONSE_CHARS / TRUNCATION_NOTICE);
|
|
22
|
+
// kept separate so the MCP server module and its node:sqlite loading path stay
|
|
23
|
+
// out of the bootstrap/diagnostics path.
|
|
24
|
+
exports.wikiAnswerCharCap = 4000;
|
|
25
|
+
exports.wikiAnswerTruncationNotice = "[truncated — refine the query]";
|
|
26
|
+
function finalizeWikiAnswer(body) {
|
|
27
|
+
if (body.length <= exports.wikiAnswerCharCap)
|
|
28
|
+
return body;
|
|
29
|
+
const budget = exports.wikiAnswerCharCap - exports.wikiAnswerTruncationNotice.length - 1;
|
|
30
|
+
return `${body.slice(0, budget > 0 ? budget : 0).trimEnd()}\n${exports.wikiAnswerTruncationNotice}`;
|
|
31
|
+
}
|
|
32
|
+
// decision_ref is frontmatter, not a wiki link, so the link extractor never sees
|
|
33
|
+
// it; normalize it here into a page edge. "none"/"-" are the documented empty
|
|
34
|
+
// markers in generated metadata headers.
|
|
35
|
+
function normalizedDecisionRef(file, value) {
|
|
36
|
+
const trimmed = value.trim();
|
|
37
|
+
if (!trimmed || trimmed === "none" || trimmed === "-")
|
|
38
|
+
return "";
|
|
39
|
+
return (0, wiki_files_1.normalizeWikiLinkTarget)(file, trimmed.replace(/^\[\[|\]\]$/g, ""));
|
|
40
|
+
}
|
|
41
|
+
function buildWikiGraph(pages) {
|
|
42
|
+
const files = new Set(pages.map((page) => page.file));
|
|
43
|
+
const links = [];
|
|
44
|
+
const incomingLinks = new Map();
|
|
45
|
+
const outgoingLinks = new Map();
|
|
46
|
+
const incomingDecisionRefs = new Map();
|
|
47
|
+
const outgoingDecisionRef = new Map();
|
|
48
|
+
for (const page of pages) {
|
|
49
|
+
for (const link of (0, wiki_files_1.extractWikiLinks)(page.file, page.text)) {
|
|
50
|
+
links.push(link);
|
|
51
|
+
outgoingLinks.set(page.file, [...(outgoingLinks.get(page.file) ?? []), link]);
|
|
52
|
+
incomingLinks.set(link.normalizedTarget, [...(incomingLinks.get(link.normalizedTarget) ?? []), link]);
|
|
53
|
+
}
|
|
54
|
+
const ref = normalizedDecisionRef(page.file, (0, workspace_1.metadataValue)(page.text, "decision_ref"));
|
|
55
|
+
if (ref && files.has(ref)) {
|
|
56
|
+
outgoingDecisionRef.set(page.file, ref);
|
|
57
|
+
incomingDecisionRefs.set(ref, [...(incomingDecisionRefs.get(ref) ?? []), page.file]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { files, links, incomingLinks, outgoingLinks, incomingDecisionRefs, outgoingDecisionRef };
|
|
61
|
+
}
|
|
62
|
+
// BFS depths over existing pages from wiki/startup.md (depth 0). Pages absent
|
|
63
|
+
// from the result are unreachable through the router chain. Only links whose
|
|
64
|
+
// target exists are traversed; broken links are the broken-link rule's job.
|
|
65
|
+
function wikiRouterDepths(graph) {
|
|
66
|
+
const depths = new Map();
|
|
67
|
+
if (!graph.files.has(exports.wikiRouterRoot))
|
|
68
|
+
return depths;
|
|
69
|
+
depths.set(exports.wikiRouterRoot, 0);
|
|
70
|
+
const queue = [exports.wikiRouterRoot];
|
|
71
|
+
while (queue.length > 0) {
|
|
72
|
+
const current = queue.shift();
|
|
73
|
+
const depth = depths.get(current) ?? 0;
|
|
74
|
+
for (const link of graph.outgoingLinks.get(current) ?? []) {
|
|
75
|
+
const target = link.normalizedTarget;
|
|
76
|
+
if (!graph.files.has(target) || depths.has(target))
|
|
77
|
+
continue;
|
|
78
|
+
depths.set(target, depth + 1);
|
|
79
|
+
queue.push(target);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return depths;
|
|
83
|
+
}
|
|
84
|
+
// Wiki impact: the --code-impact envelope shape applied to wiki maintenance.
|
|
85
|
+
// Given a page or term, report which pages link to it (review candidates when it
|
|
86
|
+
// changes), which pages cite it as decision_ref, what it depends on, and how the
|
|
87
|
+
// router reaches it. Bounded by sampling plus the shared answer cap.
|
|
88
|
+
const impactMatchCap = 5;
|
|
89
|
+
const impactListCap = 12;
|
|
90
|
+
function sampled(items, cap) {
|
|
91
|
+
if (items.length === 0)
|
|
92
|
+
return "none";
|
|
93
|
+
const shown = items.slice(0, cap).join(", ");
|
|
94
|
+
return items.length > cap ? `${shown}, …+${items.length - cap} more` : shown;
|
|
95
|
+
}
|
|
96
|
+
function uniqueSorted(values) {
|
|
97
|
+
return Array.from(new Set(values)).sort();
|
|
98
|
+
}
|
|
99
|
+
function plural(count, noun) {
|
|
100
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
101
|
+
}
|
|
102
|
+
function wikiImpactAnswer(pages, term) {
|
|
103
|
+
const graph = buildWikiGraph(pages);
|
|
104
|
+
const depths = wikiRouterDepths(graph);
|
|
105
|
+
const textByFile = new Map(pages.map((page) => [page.file, page.text]));
|
|
106
|
+
const lowered = term.toLowerCase();
|
|
107
|
+
const exactTarget = (0, wiki_files_1.normalizeWikiLinkTarget)("wiki/index.md", term.replace(/^\[\[|\]\]$/g, ""));
|
|
108
|
+
const matches = pages
|
|
109
|
+
.map((page) => ({ file: page.file, title: (0, wiki_files_1.wikiTitleForFile)(page.file, page.text) }))
|
|
110
|
+
.filter((page) => page.file === exactTarget || page.file.toLowerCase().includes(lowered) || page.title.toLowerCase().includes(lowered))
|
|
111
|
+
.sort((a, b) => Number(b.file === exactTarget) - Number(a.file === exactTarget) || a.file.localeCompare(b.file));
|
|
112
|
+
if (matches.length === 0)
|
|
113
|
+
return `Wiki impact "${term}": no matching wiki pages.`;
|
|
114
|
+
const shown = matches.slice(0, impactMatchCap);
|
|
115
|
+
// Headline counts are unions across the shown matches, not sums: a page that
|
|
116
|
+
// links two matched targets is one review candidate, not two.
|
|
117
|
+
const incomingUnion = new Set(shown.flatMap((match) => (graph.incomingLinks.get(match.file) ?? []).map((link) => link.file)));
|
|
118
|
+
const refUnion = new Set(shown.flatMap((match) => graph.incomingDecisionRefs.get(match.file) ?? []));
|
|
119
|
+
const lines = [
|
|
120
|
+
`Wiki impact "${term}": ${plural(matches.length, "matching page")}${matches.length > impactMatchCap ? ` (top ${impactMatchCap} shown)` : ""}; review the ${plural(incomingUnion.size, "linking page")} and ${plural(refUnion.size, "decision_ref citation")} below when ${matches.length === 1 ? "this page changes" : "these pages change"}.`,
|
|
121
|
+
];
|
|
122
|
+
for (const match of shown) {
|
|
123
|
+
const text = textByFile.get(match.file) ?? "";
|
|
124
|
+
const incoming = uniqueSorted((graph.incomingLinks.get(match.file) ?? []).map((link) => link.file));
|
|
125
|
+
const refs = uniqueSorted(graph.incomingDecisionRefs.get(match.file) ?? []);
|
|
126
|
+
const outgoing = uniqueSorted((graph.outgoingLinks.get(match.file) ?? []).map((link) => link.normalizedTarget));
|
|
127
|
+
const depth = depths.get(match.file);
|
|
128
|
+
const trigger = (0, workspace_1.metadataValue)(text, "review_trigger");
|
|
129
|
+
lines.push("");
|
|
130
|
+
lines.push(`${match.file} — ${match.title}`);
|
|
131
|
+
if (trigger)
|
|
132
|
+
lines.push(` review_trigger: ${trigger}`);
|
|
133
|
+
lines.push(` incoming links (${incoming.length}): ${sampled(incoming, impactListCap)}`);
|
|
134
|
+
lines.push(` decision_ref from (${refs.length}): ${sampled(refs, impactListCap)}`);
|
|
135
|
+
lines.push(` outgoing links (${outgoing.length}): ${sampled(outgoing, impactListCap)}`);
|
|
136
|
+
lines.push(depth === undefined
|
|
137
|
+
? ` router: unreachable from ${exports.wikiRouterRoot}`
|
|
138
|
+
: ` router: reachable at depth ${depth} (budget ${exports.wikiRouterDepthBudget})`);
|
|
139
|
+
}
|
|
140
|
+
return finalizeWikiAnswer(lines.join("\n"));
|
|
141
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "project-librarian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Create and maintain compact project context for humans and LLM coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -28,8 +28,6 @@
|
|
|
28
28
|
"LICENSE",
|
|
29
29
|
"README.md",
|
|
30
30
|
"README.ko.md",
|
|
31
|
-
"README.ja.md",
|
|
32
|
-
"README.zh.md",
|
|
33
31
|
"SKILL.md"
|
|
34
32
|
],
|
|
35
33
|
"bin": {
|
|
@@ -45,6 +43,8 @@
|
|
|
45
43
|
"benchmark:llm": "npm run build && node benchmarks/codex-llm-metrics.js",
|
|
46
44
|
"benchmark:llm:dry-run": "npm run build && node benchmarks/codex-llm-metrics.js --dry-run",
|
|
47
45
|
"benchmark:llm:parse-smoke": "node tests/validators/codex-llm-benchmark-smoke.js",
|
|
46
|
+
"benchmark:injection-sentinel": "node benchmarks/tools/injection-sentinel.js",
|
|
47
|
+
"benchmark:real-corpus:demo": "npm run build && node benchmarks/tools/real-corpus-offline-demo.js",
|
|
48
48
|
"benchmark:release": "npm run benchmark:llm -- --full-matrix --runs 3 --warmup-runs 1 --min-runs-for-claim 3 --require-clean --require-claimable --out benchmarks/reports/llm/current.json --markdown benchmarks/reports/llm/current.md",
|
|
49
49
|
"build": "tsc && chmod +x dist/init-project-wiki.js",
|
|
50
50
|
"typecheck": "tsc --noEmit",
|