@ngockhoale/ukit 2.6.7 → 2.6.8
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/manifests/documentation.yaml +77 -6
- package/manifests/hostCapabilities.yaml +49 -0
- package/manifests/instructionRules.yaml +7 -0
- package/package.json +1 -1
- package/scripts/bench/goldTasks.json +38 -0
- package/scripts/bench/runGold.mjs +220 -0
- package/scripts/release/verify-release.mjs +6 -0
- package/src/cli/commands/code.js +182 -0
- package/src/cli/commands/doctor.js +35 -3
- package/src/cli/commands/indexTools.js +102 -1
- package/src/cli/commands/memory.js +137 -0
- package/src/cli/index.js +7 -0
- package/src/core/codeintel/compiler.js +316 -0
- package/src/core/codeintel/diagnostics.js +114 -0
- package/src/core/codeintel/freshness.js +295 -0
- package/src/core/codeintel/impact.js +251 -0
- package/src/core/codeintel/invalidation.js +150 -0
- package/src/core/codeintel/manifest.js +176 -0
- package/src/core/codeintel/packet.js +146 -0
- package/src/core/codeintel/providers.js +201 -0
- package/src/core/codeintel/retriever.js +372 -0
- package/src/core/codeintel/router.js +149 -0
- package/src/core/codeintel/semanticProvider.js +235 -0
- package/src/core/docContracts.js +723 -0
- package/src/core/memory/migrate.js +324 -0
- package/src/core/memory/records.js +172 -0
- package/src/core/memory/retrieval.js +161 -11
- package/src/core/memory/store.js +398 -0
- package/src/core/memory/storeV2.js +171 -0
- package/src/core/memory/storeV2Loader.js +22 -0
- package/src/core/runtimeConfig.js +125 -0
- package/src/core/runtimePaths.js +3 -0
- package/src/index/taskRouting.js +39 -0
- package/templates/.claude/ukit/index/route-task.mjs +40 -0
- package/templates/AGENTS.md +46 -99
- package/templates/CLAUDE.md +46 -99
- package/templates/docs/AI_HANDOFF/tasks/_TEMPLATE.md +5 -0
- package/templates/docs/BUGFIX.md +2 -19
- package/templates/docs/BUG_INDEX.md +43 -0
- package/templates/docs/BUG_METRICS.md +1 -5
- package/templates/docs/BUG_TEMPLATE.md +1 -11
- package/templates/docs/UKIT_INTERNALS.md +4 -0
- package/templates/instructions/core.md +46 -99
- package/templates/ukit/storage/config.json +30 -0
|
@@ -22,10 +22,11 @@ import {
|
|
|
22
22
|
inspectProjectImportant,
|
|
23
23
|
inspectProjectImportantWiring,
|
|
24
24
|
} from '../../core/projectImportant.js';
|
|
25
|
+
import { runDocContractChecks } from '../../core/docContracts.js';
|
|
25
26
|
|
|
26
27
|
export const DOCTOR_HELP_FLAGS = new Set(['--help', '-h']);
|
|
27
|
-
const KNOWN_FLAGS = new Set([...DOCTOR_HELP_FLAGS, '--skills', '--gateway']);
|
|
28
|
-
const SUPPORTED_FLAGS_LIST = '--help, -h, --skills, --gateway';
|
|
28
|
+
const KNOWN_FLAGS = new Set([...DOCTOR_HELP_FLAGS, '--skills', '--gateway', '--docs']);
|
|
29
|
+
const SUPPORTED_FLAGS_LIST = '--help, -h, --skills, --gateway, --docs';
|
|
29
30
|
|
|
30
31
|
export function printDoctorHelp() {
|
|
31
32
|
console.log('Usage: ukit doctor [options]');
|
|
@@ -36,6 +37,7 @@ export function printDoctorHelp() {
|
|
|
36
37
|
console.log(' --help, -h Show this help message');
|
|
37
38
|
console.log(' --skills Also print a skill word-count/budget report');
|
|
38
39
|
console.log(' --gateway Live gateway probe (streaming + non-streaming); advisory only');
|
|
40
|
+
console.log(' --docs Run doc-contract checks (manifests/documentation.yaml projects only)');
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir = os.homedir() }) {
|
|
@@ -366,6 +368,36 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir =
|
|
|
366
368
|
}
|
|
367
369
|
}
|
|
368
370
|
|
|
371
|
+
// FR-007: doc-contract checks (DOC-203 validator) — only when the project root
|
|
372
|
+
// carries manifests/documentation.yaml (doc-governed maintainer repo). Downstream
|
|
373
|
+
// projects get a skip advisory; error-severity failures block via exitCode 1,
|
|
374
|
+
// warnings are advisory only.
|
|
375
|
+
let docContractErrors = false;
|
|
376
|
+
if (argv.includes('--docs')) {
|
|
377
|
+
const docManifestPath = path.join(projectRoot, 'manifests', 'documentation.yaml');
|
|
378
|
+
if (!(await pathExists(docManifestPath))) {
|
|
379
|
+
console.log('');
|
|
380
|
+
console.log('[UKit] Doc contract checks — not a doc-governed project — skipped (no manifests/documentation.yaml).');
|
|
381
|
+
} else {
|
|
382
|
+
const report = await runDocContractChecks({ rootDir: projectRoot });
|
|
383
|
+
console.log('');
|
|
384
|
+
console.log('[UKit] Doc contract checks:');
|
|
385
|
+
for (const check of report.checks) {
|
|
386
|
+
const mark = check.skipped ? '-' : ok(check.passed);
|
|
387
|
+
const severity = check.severity === 'warning' ? ' (warning)' : '';
|
|
388
|
+
console.log(`[UKit] ${mark} ${check.label}${severity}`);
|
|
389
|
+
if (check.detail) console.log(`[UKit] detail: ${check.detail}`);
|
|
390
|
+
if (check.remedy && (!check.passed || check.severity === 'warning')) {
|
|
391
|
+
console.log(`[UKit] remedy: ${check.remedy}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
console.log(
|
|
395
|
+
`[UKit] summary: ${report.summary.passed} passed, ${report.summary.errors} errors, ${report.summary.warnings} warnings, ${report.summary.skipped} skipped`,
|
|
396
|
+
);
|
|
397
|
+
docContractErrors = report.summary.errors > 0;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
369
401
|
const allPassed = Object.values(checks).every(Boolean);
|
|
370
402
|
const failedProjectChecks = projectChecks.filter(
|
|
371
403
|
(check) => check.applicable !== false && !check.passed,
|
|
@@ -381,7 +413,7 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir =
|
|
|
381
413
|
}
|
|
382
414
|
}
|
|
383
415
|
|
|
384
|
-
if (!allPassed || blockingFailures.length > 0) {
|
|
416
|
+
if (!allPassed || blockingFailures.length > 0 || docContractErrors) {
|
|
385
417
|
console.log('[UKit] Some checks failed.');
|
|
386
418
|
if (!allPassed && blockingFailures.length === 0) {
|
|
387
419
|
console.log('[UKit] Re-run `ukit install` to repair install-managed files.');
|
|
@@ -10,6 +10,9 @@ import { deriveTaskRoute } from '../../index/taskRouting.js';
|
|
|
10
10
|
import { queryCodeIndex, getFileOutline } from '../../index/queryIndex.js';
|
|
11
11
|
import { triageBug } from '../../bug/triageBug.js';
|
|
12
12
|
import { installIndexRefreshHooks, removeIndexRefreshHooks } from '../../index/gitHooks.js';
|
|
13
|
+
import fs from 'node:fs/promises';
|
|
14
|
+
import { INDEX_ARTIFACTS, INDEX_SCHEMA_VERSION, getArtifactPath } from '../../index/paths.js';
|
|
15
|
+
import { computeIdentity, readSnapshot, guardLevel } from '../../core/codeintel/freshness.js';
|
|
13
16
|
import {
|
|
14
17
|
parseIndexArgs,
|
|
15
18
|
CONTEXT_FLAG_DEFINITIONS,
|
|
@@ -221,6 +224,64 @@ export async function runIndexTools({ projectRoot, argv = [] }) {
|
|
|
221
224
|
return;
|
|
222
225
|
}
|
|
223
226
|
|
|
227
|
+
if (subcommand === 'status') {
|
|
228
|
+
// L0 freshness identity report (SPEC §7) — never refreshes, never throws.
|
|
229
|
+
const identity = await computeIdentity(projectRoot);
|
|
230
|
+
const snapshot = await readSnapshot(projectRoot);
|
|
231
|
+
const stale = !snapshot || snapshot.identity !== identity.identity;
|
|
232
|
+
|
|
233
|
+
console.log('[UKit] Index status:');
|
|
234
|
+
console.log(`identity: ${identity.identity}`);
|
|
235
|
+
console.log(`headSha: ${identity.headSha}`);
|
|
236
|
+
console.log(`overlayHash: ${identity.overlayHash}`);
|
|
237
|
+
console.log(`configHash: ${identity.configHash}`);
|
|
238
|
+
console.log(`snapshot: ${snapshot ? snapshot.identity : 'none'}`);
|
|
239
|
+
console.log(`stale: ${stale ? 'yes' : 'no'}`);
|
|
240
|
+
|
|
241
|
+
const artifacts = await collectArtifactAges(projectRoot);
|
|
242
|
+
if (artifacts.length === 0) {
|
|
243
|
+
console.log('artifacts: none (index not built)');
|
|
244
|
+
} else {
|
|
245
|
+
console.log('artifacts:');
|
|
246
|
+
for (const item of artifacts) {
|
|
247
|
+
console.log(` ${item.name}: ${item.age}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (subcommand === 'doctor') {
|
|
254
|
+
// Freshness guard + artifact schema checks (SPEC §7). Exit non-zero when
|
|
255
|
+
// the recommended repair level is L2 or higher.
|
|
256
|
+
const guard = await guardLevel(projectRoot, { maxLevel: 'L4' });
|
|
257
|
+
const problems = [];
|
|
258
|
+
|
|
259
|
+
console.log('[UKit] Index doctor:');
|
|
260
|
+
console.log(`identity: ${guard.identity.identity}`);
|
|
261
|
+
console.log(`headSha: ${guard.identity.headSha}`);
|
|
262
|
+
console.log(`snapshot: ${guard.snapshot ? guard.snapshot.identity : 'none'}`);
|
|
263
|
+
console.log(`stale: ${guard.stale ? 'yes' : 'no'}`);
|
|
264
|
+
console.log(`recommendedLevel: ${guard.recommendedLevel}`);
|
|
265
|
+
|
|
266
|
+
const schemaIssues = await checkArtifactSchemas(projectRoot);
|
|
267
|
+
for (const issue of schemaIssues) {
|
|
268
|
+
problems.push(issue);
|
|
269
|
+
console.log(`problem: ${issue}`);
|
|
270
|
+
}
|
|
271
|
+
if (schemaIssues.length === 0) {
|
|
272
|
+
console.log('schema: ok');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const needsRepair = ['L2', 'L3', 'L4'].includes(guard.recommendedLevel) || problems.length > 0;
|
|
276
|
+
if (needsRepair) {
|
|
277
|
+
console.log('[UKit] Index needs repair. Run "ukit index build".');
|
|
278
|
+
process.exitCode = 1;
|
|
279
|
+
} else {
|
|
280
|
+
console.log('[UKit] Index healthy.');
|
|
281
|
+
}
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
224
285
|
if (subcommand === 'hooks') {
|
|
225
286
|
const action = (rest[0] ?? 'install').toLowerCase();
|
|
226
287
|
if (action === 'help' || action === '--help' || action === '-h') {
|
|
@@ -250,7 +311,7 @@ export async function runIndexTools({ projectRoot, argv = [] }) {
|
|
|
250
311
|
|
|
251
312
|
export function printIndexHelp() {
|
|
252
313
|
console.log('UKit Index Commands');
|
|
253
|
-
console.log('Usage: ukit index <build|refresh|query|triage|context|verify|route> [args]');
|
|
314
|
+
console.log('Usage: ukit index <build|refresh|query|triage|context|verify|route|status|doctor> [args]');
|
|
254
315
|
console.log('');
|
|
255
316
|
console.log('Subcommands:');
|
|
256
317
|
console.log(' build Build codebase index cache');
|
|
@@ -260,6 +321,8 @@ export function printIndexHelp() {
|
|
|
260
321
|
console.log(' context "<intent>" Suggest minimal file context with reasons');
|
|
261
322
|
console.log(' verify "<intent>" Suggest verification lane from indexed context');
|
|
262
323
|
console.log(' route "<prompt>" Suggest skill + context + verification next step');
|
|
324
|
+
console.log(' status Show freshness identity, snapshot, artifact ages');
|
|
325
|
+
console.log(' doctor Freshness guard + artifact schema checks');
|
|
263
326
|
console.log(' hooks [install|remove] Manage git-hook auto-refresh');
|
|
264
327
|
console.log('');
|
|
265
328
|
console.log('Aliases:');
|
|
@@ -275,6 +338,44 @@ function printIndexHooksHelp() {
|
|
|
275
338
|
console.log(' ukit index hooks remove');
|
|
276
339
|
}
|
|
277
340
|
|
|
341
|
+
async function collectArtifactAges(rootDir) {
|
|
342
|
+
const entries = [];
|
|
343
|
+
for (const [key, fileName] of Object.entries(INDEX_ARTIFACTS)) {
|
|
344
|
+
try {
|
|
345
|
+
const stat = await fs.stat(getArtifactPath(rootDir, fileName));
|
|
346
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
347
|
+
const ageMinutes = Math.max(0, Math.round(ageMs / 60000));
|
|
348
|
+
entries.push({ name: fileName, age: `${ageMinutes}m old` });
|
|
349
|
+
} catch {
|
|
350
|
+
// missing artifact — not listed
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return entries;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function checkArtifactSchemas(rootDir) {
|
|
357
|
+
const issues = [];
|
|
358
|
+
const required = ['meta', 'files', 'symbols'];
|
|
359
|
+
for (const key of required) {
|
|
360
|
+
const fileName = INDEX_ARTIFACTS[key];
|
|
361
|
+
let parsed;
|
|
362
|
+
try {
|
|
363
|
+
const raw = await fs.readFile(getArtifactPath(rootDir, fileName), 'utf8');
|
|
364
|
+
parsed = JSON.parse(raw);
|
|
365
|
+
} catch {
|
|
366
|
+
issues.push(`${fileName}: missing or unreadable`);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (parsed?.schemaVersion !== INDEX_SCHEMA_VERSION) {
|
|
370
|
+
issues.push(`${fileName}: schemaVersion ${parsed?.schemaVersion ?? 'none'} != ${INDEX_SCHEMA_VERSION}`);
|
|
371
|
+
}
|
|
372
|
+
if (key !== 'meta' && !Array.isArray(parsed?.items)) {
|
|
373
|
+
issues.push(`${fileName}: items is not an array`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return issues;
|
|
377
|
+
}
|
|
378
|
+
|
|
278
379
|
async function refreshIndexIfStale(rootDir) {
|
|
279
380
|
const lastRefreshMs = await getIndexArtifactGeneratedAt({ rootDir });
|
|
280
381
|
const stale = await isIndexStale({
|
|
@@ -7,6 +7,14 @@ import {
|
|
|
7
7
|
resolvePatternCandidate,
|
|
8
8
|
runProjectHygiene,
|
|
9
9
|
} from '../../core/memory/store.js';
|
|
10
|
+
import {
|
|
11
|
+
getRecord,
|
|
12
|
+
loadRecords,
|
|
13
|
+
queryRecords,
|
|
14
|
+
stats as v2Stats,
|
|
15
|
+
updateRecord,
|
|
16
|
+
} from '../../core/memory/storeV2.js';
|
|
17
|
+
import { runMigration } from '../../core/memory/migrate.js';
|
|
10
18
|
import { getContextInjection, search } from '../../core/memory/retrieval.js';
|
|
11
19
|
import { inspectRuntimeConfig } from '../../core/runtimeConfig.js';
|
|
12
20
|
import { buildRuntimePaths } from '../../core/runtimePaths.js';
|
|
@@ -26,6 +34,30 @@ function extractFlag(args, flag) {
|
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
async function listAllPendingPatternCandidates(projectRoot, runtimePaths) {
|
|
37
|
+
// v2 mode: pending pattern candidates live as derived_fact records with
|
|
38
|
+
// meta.legacyStatus === 'pending' (facade handles the conversion).
|
|
39
|
+
// Respect memoryV2.enabled — without this check loadRecords would run the
|
|
40
|
+
// lazy v1→v2 migration even when the whole v2 lane is disabled.
|
|
41
|
+
let v2Enabled = true;
|
|
42
|
+
try {
|
|
43
|
+
const { config } = await inspectRuntimeConfig(projectRoot);
|
|
44
|
+
if (config?.memoryV2?.enabled === false) v2Enabled = false;
|
|
45
|
+
} catch {
|
|
46
|
+
// unreadable config → default enabled
|
|
47
|
+
}
|
|
48
|
+
const records = v2Enabled ? await loadRecords(projectRoot) : [];
|
|
49
|
+
if (records.length > 0) {
|
|
50
|
+
const projectIds = new Set(records.map((r) => r.project_id).filter(Boolean));
|
|
51
|
+
const results = [];
|
|
52
|
+
for (const projectId of projectIds) {
|
|
53
|
+
const pending = await listPendingPatternCandidates(projectRoot, projectId);
|
|
54
|
+
for (const candidate of pending) {
|
|
55
|
+
results.push({ ...candidate, projectId });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
|
|
29
61
|
let entries = [];
|
|
30
62
|
try {
|
|
31
63
|
entries = await fs.readdir(runtimePaths.projectsDir, { withFileTypes: true });
|
|
@@ -45,6 +77,106 @@ async function listAllPendingPatternCandidates(projectRoot, runtimePaths) {
|
|
|
45
77
|
return results;
|
|
46
78
|
}
|
|
47
79
|
|
|
80
|
+
// ---- `ukit memory v2` ops (SPEC §11) ----
|
|
81
|
+
|
|
82
|
+
async function runMemoryV2(projectRoot, args) {
|
|
83
|
+
const [opRaw, ...rest] = args;
|
|
84
|
+
const op = (opRaw ?? 'list').toLowerCase();
|
|
85
|
+
|
|
86
|
+
if (op === 'list') {
|
|
87
|
+
const typeFlag = extractFlag(rest, '--type');
|
|
88
|
+
const scopeFlag = extractFlag(typeFlag.rest, '--scope');
|
|
89
|
+
const statusFlag = extractFlag(scopeFlag.rest, '--status');
|
|
90
|
+
const records = await queryRecords(projectRoot, {
|
|
91
|
+
type: typeFlag.value ?? undefined,
|
|
92
|
+
scope: scopeFlag.value ?? undefined,
|
|
93
|
+
status: statusFlag.value ?? undefined,
|
|
94
|
+
});
|
|
95
|
+
if (records.length === 0) {
|
|
96
|
+
console.log('[UKit] No memory v2 records found.');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
for (const record of records) {
|
|
100
|
+
const scopeLabel = record.project_id ?? record.scope;
|
|
101
|
+
console.log(`${record.id} [${record.type}/${scopeLabel}/${record.status}] — ${record.text}`);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (op === 'show') {
|
|
107
|
+
const id = rest.join(' ').trim();
|
|
108
|
+
if (!id) {
|
|
109
|
+
throw new Error('Missing record id. Usage: ukit memory v2 show <id>');
|
|
110
|
+
}
|
|
111
|
+
const record = await getRecord(projectRoot, id);
|
|
112
|
+
if (!record) {
|
|
113
|
+
throw new Error(`Memory v2 record not found: ${id}`);
|
|
114
|
+
}
|
|
115
|
+
console.log(JSON.stringify(record, null, 2));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (op === 'promote') {
|
|
120
|
+
const id = rest.join(' ').trim();
|
|
121
|
+
if (!id) {
|
|
122
|
+
throw new Error('Missing record id. Usage: ukit memory v2 promote <id>');
|
|
123
|
+
}
|
|
124
|
+
const record = await getRecord(projectRoot, id);
|
|
125
|
+
if (!record) {
|
|
126
|
+
throw new Error(`Memory v2 record not found: ${id}`);
|
|
127
|
+
}
|
|
128
|
+
if (record.type === 'project_rule') {
|
|
129
|
+
console.log(`[UKit] ${id} is already a project_rule — nothing to do.`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (record.type !== 'derived_fact' && record.type !== 'episode') {
|
|
133
|
+
throw new Error(`Cannot promote ${record.type} records (only derived_fact or episode).`);
|
|
134
|
+
}
|
|
135
|
+
// Explicit approval only — no auto-promotion (SPEC §11,
|
|
136
|
+
// memoryV2.promotion.episodeToRuleRequiresApproval).
|
|
137
|
+
const updated = await updateRecord(projectRoot, id, {
|
|
138
|
+
type: 'project_rule',
|
|
139
|
+
scope: 'repo',
|
|
140
|
+
provenance: `${record.provenance ?? 'manual'};promoted-from:${record.id}`,
|
|
141
|
+
});
|
|
142
|
+
console.log(`[UKit] Promoted ${updated.id} → project_rule.`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (op === 'stale') {
|
|
147
|
+
const id = rest.join(' ').trim();
|
|
148
|
+
if (!id) {
|
|
149
|
+
throw new Error('Missing record id. Usage: ukit memory v2 stale <id>');
|
|
150
|
+
}
|
|
151
|
+
const updated = await updateRecord(projectRoot, id, { status: 'stale' });
|
|
152
|
+
if (!updated) {
|
|
153
|
+
throw new Error(`Memory v2 record not found: ${id}`);
|
|
154
|
+
}
|
|
155
|
+
console.log(`[UKit] Marked ${id} as stale.`);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (op === 'migrate') {
|
|
160
|
+
const dryRun = rest.includes('--dry-run');
|
|
161
|
+
const result = await runMigration(projectRoot, { dryRun });
|
|
162
|
+
if (dryRun) {
|
|
163
|
+
console.log(`[UKit] Dry-run: would migrate ${result.migrated} record(s), skip ${result.skipped}.`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (result.migrated === 0) {
|
|
167
|
+
console.log('[UKit] Nothing to migrate (marker present or no legacy memory).');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.log(`[UKit] Migrated ${result.migrated} record(s) to v2.`);
|
|
171
|
+
console.log(`[UKit] Backup: ${result.backupDir ?? 'none'} — marker: ${result.markerPath}`);
|
|
172
|
+
const stats = await v2Stats(projectRoot);
|
|
173
|
+
console.log(`[UKit] v2 store: ${stats.total} record(s) — ${JSON.stringify(stats.byType)}`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
throw new Error(`Unknown memory v2 op: ${op}. Expected list|show|promote|stale|migrate.`);
|
|
178
|
+
}
|
|
179
|
+
|
|
48
180
|
export async function runMemory({ projectRoot, argv = [] }) {
|
|
49
181
|
const runtimePaths = buildRuntimePaths(projectRoot);
|
|
50
182
|
if (!(await pathExists(runtimePaths.runtimeRoot))) {
|
|
@@ -59,6 +191,11 @@ export async function runMemory({ projectRoot, argv = [] }) {
|
|
|
59
191
|
return;
|
|
60
192
|
}
|
|
61
193
|
|
|
194
|
+
if (subcommand === 'v2') {
|
|
195
|
+
await runMemoryV2(projectRoot, rest);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
62
199
|
if (subcommand === 'list') {
|
|
63
200
|
if (rest.includes('--pending')) {
|
|
64
201
|
const pending = await listAllPendingPatternCandidates(projectRoot, runtimePaths);
|
package/src/cli/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { runIndexTools } from './commands/indexTools.js';
|
|
|
6
6
|
import { runStatus } from './commands/status.js';
|
|
7
7
|
import { runMemory } from './commands/memory.js';
|
|
8
8
|
import { runUpdate } from './commands/update.js';
|
|
9
|
+
import { runCode } from './commands/code.js';
|
|
9
10
|
|
|
10
11
|
const GLOBAL_FLAGS = new Set(['--help', '-h', '--version', '-v']);
|
|
11
12
|
|
|
@@ -49,6 +50,11 @@ export async function runCli({ argv, packageRoot, projectRoot, packageVersion })
|
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
if (command === 'code') {
|
|
54
|
+
await runCode({ projectRoot, argv: commandArgv });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
52
58
|
if (command === 'status') {
|
|
53
59
|
await runStatus({ projectRoot, argv: commandArgv });
|
|
54
60
|
return;
|
|
@@ -89,6 +95,7 @@ export async function runCli({ argv, packageRoot, projectRoot, packageVersion })
|
|
|
89
95
|
console.log(' doctor Validate manifest, stack, docs, and UKit state');
|
|
90
96
|
console.log(' uninstall Remove all UKit-managed assets');
|
|
91
97
|
console.log(' index Codebase index tools (build/query/triage)');
|
|
98
|
+
console.log(' code Context compiler surface (peek/search/context/impact)');
|
|
92
99
|
console.log(' status Show UKit runtime status');
|
|
93
100
|
console.log(' memory Inspect shared UKit memory');
|
|
94
101
|
console.log(' update Upgrade the global UKit CLI to the latest version');
|