kc-cli 0.4.0__py3-none-any.whl
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.
- kc/__init__.py +5 -0
- kc/__main__.py +11 -0
- kc/artifacts/__init__.py +1 -0
- kc/artifacts/diff.py +76 -0
- kc/artifacts/frontmatter.py +26 -0
- kc/artifacts/markdown.py +116 -0
- kc/atomic_write.py +33 -0
- kc/cli.py +284 -0
- kc/commands/__init__.py +1 -0
- kc/commands/artifact.py +1190 -0
- kc/commands/citation.py +231 -0
- kc/commands/common.py +346 -0
- kc/commands/conformance.py +293 -0
- kc/commands/context.py +190 -0
- kc/commands/doctor.py +81 -0
- kc/commands/eval.py +133 -0
- kc/commands/export.py +97 -0
- kc/commands/guide.py +571 -0
- kc/commands/index.py +54 -0
- kc/commands/init.py +207 -0
- kc/commands/lint.py +238 -0
- kc/commands/source.py +464 -0
- kc/commands/status.py +52 -0
- kc/commands/task.py +260 -0
- kc/config.py +127 -0
- kc/embedding_models/potion-base-8M/README.md +97 -0
- kc/embedding_models/potion-base-8M/config.json +13 -0
- kc/embedding_models/potion-base-8M/model.safetensors +0 -0
- kc/embedding_models/potion-base-8M/modules.json +14 -0
- kc/embedding_models/potion-base-8M/tokenizer.json +1 -0
- kc/errors.py +141 -0
- kc/fingerprints.py +35 -0
- kc/ids.py +23 -0
- kc/locks.py +65 -0
- kc/models/__init__.py +17 -0
- kc/models/artifact.py +34 -0
- kc/models/citation.py +60 -0
- kc/models/context.py +23 -0
- kc/models/eval.py +21 -0
- kc/models/plan.py +37 -0
- kc/models/source.py +37 -0
- kc/models/source_range.py +29 -0
- kc/models/source_revision.py +19 -0
- kc/models/task.py +35 -0
- kc/output.py +838 -0
- kc/paths.py +126 -0
- kc/provenance/__init__.py +1 -0
- kc/provenance/citations.py +296 -0
- kc/search/__init__.py +1 -0
- kc/search/extract.py +268 -0
- kc/search/fts.py +284 -0
- kc/search/semantic.py +346 -0
- kc/store/__init__.py +1 -0
- kc/store/jsonl.py +55 -0
- kc/store/sqlite.py +444 -0
- kc/store/transaction.py +67 -0
- kc/templates/agents/skills/kc/SKILL.md +282 -0
- kc/templates/agents/skills/kc/agents/openai.yaml +5 -0
- kc/templates/agents/skills/kc/scripts/resolve_query_citations.py +134 -0
- kc/workspace.py +98 -0
- kc_cli-0.4.0.dist-info/METADATA +522 -0
- kc_cli-0.4.0.dist-info/RECORD +65 -0
- kc_cli-0.4.0.dist-info/WHEEL +4 -0
- kc_cli-0.4.0.dist-info/entry_points.txt +2 -0
- kc_cli-0.4.0.dist-info/licenses/LICENSE +21 -0
kc/commands/guide.py
ADDED
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from kc import __version__
|
|
8
|
+
from kc.commands.common import run
|
|
9
|
+
from kc.errors import ERROR_EXIT_MAP
|
|
10
|
+
from kc.output import SCHEMA_VERSION, emit_success
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def build_guide(section: str | None = None) -> dict[str, Any]:
|
|
14
|
+
full = {
|
|
15
|
+
"name": "kc",
|
|
16
|
+
"version": __version__,
|
|
17
|
+
"description": "Deterministic local-first knowledge compiler harness for external agents.",
|
|
18
|
+
"schema_version": SCHEMA_VERSION,
|
|
19
|
+
"compatibility": {
|
|
20
|
+
"additive_changes": "minor",
|
|
21
|
+
"breaking_changes": "major",
|
|
22
|
+
"stable_contracts": [
|
|
23
|
+
"kc.result.v1 JSON envelopes",
|
|
24
|
+
"KC_* error codes",
|
|
25
|
+
"core JSONL schemas",
|
|
26
|
+
"deterministic table and markdown human views",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
"capabilities": {
|
|
30
|
+
"calls_llm": False,
|
|
31
|
+
"local_first": True,
|
|
32
|
+
"bm25_search": True,
|
|
33
|
+
"semantic_search": "bundled_model2vec_default",
|
|
34
|
+
"hybrid_search": "default_rrf",
|
|
35
|
+
"safe_apply": True,
|
|
36
|
+
"task_wait_state": True,
|
|
37
|
+
},
|
|
38
|
+
"retrieval_models": {
|
|
39
|
+
"bm25": {
|
|
40
|
+
"provider": "sqlite_fts5",
|
|
41
|
+
"score": "SQLite FTS5 bm25(); lower scores rank better and scores may be negative.",
|
|
42
|
+
"purpose": "ranking_only",
|
|
43
|
+
},
|
|
44
|
+
"semantic": {
|
|
45
|
+
"provider": "model2vec",
|
|
46
|
+
"model": "potion-base-8M",
|
|
47
|
+
"purpose": "ranking_only",
|
|
48
|
+
"network": "never called by kc at runtime",
|
|
49
|
+
"activation": "default hybrid retrieval and kc index build",
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"bootstrap": {
|
|
53
|
+
"bootstrap_sequence": [
|
|
54
|
+
"kc guide --section bootstrap",
|
|
55
|
+
"kc init --yes",
|
|
56
|
+
"kc source add <file> --domain <domain> --yes",
|
|
57
|
+
"kc source refresh <source-id-or-path> --dry-run",
|
|
58
|
+
"kc index build",
|
|
59
|
+
"kc context prepare --ask '<task>' --shape knowledge_page --grounding required",
|
|
60
|
+
"Edit or create the requested artifact yourself; kc will not generate it.",
|
|
61
|
+
"kc artifact validate --file <path>",
|
|
62
|
+
"kc artifact diff --file <path>",
|
|
63
|
+
"kc artifact apply --file <path> --dry-run",
|
|
64
|
+
"kc artifact apply --file <path> --yes",
|
|
65
|
+
"kc lint",
|
|
66
|
+
],
|
|
67
|
+
"agent_rule": "The agent writes semantic content. kc validates, indexes, and applies safely.",
|
|
68
|
+
},
|
|
69
|
+
"quickstart": {
|
|
70
|
+
"commands": [
|
|
71
|
+
"kc status",
|
|
72
|
+
"kc init --yes",
|
|
73
|
+
"kc source add docs/policy.md --domain policy --yes",
|
|
74
|
+
"kc source search 'ownership responsibilities' --domain policy",
|
|
75
|
+
"kc context prepare --ask 'Create ownership page' --target knowledge/wiki/ownership.md --out .kc/context/ownership.json",
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"troubleshooting": {
|
|
79
|
+
"commands": ["kc status", "kc doctor", "kc lint", "kc doctor locks"],
|
|
80
|
+
"common_next_commands": {
|
|
81
|
+
"uninitialized": "kc init --yes",
|
|
82
|
+
"stale_index": "kc index build",
|
|
83
|
+
"legacy_citations": "kc citation rewrite --file <artifact> --dry-run",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
"agent_contract": {
|
|
87
|
+
"preferred_context": "kc context prepare --ask '<task>' --target <artifact> --out .kc/context/<id>.json",
|
|
88
|
+
"preferred_citations": "Use v2 citation_token values containing rng_ IDs.",
|
|
89
|
+
"task_loop": [
|
|
90
|
+
"kc task start --goal '<goal>' --target <artifact>",
|
|
91
|
+
"kc task next --task-id <id>",
|
|
92
|
+
"kc task resume --task-id <id> --event <expected> --input @event.json",
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
"global_options": {
|
|
96
|
+
"--root": {"default": "auto", "contract": "workspace root override; otherwise kc.toml/.git/cwd discovery"},
|
|
97
|
+
"--format": {
|
|
98
|
+
"values": ["json", "table", "markdown"],
|
|
99
|
+
"default": "json",
|
|
100
|
+
"contract": "json emits kc.result.v1; table and markdown emit deterministic human views",
|
|
101
|
+
},
|
|
102
|
+
"--data-dir": {"default": "knowledge"},
|
|
103
|
+
"--state-dir": {"default": ".kc"},
|
|
104
|
+
"--quiet": {"type": "bool"},
|
|
105
|
+
"--request-id": {"type": "string"},
|
|
106
|
+
"--no-input": {"type": "bool"},
|
|
107
|
+
},
|
|
108
|
+
"output_formats": {
|
|
109
|
+
"json": {
|
|
110
|
+
"contract": "machine",
|
|
111
|
+
"shape": "kc.result.v1 envelope",
|
|
112
|
+
"failure_result": None,
|
|
113
|
+
},
|
|
114
|
+
"table": {
|
|
115
|
+
"contract": "human",
|
|
116
|
+
"shape": "deterministic command-specific text table",
|
|
117
|
+
},
|
|
118
|
+
"markdown": {
|
|
119
|
+
"contract": "human",
|
|
120
|
+
"shape": "deterministic command-specific markdown",
|
|
121
|
+
},
|
|
122
|
+
"llm_mode": "LLM=true always forces json output, quiet mode, no prompts, and no ANSI.",
|
|
123
|
+
"usage_errors": "Command-line usage errors are returned as kc.result.v1 envelopes with KC_USAGE_ERROR and process exit 2.",
|
|
124
|
+
},
|
|
125
|
+
"environment": {
|
|
126
|
+
"LLM=true": "forces JSON, quiet/no ANSI/no prompts, and blocks unsafe validation skips",
|
|
127
|
+
},
|
|
128
|
+
"commands": _commands(),
|
|
129
|
+
"schemas": {
|
|
130
|
+
"source": "kc.source.v1",
|
|
131
|
+
"source_revision": "kc.source_revision.v1",
|
|
132
|
+
"source_range": "kc.source_range.v1",
|
|
133
|
+
"artifact": "kc.artifact.v1",
|
|
134
|
+
"citation_edge": "kc.citation_edge.v1",
|
|
135
|
+
"context_pack": "kc.context_pack.v1",
|
|
136
|
+
"task": "kc.task.v1",
|
|
137
|
+
"plan": "kc.plan.v1",
|
|
138
|
+
},
|
|
139
|
+
"citation_syntax": {
|
|
140
|
+
"markdown": [
|
|
141
|
+
"[kc:src_<id>:rng_<id>]",
|
|
142
|
+
"[kc:src_<id>:rng_<id>:L<start>-L<end>]",
|
|
143
|
+
"[kc:src_<id>:rng_<id>:JP:<percent-encoded-json-pointer>]",
|
|
144
|
+
"[kc:src_<id>:rng_<id>:CSV:R<start>-R<end>]",
|
|
145
|
+
],
|
|
146
|
+
"legacy_markdown": [
|
|
147
|
+
"[kc:src_<id>:L<start>-L<end>]",
|
|
148
|
+
"[kc:src_<id>:JP:<percent-encoded-json-pointer>]",
|
|
149
|
+
"[kc:src_<id>:CSV:R<start>-R<end>]",
|
|
150
|
+
],
|
|
151
|
+
"json_artifacts": "Use structured citations: [{\"source_id\":\"src_...\",\"range_id\":\"rng_...\"}]",
|
|
152
|
+
"markers": {
|
|
153
|
+
"[kc:inference]": "marks explicit synthesis or inference",
|
|
154
|
+
"[kc:todo]": "marks unresolved work and is valid only while artifact status is draft",
|
|
155
|
+
"[kc:uncited]": "marks intentionally uncited content and fails unless --allow-uncited is used",
|
|
156
|
+
},
|
|
157
|
+
"rule": "[kc:uncited] fails unless explicitly allowed; [kc:todo] is draft-only.",
|
|
158
|
+
},
|
|
159
|
+
"workflows": {
|
|
160
|
+
"add_source": [
|
|
161
|
+
"kc source add docs/policy.md --domain policy --dry-run",
|
|
162
|
+
"kc source add docs/policy.md --domain policy --yes",
|
|
163
|
+
"kc source search 'ownership responsibilities' --domain policy",
|
|
164
|
+
],
|
|
165
|
+
"refresh_source": [
|
|
166
|
+
"kc source inspect docs/policy.md --ranges",
|
|
167
|
+
"kc source refresh docs/policy.md --dry-run",
|
|
168
|
+
"kc source refresh docs/policy.md --yes",
|
|
169
|
+
"kc lint",
|
|
170
|
+
],
|
|
171
|
+
"create_page": [
|
|
172
|
+
"kc context prepare --ask 'Create an ownership page' --shape knowledge_page --target knowledge/wiki/ownership.md",
|
|
173
|
+
"kc artifact new --type knowledge_page --path knowledge/wiki/ownership.md --title 'Ownership' --yes",
|
|
174
|
+
"Edit the page with cited facts.",
|
|
175
|
+
"kc artifact validate --file knowledge/wiki/ownership.md",
|
|
176
|
+
"kc artifact diff --file knowledge/wiki/ownership.md",
|
|
177
|
+
"kc artifact apply --file knowledge/wiki/ownership.md --dry-run",
|
|
178
|
+
"kc artifact apply --file knowledge/wiki/ownership.md --yes",
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
"anti_patterns": [
|
|
182
|
+
"Do not ask kc to summarize, answer, rewrite, classify, or judge truth.",
|
|
183
|
+
"Do not invent source authority, owner, review date, or lifecycle status.",
|
|
184
|
+
"Do not apply artifacts with stale or missing citations.",
|
|
185
|
+
"Do not run parallel write commands against the same repo.",
|
|
186
|
+
],
|
|
187
|
+
"quality_rubric": [
|
|
188
|
+
"Material claims have kc citation tokens.",
|
|
189
|
+
"Inferences are explicitly marked.",
|
|
190
|
+
"Draft TODOs are not promoted to active artifacts.",
|
|
191
|
+
"Artifacts validate before apply.",
|
|
192
|
+
],
|
|
193
|
+
"concurrency": {
|
|
194
|
+
"rule": "Read commands can run in parallel; write commands are serialized with .kc/locks.",
|
|
195
|
+
"lock_error": "KC_LOCK_HELD",
|
|
196
|
+
},
|
|
197
|
+
"error_codes": {
|
|
198
|
+
code: {
|
|
199
|
+
"exit_code": exit_code,
|
|
200
|
+
"retryable": code == "KC_LOCK_HELD",
|
|
201
|
+
}
|
|
202
|
+
for code, exit_code in sorted(ERROR_EXIT_MAP.items())
|
|
203
|
+
},
|
|
204
|
+
"exit_codes": {
|
|
205
|
+
"2": "Usage error",
|
|
206
|
+
"0": "Success",
|
|
207
|
+
"10": "Validation error",
|
|
208
|
+
"11": "Not found",
|
|
209
|
+
"12": "Already exists",
|
|
210
|
+
"13": "Conflict or invalid transition",
|
|
211
|
+
"20": "Provenance/citation error",
|
|
212
|
+
"30": "Index/build error",
|
|
213
|
+
"31": "Retrieval model error",
|
|
214
|
+
"40": "Optional waiting-state code when enable_wait_exit_code is explicitly enabled",
|
|
215
|
+
"50": "I/O error",
|
|
216
|
+
"60": "Lock/concurrency error",
|
|
217
|
+
"70": "Persistence/state error",
|
|
218
|
+
"80": "Unsupported feature or configuration",
|
|
219
|
+
"90": "Internal error",
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
full["errors"] = {
|
|
223
|
+
"shape": {
|
|
224
|
+
"code": "KC_*",
|
|
225
|
+
"category": "stable category string",
|
|
226
|
+
"message": "human-readable explanation",
|
|
227
|
+
"exit_code": "stable numeric exit code",
|
|
228
|
+
"retryable": "boolean",
|
|
229
|
+
"suggested_action": "machine-friendly next action",
|
|
230
|
+
"details": "structured details object",
|
|
231
|
+
},
|
|
232
|
+
"error_codes": full["error_codes"],
|
|
233
|
+
"exit_codes": full["exit_codes"],
|
|
234
|
+
"process_exit_code": "When multiple errors are present, the process exits with the maximum error exit_code in the envelope.",
|
|
235
|
+
}
|
|
236
|
+
full["examples"] = {
|
|
237
|
+
"json_contract": "kc --format json guide --section commands",
|
|
238
|
+
"table_human": "kc --format table lint",
|
|
239
|
+
"markdown_human": "kc --format markdown source search 'ownership lifecycle'",
|
|
240
|
+
"llm_forced_json": "LLM=true kc --format table guide",
|
|
241
|
+
}
|
|
242
|
+
if section:
|
|
243
|
+
if section not in full:
|
|
244
|
+
return {"section": section, "available_sections": sorted(full)}
|
|
245
|
+
return {section: full[section]}
|
|
246
|
+
return full
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _command(
|
|
250
|
+
syntax: str,
|
|
251
|
+
*,
|
|
252
|
+
mutates: bool,
|
|
253
|
+
confirmation: str,
|
|
254
|
+
important_options: list[str],
|
|
255
|
+
result_summary: str,
|
|
256
|
+
examples: list[str],
|
|
257
|
+
common_errors: list[str],
|
|
258
|
+
exit_codes: list[int],
|
|
259
|
+
) -> dict[str, Any]:
|
|
260
|
+
return {
|
|
261
|
+
"command_id": "",
|
|
262
|
+
"mutates": mutates,
|
|
263
|
+
"confirmation": confirmation,
|
|
264
|
+
"syntax": syntax,
|
|
265
|
+
"important_options": important_options,
|
|
266
|
+
"result_summary": result_summary,
|
|
267
|
+
"examples": examples,
|
|
268
|
+
"common_errors": common_errors,
|
|
269
|
+
"exit_codes": exit_codes,
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _commands() -> dict[str, Any]:
|
|
274
|
+
commands = {
|
|
275
|
+
"guide": _command(
|
|
276
|
+
"kc guide [--section SECTION]",
|
|
277
|
+
mutates=False,
|
|
278
|
+
confirmation="none",
|
|
279
|
+
important_options=["--section"],
|
|
280
|
+
result_summary="CLI manifest, schemas, workflows, examples, and error taxonomy.",
|
|
281
|
+
examples=["kc guide", "kc guide --section commands"],
|
|
282
|
+
common_errors=["KC_UNSUPPORTED_FEATURE"],
|
|
283
|
+
exit_codes=[0, 80],
|
|
284
|
+
),
|
|
285
|
+
"conformance": _command(
|
|
286
|
+
"kc conformance",
|
|
287
|
+
mutates=False,
|
|
288
|
+
confirmation="none",
|
|
289
|
+
important_options=[],
|
|
290
|
+
result_summary="Read-only V1 CLI manifest, renderer, error, and envelope conformance checks.",
|
|
291
|
+
examples=["kc conformance", "kc --format markdown conformance"],
|
|
292
|
+
common_errors=["KC_CONFORMANCE_FAILED"],
|
|
293
|
+
exit_codes=[0, 10],
|
|
294
|
+
),
|
|
295
|
+
"init": _command(
|
|
296
|
+
"kc init --dry-run|--yes",
|
|
297
|
+
mutates=True,
|
|
298
|
+
confirmation="dry-run unless --yes",
|
|
299
|
+
important_options=["--profile", "--dry-run", "--yes"],
|
|
300
|
+
result_summary="Planned, created, updated, and existing repository layout paths.",
|
|
301
|
+
examples=["kc init --dry-run", "kc init --yes"],
|
|
302
|
+
common_errors=["KC_VALIDATION_INVALID_ARGUMENT", "KC_PATH_OUTSIDE_REPO", "KC_CONFIG_INVALID"],
|
|
303
|
+
exit_codes=[0, 10],
|
|
304
|
+
),
|
|
305
|
+
"status": _command(
|
|
306
|
+
"kc status",
|
|
307
|
+
mutates=False,
|
|
308
|
+
confirmation="none",
|
|
309
|
+
important_options=[],
|
|
310
|
+
result_summary="Workspace initialization state, counts, index status, and next commands.",
|
|
311
|
+
examples=["kc status", "kc --format markdown status"],
|
|
312
|
+
common_errors=["KC_CONFIG_INVALID"],
|
|
313
|
+
exit_codes=[0, 10],
|
|
314
|
+
),
|
|
315
|
+
"source.add": _command(
|
|
316
|
+
"kc source add FILE --domain DOMAIN --dry-run|--yes",
|
|
317
|
+
mutates=True,
|
|
318
|
+
confirmation="dry-run unless --yes",
|
|
319
|
+
important_options=["--domain", "--copy", "--dry-run", "--yes"],
|
|
320
|
+
result_summary="Source ID, fingerprints, media type, copied path, and extracted range count.",
|
|
321
|
+
examples=["kc source add docs/policy.md --domain policy --dry-run"],
|
|
322
|
+
common_errors=["KC_SOURCE_ALREADY_REGISTERED", "KC_FILE_NOT_FOUND", "KC_SOURCE_UNSUPPORTED_MEDIA_TYPE"],
|
|
323
|
+
exit_codes=[0, 11, 12, 80],
|
|
324
|
+
),
|
|
325
|
+
"source.inspect": _command(
|
|
326
|
+
"kc source inspect SOURCE_OR_PATH [--ranges]",
|
|
327
|
+
mutates=False,
|
|
328
|
+
confirmation="none",
|
|
329
|
+
important_options=["--ranges"],
|
|
330
|
+
result_summary="Registered source metadata, current fingerprint state, and optional ranges.",
|
|
331
|
+
examples=["kc source inspect docs/policy.md --ranges"],
|
|
332
|
+
common_errors=["KC_SOURCE_NOT_FOUND"],
|
|
333
|
+
exit_codes=[0, 11],
|
|
334
|
+
),
|
|
335
|
+
"source.refresh": _command(
|
|
336
|
+
"kc source refresh SOURCE_OR_PATH --dry-run|--yes",
|
|
337
|
+
mutates=True,
|
|
338
|
+
confirmation="dry-run unless --yes",
|
|
339
|
+
important_options=["--dry-run", "--yes"],
|
|
340
|
+
result_summary="Fingerprint changes, replaced ranges, impacted artifacts, and index status.",
|
|
341
|
+
examples=["kc source refresh docs/policy.md --dry-run"],
|
|
342
|
+
common_errors=["KC_SOURCE_NOT_FOUND", "KC_FILE_NOT_FOUND", "KC_SOURCE_UNSUPPORTED_MEDIA_TYPE"],
|
|
343
|
+
exit_codes=[0, 11, 80],
|
|
344
|
+
),
|
|
345
|
+
"source.search": _command(
|
|
346
|
+
"kc source search QUERY [--domain DOMAIN]",
|
|
347
|
+
mutates=False,
|
|
348
|
+
confirmation="none",
|
|
349
|
+
important_options=["--domain", "--limit"],
|
|
350
|
+
result_summary="Ranked source ranges with citation tokens and retrieval scores.",
|
|
351
|
+
examples=["kc source search 'ownership lifecycle' --domain policy"],
|
|
352
|
+
common_errors=["KC_VALIDATION_INVALID_ARGUMENT", "KC_INDEX_BUILD_FAILED", "KC_RETRIEVAL_MODEL_UNAVAILABLE"],
|
|
353
|
+
exit_codes=[0, 10, 30, 31],
|
|
354
|
+
),
|
|
355
|
+
"index.build": _command(
|
|
356
|
+
"kc index build [--dry-run]",
|
|
357
|
+
mutates=True,
|
|
358
|
+
confirmation="cache rebuild; --dry-run previews",
|
|
359
|
+
important_options=["--clean", "--dry-run"],
|
|
360
|
+
result_summary="SQLite/BM25 rebuild status and semantic index metadata.",
|
|
361
|
+
examples=["kc index build"],
|
|
362
|
+
common_errors=["KC_VALIDATION_INVALID_ARGUMENT", "KC_INDEX_BUILD_FAILED", "KC_RETRIEVAL_MODEL_UNAVAILABLE"],
|
|
363
|
+
exit_codes=[0, 10, 30, 31],
|
|
364
|
+
),
|
|
365
|
+
"context.prepare": _command(
|
|
366
|
+
"kc context prepare --ask ASK --shape SHAPE",
|
|
367
|
+
mutates=False,
|
|
368
|
+
confirmation="none",
|
|
369
|
+
important_options=["--ask", "--shape", "--domain", "--target", "--grounding", "--budget"],
|
|
370
|
+
result_summary="Grounded source context, artifact matches, citation policy, and next commands.",
|
|
371
|
+
examples=["kc context prepare --ask 'Create an ownership page' --shape knowledge_page --out .kc/context/ownership.json"],
|
|
372
|
+
common_errors=["KC_INDEX_BUILD_FAILED", "KC_RETRIEVAL_MODEL_UNAVAILABLE"],
|
|
373
|
+
exit_codes=[0, 30, 31],
|
|
374
|
+
),
|
|
375
|
+
"artifact.new": _command(
|
|
376
|
+
"kc artifact new --type TYPE --path PATH --title TITLE --dry-run|--yes",
|
|
377
|
+
mutates=True,
|
|
378
|
+
confirmation="dry-run unless --yes",
|
|
379
|
+
important_options=["--path", "--title", "--type", "--domain", "--source-id", "--status", "--dry-run", "--yes"],
|
|
380
|
+
result_summary="Deterministic artifact skeleton metadata and preview content on dry run.",
|
|
381
|
+
examples=["kc artifact new --type knowledge_page --path knowledge/wiki/ownership.md --title Ownership --dry-run"],
|
|
382
|
+
common_errors=["KC_VALIDATION_INVALID_ARGUMENT", "KC_FILE_EXISTS", "KC_PATH_OUTSIDE_REPO"],
|
|
383
|
+
exit_codes=[0, 10, 12],
|
|
384
|
+
),
|
|
385
|
+
"artifact.validate": _command(
|
|
386
|
+
"kc artifact validate --file PATH",
|
|
387
|
+
mutates=False,
|
|
388
|
+
confirmation="none",
|
|
389
|
+
important_options=["--file", "--schema", "--allow-uncited"],
|
|
390
|
+
result_summary="Artifact validity, checks, fingerprint, and citation edges.",
|
|
391
|
+
examples=["kc artifact validate --file knowledge/wiki/ownership.md"],
|
|
392
|
+
common_errors=["KC_ARTIFACT_NOT_FOUND", "KC_VALIDATION_MISSING_CITATION", "KC_CITATION_RANGE_MISSING"],
|
|
393
|
+
exit_codes=[0, 10, 11, 20],
|
|
394
|
+
),
|
|
395
|
+
"artifact.diff": _command(
|
|
396
|
+
"kc artifact diff --file PATH",
|
|
397
|
+
mutates=False,
|
|
398
|
+
confirmation="none",
|
|
399
|
+
important_options=["--file", "--against"],
|
|
400
|
+
result_summary="Structured artifact apply plan, diff text, and risk flags.",
|
|
401
|
+
examples=["kc artifact diff --file knowledge/wiki/ownership.md"],
|
|
402
|
+
common_errors=["KC_ARTIFACT_NOT_FOUND", "KC_UNSUPPORTED_FEATURE"],
|
|
403
|
+
exit_codes=[0, 11, 80],
|
|
404
|
+
),
|
|
405
|
+
"artifact.apply": _command(
|
|
406
|
+
"kc artifact apply --file PATH|--plan PLAN --dry-run|--yes [--idempotency-key KEY]",
|
|
407
|
+
mutates=True,
|
|
408
|
+
confirmation="dry-run unless --yes",
|
|
409
|
+
important_options=["--file", "--plan", "--dry-run", "--yes", "--skip-validate", "--idempotency-key"],
|
|
410
|
+
result_summary="Apply plan, validation result, artifact record, citation edge count, and snapshot.",
|
|
411
|
+
examples=["kc artifact apply --file knowledge/wiki/ownership.md --dry-run"],
|
|
412
|
+
common_errors=["KC_FILE_NOT_FOUND", "KC_APPLY_NOT_VALIDATED", "KC_PLAN_PRECONDITION_FAILED", "KC_LOCK_HELD"],
|
|
413
|
+
exit_codes=[0, 10, 11, 13, 60],
|
|
414
|
+
),
|
|
415
|
+
"citation.check": _command(
|
|
416
|
+
"kc citation check --file PATH|--all",
|
|
417
|
+
mutates=False,
|
|
418
|
+
confirmation="none",
|
|
419
|
+
important_options=["--file", "--all", "--fail-on-warning"],
|
|
420
|
+
result_summary="Citation edge validity and provenance problems for selected artifacts.",
|
|
421
|
+
examples=["kc citation check --file knowledge/wiki/ownership.md"],
|
|
422
|
+
common_errors=["KC_USAGE_ERROR", "KC_CITATION_INVALID_TOKEN", "KC_CITATION_RANGE_MISSING"],
|
|
423
|
+
exit_codes=[0, 2, 20],
|
|
424
|
+
),
|
|
425
|
+
"citation.rewrite": _command(
|
|
426
|
+
"kc citation rewrite --file PATH --dry-run|--yes",
|
|
427
|
+
mutates=True,
|
|
428
|
+
confirmation="dry-run unless --yes",
|
|
429
|
+
important_options=["--file", "--dry-run", "--yes"],
|
|
430
|
+
result_summary="Legacy locator citation replacements that resolve exactly to v2 range tokens.",
|
|
431
|
+
examples=["kc citation rewrite --file knowledge/wiki/ownership.md --dry-run"],
|
|
432
|
+
common_errors=["KC_ARTIFACT_NOT_FOUND", "KC_CITATION_RANGE_MISSING"],
|
|
433
|
+
exit_codes=[0, 11, 20],
|
|
434
|
+
),
|
|
435
|
+
"citation.repair": _command(
|
|
436
|
+
"kc citation repair --file PATH --dry-run|--yes",
|
|
437
|
+
mutates=True,
|
|
438
|
+
confirmation="dry-run unless --yes",
|
|
439
|
+
important_options=["--file", "--dry-run", "--yes"],
|
|
440
|
+
result_summary="Deterministic repair candidates and exact mechanical citation rewrites.",
|
|
441
|
+
examples=["kc citation repair --file knowledge/wiki/ownership.md --dry-run"],
|
|
442
|
+
common_errors=["KC_ARTIFACT_NOT_FOUND", "KC_CITATION_RANGE_MISSING"],
|
|
443
|
+
exit_codes=[0, 11, 20],
|
|
444
|
+
),
|
|
445
|
+
"lint": _command(
|
|
446
|
+
"kc lint [--checks citations,stale,orphans,duplicates,index,log|all]",
|
|
447
|
+
mutates=False,
|
|
448
|
+
confirmation="none",
|
|
449
|
+
important_options=["--checks"],
|
|
450
|
+
result_summary="Repository integrity status, enabled checks, counts, and issues.",
|
|
451
|
+
examples=["kc lint", "kc --format markdown lint"],
|
|
452
|
+
common_errors=["KC_VALIDATION_INVALID_ARGUMENT", "KC_SOURCE_STALE", "KC_ARTIFACT_SCHEMA_INVALID"],
|
|
453
|
+
exit_codes=[0, 10, 20],
|
|
454
|
+
),
|
|
455
|
+
"task.start": _command(
|
|
456
|
+
"kc task start --goal GOAL",
|
|
457
|
+
mutates=True,
|
|
458
|
+
confirmation="task state write; no --yes required",
|
|
459
|
+
important_options=["--goal", "--shape", "--domain", "--target", "--await-agent"],
|
|
460
|
+
result_summary="Task record, candidate ranges, instructions, and resume command.",
|
|
461
|
+
examples=["kc task start --goal 'Create ownership page' --target knowledge/wiki/ownership.md"],
|
|
462
|
+
common_errors=["KC_INDEX_BUILD_FAILED"],
|
|
463
|
+
exit_codes=[0, 30],
|
|
464
|
+
),
|
|
465
|
+
"task.status": _command(
|
|
466
|
+
"kc task status --task-id TASK_ID",
|
|
467
|
+
mutates=False,
|
|
468
|
+
confirmation="none",
|
|
469
|
+
important_options=["--task-id"],
|
|
470
|
+
result_summary="Compact task state and next commands.",
|
|
471
|
+
examples=["kc task status --task-id task_01HX"],
|
|
472
|
+
common_errors=["KC_TASK_NOT_FOUND"],
|
|
473
|
+
exit_codes=[0, 11],
|
|
474
|
+
),
|
|
475
|
+
"task.inspect": _command(
|
|
476
|
+
"kc task inspect --task-id TASK_ID",
|
|
477
|
+
mutates=False,
|
|
478
|
+
confirmation="none",
|
|
479
|
+
important_options=["--task-id"],
|
|
480
|
+
result_summary="Full stored task record.",
|
|
481
|
+
examples=["kc task inspect --task-id task_01HX"],
|
|
482
|
+
common_errors=["KC_TASK_NOT_FOUND"],
|
|
483
|
+
exit_codes=[0, 11],
|
|
484
|
+
),
|
|
485
|
+
"task.next": _command(
|
|
486
|
+
"kc task next --task-id TASK_ID",
|
|
487
|
+
mutates=False,
|
|
488
|
+
confirmation="none",
|
|
489
|
+
important_options=["--task-id"],
|
|
490
|
+
result_summary="State-specific expected event and next commands.",
|
|
491
|
+
examples=["kc task next --task-id task_01HX"],
|
|
492
|
+
common_errors=["KC_TASK_NOT_FOUND"],
|
|
493
|
+
exit_codes=[0, 11],
|
|
494
|
+
),
|
|
495
|
+
"task.resume": _command(
|
|
496
|
+
"kc task resume --task-id TASK_ID --event EVENT --input JSON",
|
|
497
|
+
mutates=True,
|
|
498
|
+
confirmation="task state write; no --yes required",
|
|
499
|
+
important_options=["--task-id", "--event", "--input"],
|
|
500
|
+
result_summary="Updated task record with appended event.",
|
|
501
|
+
examples=["kc task resume --task-id task_01HX --event artifact_created --input @event.json"],
|
|
502
|
+
common_errors=["KC_TASK_NOT_FOUND", "KC_TASK_NOT_WAITING", "KC_EVENT_INVALID", "KC_JSON_INVALID"],
|
|
503
|
+
exit_codes=[0, 10, 11, 13],
|
|
504
|
+
),
|
|
505
|
+
"eval.run": _command(
|
|
506
|
+
"kc eval run --pack FILE",
|
|
507
|
+
mutates=False,
|
|
508
|
+
confirmation="none",
|
|
509
|
+
important_options=["--pack"],
|
|
510
|
+
result_summary="Retrieval eval case totals, pass count, and case results.",
|
|
511
|
+
examples=["kc eval run --pack knowledge/evals/basic.yaml"],
|
|
512
|
+
common_errors=[
|
|
513
|
+
"KC_USAGE_ERROR",
|
|
514
|
+
"KC_INDEX_BUILD_FAILED",
|
|
515
|
+
"KC_FILE_NOT_FOUND",
|
|
516
|
+
"KC_CONFIG_INVALID",
|
|
517
|
+
"KC_ARTIFACT_SCHEMA_INVALID",
|
|
518
|
+
],
|
|
519
|
+
exit_codes=[0, 2, 10, 11, 30],
|
|
520
|
+
),
|
|
521
|
+
"export": _command(
|
|
522
|
+
"kc export --format jsonl|markdown-bundle|llms-txt [--out FILE]",
|
|
523
|
+
mutates=True,
|
|
524
|
+
confirmation="writes --out when provided; no --yes required",
|
|
525
|
+
important_options=["--format", "--out"],
|
|
526
|
+
result_summary="Export format, byte count, output path, content location, or inline content.",
|
|
527
|
+
examples=["kc export --format llms-txt", "kc export --format markdown-bundle --out knowledge/exports/bundle.md"],
|
|
528
|
+
common_errors=["KC_VALIDATION_INVALID_ARGUMENT", "KC_PATH_OUTSIDE_REPO"],
|
|
529
|
+
exit_codes=[0, 10, 80],
|
|
530
|
+
),
|
|
531
|
+
"doctor": _command(
|
|
532
|
+
"kc doctor",
|
|
533
|
+
mutates=False,
|
|
534
|
+
confirmation="none",
|
|
535
|
+
important_options=[],
|
|
536
|
+
result_summary="Config, state, lock count, and semantic index health.",
|
|
537
|
+
examples=["kc doctor"],
|
|
538
|
+
common_errors=["KC_RETRIEVAL_MODEL_UNAVAILABLE"],
|
|
539
|
+
exit_codes=[0, 31],
|
|
540
|
+
),
|
|
541
|
+
"doctor.locks": _command(
|
|
542
|
+
"kc doctor locks [--clear-stale --yes]",
|
|
543
|
+
mutates=True,
|
|
544
|
+
confirmation="dry-run unless --clear-stale --yes",
|
|
545
|
+
important_options=["--clear-stale", "--yes"],
|
|
546
|
+
result_summary="Lock files, metadata, clear-stale flag, and cleared files.",
|
|
547
|
+
examples=["kc doctor locks", "kc doctor locks --clear-stale --yes"],
|
|
548
|
+
common_errors=["KC_LOCK_HELD"],
|
|
549
|
+
exit_codes=[0, 60],
|
|
550
|
+
),
|
|
551
|
+
}
|
|
552
|
+
for command_id, contract in commands.items():
|
|
553
|
+
contract["command_id"] = command_id
|
|
554
|
+
return commands
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def register(app: typer.Typer) -> None:
|
|
558
|
+
@app.command("guide", help="Emit the machine-readable kc playbook for agents and tooling.")
|
|
559
|
+
def guide(
|
|
560
|
+
section: Annotated[
|
|
561
|
+
str | None,
|
|
562
|
+
typer.Option(
|
|
563
|
+
"--section",
|
|
564
|
+
help="Return a specific guide section.",
|
|
565
|
+
),
|
|
566
|
+
] = None,
|
|
567
|
+
) -> None:
|
|
568
|
+
def _run() -> None:
|
|
569
|
+
emit_success("guide", build_guide(section), target={"section": section})
|
|
570
|
+
|
|
571
|
+
run("guide", _run)
|
kc/commands/index.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from kc.commands.common import load_artifacts, load_citation_edges, load_ranges, load_sources, run
|
|
8
|
+
from kc.output import emit_success
|
|
9
|
+
from kc.paths import current_paths
|
|
10
|
+
from kc.search.semantic import build_semantic_index, load_semantic_model, semantic_model_metadata
|
|
11
|
+
from kc.store.sqlite import index_status, rebuild_index
|
|
12
|
+
from kc.store.transaction import mutation_transaction
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(help="Build or rebuild derived SQLite search indexes.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command("build", help="Rebuild BM25 and semantic search indexes.")
|
|
18
|
+
def build(
|
|
19
|
+
clean: Annotated[bool, typer.Option("--clean", help="Force a clean rebuild.")] = False,
|
|
20
|
+
dry_run: Annotated[bool, typer.Option("--dry-run", help="Preview without writing.")] = False,
|
|
21
|
+
) -> None:
|
|
22
|
+
def _run() -> None:
|
|
23
|
+
sources = load_sources()
|
|
24
|
+
ranges = load_ranges()
|
|
25
|
+
paths = current_paths()
|
|
26
|
+
if dry_run:
|
|
27
|
+
semantic_model = semantic_model_metadata(load_semantic_model())
|
|
28
|
+
result = {
|
|
29
|
+
"dry_run": True,
|
|
30
|
+
"clean": clean,
|
|
31
|
+
"semantic": {"enabled": True, "model": semantic_model, "embeddings": len(ranges)},
|
|
32
|
+
"sources": len(sources),
|
|
33
|
+
"ranges": len(ranges),
|
|
34
|
+
"db_path": str(paths.sqlite_path),
|
|
35
|
+
"index": index_status(paths.sqlite_path, sources, ranges),
|
|
36
|
+
}
|
|
37
|
+
else:
|
|
38
|
+
with mutation_transaction(paths, "index.build", [paths.sqlite_path]) as tx:
|
|
39
|
+
result = rebuild_index(
|
|
40
|
+
paths.sqlite_path,
|
|
41
|
+
sources,
|
|
42
|
+
ranges,
|
|
43
|
+
load_artifacts(),
|
|
44
|
+
load_citation_edges(),
|
|
45
|
+
)
|
|
46
|
+
result["semantic"] = build_semantic_index(paths.sqlite_path, ranges)
|
|
47
|
+
result["dry_run"] = False
|
|
48
|
+
result["clean"] = clean
|
|
49
|
+
result["db_path"] = str(paths.sqlite_path)
|
|
50
|
+
result["index"] = index_status(paths.sqlite_path, sources, ranges)
|
|
51
|
+
tx.commit({"db_path": str(paths.sqlite_path)})
|
|
52
|
+
emit_success("index.build", result)
|
|
53
|
+
|
|
54
|
+
run("index.build", _run)
|