kibi-cli 2.21.2 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-register-foundation.d.ts.map +1 -1
- package/dist/cli-register-foundation.js +1 -0
- package/dist/commands/check.d.ts +0 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +47 -111
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +96 -6
- package/dist/commands/init-helpers.d.ts +14 -1
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +49 -10
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -1
- package/dist/commands/legacy-storage-migration.d.ts +46 -1
- package/dist/commands/legacy-storage-migration.d.ts.map +1 -1
- package/dist/commands/legacy-storage-migration.js +219 -9
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +48 -182
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +9 -0
- package/dist/extractors/symbols-coordinator.js +1 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +28 -6
- package/dist/operations/migration/inventory-rederive.d.ts +40 -1
- package/dist/operations/migration/inventory-rederive.d.ts.map +1 -1
- package/dist/operations/migration/inventory-rederive.js +99 -8
- package/dist/operations/migration/requirement-status.d.ts +25 -0
- package/dist/operations/migration/requirement-status.d.ts.map +1 -0
- package/dist/operations/migration/requirement-status.js +105 -0
- package/dist/operations/migration/schema6.d.ts +25 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +265 -7
- package/dist/operations/migration/symbol-legacy-links.d.ts +51 -0
- package/dist/operations/migration/symbol-legacy-links.d.ts.map +1 -0
- package/dist/operations/migration/symbol-legacy-links.js +319 -0
- package/dist/operations/mutation/context-warning.d.ts +12 -2
- package/dist/operations/mutation/context-warning.d.ts.map +1 -1
- package/dist/operations/mutation/context-warning.js +6 -6
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +130 -35
- package/dist/operations/mutation/types.d.ts +2 -1
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts +17 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +28 -11
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +40 -8
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +18 -3
- package/dist/public/impact/diagnostics.d.ts.map +1 -1
- package/dist/public/impact/diagnostics.js +24 -14
- package/dist/public/operations/catalog.d.ts +3 -3
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +6 -1
- package/dist/public/operations/discovery-executors.d.ts +2 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +9 -2
- package/dist/public/operations/migration-plan.d.ts +2 -0
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +101 -16
- package/dist/public/operations/result-envelope.d.ts.map +1 -1
- package/dist/public/operations/result-envelope.js +27 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +2 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/planning.d.ts +2 -2
- package/dist/public/operations/specs/planning.js +2 -2
- package/dist/public/operations/symbol-granularity-check.d.ts +18 -0
- package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -0
- package/dist/public/operations/symbol-granularity-check.js +175 -0
- package/dist/public/symbol-granularity.d.ts +17 -0
- package/dist/public/symbol-granularity.d.ts.map +1 -1
- package/dist/public/symbol-granularity.js +21 -0
- package/dist/traceability/evidence-model.d.ts +7 -3
- package/dist/traceability/evidence-model.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +6 -5
- package/dist/traceability/validate.d.ts +14 -1
- package/dist/traceability/validate.d.ts.map +1 -1
- package/dist/traceability/validate.js +41 -0
- package/dist/utils/rule-registry.generated.d.ts +5 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +6 -0
- package/package.json +3 -3
- package/src/public/impact/diagnostics.ts +29 -17
- package/src/public/operations/check-executor.ts +7 -0
- package/src/public/operations/contracts.ts +6 -1
- package/src/public/operations/discovery-executors.ts +12 -2
- package/src/public/operations/migration-plan.ts +100 -19
- package/src/public/operations/result-envelope.ts +34 -1
- package/src/public/operations/specs/check-rules.generated.ts +2 -1
- package/src/public/operations/specs/planning.ts +2 -2
- package/src/public/operations/symbol-granularity-check.ts +233 -0
- package/src/public/symbol-granularity.ts +37 -0
|
@@ -15,13 +15,16 @@
|
|
|
15
15
|
* You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
import { execFileSync } from "node:child_process";
|
|
18
19
|
import { createHash } from "node:crypto";
|
|
19
20
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
20
21
|
import * as path from "node:path";
|
|
21
22
|
import fg from "fast-glob";
|
|
23
|
+
import { load as parseYaml } from "js-yaml";
|
|
24
|
+
import { writePendingSourceReceipt } from "../operations/mutation/source-authoring.js";
|
|
22
25
|
import { readLegacyKbConfig, resolveLegacyEntityPaths, } from "../utils/config.js";
|
|
23
26
|
import { defaultKbManifest, readKbManifest, writeKbManifest, } from "../utils/kb-manifest.js";
|
|
24
|
-
import { CANONICAL_ENTITY_PATHS, ENTITY_LANES, KB_PATHS, } from "../utils/kb-paths.js";
|
|
27
|
+
import { CANONICAL_ENTITY_PATHS, ENTITY_LANES, KB_PATHS, LEGACY_DEFAULT_ENTITY_PATHS, } from "../utils/kb-paths.js";
|
|
25
28
|
import { LATEST_KB_SCHEMA_VERSION } from "../utils/schema-version.js";
|
|
26
29
|
import { updateGitIgnore } from "./init-helpers.js";
|
|
27
30
|
const LANE_BY_CONFIG_KEY = {
|
|
@@ -57,6 +60,8 @@ export function planLegacyStorageMigration(cwd) {
|
|
|
57
60
|
legacyConfigError: legacyConfigResult.error,
|
|
58
61
|
schemaVersion: null,
|
|
59
62
|
semanticAdvisorBackfill: null,
|
|
63
|
+
removals: [],
|
|
64
|
+
conflicts: [],
|
|
60
65
|
blockers: [
|
|
61
66
|
`Legacy .kb/config.json is malformed (${legacyConfigResult.error}). Repair the JSON or provide an explicit recovery/migration override; Kibi will not infer default legacy paths.`,
|
|
62
67
|
],
|
|
@@ -96,7 +101,11 @@ export function planLegacyStorageMigration(cwd) {
|
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
// Symbols manifest + coordinates.
|
|
99
|
-
const
|
|
104
|
+
const conflicts = [];
|
|
105
|
+
const symbolsSource = resolveLegacySymbolsSource(cwd, config, legacyPaths.symbols);
|
|
106
|
+
if (symbolsSource.conflict !== undefined)
|
|
107
|
+
conflicts.push(symbolsSource.conflict);
|
|
108
|
+
const legacySymbols = symbolsSource.path;
|
|
100
109
|
if (typeof legacySymbols === "string" && legacySymbols.trim().length > 0) {
|
|
101
110
|
const legacyManifest = path.resolve(cwd, legacySymbols);
|
|
102
111
|
if (existsSync(legacyManifest) &&
|
|
@@ -122,17 +131,33 @@ export function planLegacyStorageMigration(cwd) {
|
|
|
122
131
|
});
|
|
123
132
|
}
|
|
124
133
|
}
|
|
125
|
-
// Destination
|
|
126
|
-
//
|
|
134
|
+
// Destination classification: an identical legacy copy is removed, an
|
|
135
|
+
// empty seeded symbols manifest is replaced, and anything else is an
|
|
136
|
+
// operator decision with the resolution Kibi can tell.
|
|
137
|
+
const removals = [];
|
|
138
|
+
const pending = [];
|
|
127
139
|
for (const move of moves) {
|
|
128
140
|
const destinationAbsolute = path.resolve(cwd, move.to);
|
|
129
|
-
if (!existsSync(destinationAbsolute))
|
|
141
|
+
if (!existsSync(destinationAbsolute)) {
|
|
142
|
+
pending.push(move);
|
|
130
143
|
continue;
|
|
144
|
+
}
|
|
131
145
|
// 'kibi init' seeds an empty symbols manifest; the legacy one replaces it.
|
|
132
|
-
if (move.lane === "symbols" && isEmptySymbolsStub(destinationAbsolute))
|
|
146
|
+
if (move.lane === "symbols" && isEmptySymbolsStub(destinationAbsolute)) {
|
|
147
|
+
pending.push(move);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const conflict = classifyExistingDestination(cwd, move);
|
|
151
|
+
if (conflict === null) {
|
|
152
|
+
removals.push({ path: move.from, duplicateOf: move.to });
|
|
133
153
|
continue;
|
|
134
|
-
|
|
154
|
+
}
|
|
155
|
+
pending.push(move);
|
|
156
|
+
conflicts.push(conflict);
|
|
135
157
|
}
|
|
158
|
+
moves.splice(0, moves.length, ...pending);
|
|
159
|
+
for (const conflict of conflicts)
|
|
160
|
+
blockers.push(conflict.resolution);
|
|
136
161
|
// Duplicate destinations (two legacy sources collapsing onto one target).
|
|
137
162
|
const destinations = new Map();
|
|
138
163
|
for (const move of moves) {
|
|
@@ -148,9 +173,126 @@ export function planLegacyStorageMigration(cwd) {
|
|
|
148
173
|
legacyConfig: legacyConfigResult.kind === "none" ? "absent" : "present",
|
|
149
174
|
schemaVersion: typeof config?.schemaVersion === "number" ? config.schemaVersion : null,
|
|
150
175
|
semanticAdvisorBackfill: config?.semanticAdvisorBackfill ?? null,
|
|
176
|
+
removals,
|
|
177
|
+
conflicts,
|
|
151
178
|
blockers,
|
|
152
179
|
};
|
|
153
180
|
}
|
|
181
|
+
function hashFile(filePath) {
|
|
182
|
+
try {
|
|
183
|
+
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/** Symbol ids a manifest declares, or null when it does not parse. */
|
|
190
|
+
function manifestSymbolIds(filePath) {
|
|
191
|
+
try {
|
|
192
|
+
const parsed = parseYaml(readFileSync(filePath, "utf8"));
|
|
193
|
+
if (!Array.isArray(parsed?.symbols))
|
|
194
|
+
return null;
|
|
195
|
+
return new Set(parsed.symbols.flatMap((symbol) => symbol !== null &&
|
|
196
|
+
typeof symbol === "object" &&
|
|
197
|
+
typeof symbol.id === "string"
|
|
198
|
+
? [symbol.id]
|
|
199
|
+
: []));
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* How a move whose destination already exists is resolved: null when the
|
|
207
|
+
* legacy copy is identical (it is removed), otherwise the conflict and the
|
|
208
|
+
* resolution Kibi can tell.
|
|
209
|
+
*/
|
|
210
|
+
// implements REQ-cli-schema-migration
|
|
211
|
+
function classifyExistingDestination(cwd, move) {
|
|
212
|
+
const from = path.resolve(cwd, move.from);
|
|
213
|
+
const to = path.resolve(cwd, move.to);
|
|
214
|
+
const legacyHash = hashFile(from);
|
|
215
|
+
if (legacyHash !== null && legacyHash === hashFile(to))
|
|
216
|
+
return null;
|
|
217
|
+
if (move.to === CANONICAL_ENTITY_PATHS.symbols) {
|
|
218
|
+
const legacyIds = manifestSymbolIds(from);
|
|
219
|
+
const currentIds = manifestSymbolIds(to);
|
|
220
|
+
if (legacyIds !== null &&
|
|
221
|
+
currentIds !== null &&
|
|
222
|
+
[...legacyIds].every((id) => currentIds.has(id))) {
|
|
223
|
+
return {
|
|
224
|
+
from: move.from,
|
|
225
|
+
to: move.to,
|
|
226
|
+
kind: "stale_subset",
|
|
227
|
+
resolution: `The legacy copy ${move.from} is a stale subset of ${move.to}: every symbol it declares (${legacyIds.size}) is already there. Remove it (git rm ${move.from}); Kibi removes only a copy identical to its destination.`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (move.to === KB_PATHS.symbolCoordinates) {
|
|
232
|
+
return {
|
|
233
|
+
from: move.from,
|
|
234
|
+
to: move.to,
|
|
235
|
+
kind: "generated",
|
|
236
|
+
resolution: `${move.from} is a generated coordinates file and ${move.to} already exists. Keep ${move.to} and remove the legacy copy (git rm ${move.from}); kibi sync --refresh-symbol-coordinates regenerates coordinates.`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
from: move.from,
|
|
241
|
+
to: move.to,
|
|
242
|
+
kind: "conflict",
|
|
243
|
+
resolution: `Destination ${move.to} already exists with different content than ${move.from}. Compare them and keep the current one: replace ${move.to} when the legacy copy is newer, or remove (git rm) ${move.from} when it is a stale duplicate.`,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/** The parent folders of the lane roots a legacy config names explicitly. */
|
|
247
|
+
function configuredLaneParents(config) {
|
|
248
|
+
const parents = new Set();
|
|
249
|
+
for (const key of Object.keys(LANE_BY_CONFIG_KEY)) {
|
|
250
|
+
const value = config?.paths?.[key];
|
|
251
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
252
|
+
continue;
|
|
253
|
+
const { root } = normalizeLegacySource(value.trim());
|
|
254
|
+
const parent = path.posix.dirname(root.replace(/^\.\//, ""));
|
|
255
|
+
if (parent !== "." && parent !== "")
|
|
256
|
+
parents.add(parent);
|
|
257
|
+
}
|
|
258
|
+
return [...parents].sort();
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The legacy symbols manifest to move. A configured path wins. Without one,
|
|
262
|
+
* the historical `documentation/symbols.yaml` default applies only when the
|
|
263
|
+
* config does not place its lanes under another folder: there the manifest
|
|
264
|
+
* sits beside the lanes, and a `documentation/` copy may be a stale leftover.
|
|
265
|
+
* When Kibi cannot tell which file is meant, it moves none and reports the
|
|
266
|
+
* ambiguity instead.
|
|
267
|
+
*/
|
|
268
|
+
// implements REQ-cli-schema-migration
|
|
269
|
+
function resolveLegacySymbolsSource(cwd, config, resolved) {
|
|
270
|
+
const configured = config?.paths?.symbols ?? config?.symbolsManifest;
|
|
271
|
+
if (typeof configured === "string" && configured.trim().length > 0)
|
|
272
|
+
return { path: resolved };
|
|
273
|
+
const parents = configuredLaneParents(config).filter((parent) => parent !== path.posix.dirname(LEGACY_DEFAULT_ENTITY_PATHS.symbols));
|
|
274
|
+
if (parents.length === 0)
|
|
275
|
+
return { path: resolved };
|
|
276
|
+
const candidates = parents
|
|
277
|
+
.map((parent) => `${parent}/symbols.yaml`)
|
|
278
|
+
.filter((candidate) => existsSync(path.resolve(cwd, candidate)));
|
|
279
|
+
const fallback = LEGACY_DEFAULT_ENTITY_PATHS.symbols;
|
|
280
|
+
const fallbackExists = existsSync(path.resolve(cwd, fallback));
|
|
281
|
+
if (candidates.length === 1 && !fallbackExists)
|
|
282
|
+
return { path: candidates[0] ?? null };
|
|
283
|
+
if (candidates.length === 0 && !fallbackExists)
|
|
284
|
+
return { path: null };
|
|
285
|
+
const all = [...candidates, ...(fallbackExists ? [fallback] : [])];
|
|
286
|
+
return {
|
|
287
|
+
path: null,
|
|
288
|
+
conflict: {
|
|
289
|
+
from: all.join(", "),
|
|
290
|
+
to: CANONICAL_ENTITY_PATHS.symbols,
|
|
291
|
+
kind: "ambiguous",
|
|
292
|
+
resolution: `The legacy .kb/config.json places its lanes under ${parents.join(", ")} but names no symbols manifest, and ${all.length === 1 ? `${all[0]} exists outside that folder` : `${all.join(" and ")} all exist`}; Kibi will not guess which one is current. Set paths.symbols in .kb/config.json to the current manifest, or remove (git rm) the stale one, then run kibi migrate --yes.`,
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
154
296
|
/**
|
|
155
297
|
* Apply the legacy storage migration. Moves every planned file, writes the
|
|
156
298
|
* canonical lifecycle manifest, retires the legacy config, and prunes empty
|
|
@@ -160,6 +302,18 @@ export function applyLegacyStorageMigration(cwd, plan) {
|
|
|
160
302
|
if (plan.blockers.length > 0) {
|
|
161
303
|
throw new Error(`Legacy storage migration is blocked: ${plan.blockers.join(" ")}`);
|
|
162
304
|
}
|
|
305
|
+
// A legacy copy identical to its destination carries nothing the
|
|
306
|
+
// destination lacks; it is removed rather than left to block a later run.
|
|
307
|
+
const removedFiles = [];
|
|
308
|
+
for (const removal of plan.removals) {
|
|
309
|
+
const absolute = path.resolve(cwd, removal.path);
|
|
310
|
+
if (!existsSync(absolute))
|
|
311
|
+
continue;
|
|
312
|
+
if (hashFile(absolute) !== hashFile(path.resolve(cwd, removal.duplicateOf)))
|
|
313
|
+
throw new Error(`Legacy storage migration is blocked: ${removal.path} changed since planning and no longer matches ${removal.duplicateOf}.`);
|
|
314
|
+
rmSync(absolute);
|
|
315
|
+
removedFiles.push(removal.path);
|
|
316
|
+
}
|
|
163
317
|
const movedFiles = [];
|
|
164
318
|
for (const move of plan.moves) {
|
|
165
319
|
const sourceAbsolute = path.resolve(cwd, move.from);
|
|
@@ -196,9 +350,12 @@ export function applyLegacyStorageMigration(cwd, plan) {
|
|
|
196
350
|
}
|
|
197
351
|
pruneEmptyLegacyDirs(cwd, plan);
|
|
198
352
|
rewritePendingSourceReceiptPaths(cwd, plan.moves);
|
|
353
|
+
const untrackedMovedFiles = writeMovedSourceReceipts(cwd, plan.moves);
|
|
199
354
|
updateGitIgnore(cwd);
|
|
200
355
|
return {
|
|
201
356
|
movedFiles,
|
|
357
|
+
removedFiles,
|
|
358
|
+
untrackedMovedFiles,
|
|
202
359
|
retiredLegacyConfig,
|
|
203
360
|
manifestPath: path.relative(cwd, manifestPath).replaceAll(path.sep, "/"),
|
|
204
361
|
schemaVersion: manifest.schemaVersion,
|
|
@@ -207,8 +364,11 @@ export function applyLegacyStorageMigration(cwd, plan) {
|
|
|
207
364
|
}
|
|
208
365
|
function pruneEmptyLegacyDirs(cwd, plan) {
|
|
209
366
|
const roots = new Set();
|
|
210
|
-
for (const
|
|
211
|
-
|
|
367
|
+
for (const from of [
|
|
368
|
+
...plan.moves.map((move) => move.from),
|
|
369
|
+
...plan.removals.map((removal) => removal.path),
|
|
370
|
+
]) {
|
|
371
|
+
const absolute = path.resolve(cwd, from);
|
|
212
372
|
let dir = path.dirname(absolute);
|
|
213
373
|
while (dir.startsWith(path.resolve(cwd)) &&
|
|
214
374
|
dir !== path.resolve(cwd) &&
|
|
@@ -270,6 +430,54 @@ export function rewritePendingSourceReceiptPaths(cwd, moves) {
|
|
|
270
430
|
}
|
|
271
431
|
return rewritten;
|
|
272
432
|
}
|
|
433
|
+
/** Workspace-relative paths Git tracks, or null outside a repository. */
|
|
434
|
+
function gitTrackedFiles(cwd) {
|
|
435
|
+
try {
|
|
436
|
+
return new Set(execFileSync("git", ["-C", cwd, "ls-files", "--cached", "-z"], {
|
|
437
|
+
encoding: "utf8",
|
|
438
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
439
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
440
|
+
timeout: 30_000,
|
|
441
|
+
})
|
|
442
|
+
.split("\0")
|
|
443
|
+
.filter((file) => file.length > 0)
|
|
444
|
+
.map((file) => file.replaceAll("\\", "/")));
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Bind every moved file Git does not track to its bytes with a
|
|
452
|
+
* pending-source receipt, the record kb_upsert writes for the files it
|
|
453
|
+
* creates. `kibi sync` compiles tracked sources plus receipted ones, so the
|
|
454
|
+
* moved knowledge compiles at once; Kibi never stages anything itself, and
|
|
455
|
+
* each receipt retires when Git starts tracking its file. Later migration
|
|
456
|
+
* rewrites rebind the receipt they find. Covers files a previous,
|
|
457
|
+
* interrupted run moved too. Returns the untracked destinations.
|
|
458
|
+
*/
|
|
459
|
+
// implements REQ-cli-schema-migration, REQ-core-atomic-upsert-persistence
|
|
460
|
+
export function writeMovedSourceReceipts(cwd, moves) {
|
|
461
|
+
const tracked = gitTrackedFiles(cwd);
|
|
462
|
+
if (tracked === null)
|
|
463
|
+
return [];
|
|
464
|
+
const untracked = [];
|
|
465
|
+
for (const move of moves) {
|
|
466
|
+
if (tracked.has(move.to))
|
|
467
|
+
continue;
|
|
468
|
+
const absolute = path.resolve(cwd, move.to);
|
|
469
|
+
let bytes;
|
|
470
|
+
try {
|
|
471
|
+
bytes = readFileSync(absolute);
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
writePendingSourceReceipt(cwd, move.to, createHash("sha256").update(bytes).digest("hex"));
|
|
477
|
+
untracked.push(move.to);
|
|
478
|
+
}
|
|
479
|
+
return untracked;
|
|
480
|
+
}
|
|
273
481
|
// implements REQ-cli-schema-migration
|
|
274
482
|
function isEmptySymbolsStub(filePath) {
|
|
275
483
|
try {
|
|
@@ -293,6 +501,8 @@ function sourceSchemaVersion(legacyVersion, existing) {
|
|
|
293
501
|
export function needsLegacyStorageMigration(cwd) {
|
|
294
502
|
const plan = planLegacyStorageMigration(cwd);
|
|
295
503
|
return (plan.moves.length > 0 ||
|
|
504
|
+
plan.removals.length > 0 ||
|
|
505
|
+
plan.blockers.length > 0 ||
|
|
296
506
|
plan.legacyConfig === "present" ||
|
|
297
507
|
plan.legacyConfig === "malformed");
|
|
298
508
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAmEA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AA+JD,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,OAAO,EACzB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,MAAM,CAUR;AAsOD,wBAAgB,+BAA+B,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAKtE;AAGD,wBAAsB,cAAc,CAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA2Y/B"}
|
package/dist/commands/migrate.js
CHANGED
|
@@ -15,15 +15,13 @@
|
|
|
15
15
|
* You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
import {
|
|
19
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
|
|
18
|
+
import { existsSync, mkdirSync, renameSync, writeFileSync, } from "node:fs";
|
|
20
19
|
import * as path from "node:path";
|
|
21
|
-
import { load as parseYAML } from "js-yaml";
|
|
22
20
|
import { applySafeInventoryRederivations, planInventoryRederivation, } from "../operations/migration/inventory-rederive.js";
|
|
23
21
|
import { applyOriginBackfill, planOriginBackfill, } from "../operations/migration/origin-backfill.js";
|
|
24
22
|
import { applySourcePathRepairs, findSourceRepairs, } from "../operations/migration/source-paths.js";
|
|
25
23
|
import { applySupersededClosures, planSupersededClosures, } from "../operations/migration/superseded-closure.js";
|
|
26
|
-
import {
|
|
24
|
+
import { applySymbolLegacyLinks, planSymbolLegacyLinks, } from "../operations/migration/symbol-legacy-links.js";
|
|
27
25
|
import { resolveBranchAttachment } from "../utils/branch-resolver.js";
|
|
28
26
|
import { defaultKbManifest, readKbManifest, readKbManifestStatus, writeKbManifest, } from "../utils/kb-manifest.js";
|
|
29
27
|
import { CANONICAL_ENTITY_PATHS } from "../utils/kb-paths.js";
|
|
@@ -162,137 +160,25 @@ function normalizeSemanticAdvisorBackfill(value) {
|
|
|
162
160
|
? value
|
|
163
161
|
: null;
|
|
164
162
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return (typeof type === "string" && TRACEABILITY_RELATIONSHIP_TYPES.has(type));
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
function getGranularNames(cwd, sourceFile) {
|
|
188
|
-
const absolutePath = path.isAbsolute(sourceFile)
|
|
189
|
-
? sourceFile
|
|
190
|
-
: path.join(cwd, sourceFile);
|
|
191
|
-
if (!existsSync(absolutePath)) {
|
|
192
|
-
return new Set();
|
|
193
|
-
}
|
|
194
|
-
const symbols = extractSymbolsFromStagedFile({
|
|
195
|
-
path: sourceFile,
|
|
196
|
-
status: "M",
|
|
197
|
-
hunkRanges: [{ start: 1, end: Number.MAX_SAFE_INTEGER }],
|
|
198
|
-
content: readFileSync(absolutePath, "utf8"),
|
|
199
|
-
});
|
|
200
|
-
return new Set(symbols.map((symbol) => symbol.name));
|
|
201
|
-
}
|
|
202
|
-
function addLegacyReasonsToManifestText(content, symbolIds) {
|
|
203
|
-
if (symbolIds.size === 0)
|
|
204
|
-
return content;
|
|
205
|
-
const lines = content.split("\n");
|
|
206
|
-
const output = [];
|
|
207
|
-
let activeId = null;
|
|
208
|
-
let activeHasReason = false;
|
|
209
|
-
let activePropertyIndent = "";
|
|
210
|
-
const flushLegacyReason = () => {
|
|
211
|
-
if (activeId !== null &&
|
|
212
|
-
symbolIds.has(activeId) &&
|
|
213
|
-
!activeHasReason &&
|
|
214
|
-
activePropertyIndent.length > 0) {
|
|
215
|
-
output.push(`${activePropertyIndent}granularity_reason: legacy-link`);
|
|
216
|
-
activeHasReason = true;
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
for (const line of lines) {
|
|
220
|
-
const idMatch = line.match(/^(\s*)-\s+id:\s+(.+)\s*$/);
|
|
221
|
-
if (idMatch) {
|
|
222
|
-
flushLegacyReason();
|
|
223
|
-
activeId = idMatch[2]?.trim() ?? null;
|
|
224
|
-
activeHasReason = false;
|
|
225
|
-
activePropertyIndent = `${idMatch[1] ?? ""} `;
|
|
226
|
-
}
|
|
227
|
-
if (activeId !== null && /^\s+granularity_reason:\s+/.test(line)) {
|
|
228
|
-
activeHasReason = true;
|
|
229
|
-
}
|
|
230
|
-
if (activeId !== null &&
|
|
231
|
-
symbolIds.has(activeId) &&
|
|
232
|
-
!activeHasReason &&
|
|
233
|
-
/^\s+status:\s+/.test(line)) {
|
|
234
|
-
const indent = line.match(/^\s*/)?.[0] ?? "";
|
|
235
|
-
output.push(`${indent}granularity_reason: legacy-link`);
|
|
236
|
-
activeHasReason = true;
|
|
237
|
-
}
|
|
238
|
-
output.push(line);
|
|
239
|
-
}
|
|
240
|
-
flushLegacyReason();
|
|
241
|
-
return output.join("\n");
|
|
242
|
-
}
|
|
243
|
-
function migrateSymbolGranularity(options) {
|
|
244
|
-
const manifestPath = options.manifestPath ??
|
|
245
|
-
path.join(options.cwd, CANONICAL_ENTITY_PATHS.symbols);
|
|
246
|
-
if (!existsSync(manifestPath)) {
|
|
247
|
-
return { count: 0, manifestPath };
|
|
248
|
-
}
|
|
249
|
-
const manifestContent = readFileSync(manifestPath, "utf8");
|
|
250
|
-
const parsed = parseYAML(manifestContent);
|
|
251
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
252
|
-
return { count: 0, manifestPath };
|
|
253
|
-
}
|
|
254
|
-
const manifest = parsed;
|
|
255
|
-
if (!Array.isArray(manifest.symbols)) {
|
|
256
|
-
return { count: 0, manifestPath };
|
|
257
|
-
}
|
|
258
|
-
let count = 0;
|
|
259
|
-
const migratedSymbolIds = new Set();
|
|
260
|
-
const granularNamesByFile = new Map();
|
|
261
|
-
for (const symbol of manifest.symbols) {
|
|
262
|
-
if (symbol === null ||
|
|
263
|
-
typeof symbol !== "object" ||
|
|
264
|
-
Array.isArray(symbol)) {
|
|
265
|
-
continue;
|
|
266
|
-
}
|
|
267
|
-
const record = symbol;
|
|
268
|
-
if (typeof record.sourceFile !== "string")
|
|
269
|
-
continue;
|
|
270
|
-
if (typeof record.title !== "string")
|
|
271
|
-
continue;
|
|
272
|
-
if (typeof record.id !== "string")
|
|
273
|
-
continue;
|
|
274
|
-
if (record.granularity_reason !== undefined)
|
|
275
|
-
continue;
|
|
276
|
-
if (!hasTraceabilityRelationship(record))
|
|
277
|
-
continue;
|
|
278
|
-
let granularNames = granularNamesByFile.get(record.sourceFile);
|
|
279
|
-
if (granularNames === undefined) {
|
|
280
|
-
granularNames = getGranularNames(options.cwd, record.sourceFile);
|
|
281
|
-
granularNamesByFile.set(record.sourceFile, granularNames);
|
|
282
|
-
}
|
|
283
|
-
if (granularNames.size === 0 || granularNames.has(record.title)) {
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
count += 1;
|
|
287
|
-
if (!options.dryRun) {
|
|
288
|
-
record.granularity_reason = "legacy-link";
|
|
289
|
-
migratedSymbolIds.add(record.id);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
if (count > 0 && !options.dryRun) {
|
|
293
|
-
writeTextAtomically(manifestPath, addLegacyReasonsToManifestText(manifestContent, migratedSymbolIds));
|
|
294
|
-
}
|
|
295
|
-
return { count, manifestPath };
|
|
163
|
+
/**
|
|
164
|
+
* Mark the coarse symbol links the staged granularity gate would block as
|
|
165
|
+
* legacy-link. Runs at any schema version: the rule can call a link coarse
|
|
166
|
+
* that an older run (or a KB that skipped the schema 2 step) left unmarked.
|
|
167
|
+
*/
|
|
168
|
+
// implements REQ-cli-schema-migration, REQ-symbol-behavioral-anchors
|
|
169
|
+
function markLegacySymbolLinks(cwd, dryRun, manifestPath) {
|
|
170
|
+
if (dryRun) {
|
|
171
|
+
const count = planSymbolLegacyLinks(cwd, manifestPath).targets.length;
|
|
172
|
+
if (count > 0)
|
|
173
|
+
console.log(`dry run: would mark ${count} coarse symbol link(s) as legacy-link (granularity_reason), so the staged check accepts them.`);
|
|
174
|
+
return count;
|
|
175
|
+
}
|
|
176
|
+
const { marked, unmarked } = applySymbolLegacyLinks(cwd);
|
|
177
|
+
if (marked.length > 0)
|
|
178
|
+
console.log(`Marked ${marked.length} existing coarse symbol link(s) as legacy-link.`);
|
|
179
|
+
if (unmarked.length > 0)
|
|
180
|
+
printWarning(`Could not mark ${unmarked.join(", ")} as legacy-link in place; add granularity_reason: legacy-link to them in ${CANONICAL_ENTITY_PATHS.symbols} by hand.`);
|
|
181
|
+
return marked.length;
|
|
296
182
|
}
|
|
297
183
|
function describeRederivation(plan) {
|
|
298
184
|
const { keptModeled, roleChanges, newlyUnresolved, downgradedModeled } = plan.summary;
|
|
@@ -300,7 +186,7 @@ function describeRederivation(plan) {
|
|
|
300
186
|
}
|
|
301
187
|
function printManualRederivations(plans) {
|
|
302
188
|
for (const plan of plans) {
|
|
303
|
-
printWarning(`${plan.requirementId} (${plan.path}) no longer matches the current semantic advisor and needs a manual fix: ${plan.reasons.join("; ")}. Run 'kibi migrate --format json' for the exact repair steps.`);
|
|
189
|
+
printWarning(`${plan.requirementId} (${plan.path}) no longer matches the current semantic advisor and needs a manual fix: ${plan.reasons.join("; ")}. Run 'kibi migrate --format json' for the exact repair steps.${plan.rederivableByDroppingGrounding ? ` Or approve semantic-inventory-rederive-drop-grounding-${plan.requirementId} with --apply-safe --approved-action to drop the ${plan.orphanedGrounding.length} orphaned grounding link(s).` : ""}`);
|
|
304
190
|
}
|
|
305
191
|
}
|
|
306
192
|
/**
|
|
@@ -456,7 +342,9 @@ export async function migrateCommand(options = {}) {
|
|
|
456
342
|
const configStatus = getSchemaVersionStatus(normalizedVersion === null
|
|
457
343
|
? undefined
|
|
458
344
|
: { schemaVersion: normalizedVersion });
|
|
459
|
-
const needsStorageMigration = storagePlan.moves.length > 0 ||
|
|
345
|
+
const needsStorageMigration = storagePlan.moves.length > 0 ||
|
|
346
|
+
storagePlan.removals.length > 0 ||
|
|
347
|
+
storagePlan.legacyConfig !== "absent";
|
|
460
348
|
const needsSchemaUpgrade = configStatus.needsMigration || normalizedVersion === null;
|
|
461
349
|
const migrationWarning = manifestStatus.state === "invalid" || manifestStatus.state === "future"
|
|
462
350
|
? manifestStatus.warning
|
|
@@ -489,7 +377,9 @@ export async function migrateCommand(options = {}) {
|
|
|
489
377
|
// and lifecycle findings block kibi check at any version.
|
|
490
378
|
const drift = rederiveDriftedInventories(cwd, options.dryRun === true);
|
|
491
379
|
const lifecycle = repairLifecycleFindings(cwd, options.dryRun === true);
|
|
380
|
+
const legacyLinks = markLegacySymbolLinks(cwd, options.dryRun === true);
|
|
492
381
|
const rewroteSources = polarityCount > 0 ||
|
|
382
|
+
legacyLinks > 0 ||
|
|
493
383
|
drift.rederived.length > 0 ||
|
|
494
384
|
lifecycle.closed > 0 ||
|
|
495
385
|
lifecycle.rewritten > 0 ||
|
|
@@ -513,7 +403,6 @@ export async function migrateCommand(options = {}) {
|
|
|
513
403
|
}
|
|
514
404
|
const fromVersionLabel = formatSchemaVersion(currentVersion, normalizedVersion);
|
|
515
405
|
const migrationSteps = migrationStepsFor(configStatus.currentVersion);
|
|
516
|
-
const symbolGranularityStep = migrationSteps.some((step) => step.id === "symbol-granularity-v2");
|
|
517
406
|
const semanticBackfillStep = migrationSteps.some((step) => step.id === "semantic-backfill-v4");
|
|
518
407
|
const originBackfillStep = migrationSteps.some((step) => step.id === "entity-origin-v6");
|
|
519
408
|
const { planPolarityValueBackfill, applyPolarityValueBackfill } = await import("../operations/migration/polarity-values.js");
|
|
@@ -548,21 +437,17 @@ export async function migrateCommand(options = {}) {
|
|
|
548
437
|
console.log(` ${move.from} -> ${move.to}`);
|
|
549
438
|
}
|
|
550
439
|
}
|
|
440
|
+
if (storagePlan.removals.length > 0) {
|
|
441
|
+
console.log(`dry run: would remove ${storagePlan.removals.length} legacy cop(ies) identical to their .kb/ file:`);
|
|
442
|
+
for (const removal of storagePlan.removals) {
|
|
443
|
+
console.log(` ${removal.path} (same as ${removal.duplicateOf})`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
551
446
|
if (storagePlan.legacyConfig !== "absent") {
|
|
552
447
|
console.log("dry run: would retire legacy .kb/config.json after moving knowledge into .kb/.");
|
|
553
448
|
}
|
|
554
449
|
console.log(`dry run: would set schemaVersion from ${fromVersionLabel} to ${LATEST_KB_SCHEMA_VERSION} in .kb/manifest.json.`);
|
|
555
|
-
|
|
556
|
-
const symbolsSource = storagePlan.moves.find((move) => move.to === CANONICAL_ENTITY_PATHS.symbols)?.from ?? CANONICAL_ENTITY_PATHS.symbols;
|
|
557
|
-
const preview = migrateSymbolGranularity({
|
|
558
|
-
cwd,
|
|
559
|
-
dryRun: true,
|
|
560
|
-
manifestPath: path.join(cwd, symbolsSource),
|
|
561
|
-
});
|
|
562
|
-
if (preview.count > 0) {
|
|
563
|
-
console.log(`dry run: would mark ${preview.count} legacy coarse symbol link(s) as legacy-link.`);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
450
|
+
markLegacySymbolLinks(cwd, true, storagePlan.moves.find((move) => move.to === CANONICAL_ENTITY_PATHS.symbols)?.from);
|
|
566
451
|
if (originBackfillStep) {
|
|
567
452
|
const backfill = planOriginBackfill(cwd);
|
|
568
453
|
if (backfill.targets.length > 0) {
|
|
@@ -581,20 +466,18 @@ export async function migrateCommand(options = {}) {
|
|
|
581
466
|
const storageResult = applyLegacyStorageMigration(cwd, storagePlan);
|
|
582
467
|
if (storageResult.movedFiles.length > 0) {
|
|
583
468
|
console.log(`Moved ${storageResult.movedFiles.length} knowledge file(s) into the canonical .kb/ layout.`);
|
|
584
|
-
const untracked =
|
|
469
|
+
const untracked = storageResult.untrackedMovedFiles.length;
|
|
585
470
|
if (untracked > 0)
|
|
586
|
-
printWarning(`${untracked} moved file(s) are not tracked by Git yet,
|
|
471
|
+
printWarning(`${untracked} moved file(s) are not tracked by Git yet. Kibi recorded a pending-source receipt for each, so kibi sync compiles them now; stage them before you commit (git add .kb, plus the removals under the legacy folders). Each receipt retires once Git tracks its file.`);
|
|
472
|
+
}
|
|
473
|
+
if (storageResult.removedFiles.length > 0) {
|
|
474
|
+
console.log(`Removed ${storageResult.removedFiles.length} legacy cop(ies) identical to their .kb/ file: ${storageResult.removedFiles.join(", ")}.`);
|
|
587
475
|
}
|
|
588
476
|
if (storageResult.retiredLegacyConfig) {
|
|
589
477
|
console.log("Retired legacy .kb/config.json.");
|
|
590
478
|
}
|
|
591
479
|
}
|
|
592
|
-
const
|
|
593
|
-
? migrateSymbolGranularity({
|
|
594
|
-
cwd,
|
|
595
|
-
dryRun: options.yes !== true,
|
|
596
|
-
})
|
|
597
|
-
: { count: 0 };
|
|
480
|
+
const legacyLinksMarked = markLegacySymbolLinks(cwd, false);
|
|
598
481
|
const semanticAdvisorBackfill = normalizeSemanticAdvisorBackfill(readKbManifest(cwd)?.semanticAdvisorBackfill) ??
|
|
599
482
|
normalizeSemanticAdvisorBackfill(storagePlan.semanticAdvisorBackfill) ??
|
|
600
483
|
(semanticBackfillStep || needsStorageMigration
|
|
@@ -657,7 +540,7 @@ export async function migrateCommand(options = {}) {
|
|
|
657
540
|
fromVersion: configStatus.currentVersion,
|
|
658
541
|
migratedAt,
|
|
659
542
|
semanticAdvisorBackfill,
|
|
660
|
-
symbolGranularityLegacyLinks:
|
|
543
|
+
symbolGranularityLegacyLinks: legacyLinksMarked,
|
|
661
544
|
entityOriginBackfill: originBackfill.written.length + originBackfill.previouslyStamped,
|
|
662
545
|
supersededRequirementsClosed: lifecycle.closed,
|
|
663
546
|
sourcePathsRewritten: lifecycle.rewritten,
|
|
@@ -666,9 +549,6 @@ export async function migrateCommand(options = {}) {
|
|
|
666
549
|
steps: migrationSteps.map((step) => step.id),
|
|
667
550
|
}));
|
|
668
551
|
console.log(`Migrated the KB to schemaVersion ${LATEST_KB_SCHEMA_VERSION} on the canonical .kb/ layout (was ${fromVersionLabel}).`);
|
|
669
|
-
if (symbolGranularityMigration.count > 0) {
|
|
670
|
-
console.log(`Marked ${symbolGranularityMigration.count} existing coarse symbol link(s) as legacy-link.`);
|
|
671
|
-
}
|
|
672
552
|
if (semanticAdvisorBackfill === "pending") {
|
|
673
553
|
console.log(`Marked semantic advisor backfill as pending in ${KB_MANIFEST_RELATIVE}.`);
|
|
674
554
|
}
|
|
@@ -750,9 +630,13 @@ async function buildWorkspaceMigrationPlan(workspaceRoot = process.cwd()) {
|
|
|
750
630
|
if (checkable && storeSynced) {
|
|
751
631
|
const checkResult = await executeOperation(runtime, checkSpec, {});
|
|
752
632
|
if (checkResult.structuredContent?.migrationPlan !== undefined) {
|
|
753
|
-
// Lifecycle repairs
|
|
754
|
-
// sources, which may be newer than the
|
|
755
|
-
|
|
633
|
+
// Lifecycle repairs, their sync and requirement status mappings are
|
|
634
|
+
// planned above from authored sources, which may be newer than the
|
|
635
|
+
// compiled store.
|
|
636
|
+
plans.push(withoutActionCodes(checkResult.structuredContent.migrationPlan, new Set([
|
|
637
|
+
...SOURCE_PLANNED_LIFECYCLE_CODES,
|
|
638
|
+
"check_req-status-vocabulary",
|
|
639
|
+
])));
|
|
756
640
|
}
|
|
757
641
|
const coverageInputs = [
|
|
758
642
|
{ by: "req", limit: 10_000, offset: 0 },
|
|
@@ -858,24 +742,6 @@ function approvedActionIdsOf(options) {
|
|
|
858
742
|
.filter((id) => id.length > 0);
|
|
859
743
|
return [...new Set(ids)];
|
|
860
744
|
}
|
|
861
|
-
/** How many of `files` Git does not track; 0 outside a repository. */
|
|
862
|
-
// implements REQ-cli-schema-migration
|
|
863
|
-
function untrackedFiles(cwd, files) {
|
|
864
|
-
let tracked;
|
|
865
|
-
try {
|
|
866
|
-
tracked = new Set(execFileSync("git", ["-C", cwd, "ls-files", "-z", "--", ".kb"], {
|
|
867
|
-
encoding: "utf8",
|
|
868
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
869
|
-
timeout: 10_000,
|
|
870
|
-
})
|
|
871
|
-
.split("\0")
|
|
872
|
-
.filter((file) => file.length > 0));
|
|
873
|
-
}
|
|
874
|
-
catch {
|
|
875
|
-
return 0;
|
|
876
|
-
}
|
|
877
|
-
return files.filter((file) => !tracked.has(file)).length;
|
|
878
|
-
}
|
|
879
745
|
/** The table rendering of an apply result; --format json prints it whole. */
|
|
880
746
|
// implements REQ-cli-schema-migration
|
|
881
747
|
function printApplySummary(content) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/manifest.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAE9D,OAAO,EAML,uBAAuB,EACxB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,KAAK,mBAAmB,EACxB,uBAAuB,EACxB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,0BAA0B,EAG3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,2BAA2B,EAAE,OAAO,2BAA2B,CAAC;CACjE;AAkBD,eAAO,MAAM,8BAA8B,QAc1C,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/manifest.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAE9D,OAAO,EAML,uBAAuB,EACxB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,KAAK,mBAAmB,EACxB,uBAAuB,EACxB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,0BAA0B,EAG3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,2BAA2B,EAAE,OAAO,2BAA2B,CAAC;CACjE;AAkBD,eAAO,MAAM,8BAA8B,QAc1C,CAAC;AAeF;;;;;;;;;GASG;AACH,OAAO,EAAE,0BAA0B,EAAE,CAAC;AAEtC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAG7E;AA2HD,wBAAsB,0BAA0B,CAE9C,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GACA,OAAO,CAAC,IAAI,CAAC,CA0Mf;AAED;;;;;;;;GAQG;AAEH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,MAAM,GAAG,IAAI,CAWf;AAED,wBAAgB,0BAA0B,CAExC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAOT;AAED,wBAAgB,8BAA8B,CAE5C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,OAAO,CAUT"}
|