@c4a/context 0.6.2 → 0.6.4

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.md CHANGED
@@ -67,6 +67,21 @@ code extractor. Use `customPhase()` only for orchestration that does not publish
67
67
  knowledge candidates; it is not a replacement for source, extraction, Review,
68
68
  and package lifecycle rules.
69
69
 
70
+ Context CLI intentionally does not bundle every language or repository parser.
71
+ Optional structural libraries can be installed by the knowledge project and
72
+ used inside `extractCustom()`:
73
+
74
+ | Package | Structural facts |
75
+ |---|---|
76
+ | `@c4a/extract-go` | Go declarations, imports, calls, and common HTTP route registrations |
77
+ | `@c4a/extract-rush` | Rush projects, tags, entry signals, workspace dependencies, and owner boundaries |
78
+ | `@c4a/extract-ts` | TypeScript extraction plus reusable React Router route facts |
79
+
80
+ These libraries do not create Context phases or candidates by themselves. The
81
+ project maps their deterministic facts to its own candidate identities and
82
+ review summaries; Context continues to own evidence validation, freshness,
83
+ Review, close, and package output.
84
+
70
85
  ## Knowledge Collections
71
86
 
72
87
  Approved Markdown is organized under `knowledge/<collection>/`:
@@ -126,11 +141,27 @@ it is not repeated inside knowledge paths. Context still accepts
126
141
  no longer changes build output and new declarations do not need it. Skill names
127
142
  remain author-maintained and independent.
128
143
 
144
+ New KB setup should offer `assets: { delivery: "git-raw" }` first. Build
145
+ rewrites resource links to Git raw URLs; committing and publishing the resource
146
+ files remains the package author's responsibility. Non-Git workspaces may use
147
+ an explicit `urlPrefix`; without one they can bundle resources or explicitly
148
+ omit them and retain unresolved references. Bundled delivery may
149
+ install `sharp` in the workspace and configure `assets.optimize`; Context
150
+ itself has no image dependency and never changes source snapshots or approved
151
+ resources.
152
+
129
153
  For advanced routing and retrieval, a template may carry a local script such as
130
154
  `query.ts`, with a Skill describing when and how an Agent should call it. The
131
155
  Skill can also route the Agent to MCP servers, CLI commands, or other tools to
132
156
  form a package-specific Agentic Search workflow.
133
157
 
158
+ Long-lived, multi-source production workspaces can copy
159
+ `templates/project-skills/maintain-project-knowledge/SKILL.md` into their
160
+ `.agents/skills/` directory and customize it with project ownership, source
161
+ impact mappings, and readiness criteria. This project adapter is not included
162
+ in knowledge packages; lifecycle authority remains with the installed Context
163
+ Skill and current Route.
164
+
134
165
  ## State Boundary
135
166
 
136
167
  The SDK stays declarative. It may describe reads, writes, phases, review, and
@@ -147,5 +178,6 @@ state. The CLI owns that runtime state and removes it after a successful close.
147
178
  - [Agent Guide](./docs/guides/agent-guide.md)
148
179
  - [Project API](./docs/reference/project-api.md)
149
180
  - [Package Outputs](./docs/guides/package-outputs.md)
181
+ - [Lark Resource Materialization](./docs/guides/lark-resources.md)
150
182
  - [Package Templates](./docs/reference/package-templates.md)
151
183
  - [Template Variables](./docs/reference/template-variables.md)
package/README.zh-CN.md CHANGED
@@ -57,6 +57,18 @@ export default defineProject({
57
57
  非 TypeScript 或需要聚合代码事实时使用 `extractCustom()`。`customPhase()`
58
58
  只用于不发布知识候选的项目专用编排,不能绕开来源、提取、审核和打包生命周期。
59
59
 
60
+ Context CLI 不会把所有语言和仓库解析器都打入自身。知识项目可以按需安装结构
61
+ 提取库,并在 `extractCustom()` 中使用:
62
+
63
+ | 包 | 提供的结构事实 |
64
+ |---|---|
65
+ | `@c4a/extract-go` | Go 声明、导入、调用和常见 HTTP 路由注册 |
66
+ | `@c4a/extract-rush` | Rush 项目、标签、入口信号、工作区依赖和所有者边界 |
67
+ | `@c4a/extract-ts` | TypeScript 提取,以及可复用的 React Router 路由事实 |
68
+
69
+ 这些库本身不会创建 Context 阶段或候选。项目负责把确定性事实映射为自己的候选
70
+ 身份和审核摘要;证据校验、新鲜度、审核、close 和打包仍由 Context 管理。
71
+
60
72
  ## 知识分类
61
73
 
62
74
  审核通过的 Markdown 会存放在 `knowledge/<collection>/`:
@@ -104,8 +116,21 @@ kb/
104
116
  `distribution.knowledgeNamespace` 仍可被读取,但不再改变构建结果;新声明无需配置它。
105
117
  Skill 名称继续由作者独立维护。
106
118
 
119
+ 新建 KB 时优先选择 `assets: { delivery: "git-raw" }`:构建器把资源链接改写到
120
+ Git raw 地址;资源的提交和发布由知识包作者负责,Context 不做远端探测。
121
+ 非 Git 工作区也可以配置显式 `urlPrefix`,引用另一个仓库已经发布的资源;没有
122
+ 可用 Git 或显式前缀时,可选择 `delivery: "bundle"` 随包分发,或显式选择
123
+ `delivery: "omit"` 不输出资源并保留失效引用。随包分发还可以在工作区安装 `sharp` 并通过
124
+ `assets.optimize` 仅优化生成的知识包;Context 本身不依赖图片处理库。
125
+
107
126
  如果需要更强的路由和检索能力,模板可以携带 `query.ts` 一类本地脚本,再由 Skill 约定 Agent 何时、如何调用。Skill 也可以把 Agent 路由到 MCP、CLI 或其他工具,组成适合当前知识包的 Agentic Search 流程。
108
127
 
128
+ 长期维护、多来源的知识生产工作区可以从
129
+ `templates/project-skills.zh-CN/maintain-project-knowledge/SKILL.md` 复制一份
130
+ 项目维护 Skill 到 `.agents/skills/`。它不进入知识包,而是补充项目专属的来源
131
+ 归属、仓库变化影响范围和准出标准;Context 生命周期仍由已安装的 Context Skill
132
+ 和当前 Route 负责。
133
+
109
134
  ## 状态边界
110
135
 
111
136
  SDK 只负责声明。它可以描述读取、写入、阶段、审核和知识包选择,但来源物化、内容读取、代码提取、审核应用、正式知识写入、质量验证和构建都由 CLI 负责。不要通过直接编辑 `sources/`、`knowledge/`、`dist/` 或被忽略的 `.tmp/context-runtime/lifecycle/` 运行态来替代 CLI 生命周期操作;成功 close 后 CLI 会清理该运行态。
@@ -117,5 +142,6 @@ SDK 只负责声明。它可以描述读取、写入、阶段、审核和知识
117
142
  - [Agent 指南](./docs/guides/agent-guide.md)
118
143
  - [项目 API](./docs/reference/project-api.md)
119
144
  - [知识包输出](./docs/guides/package-outputs.md)
145
+ - [飞书资源物化](./docs/guides/lark-resources.md)
120
146
  - [知识包模板](./docs/reference/package-templates.md)
121
147
  - [模板变量](./docs/reference/template-variables.md)
package/docs/README.md CHANGED
@@ -17,7 +17,9 @@ general reference; do not preload the whole manual set.
17
17
  - [Agent Guide](./guides/agent-guide.md) — what an agent should do, and what it should not inspect manually.
18
18
  - [Agent Dialogue](./guides/agent-dialogue.md) — stable dialogue principles and how route-selected gate resources are discovered.
19
19
  - [Package Outputs](./guides/package-outputs.md) — how to choose between an agent knowledge-base package, LLM text, or no package output.
20
+ - [Lark Resource Materialization](./guides/lark-resources.md) — how embedded resources move from source evidence to approved knowledge and package assets.
20
21
  - [Project API](./reference/project-api.md) — `defineProject`, sources, phases, review, and packages.
22
+ - [Code Extractor Selection](./reference/code-extractors.md) — inspect module technology signals and choose a built-in extractor, reusable structural package, or project adapter.
21
23
  - [Package Templates](./reference/package-templates.md) — `kbPackage`, `llmsPackage`, template variables, and examples.
22
24
  - [Template Variables](./reference/template-variables.md) — Handlebars variables, loops, comments, and default knowledge inventories.
23
25
 
@@ -40,3 +42,15 @@ node_modules/@c4a/context/templates/package-templates/
40
42
 
41
43
  Copy or mirror these into a workspace under `src/package-templates/` when the
42
44
  project needs package outputs.
45
+
46
+ Long-lived multi-source production workspaces may also start from the optional
47
+ project-maintenance Skill template at:
48
+
49
+ ```text
50
+ node_modules/@c4a/context/templates/project-skills/maintain-project-knowledge/SKILL.md
51
+ ```
52
+
53
+ Copy it into the project's `.agents/skills/`, rename it for the project, and
54
+ replace its project-fact and impact-map sections. It is a project adapter; it is
55
+ not included in a built knowledge package and does not replace the installed
56
+ Context Skill.
@@ -7,7 +7,7 @@ source boundary, then declare the matching phases in `src/index.ts`.
7
7
  ## 1. Initialize
8
8
 
9
9
  ```bash
10
- context init context --dev
10
+ context init context
11
11
  cd context
12
12
  bun install
13
13
  context status --format json
@@ -18,10 +18,10 @@ generated README, AGENTS contract, and package starter templates should use a
18
18
  specific language. Context stores this choice in `package.json`; it does not
19
19
  guess from the shell locale or Agent conversation.
20
20
 
21
- Use `--dev` when testing a local link or prepared pack before the matching SDK
22
- version is published. It writes a `file:` dependency to the SDK resolved beside
23
- the active CLI. Published users can omit it and install the versioned SDK from
24
- the registry.
21
+ Use `--dev` only when testing a locally linked CLI or a prepared package before
22
+ the matching SDK version is published. It writes a `file:` dependency to the SDK
23
+ resolved beside the active CLI. Registry installs should use the default command
24
+ above so the workspace receives the matching versioned SDK dependency.
25
25
 
26
26
  Without `project-dir`, init uses the dedicated `context/` directory. Initializing
27
27
  inside a non-empty directory that is not already a Context workspace is blocked
@@ -187,8 +187,19 @@ and suggested `context source add` commands.
187
187
 
188
188
  Remote Git sources need the same boundary decision. Ask for the remote URL, the
189
189
  pinned commit/ref, and whether the user approves cloning. The CLI does not
190
- clone, checkout, reset, or fetch silently. If source material is missing or at
191
- the wrong ref, ask the user before running repo operations outside the CLI.
190
+ clone, checkout, reset, or fetch silently. If registered source material is
191
+ missing, the current Route exposes a repository recovery plan. The user chooses
192
+ an existing checkout, a bounded local scan, or an explicit shallow/partial clone
193
+ of the registered pinned commit. Context validates the remote, commit, and
194
+ subpaths, restores local aliases, and materializes module links. Advancing to a
195
+ new upstream commit remains a separate source-update decision.
196
+
197
+ For a long-lived production workspace with project-specific source ownership or
198
+ impact rules, copy the optional maintenance Skill template from
199
+ `templates/project-skills/maintain-project-knowledge/SKILL.md` into the
200
+ project's `.agents/skills/`, rename it for the project, and edit its project
201
+ facts. Keep Context lifecycle commands in the installed Context Skill and
202
+ current Route rather than duplicating them in the project Skill.
192
203
 
193
204
  ## 3. Declare The Flow
194
205
 
@@ -72,6 +72,13 @@ node_modules/@c4a/context/docs/reference/project-api.md
72
72
  node_modules/@c4a/context/docs/reference/package-templates.md
73
73
  ```
74
74
 
75
+ When configuring code extraction, use the Route-selected
76
+ `reference/code-extractors.md` manual. Run the Gate's read-only source
77
+ inspection first, use its manifest signals to select a matching extractor, and
78
+ read that package's public README before implementing an `extractCustom()`
79
+ adapter. Do not probe compiled package output or treat TypeScript as the default
80
+ for a non-TypeScript module.
81
+
75
82
  ## Workspace State Rules
76
83
 
77
84
  - `src/index.ts` declares sources, phases, and packages.
@@ -107,7 +114,7 @@ Present only the current workflow surface:
107
114
  | Task | Current route |
108
115
  |---|---|
109
116
  | Register a knowledge boundary | `context source add file/lark/repo ...`, followed by the matching project phase declaration. Source registration is a user-confirmed boundary decision. |
110
- | Capture document sources | Run the declared `capture:file:<date>/<module>` or `capture:lark:<date>/<module>` phase only after read permission. Capture writes a sibling document file under the matching date directory and updates that directory's single `manifest.json`. |
117
+ | Capture document sources | Run the declared `capture:file:<date>/<module>` or `capture:lark:<date>/<module>` phase only after read permission. Capture writes a sibling document file under the matching date directory, updates that directory's single `manifest.json`, and mechanically materializes supported Lark resources. Do not download or rewrite embedded resources outside the CLI. |
111
118
  | Investigate captured material | Use `context status` and the returned `context run align:<type>:<source>:<collection> --view ...` commands. Evidence views drive reading; raw directory grep is not the workflow. |
112
119
  | Confirm prose structure | `alignProse` validates and stages CLI-managed lifecycle structure. Validation does not equal user confirmation; only confirmed lifecycle state may enter prose compile. |
113
120
  | Compile source-bound drafts | `compileProse` turns confirmed structure into source-bound draft pages. It does not approve knowledge. |
@@ -0,0 +1,115 @@
1
+ # Lark Resource Materialization
2
+
3
+ Lark documents can contain evidence that is not present in the readable text
4
+ body. Context handles these resources mechanically during `captureLark`; the
5
+ Agent does not download, summarize, or reconstruct them itself.
6
+
7
+ ## Resource policy
8
+
9
+ | Resource | Default capture behavior |
10
+ |---|---|
11
+ | Image and attachment | Download the original file and link it from the Markdown projection. |
12
+ | Sheet | Read the complete selected sheet, render a Markdown table, and retain a CSV snapshot. |
13
+ | Base | Read the selected table/view with pagination, render a Markdown table, and retain a canonical JSON snapshot. |
14
+ | Whiteboard and diagram | Retain a readable preview plus the raw structured export. |
15
+ | Synced block | Resolve the exact source block, project its body, and retain a Markdown evidence snapshot. |
16
+ | Poll | Preserve exported options and metadata as non-interactive Markdown; warn when the export omits them. |
17
+ | Bookmark, citation, sub-document, chat, and generic embed | Preserve a stable navigation reference and provenance. |
18
+ | Video | Preserve a stable reference by default; download only when `resources.videos` is `bundle`. |
19
+
20
+ Required inline resources fail closed when their stable identity, bytes, or
21
+ complete structured data cannot be obtained. When the remote API explicitly
22
+ confirms that a referenced whiteboard or diagram no longer exists, Context
23
+ preserves an unavailable-resource notice with the reason code
24
+ `document.resource.source-missing`, reports a warning, and continues capture;
25
+ it does not pretend that the deleted content was materialized. When the current
26
+ identity can read the document body but the API explicitly returns
27
+ `authorization/permission_denied` for an embedded resource, Context records
28
+ `document.resource.permission-denied`, keeps the stable resource identity in
29
+ the audit layer, renders the same unavailable-resource notice, and continues
30
+ with a warning. Missing scopes, transient network errors, malformed payloads,
31
+ and unclassified authorization failures still block capture. Reference-only
32
+ resources remain explicit in the capture report. Unknown non-empty XML blocks
33
+ stay auditable in the raw XML and receive a warning; the CLI does not infer
34
+ their meaning.
35
+
36
+ ## Storage lifecycle
37
+
38
+ Resources have three distinct locations:
39
+
40
+ ```text
41
+ sources/lark/<date>/
42
+ ├── <module>.md
43
+ ├── manifest.json
44
+ └── assets/<module>/
45
+ ├── source.xml
46
+ ├── capture-report.json
47
+ └── materialized/**
48
+ knowledge/assets/<resource-kind>/<content-sha256>.<ext>
49
+ dist/<package>/others/assets/<resource-kind>/<content-sha256>.<ext>
50
+ ```
51
+
52
+ - `sources/` is the captured source and audit layer. `source.xml` preserves the
53
+ structured source, one `capture-report.json` closes fidelity and resource
54
+ handling for the document, and `materialized/` contains downloaded files and
55
+ structured exports. Resource descriptors are consolidated in the report;
56
+ capture does not create one metadata file per embedded resource.
57
+ - The date-level `manifest.json` is a compact inventory. It records hashes,
58
+ asset roles, the report path, and status summaries without duplicating the
59
+ complete report.
60
+ - `knowledge/assets/` contains only resources referenced by approved pages.
61
+ Paths are content-addressed, so identical bytes are reused and changed bytes
62
+ produce a new identity. Review apply rewrites page links mechanically;
63
+ verification compares the underlying content identity, so this deterministic
64
+ path projection does not count as a change to a verbatim section.
65
+ Markdown files below `knowledge/assets/` remain evidence resources and are
66
+ never interpreted as approved knowledge pages or structure views.
67
+ - `others/assets/` is the portable package projection. Build copies only
68
+ resources referenced by selected package pages and rewrites their relative
69
+ links. Audit-only source files are not distributed.
70
+
71
+ Deleting an approved page allows unreferenced `knowledge/assets` files to be
72
+ cleaned. A missing approved or packaged resource is a verification error rather
73
+ than a silent broken link.
74
+
75
+ Source assets are part of the reproducible evidence snapshot and should not be
76
+ ignored when the workspace is versioned. Repositories with many binary source
77
+ assets can use Git LFS for `materialized/` while keeping Markdown, XML, JSON, and
78
+ CSV directly reviewable in Git. The workspace must remain private when the
79
+ captured source or screenshots are access-controlled.
80
+
81
+ ## SDK configuration
82
+
83
+ Defaults are suitable for ordinary documents:
84
+
85
+ ```ts
86
+ captureLark({ source: handbook });
87
+ ```
88
+
89
+ Projects can opt into bundled video and adjust deterministic byte limits:
90
+
91
+ ```ts
92
+ captureLark({
93
+ source: handbook,
94
+ resources: {
95
+ videos: "bundle",
96
+ maxBytesPerResource: 20 * 1024 * 1024,
97
+ maxTotalBytes: 200 * 1024 * 1024,
98
+ },
99
+ });
100
+ ```
101
+
102
+ The limits are capture constraints, not semantic filters. Context does not
103
+ decide which resources are important from their business content.
104
+
105
+ ## Agent behavior
106
+
107
+ Use the capture command returned by the current Route. Inspect the structured
108
+ resource summary and fidelity diagnostics; do not manually edit `sources/`,
109
+ `knowledge/assets/`, or package links. Required materialization failures other
110
+ than a confirmed source-side deletion or an explicit resource-level permission
111
+ denial must be resolved by recapturing after access or source problems are
112
+ fixed. Accepted failures remain visible as warnings and unavailable-resource
113
+ notices; they are never represented as downloaded evidence. Review shows
114
+ available previews, references, and warnings so the human or managed policy can
115
+ assess the page with its non-text evidence.
@@ -61,6 +61,7 @@ wikis/index.md
61
61
  guides/...
62
62
  rules/...
63
63
  feats/...
64
+ others/assets/...
64
65
  ```
65
66
 
66
67
  Do not ask for another distribution namespace. Older workspaces may still
@@ -88,6 +89,27 @@ package needs project-specific terminology, entry points, known limits, or
88
89
  task workflows. Authors may explicitly accept the generic default when it is
89
90
  intentionally sufficient.
90
91
 
92
+ When approved pages reference materialized document resources, Context keeps
93
+ their production copies in content-addressed `knowledge/assets/` paths. New KB
94
+ setup should offer Git raw delivery first. It rewrites package links to either
95
+ an automatically derived raw prefix or an explicit author-provided prefix.
96
+ Context does not check whether resource files are committed, pushed, or
97
+ remotely readable; that is the package author's responsibility. With no
98
+ explicit prefix, supported remotes use an immutable commit URL. An explicit
99
+ prefix can contain `{commit}` when the Context workspace is in Git, or name a
100
+ mutable branch when that lifecycle is intentional; a literal prefix also works
101
+ when resources are published from a separate repository.
102
+
103
+ Workspaces without usable Git or an explicit raw prefix can choose bundled
104
+ delivery, which copies only selected resources to `others/assets/`, or explicit
105
+ omission, which does not copy resources and reports that links remain
106
+ unresolved. Bundled output may
107
+ optionally install `sharp` in the workspace and configure
108
+ `assets.optimize`; Context itself has no image dependency. Optimization changes
109
+ only `dist/`, content-addresses smaller WebP output, and leaves `sources/` and
110
+ `knowledge/assets/` unchanged. Source audit XML and capture reports are never
111
+ distributed as reader assets. See [Lark Resource Materialization](./lark-resources.md).
112
+
91
113
  The same inventory exposes `structure.relationship_coverage`. It records
92
114
  whether selected codegraph pages have current source-backed AST relationship
93
115
  metadata, how many codegraph views were selected, and how many package-visible
@@ -0,0 +1,88 @@
1
+ # Code Extractor Selection
2
+
3
+ Use this manual only when the current code-extraction Route asks the Agent to
4
+ choose or declare an extractor. The CLI reports repository facts; the Agent
5
+ chooses how those facts become source-backed code knowledge.
6
+
7
+ ## Inspect Before Declaring
8
+
9
+ Run every read-only inspection command returned by the extraction-scope Gate.
10
+ The result identifies each confirmed module and its recognized `manifests`.
11
+ Treat these as deterministic technology signals, not as product semantics:
12
+
13
+ | Signal | Technology candidate |
14
+ |---|---|
15
+ | `package.json` | TypeScript, TSX, JavaScript, or JSX |
16
+ | `go.mod` | Go |
17
+ | `Cargo.toml` | Rust |
18
+ | `pyproject.toml` or `setup.py` | Python |
19
+ | `pom.xml` or `build.gradle` | Java or JVM |
20
+ | multiple manifests | a mixed module that may need more than one extractor |
21
+
22
+ Do not select `extractTs()` merely because a repository contains some
23
+ TypeScript. Decide against the exact confirmed module and include boundary. A
24
+ mixed module may compose multiple structural passes; parser selection is not an
25
+ exclusive repository-wide switch.
26
+
27
+ ## Selection Order
28
+
29
+ Use the narrowest reusable capability that covers the confirmed source:
30
+
31
+ 1. Use a Context-owned phase when its contract matches the source.
32
+ 2. Otherwise use a reusable structural package inside `extractCustom()`.
33
+ 3. If no reusable package covers the syntax or repository protocol, implement a
34
+ project-owned adapter and keep it in the Context workspace.
35
+
36
+ Current reusable capabilities are:
37
+
38
+ | Source fact | Preferred capability | Lifecycle integration |
39
+ |---|---|---|
40
+ | TypeScript/TSX package or file scope | `extractTs()` | Context-owned phase |
41
+ | Go declarations, imports, calls, and common HTTP routes | `@c4a/extract-go` | call from `extractCustom()` |
42
+ | Rush workspace packages, tags, dependencies, entries, and owners | `@c4a/extract-rush` | call from `extractCustom()`; may complement a language extractor |
43
+ | React Router route declarations | `extractReactRouterRoutes()` from `@c4a/extract-ts` | call from `extractCustom()`; complements TypeScript symbols |
44
+ | Rust, Python, Java/JVM, or an unsupported framework/protocol | no assumed built-in parser | project-owned `extractCustom()` adapter |
45
+
46
+ An optional package does not create a new CLI phase. Add it as an explicit
47
+ workspace dependency, then map its structural facts to candidates in the
48
+ project callback. Do not add a parser package when its documented coverage does
49
+ not match the inspected source.
50
+
51
+ ## Read The Contract Before Extending
52
+
53
+ Before editing `src/index.ts`, read the relevant installed public manual or
54
+ package README. Do not infer APIs from bundled JavaScript.
55
+
56
+ - Context lifecycle and `extractCustom()`:
57
+ `node_modules/@c4a/context/docs/reference/project-api.md`
58
+ - Generic plugin protocol:
59
+ `node_modules/@c4a/extract/README.md`
60
+ - TypeScript:
61
+ `node_modules/@c4a/extract-ts/README.md`
62
+ - Go:
63
+ `node_modules/@c4a/extract-go/README.md`
64
+ - Rush:
65
+ `node_modules/@c4a/extract-rush/README.md`
66
+
67
+ If an optional package is not installed, use this capability matrix to decide
68
+ whether it is relevant, add only that dependency, and then read its shipped
69
+ README before implementing the callback.
70
+
71
+ A project-owned adapter may use an existing parser, compiler API, or command
72
+ whose output is deterministic. It must return source-backed candidates through
73
+ `extractCustom()`; it must not write lifecycle, knowledge, or Review files.
74
+ Framework-specific classification and rendering remain in the project. The CLI
75
+ and structural parser must not infer product meaning.
76
+
77
+ ## Decision To Report
78
+
79
+ Before the first extraction preview, state briefly:
80
+
81
+ - the inspected module and manifest signals;
82
+ - the selected Context phase or structural package;
83
+ - whether coverage is complete or which facts remain project-owned; and
84
+ - why another available extractor is not needed.
85
+
86
+ If no current capability can parse the source reliably, stop at configuration
87
+ and report the missing generic capability. Do not silently emit an empty
88
+ codegraph or reuse an unrelated parser.
@@ -31,6 +31,10 @@ kbPackage({
31
31
  foldDirectoryIndexes: true,
32
32
  maxInlineEntries: 50,
33
33
  },
34
+ assets: {
35
+ delivery: "git-raw",
36
+ urlPrefix: "https://code.example.com/team/knowledge/raw/{commit}",
37
+ },
34
38
  });
35
39
  ```
36
40
 
@@ -52,8 +56,56 @@ llmsPackage({
52
56
  | `template` | yes | Project-relative template directory or `{ path, vars }`. |
53
57
  | `select` | no | Approved knowledge selector. Omit to include all approved knowledge. Supports internal `collections`, OKF `okfRoots`, and `include` / `exclude` path patterns relative to `knowledge/`. |
54
58
  | `navigation` | no | KB directory-index policy. Defaults to `{ foldDirectoryIndexes: true, maxInlineEntries: 50 }`. |
59
+ | `assets` | no | Resource delivery: Git raw links, bundled files, or explicit omission. New KB setup should offer Git raw first. Omit for legacy byte-for-byte bundling. |
55
60
  | `distribution` | no | Legacy input accepted from older workspaces. It no longer changes package paths and should not be added to new declarations. |
56
61
 
62
+ Use Git raw delivery when resources are published from a Git repository.
63
+ Without `urlPrefix`, the Context workspace must be inside Git; GitHub remotes
64
+ are derived automatically and pinned to the current commit. Other hosts and
65
+ workspaces outside Git accept an explicit HTTPS prefix; Context appends the
66
+ project-relative `knowledge/assets/...` path. Context does not check whether
67
+ the resources are committed, pushed, or remotely readable; publishing them is
68
+ the package author's responsibility.
69
+ `{commit}` is replaced when present. A literal branch in the prefix is allowed
70
+ but intentionally follows that mutable branch. The configured raw host must be
71
+ reachable by the eventual package consumers.
72
+
73
+ ```ts
74
+ assets: {
75
+ delivery: "git-raw",
76
+ urlPrefix: "https://code.example.com/team/knowledge/raw/{commit}",
77
+ }
78
+ ```
79
+
80
+ When the workspace is not in Git and has no explicit raw prefix, choose bundled
81
+ delivery or explicit omission:
82
+
83
+ ```ts
84
+ assets: { delivery: "bundle" }
85
+ assets: { delivery: "omit" } // keeps unresolved links and reports them
86
+ ```
87
+
88
+ Bundled resources are copied byte-for-byte unless image optimization is
89
+ configured. When optimizable PNG/JPEG resources exceed 20 MiB, build and status
90
+ return `package.assets.optimization-recommended`. To optimize bundled output:
91
+
92
+ ```bash
93
+ bun add -D sharp
94
+ ```
95
+
96
+ ```ts
97
+ assets: {
98
+ delivery: "bundle",
99
+ optimize: { processor: "sharp", mode: "lossless-webp" },
100
+ }
101
+ ```
102
+
103
+ `optimize.mode: "webp"` additionally accepts `quality` from 1 to 100. Both modes accept
104
+ an optional positive `maxDimension`; images are never enlarged. Context adopts
105
+ a generated image only when it is smaller, uses a digest-derived `.webp` path,
106
+ and rewrites package links. A configured but missing processor blocks before
107
+ the previous `dist/` package is replaced.
108
+
57
109
  `template` is required. Do not call `kbPackage({ name })` or
58
110
  `llmsPackage({ name })`.
59
111
 
@@ -209,6 +209,13 @@ extraction phases, review gates, close/build, and packages explicitly. The CLI
209
209
  then routes work through `context status`, `context run <phase-id>`, `context
210
210
  review html/apply`, `context close`, `context verify`, and `context build`.
211
211
 
212
+ For Agent and automation output, use `context verify --format json --compact`.
213
+ It returns deterministic groups, counts, affected-scope totals, and a few
214
+ representative samples instead of repeating every issue. Read the complete,
215
+ auditable issue set only when needed with `context verify --view diagnostics
216
+ --page-size 25 --format json`; follow its executable pagination command without
217
+ inventing overlapping file ranges.
218
+
212
219
  ### Status declaration coverage
213
220
 
214
221
  `context status --format json --view full` includes a `declarationGraph` and
@@ -321,6 +328,21 @@ Markdown snapshot:
321
328
  captureLark({ source: handbook });
322
329
  ```
323
330
 
331
+ Embedded resources are materialized with deterministic defaults. Video remains
332
+ reference-only unless a project opts into bundling, and byte limits prevent an
333
+ unexpected document from expanding the workspace without bound:
334
+
335
+ ```ts
336
+ captureLark({
337
+ source: handbook,
338
+ resources: {
339
+ videos: "bundle",
340
+ maxBytesPerResource: 20 * 1024 * 1024,
341
+ maxTotalBytes: 200 * 1024 * 1024,
342
+ },
343
+ });
344
+ ```
345
+
324
346
  Phase id:
325
347
 
326
348
  ```text
@@ -334,19 +356,33 @@ one date batch; when `--module` is omitted, the CLI derives an opaque,
334
356
  credential-safe module id. Capture reads the
335
357
  remote document through the CLI runner as structured Docx XML. Context keeps a
336
358
  redacted XML audit asset, projects supported blocks deterministically into
337
- readable Markdown, and registers external resources such as document citations,
338
- images, video, whiteboards, and Base references in the snapshot manifest even
339
- when their binary content is not downloaded. The projection does not infer or
340
- summarize document meaning. Its fidelity report closes discovered blocks
359
+ readable Markdown, and materializes required inline resources such as images,
360
+ attachments, Sheets, Bases, whiteboards, diagrams, and synced blocks. Navigation
361
+ resources and default video capture remain explicit references. The projection
362
+ does not infer or summarize document meaning. Its fidelity and resource reports close discovered blocks
341
363
  against converted and intentionally skipped blocks and reports evidence
342
364
  completeness separately from Markdown projection quality. Unknown non-empty XML
343
365
  blocks receive a generic, auditable, non-interactive projection and do not block
344
- downstream work. Missing source content or unresolved external-resource identity
345
- remains an evidence error and prevents downstream Review.
366
+ downstream work. A remote whiteboard or diagram explicitly confirmed as deleted
367
+ is preserved as an unavailable-resource notice with
368
+ `document.resource.source-missing` and a warning. An embedded resource whose
369
+ export is explicitly rejected as `authorization/permission_denied` is retained
370
+ the same way with `document.resource.permission-denied`. Missing scopes,
371
+ unresolved external-resource identity, retryable failures, and unclassified
372
+ authorization errors remain evidence errors and prevent downstream Review.
346
373
  Snapshot files live under `sources/lark/<date>/` as sibling document files
347
- tracked by one date-level `manifest.json`. Access credentials and transient
374
+ tracked by one compact date-level `manifest.json`. Each module keeps one raw
375
+ `source.xml`, one consolidated `capture-report.json`, and its actual downloaded
376
+ or structured resources under `assets/<module>/materialized/`; it does not emit
377
+ one descriptor file per embedded resource. Access credentials and transient
348
378
  signed media URLs are not written into the workspace.
349
379
 
380
+ Approved resource bytes are projected to content-addressed
381
+ `knowledge/assets/<kind>/` paths. KB build copies selected resources to
382
+ `others/assets/<kind>/` inside the package and rewrites page links. See
383
+ [Lark Resource Materialization](../guides/lark-resources.md) for the complete
384
+ resource table and storage lifecycle.
385
+
350
386
  Use a typed document reference in project declarations:
351
387
 
352
388
  ```ts
@@ -703,6 +739,41 @@ Review summary and source-backed evidence). It must not write `knowledge/`,
703
739
  Review snapshots directly. Context owns those files and preserves rejected and
704
740
  unchanged-approved decisions across reruns.
705
741
 
742
+ #### Optional structural extractors
743
+
744
+ For the manifest-to-capability decision and unsupported-language extension
745
+ boundary, read [Code Extractor Selection](./code-extractors.md) before declaring
746
+ the phase.
747
+
748
+ `extractCustom()` may consume optional community packages without making them
749
+ Context CLI dependencies:
750
+
751
+ ```ts
752
+ import { indexGoRepository } from "@c4a/extract-go";
753
+ import { extractCustom } from "@c4a/context";
754
+
755
+ extractCustom({
756
+ id: "extract:service:codegraph",
757
+ sources: [service],
758
+ collection: "codegraph",
759
+ extract: async ({ projectRoot }) => {
760
+ const facts = await indexGoRepository(resolveServiceCheckout(projectRoot));
761
+ return { candidates: buildServiceCandidates(facts) };
762
+ },
763
+ });
764
+ ```
765
+
766
+ Available structural libraries include:
767
+
768
+ - `@c4a/extract-go`: Go declarations, imports, calls, and common HTTP routes;
769
+ - `@c4a/extract-rush`: Rush projects, tags, entries, dependencies, and owners;
770
+ - `@c4a/extract-ts`: TypeScript extraction and `extractReactRouterRoutes()`.
771
+
772
+ The packages return syntax and repository facts only. They do not classify
773
+ product meaning, choose candidate identities, or write lifecycle state. The
774
+ knowledge project owns that mapping. Context CLI does not auto-install these
775
+ packages and does not expose a built-in Go or Rush phase.
776
+
706
777
  ### `reviewValidity`
707
778
 
708
779
  Declare the review step for a collection:
package/index.d.ts CHANGED
@@ -22,6 +22,32 @@ export type PackageDistributionDefinition = {
22
22
  /** @deprecated Accepted for older workspaces; package output roots are flat. */
23
23
  knowledgeNamespace: string;
24
24
  };
25
+ export type PackageAssetOptimizationDefinition = {
26
+ /** Image codec provider resolved from the Context workspace. */
27
+ processor: "sharp";
28
+ /** Lossless is the safe default; lossy WebP must be selected explicitly. */
29
+ mode?: "lossless-webp" | "webp";
30
+ /** WebP quality for lossy mode. */
31
+ quality?: number;
32
+ /** Optional longest-edge limit. Images are never enlarged. */
33
+ maxDimension?: number;
34
+ };
35
+ export type PackageAssetDefinition = {
36
+ /** Publish references to immutable Git-hosted resources instead of copying resource bytes. */
37
+ delivery: "git-raw";
38
+ /** Git remote used to derive the repository URL. */
39
+ remote?: string;
40
+ /** Optional HTTPS raw root. Context appends knowledge/assets/**; {commit} is supported. */
41
+ urlPrefix?: string;
42
+ } | {
43
+ /** Copy resources into the package. */
44
+ delivery: "bundle";
45
+ /** Optional image optimization, resolved from the Context workspace. */
46
+ optimize?: PackageAssetOptimizationDefinition;
47
+ } | {
48
+ /** Do not copy resources. Existing relative references remain unresolved. */
49
+ delivery: "omit";
50
+ };
25
51
  export type BasePackageDefinition = {
26
52
  name: string;
27
53
  reads: readonly PhaseResourceReference[];
@@ -34,6 +60,7 @@ export type KbPackageDefinition = BasePackageDefinition & {
34
60
  kind: "package.kb";
35
61
  navigation: PackageNavigationDefinition;
36
62
  distribution?: PackageDistributionDefinition;
63
+ assets?: PackageAssetDefinition;
37
64
  };
38
65
  export type LlmsPackageDefinition = BasePackageDefinition & {
39
66
  kind: "package.llms";
@@ -55,6 +82,7 @@ export declare const kbPackage: (definition: {
55
82
  select?: PackageSelectDefinition;
56
83
  navigation?: Partial<PackageNavigationDefinition>;
57
84
  distribution?: PackageDistributionDefinition;
85
+ assets?: PackageAssetDefinition;
58
86
  }) => KbPackageDefinition;
59
87
  export declare const llmsPackage: (definition: {
60
88
  name: string;
package/index.js CHANGED
@@ -7128,6 +7128,14 @@ var captureFile = (definition) => {
7128
7128
  var captureLark = (definition) => {
7129
7129
  const sourceDefinition = bindSourceType(definition.source, "lark", "captureLark source");
7130
7130
  const sourceId = getSourceName(sourceDefinition);
7131
+ const maxBytesPerResource = definition.resources?.maxBytesPerResource ?? 20 * 1024 * 1024;
7132
+ const maxTotalBytes = definition.resources?.maxTotalBytes ?? 200 * 1024 * 1024;
7133
+ if (!Number.isSafeInteger(maxBytesPerResource) || maxBytesPerResource < 1) {
7134
+ throw new TypeError("captureLark resources.maxBytesPerResource must be a positive safe integer");
7135
+ }
7136
+ if (!Number.isSafeInteger(maxTotalBytes) || maxTotalBytes < maxBytesPerResource) {
7137
+ throw new TypeError("captureLark resources.maxTotalBytes must be a safe integer greater than or equal to maxBytesPerResource");
7138
+ }
7131
7139
  return {
7132
7140
  kind: "phase.capture.lark",
7133
7141
  id: `capture:lark:${sourceId}`,
@@ -7136,7 +7144,12 @@ var captureLark = (definition) => {
7136
7144
  source: sourceDefinition
7137
7145
  }],
7138
7146
  writes: [sourceSnapshotResource(sourceDefinition, "lark")],
7139
- source: sourceDefinition
7147
+ source: sourceDefinition,
7148
+ resources: {
7149
+ videos: definition.resources?.videos ?? "reference-only",
7150
+ maxBytesPerResource,
7151
+ maxTotalBytes
7152
+ }
7140
7153
  };
7141
7154
  };
7142
7155
  var alignProse = (definition) => {
@@ -11901,6 +11914,58 @@ var normalizePackageDistribution = (distribution) => {
11901
11914
  }
11902
11915
  return { knowledgeNamespace };
11903
11916
  };
11917
+ var normalizePackageAssetOptimization = (assets) => {
11918
+ if (assets.processor !== "sharp") {
11919
+ throw new TypeError(`Package assets.optimize.processor must be "sharp": ${String(assets.processor)}`);
11920
+ }
11921
+ const mode = assets.mode ?? "lossless-webp";
11922
+ if (mode !== "lossless-webp" && mode !== "webp") {
11923
+ throw new TypeError(`Package assets.optimize.mode must be "lossless-webp" or "webp": ${String(mode)}`);
11924
+ }
11925
+ if (assets.quality !== undefined && (!Number.isSafeInteger(assets.quality) || assets.quality < 1 || assets.quality > 100)) {
11926
+ throw new TypeError(`Package assets.optimize.quality must be a safe integer from 1 to 100: ${assets.quality}`);
11927
+ }
11928
+ if (mode === "lossless-webp" && assets.quality !== undefined) {
11929
+ throw new TypeError('Package assets.optimize.quality is only valid when assets.optimize.mode is "webp".');
11930
+ }
11931
+ if (assets.maxDimension !== undefined && (!Number.isSafeInteger(assets.maxDimension) || assets.maxDimension < 1)) {
11932
+ throw new TypeError(`Package assets.optimize.maxDimension must be a positive safe integer: ${assets.maxDimension}`);
11933
+ }
11934
+ return {
11935
+ processor: "sharp",
11936
+ mode,
11937
+ ...assets.quality === undefined ? {} : { quality: assets.quality },
11938
+ ...assets.maxDimension === undefined ? {} : { maxDimension: assets.maxDimension }
11939
+ };
11940
+ };
11941
+ var normalizePackageAssets = (assets) => {
11942
+ if (assets === undefined)
11943
+ return;
11944
+ if (assets.delivery === "bundle") {
11945
+ return {
11946
+ delivery: "bundle",
11947
+ ...assets.optimize === undefined ? {} : { optimize: normalizePackageAssetOptimization(assets.optimize) }
11948
+ };
11949
+ }
11950
+ if (assets.delivery === "omit")
11951
+ return { delivery: "omit" };
11952
+ if (assets.delivery !== "git-raw") {
11953
+ throw new TypeError(`Package assets.delivery must be "git-raw", "bundle", or "omit": ${String(assets.delivery)}`);
11954
+ }
11955
+ const remote = assets.remote?.trim();
11956
+ if (remote !== undefined && !/^[A-Za-z0-9._-]+$/u.test(remote)) {
11957
+ throw new TypeError(`Package assets.remote must be a safe Git remote name: ${assets.remote}`);
11958
+ }
11959
+ const urlPrefix = assets.urlPrefix?.trim().replace(/\/+$/u, "");
11960
+ if (urlPrefix !== undefined && !urlPrefix.startsWith("https://")) {
11961
+ throw new TypeError("Package assets.urlPrefix must be an HTTPS URL; it may contain {commit}.");
11962
+ }
11963
+ return {
11964
+ delivery: "git-raw",
11965
+ ...remote === undefined ? {} : { remote },
11966
+ ...urlPrefix === undefined ? {} : { urlPrefix }
11967
+ };
11968
+ };
11904
11969
  var assertSelectOkfRoots = (roots) => {
11905
11970
  for (const root of roots) {
11906
11971
  assertOkfRoot(root, "Package select.okfRoots");
@@ -11946,11 +12011,13 @@ var createPackageDefinitionBase = (kind, definition) => {
11946
12011
  var kbPackage = (definition) => {
11947
12012
  const base = createPackageDefinitionBase("kb", definition);
11948
12013
  const distribution = normalizePackageDistribution(definition.distribution);
12014
+ const assets = normalizePackageAssets(definition.assets);
11949
12015
  return {
11950
12016
  kind: "package.kb",
11951
12017
  ...base,
11952
12018
  navigation: normalizePackageNavigation(definition.navigation),
11953
- ...distribution === undefined ? {} : { distribution }
12019
+ ...distribution === undefined ? {} : { distribution },
12020
+ ...assets === undefined ? {} : { assets }
11954
12021
  };
11955
12022
  };
11956
12023
  var llmsPackage = (definition) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c4a/context",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "type": "module",
5
5
  "description": "Context SDK — project-local configuration and workspace primitives",
6
6
  "license": "MIT",
@@ -15,6 +15,9 @@
15
15
  "knowledge",
16
16
  "workspace"
17
17
  ],
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
18
21
  "dependencies": {
19
22
  "yaml": "^2.5.1",
20
23
  "zod": "^3.23.8"
package/phases.d.ts CHANGED
@@ -143,6 +143,11 @@ export type CaptureLarkPhaseDefinition = {
143
143
  reads: readonly PhaseResourceReference[];
144
144
  writes: readonly PhaseResourceReference[];
145
145
  source: LarkSourceDefinition | LarkSourceReference;
146
+ resources: {
147
+ videos: "reference-only" | "bundle";
148
+ maxBytesPerResource: number;
149
+ maxTotalBytes: number;
150
+ };
146
151
  };
147
152
  export type AlignProsePhaseDefinition = {
148
153
  kind: "phase.align.prose";
@@ -200,6 +205,11 @@ export declare const captureFile: (definition: {
200
205
  }) => CaptureFilePhaseDefinition;
201
206
  export declare const captureLark: (definition: {
202
207
  source: LarkSourceDefinition | LarkSourceReference;
208
+ resources?: {
209
+ videos?: "reference-only" | "bundle";
210
+ maxBytesPerResource?: number;
211
+ maxTotalBytes?: number;
212
+ };
203
213
  }) => CaptureLarkPhaseDefinition;
204
214
  export declare const alignProse: (definition: {
205
215
  source: DocumentSourceDefinition;
@@ -78,11 +78,12 @@ phrases, or several large indexes, run the bundled
78
78
  node <current knowledge-query Skill directory>/scripts/search.mjs --query '<terms>' --limit 8
79
79
  ```
80
80
 
81
- The script locates `{{packageName}}` from a raw package or TTKB installation.
82
- If discovery is ambiguous, add `--root <package directory containing
83
- context-build-inventory.json>`. It chunks Markdown mechanically by headings and
84
- bounded line ranges, then returns paths, line ranges, headings, and previews; it
85
- does not interpret meaning.
81
+ The script locates `{{packageName}}` when it runs inside the package tree. If a
82
+ package manager copied this Skill elsewhere, add `--root <package directory
83
+ containing context-build-inventory.json>`, or use `--base <package collection>`
84
+ to locate this package by its inventory name. It chunks Markdown mechanically
85
+ by headings and bounded line ranges, then returns paths, line ranges, headings,
86
+ and previews; it does not interpret meaning.
86
87
 
87
88
  Treat every hit as a lead and open its page and section before answering. For
88
89
  relationship or impact claims, use typed edges from
@@ -14,8 +14,8 @@ function usage() {
14
14
  "Search an approved knowledge package with deterministic BM25 ranking.",
15
15
  "",
16
16
  "Usage:",
17
- " node search.mjs --query <text> [--root <package-root>] [--limit <n>] [--json]",
18
- " node search.mjs <text> [--root <package-root>] [--limit <n>] [--json]",
17
+ " node search.mjs --query <text> [--root <package-root>] [--base <package-collection>] [--limit <n>] [--json]",
18
+ " node search.mjs <text> [--root <package-root>] [--base <package-collection>] [--limit <n>] [--json]",
19
19
  "",
20
20
  "The package root is detected from context-build-inventory.json when possible.",
21
21
  ].join("\n");
@@ -23,7 +23,7 @@ function usage() {
23
23
 
24
24
  function parseArgs(argv) {
25
25
  const positional = [];
26
- const options = { root: undefined, query: undefined, limit: 8, json: false };
26
+ const options = { root: undefined, base: undefined, query: undefined, limit: 8, json: false };
27
27
  for (let index = 0; index < argv.length; index++) {
28
28
  const arg = argv[index];
29
29
  if (arg === "--help" || arg === "-h") return { help: true };
@@ -31,10 +31,11 @@ function parseArgs(argv) {
31
31
  options.json = true;
32
32
  continue;
33
33
  }
34
- if (arg === "--root" || arg === "--query" || arg === "--limit") {
34
+ if (arg === "--root" || arg === "--base" || arg === "--query" || arg === "--limit") {
35
35
  const value = argv[++index];
36
36
  if (value === undefined) throw new Error(`missing value for ${arg}`);
37
37
  if (arg === "--root") options.root = value;
38
+ else if (arg === "--base") options.base = value;
38
39
  else if (arg === "--query") options.query = value;
39
40
  else options.limit = Number(value);
40
41
  continue;
@@ -83,7 +84,7 @@ function inventoryPackageName(inventoryPath) {
83
84
  }
84
85
  }
85
86
 
86
- function resolvePackageRoot(explicitRoot) {
87
+ function resolvePackageRoot(explicitRoot, packageCollection) {
87
88
  if (explicitRoot !== undefined) {
88
89
  const root = resolve(explicitRoot);
89
90
  if (!isPackageRoot(root)) throw new Error(`package root has no context-build-inventory.json: ${root}`);
@@ -93,7 +94,10 @@ function resolvePackageRoot(explicitRoot) {
93
94
  if (scriptRoot !== undefined) return scriptRoot;
94
95
  const cwdRoot = ancestorPackageRoot(process.cwd());
95
96
  if (cwdRoot !== undefined) return cwdRoot;
96
- const inventories = findInventories(join(process.cwd(), ".ttkb", "packages"));
97
+ if (packageCollection === undefined) {
98
+ throw new Error("cannot locate the knowledge package; pass --root <package-root> or --base <package-collection>");
99
+ }
100
+ const inventories = findInventories(resolve(packageCollection));
97
101
  const matching = inventories.filter((path) => inventoryPackageName(path) === PACKAGE_NAME);
98
102
  if (matching.length === 1) return dirname(matching[0]);
99
103
  if (matching.length > 1) {
@@ -245,7 +249,7 @@ try {
245
249
  process.stdout.write(`${usage()}\n`);
246
250
  process.exit(0);
247
251
  }
248
- const root = resolvePackageRoot(options.root);
252
+ const root = resolvePackageRoot(options.root, options.base);
249
253
  const results = search(root, options.query, options.limit);
250
254
  if (options.json) {
251
255
  process.stdout.write(`${JSON.stringify({ package: PACKAGE_NAME, root, query: options.query, results }, null, 2)}\n`);
@@ -6,4 +6,3 @@ Package kind: {{packageKind}}
6
6
  Approved knowledge files: {{knowledgeCount}}
7
7
 
8
8
  {{knowledge}}
9
-
@@ -60,7 +60,7 @@ description: 查询 {{displayName}} 中经过审核、可追溯来源的知识
60
60
  node <当前 knowledge-query Skill 目录>/scripts/search.mjs --query '<关键词>' --limit 8
61
61
  ```
62
62
 
63
- 脚本会从原始包或 TTKB 安装目录定位 `{{packageName}}`;无法唯一定位时,增加 `--root <包含 context-build-inventory.json 的包目录>`。它按 Markdown 标题和固定行块机械切分,返回路径、行号、标题和短预览,不判断内容语义。
63
+ 脚本位于知识包目录内时会自动定位 `{{packageName}}`。如果包管理工具将本 Skill 复制到了其他位置,增加 `--root <包含 context-build-inventory.json 的包目录>`;也可以使用 `--base <多包集合根目录>`,按构建清单中的包名定位。它按 Markdown 标题和固定行块机械切分,返回路径、行号、标题和短预览,不判断内容语义。
64
64
 
65
65
  搜索命中只是线索。回答前必须打开命中的页面和章节;关系或影响范围仍以 `context-build-inventory.json` 的类型化边为准,不能用 BM25 分数或文本共现替代关系证据。
66
66
 
@@ -14,8 +14,8 @@ function usage() {
14
14
  "Search an approved knowledge package with deterministic BM25 ranking.",
15
15
  "",
16
16
  "Usage:",
17
- " node search.mjs --query <text> [--root <package-root>] [--limit <n>] [--json]",
18
- " node search.mjs <text> [--root <package-root>] [--limit <n>] [--json]",
17
+ " node search.mjs --query <text> [--root <package-root>] [--base <package-collection>] [--limit <n>] [--json]",
18
+ " node search.mjs <text> [--root <package-root>] [--base <package-collection>] [--limit <n>] [--json]",
19
19
  "",
20
20
  "The package root is detected from context-build-inventory.json when possible.",
21
21
  ].join("\n");
@@ -23,7 +23,7 @@ function usage() {
23
23
 
24
24
  function parseArgs(argv) {
25
25
  const positional = [];
26
- const options = { root: undefined, query: undefined, limit: 8, json: false };
26
+ const options = { root: undefined, base: undefined, query: undefined, limit: 8, json: false };
27
27
  for (let index = 0; index < argv.length; index++) {
28
28
  const arg = argv[index];
29
29
  if (arg === "--help" || arg === "-h") return { help: true };
@@ -31,10 +31,11 @@ function parseArgs(argv) {
31
31
  options.json = true;
32
32
  continue;
33
33
  }
34
- if (arg === "--root" || arg === "--query" || arg === "--limit") {
34
+ if (arg === "--root" || arg === "--base" || arg === "--query" || arg === "--limit") {
35
35
  const value = argv[++index];
36
36
  if (value === undefined) throw new Error(`missing value for ${arg}`);
37
37
  if (arg === "--root") options.root = value;
38
+ else if (arg === "--base") options.base = value;
38
39
  else if (arg === "--query") options.query = value;
39
40
  else options.limit = Number(value);
40
41
  continue;
@@ -83,7 +84,7 @@ function inventoryPackageName(inventoryPath) {
83
84
  }
84
85
  }
85
86
 
86
- function resolvePackageRoot(explicitRoot) {
87
+ function resolvePackageRoot(explicitRoot, packageCollection) {
87
88
  if (explicitRoot !== undefined) {
88
89
  const root = resolve(explicitRoot);
89
90
  if (!isPackageRoot(root)) throw new Error(`package root has no context-build-inventory.json: ${root}`);
@@ -93,7 +94,10 @@ function resolvePackageRoot(explicitRoot) {
93
94
  if (scriptRoot !== undefined) return scriptRoot;
94
95
  const cwdRoot = ancestorPackageRoot(process.cwd());
95
96
  if (cwdRoot !== undefined) return cwdRoot;
96
- const inventories = findInventories(join(process.cwd(), ".ttkb", "packages"));
97
+ if (packageCollection === undefined) {
98
+ throw new Error("cannot locate the knowledge package; pass --root <package-root> or --base <package-collection>");
99
+ }
100
+ const inventories = findInventories(resolve(packageCollection));
97
101
  const matching = inventories.filter((path) => inventoryPackageName(path) === PACKAGE_NAME);
98
102
  if (matching.length === 1) return dirname(matching[0]);
99
103
  if (matching.length > 1) {
@@ -245,7 +249,7 @@ try {
245
249
  process.stdout.write(`${usage()}\n`);
246
250
  process.exit(0);
247
251
  }
248
- const root = resolvePackageRoot(options.root);
252
+ const root = resolvePackageRoot(options.root, options.base);
249
253
  const results = search(root, options.query, options.limit);
250
254
  if (options.json) {
251
255
  process.stdout.write(`${JSON.stringify({ package: PACKAGE_NAME, root, query: options.query, results }, null, 2)}\n`);
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: maintain-project-knowledge
3
+ description: Maintain a project-local Context knowledge workspace by checking registered repository and document sources, selecting the affected project scope, and handing lifecycle actions to the installed Context Skill. Customize the name, description, project facts, and impact map before using this template in a real project.
4
+ ---
5
+
6
+ # Maintain project knowledge
7
+
8
+ Use this file as a project adapter, not as a copy of the Context workflow. Read
9
+ the installed Context Skill first and treat its current Route, resources, and
10
+ commands as authoritative. Keep only stable project facts and source-impact
11
+ mappings here.
12
+
13
+ ## Repository sources
14
+
15
+ Start with the current Context Route. If registered repository modules are
16
+ missing or their local links are broken, follow the route-selected repository
17
+ recovery procedure. Let the user choose an existing checkout, authorize a scan
18
+ inside one bounded directory, or explicitly clone the registered pinned commit.
19
+
20
+ When a checkout already exists, inspect its origin, HEAD, dirty state, and
21
+ registered subpaths before asking whether to keep the recorded commit or update
22
+ to another explicit commit. Never pull, switch, clean, or reset an external
23
+ checkout without separate authority.
24
+
25
+ Repository sources are ready for knowledge work only when every selected module
26
+ resolves to its registered remote and commit, all required subpaths exist,
27
+ unknown local changes are preserved, Context has materialized its module links,
28
+ and the current Route no longer reports a repository-readiness blocker.
29
+
30
+ Add the project's stable mapping from repository changes to declared extraction
31
+ scope here. Do not infer this mapping from filenames during a maintenance run.
32
+
33
+ ## Remote document sources
34
+
35
+ Use the current Context Route and the installed document-provider Skills or CLI
36
+ to read registered remote documents. Keep this section short: provider login,
37
+ permissions, capture, sub-page traversal, and fidelity diagnostics belong to
38
+ the provider and Context resources selected for the current step.
39
+
40
+ A remote document is ready for knowledge work only when its registered identity
41
+ is unchanged unless the user explicitly adds a new source, the current account
42
+ can read the required body and assets, relevant child pages are represented as
43
+ their own sources, capture fidelity has no blocking error, and the current Route
44
+ allows structure or extraction work to begin.
45
+
46
+ Add project-specific source ownership, expected document families, and update
47
+ boundaries here. Do not copy credentials, source bodies, or volatile command
48
+ lines into this Skill.
49
+
50
+ ## Project facts and completion
51
+
52
+ Record only durable project paths, declared package outputs, physical-to-logical
53
+ repository grouping, and evidence-backed impact rules. Do not duplicate Context
54
+ phase commands or manually edit lifecycle-owned directories.
55
+
56
+ Report completion using the current Context Route and build receipt, including
57
+ the checked source range, changed and unchanged knowledge, unresolved permissions
58
+ or fidelity blockers, and whether a package was built or separately published.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: maintain-project-knowledge
3
+ description: 维护项目内的 Context 知识生产工作区;用于检查已登记仓库和文档来源、判断项目影响范围,并把生命周期动作交回已安装的 Context Skill。用于真实项目前,请修改名称、描述、项目事实和影响映射。
4
+ ---
5
+
6
+ # 维护项目知识
7
+
8
+ 本 Skill 是项目适配层,不复制 Context 工作流。先读取已安装的 Context
9
+ Skill,并以当前 Route、资源和命令为权威;这里只保留稳定的项目事实和来源
10
+ 影响映射。
11
+
12
+ ## 仓库来源的获取和更新
13
+
14
+ 先检查当前 Context Route。已登记仓库模块缺失或本地链接断开时,使用 Route
15
+ 选择的仓库恢复流程,让用户选择已有 checkout、授权在一个限定目录内扫描,
16
+ 或明确允许 clone 已登记的固定 commit。
17
+
18
+ checkout 已存在时,先检查 origin、HEAD、dirty 状态和已登记 subpath,再询问
19
+ 用户保持当前登记版本,还是更新到另一个明确 commit。没有单独授权时,不得对
20
+ 外部 checkout 执行 pull、切换、清理或 reset。
21
+
22
+ 只有当每个目标模块都对应已登记 remote 和 commit、全部 subpath 存在、未知
23
+ 本地修改得到保护、Context 已物化模块链接,并且当前 Route 不再报告仓库未
24
+ 就绪时,仓库来源才可以进入知识更新。
25
+
26
+ 在这里补充本项目稳定的“仓库变化 → 提取范围”映射。维护过程中不得仅根据
27
+ 文件名临时猜测影响关系。
28
+
29
+ ## 远程文档来源的获取和更新
30
+
31
+ 通过当前 Context Route 以及宿主安装的文档提供方 Skill 或 CLI 读取已登记
32
+ 文档。本节保持简短:登录、权限、采集、子页遍历和保真诊断由当前步骤选择的
33
+ 提供方与 Context 资源负责。
34
+
35
+ 只有当来源身份保持稳定(除非用户明确新增来源)、当前账号能够读取所需正文
36
+ 和资源、需要正文的子页已作为独立来源处理、采集不存在阻塞性 fidelity error,
37
+ 并且当前 Route 允许开始结构或提取工作时,远程文档才可以进入知识更新。
38
+
39
+ 在这里补充本项目的来源归属、预期文档类型和更新边界。不要把凭据、来源正文
40
+ 或易漂移的完整命令写进 Skill。
41
+
42
+ ## 项目事实与完成标准
43
+
44
+ 只记录长期稳定的项目路径、包输出、物理仓库与逻辑来源分组,以及有证据的影响
45
+ 规则。不得复制 Context 阶段命令,也不得手工修改生命周期托管目录。
46
+
47
+ 以当前 Context Route 和构建回执报告完成情况,说明检查范围、知识新增/更新/
48
+ 无变化、尚未解决的权限或保真问题,以及知识包是仅完成构建还是已经另行发布。