@skill-map/cli 0.8.0 → 0.9.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.
@@ -0,0 +1,267 @@
1
+ -- Kernel initial migration. Provisions the 11 kernel tables per
2
+ -- spec/db-schema.md. Up-only. Wrapped in BEGIN / COMMIT by the runner.
3
+
4
+ -- --- Scan zone -------------------------------------------------------------
5
+
6
+ CREATE TABLE scan_nodes (
7
+ path TEXT PRIMARY KEY,
8
+ kind TEXT NOT NULL,
9
+ provider TEXT NOT NULL,
10
+ title TEXT,
11
+ description TEXT,
12
+ stability TEXT,
13
+ version TEXT,
14
+ author TEXT,
15
+ frontmatter_json TEXT NOT NULL,
16
+ body_hash TEXT NOT NULL,
17
+ frontmatter_hash TEXT NOT NULL,
18
+ bytes_frontmatter INTEGER NOT NULL,
19
+ bytes_body INTEGER NOT NULL,
20
+ bytes_total INTEGER NOT NULL,
21
+ tokens_frontmatter INTEGER,
22
+ tokens_body INTEGER,
23
+ tokens_total INTEGER,
24
+ links_out_count INTEGER NOT NULL DEFAULT 0,
25
+ links_in_count INTEGER NOT NULL DEFAULT 0,
26
+ external_refs_count INTEGER NOT NULL DEFAULT 0,
27
+ scanned_at INTEGER NOT NULL,
28
+ -- `kind` is open-by-design (Provider-declared string; the built-in
29
+ -- Claude Provider emits `skill` / `agent` / `command` / `hook` /
30
+ -- `note`, but external Providers may declare their own — see
31
+ -- `node.schema.json#/properties/kind` and `db-schema.md` § scan_nodes).
32
+ -- A CHECK whitelist would close what the spec keeps open.
33
+ CONSTRAINT ck_scan_nodes_stability CHECK (stability IS NULL OR stability IN ('experimental','stable','deprecated'))
34
+ );
35
+ CREATE INDEX ix_scan_nodes_kind ON scan_nodes(kind);
36
+ CREATE INDEX ix_scan_nodes_provider ON scan_nodes(provider);
37
+ CREATE INDEX ix_scan_nodes_body_hash ON scan_nodes(body_hash);
38
+
39
+ CREATE TABLE scan_links (
40
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
41
+ source_path TEXT NOT NULL,
42
+ target_path TEXT NOT NULL,
43
+ kind TEXT NOT NULL,
44
+ confidence TEXT NOT NULL,
45
+ sources_json TEXT NOT NULL,
46
+ original_trigger TEXT,
47
+ normalized_trigger TEXT,
48
+ location_line INTEGER,
49
+ location_column INTEGER,
50
+ location_offset INTEGER,
51
+ raw TEXT,
52
+ CONSTRAINT ck_scan_links_kind CHECK (kind IN ('invokes','references','mentions','supersedes')),
53
+ CONSTRAINT ck_scan_links_confidence CHECK (confidence IN ('high','medium','low'))
54
+ );
55
+ CREATE INDEX ix_scan_links_source_path ON scan_links(source_path);
56
+ CREATE INDEX ix_scan_links_target_path ON scan_links(target_path);
57
+ CREATE INDEX ix_scan_links_normalized_trigger ON scan_links(normalized_trigger);
58
+
59
+ CREATE TABLE scan_issues (
60
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
61
+ rule_id TEXT NOT NULL,
62
+ severity TEXT NOT NULL,
63
+ node_ids_json TEXT NOT NULL,
64
+ link_indices_json TEXT,
65
+ message TEXT NOT NULL,
66
+ detail TEXT,
67
+ fix_json TEXT,
68
+ data_json TEXT,
69
+ CONSTRAINT ck_scan_issues_severity CHECK (severity IN ('error','warn','info'))
70
+ );
71
+ CREATE INDEX ix_scan_issues_rule_id ON scan_issues(rule_id);
72
+ CREATE INDEX ix_scan_issues_severity ON scan_issues(severity);
73
+
74
+ -- --- State zone ------------------------------------------------------------
75
+
76
+ CREATE TABLE state_jobs (
77
+ id TEXT PRIMARY KEY,
78
+ action_id TEXT NOT NULL,
79
+ action_version TEXT NOT NULL,
80
+ node_id TEXT NOT NULL,
81
+ content_hash TEXT NOT NULL,
82
+ nonce TEXT NOT NULL,
83
+ priority INTEGER NOT NULL DEFAULT 0,
84
+ status TEXT NOT NULL,
85
+ failure_reason TEXT,
86
+ runner TEXT,
87
+ ttl_seconds INTEGER NOT NULL,
88
+ file_path TEXT,
89
+ created_at INTEGER NOT NULL,
90
+ claimed_at INTEGER,
91
+ finished_at INTEGER,
92
+ expires_at INTEGER,
93
+ submitted_by TEXT,
94
+ CONSTRAINT ck_state_jobs_status CHECK (status IN ('queued','running','completed','failed')),
95
+ CONSTRAINT ck_state_jobs_failure_reason CHECK (failure_reason IS NULL OR failure_reason IN ('runner-error','report-invalid','timeout','abandoned','job-file-missing','user-cancelled')),
96
+ CONSTRAINT ck_state_jobs_runner CHECK (runner IS NULL OR runner IN ('cli','skill','in-process'))
97
+ );
98
+ CREATE INDEX ix_state_jobs_status ON state_jobs(status);
99
+ -- Unique partial index for duplicate-job detection: at most one
100
+ -- queued/running job per (action_id, node_id, content_hash).
101
+ CREATE UNIQUE INDEX ix_state_jobs_action_node_hash
102
+ ON state_jobs(action_id, node_id, content_hash)
103
+ WHERE status IN ('queued','running');
104
+
105
+ CREATE TABLE state_executions (
106
+ id TEXT PRIMARY KEY,
107
+ kind TEXT NOT NULL,
108
+ extension_id TEXT NOT NULL,
109
+ extension_version TEXT NOT NULL,
110
+ node_ids_json TEXT NOT NULL DEFAULT '[]',
111
+ content_hash TEXT,
112
+ status TEXT NOT NULL,
113
+ failure_reason TEXT,
114
+ exit_code INTEGER,
115
+ runner TEXT,
116
+ started_at INTEGER NOT NULL,
117
+ finished_at INTEGER NOT NULL,
118
+ duration_ms INTEGER,
119
+ tokens_in INTEGER,
120
+ tokens_out INTEGER,
121
+ report_path TEXT,
122
+ job_id TEXT,
123
+ CONSTRAINT ck_state_executions_kind CHECK (kind IN ('action')),
124
+ CONSTRAINT ck_state_executions_status CHECK (status IN ('completed','failed','cancelled'))
125
+ );
126
+ CREATE INDEX ix_state_executions_extension_id ON state_executions(extension_id);
127
+ CREATE INDEX ix_state_executions_started_at ON state_executions(started_at);
128
+ CREATE INDEX ix_state_executions_job_id ON state_executions(job_id);
129
+
130
+ CREATE TABLE state_summaries (
131
+ node_id TEXT NOT NULL,
132
+ -- `kind` is open-by-design (mirrors `scan_nodes.kind` — see the
133
+ -- comment there for the spec rationale).
134
+ kind TEXT NOT NULL,
135
+ summarizer_action_id TEXT NOT NULL,
136
+ summarizer_version TEXT NOT NULL,
137
+ body_hash_at_generation TEXT NOT NULL,
138
+ generated_at INTEGER NOT NULL,
139
+ summary_json TEXT NOT NULL,
140
+ PRIMARY KEY (node_id, summarizer_action_id)
141
+ );
142
+ CREATE INDEX ix_state_summaries_generated_at ON state_summaries(generated_at);
143
+
144
+ CREATE TABLE state_enrichments (
145
+ node_id TEXT NOT NULL,
146
+ provider_id TEXT NOT NULL,
147
+ data_json TEXT NOT NULL,
148
+ verified INTEGER,
149
+ fetched_at INTEGER NOT NULL,
150
+ stale_after INTEGER,
151
+ PRIMARY KEY (node_id, provider_id),
152
+ CONSTRAINT ck_state_enrichments_verified CHECK (verified IS NULL OR verified IN (0,1))
153
+ );
154
+ CREATE INDEX ix_state_enrichments_stale_after ON state_enrichments(stale_after);
155
+
156
+ CREATE TABLE state_plugin_kvs (
157
+ plugin_id TEXT NOT NULL,
158
+ node_id TEXT NOT NULL DEFAULT '',
159
+ key TEXT NOT NULL,
160
+ value_json TEXT NOT NULL,
161
+ updated_at INTEGER NOT NULL,
162
+ PRIMARY KEY (plugin_id, node_id, key)
163
+ );
164
+ CREATE INDEX ix_state_plugin_kvs_plugin_id ON state_plugin_kvs(plugin_id);
165
+
166
+ -- --- Config zone -----------------------------------------------------------
167
+
168
+ CREATE TABLE config_plugins (
169
+ plugin_id TEXT PRIMARY KEY,
170
+ enabled INTEGER NOT NULL DEFAULT 1,
171
+ config_json TEXT,
172
+ updated_at INTEGER NOT NULL,
173
+ CONSTRAINT ck_config_plugins_enabled CHECK (enabled IN (0,1))
174
+ );
175
+
176
+ CREATE TABLE config_preferences (
177
+ key TEXT PRIMARY KEY,
178
+ value_json TEXT NOT NULL,
179
+ updated_at INTEGER NOT NULL
180
+ );
181
+
182
+ CREATE TABLE config_schema_versions (
183
+ scope TEXT NOT NULL,
184
+ owner_id TEXT NOT NULL,
185
+ version INTEGER NOT NULL,
186
+ description TEXT NOT NULL,
187
+ applied_at INTEGER NOT NULL,
188
+ PRIMARY KEY (scope, owner_id, version),
189
+ CONSTRAINT ck_config_schema_versions_scope CHECK (scope IN ('kernel','plugin'))
190
+ );
191
+
192
+ -- --- Scan meta envelope ----------------------------------------------------
193
+ -- Persists scan-result metadata so `loadScanResult` returns real values for
194
+ -- `scope`, `roots`, `scannedAt`, `scannedBy`, `providers`, and the non-derivable
195
+ -- `stats` fields (filesWalked / filesSkipped / durationMs) instead of a
196
+ -- synthetic envelope. Single-row table (CHECK id = 1); replaced atomically
197
+ -- with the rest of the scan_* zone on every `sm scan` via
198
+ -- `persistScanResult`. Originally landed at Step 5.1 as migration 002 and
199
+ -- folded back into the initial migration pre-1.0 (no released DBs to migrate
200
+ -- forward).
201
+
202
+ CREATE TABLE scan_meta (
203
+ id INTEGER PRIMARY KEY,
204
+ scope TEXT NOT NULL,
205
+ roots_json TEXT NOT NULL,
206
+ scanned_at INTEGER NOT NULL,
207
+ scanned_by_name TEXT NOT NULL,
208
+ scanned_by_version TEXT NOT NULL,
209
+ scanned_by_spec_version TEXT NOT NULL,
210
+ providers_json TEXT NOT NULL,
211
+ stats_files_walked INTEGER NOT NULL,
212
+ stats_files_skipped INTEGER NOT NULL,
213
+ stats_duration_ms INTEGER NOT NULL,
214
+ CONSTRAINT ck_scan_meta_singleton CHECK (id = 1),
215
+ CONSTRAINT ck_scan_meta_scope CHECK (scope IN ('project','global'))
216
+ );
217
+
218
+ -- --- Fine-grained scan cache ----------------------------------------------
219
+ -- Phase 4 / A.9 — per-(node, extractor) cache breadcrumbs. Lets the
220
+ -- orchestrator skip rerunning extractors against an unchanged body when the
221
+ -- same extractor already ran against that body_hash, and — critically —
222
+ -- detect when a NEW extractor was registered between scans (no row yet for
223
+ -- that pair) so the new extractor runs over the cached node without
224
+ -- requiring a full cache invalidation. Replace-all on every persist:
225
+ -- obsolete rows (extractor uninstalled since the last scan) disappear
226
+ -- automatically and cannot mask a stale cache hit.
227
+
228
+ CREATE TABLE scan_extractor_runs (
229
+ node_path TEXT NOT NULL,
230
+ extractor_id TEXT NOT NULL,
231
+ body_hash_at_run TEXT NOT NULL,
232
+ ran_at INTEGER NOT NULL,
233
+ PRIMARY KEY (node_path, extractor_id)
234
+ );
235
+ CREATE INDEX ix_scan_extractor_runs_node ON scan_extractor_runs(node_path);
236
+ CREATE INDEX ix_scan_extractor_runs_extractor ON scan_extractor_runs(extractor_id);
237
+
238
+ -- --- Universal enrichment layer --------------------------------------------
239
+ -- Phase 4 / A.8 — stores `ctx.enrichNode(partial)` outputs separately from
240
+ -- the author-supplied frontmatter (which remains immutable from Extractors).
241
+ -- Layer separation is universal: deterministic and probabilistic Extractors
242
+ -- both write here. Only probabilistic enrichments need stale tracking
243
+ -- (`is_probabilistic = 1`); when a node body changes between scans, those
244
+ -- rows are flagged `stale = 1` (NOT deleted, preserving the LLM cost).
245
+ -- Deterministic enrichments regenerate via the A.9 fine-grained cache and
246
+ -- simply pisar the prior row via PRIMARY KEY conflict on the next scan.
247
+ --
248
+ -- Read-side `node.merged` view (helper `mergeNodeWithEnrichments`):
249
+ -- author frontmatter + non-stale enrichments ordered by enriched_at ASC,
250
+ -- last-write-wins per field. Rules / `sm check` / `sm export` consume the
251
+ -- author frontmatter by default (CI-safe deterministic baseline);
252
+ -- enrichment consumption is opt-in.
253
+
254
+ CREATE TABLE node_enrichments (
255
+ node_path TEXT NOT NULL,
256
+ extractor_id TEXT NOT NULL,
257
+ body_hash_at_enrichment TEXT NOT NULL,
258
+ value_json TEXT NOT NULL,
259
+ stale INTEGER NOT NULL DEFAULT 0,
260
+ enriched_at INTEGER NOT NULL,
261
+ is_probabilistic INTEGER NOT NULL DEFAULT 0,
262
+ PRIMARY KEY (node_path, extractor_id),
263
+ CONSTRAINT ck_node_enrichments_stale CHECK (stale IN (0, 1)),
264
+ CONSTRAINT ck_node_enrichments_is_probabilistic CHECK (is_probabilistic IN (0, 1))
265
+ );
266
+ CREATE INDEX ix_node_enrichments_node ON node_enrichments(node_path);
267
+ CREATE INDEX ix_node_enrichments_stale ON node_enrichments(stale);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-map/cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "skill-map reference implementation — kernel + CLI + adapters.",
5
5
  "license": "MIT",
6
6
  "type": "module",