@skill-map/cli 0.50.0 → 0.51.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.js +161 -83
- package/dist/conformance/index.js +13 -25
- package/dist/index.js +91 -408
- package/dist/kernel/index.js +91 -408
- package/dist/ui/chunk-2GXE52AJ.js +123 -0
- package/dist/ui/chunk-KHRNVLJW.js +1 -0
- package/dist/ui/chunk-OZTRR4M7.js +2312 -0
- package/dist/ui/{chunk-4N5LGWJ4.js → chunk-Q5YJKCTP.js} +1 -1
- package/dist/ui/chunk-RCT3JSFL.js +1 -0
- package/dist/ui/{chunk-DOWLJNMD.js → chunk-VBTLX7GH.js} +13 -13
- package/dist/ui/index.html +8 -2
- package/dist/ui/{main-YSSSF5GW.js → main-N7D2YBEX.js} +3 -3
- package/dist/ui/{styles-HWRPHKTJ.css → styles-RG7Y33BT.css} +1 -1
- package/package.json +1 -1
- package/dist/ui/chunk-BO5IS3EQ.js +0 -123
- package/dist/ui/chunk-FQQYWQV6.js +0 -1
- package/dist/ui/chunk-OYCCFH2S.js +0 -1
- package/dist/ui/chunk-WWHD2PMO.js +0 -2349
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// cli/entry.ts
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1a42a4ca-6765-5a66-abc9-6b57464bc9c6")}catch(e){}}();
|
|
4
4
|
import { existsSync as existsSync33 } from "fs";
|
|
5
5
|
import { Builtins, Cli as Cli2 } from "clipanion";
|
|
6
6
|
|
|
@@ -246,7 +246,7 @@ function bucketByKind(kind, instance, bag) {
|
|
|
246
246
|
// package.json
|
|
247
247
|
var package_default = {
|
|
248
248
|
name: "@skill-map/cli",
|
|
249
|
-
version: "0.
|
|
249
|
+
version: "0.51.0",
|
|
250
250
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
251
251
|
license: "MIT",
|
|
252
252
|
type: "module",
|
|
@@ -2865,11 +2865,13 @@ function isPathStyleLink(link) {
|
|
|
2865
2865
|
// plugins/core/analyzers/reference-redundant/text.ts
|
|
2866
2866
|
var REFERENCE_REDUNDANT_TEXTS = {
|
|
2867
2867
|
/**
|
|
2868
|
-
* Multi-form / multi-occurrence reference message.
|
|
2869
|
-
*
|
|
2870
|
-
*
|
|
2868
|
+
* Multi-form / multi-occurrence reference message. Short and direct:
|
|
2869
|
+
* names the duplicated target + count and lists each occurrence
|
|
2870
|
+
* (trigger + line) so the operator sees the offending spots at a
|
|
2871
|
+
* glance. The source node is the finding's own node, so it is not
|
|
2872
|
+
* repeated here.
|
|
2871
2873
|
*/
|
|
2872
|
-
message: "
|
|
2874
|
+
message: "Duplicate reference to {{resolvedTarget}} ({{count}} occurrences): {{occurrences}}.",
|
|
2873
2875
|
/** Inline separator between occurrences in the message. */
|
|
2874
2876
|
occurrenceSeparator: ", ",
|
|
2875
2877
|
/** Per-occurrence formatting (trigger + line). */
|
|
@@ -3985,7 +3987,7 @@ var nodeSupersedeAction = {
|
|
|
3985
3987
|
}
|
|
3986
3988
|
};
|
|
3987
3989
|
|
|
3988
|
-
//
|
|
3990
|
+
// kernel/update-check/index.ts
|
|
3989
3991
|
var SEMVER_SHAPE_RE = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
3990
3992
|
async function fetchLatestVersion(pkg, opts) {
|
|
3991
3993
|
const controller = new AbortController();
|
|
@@ -4120,9 +4122,9 @@ function ansiFor(opts) {
|
|
|
4120
4122
|
import { randomUUID } from "crypto";
|
|
4121
4123
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "fs";
|
|
4122
4124
|
import { homedir } from "os";
|
|
4123
|
-
import { join as
|
|
4125
|
+
import { join as join3 } from "path";
|
|
4124
4126
|
|
|
4125
|
-
//
|
|
4127
|
+
// kernel/util/atomic-write.ts
|
|
4126
4128
|
import {
|
|
4127
4129
|
closeSync,
|
|
4128
4130
|
constants as fsConstants,
|
|
@@ -4180,17 +4182,31 @@ function writeJsonAtomic(path, content) {
|
|
|
4180
4182
|
}
|
|
4181
4183
|
|
|
4182
4184
|
// core/paths/db-path.ts
|
|
4183
|
-
import { join, resolve as resolve6 } from "path";
|
|
4185
|
+
import { join as join2, resolve as resolve6 } from "path";
|
|
4186
|
+
|
|
4187
|
+
// kernel/util/skill-map-paths.ts
|
|
4188
|
+
import { join } from "path";
|
|
4184
4189
|
var SKILL_MAP_DIR = ".skill-map";
|
|
4190
|
+
var KERNEL_SKILL_MAP_DIR = SKILL_MAP_DIR;
|
|
4191
|
+
var SETTINGS_FILENAME = "settings.json";
|
|
4192
|
+
var LOCAL_SETTINGS_FILENAME = "settings.local.json";
|
|
4193
|
+
function kernelSettingsPath(scopeRoot) {
|
|
4194
|
+
return join(scopeRoot, KERNEL_SKILL_MAP_DIR, SETTINGS_FILENAME);
|
|
4195
|
+
}
|
|
4196
|
+
function kernelLocalSettingsPath(scopeRoot) {
|
|
4197
|
+
return join(scopeRoot, KERNEL_SKILL_MAP_DIR, LOCAL_SETTINGS_FILENAME);
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
// core/paths/db-path.ts
|
|
4185
4201
|
var DB_FILENAME = "skill-map.db";
|
|
4186
4202
|
var JOBS_DIRNAME = "jobs";
|
|
4187
4203
|
var PLUGINS_DIRNAME = "plugins";
|
|
4188
|
-
var
|
|
4189
|
-
var
|
|
4204
|
+
var SETTINGS_FILENAME2 = "settings.json";
|
|
4205
|
+
var LOCAL_SETTINGS_FILENAME2 = "settings.local.json";
|
|
4190
4206
|
var IGNORE_FILENAME = ".skillmapignore";
|
|
4191
4207
|
var DEFAULT_DB_REL = `${SKILL_MAP_DIR}/${DB_FILENAME}`;
|
|
4192
4208
|
var GITIGNORE_ENTRIES = [
|
|
4193
|
-
`${SKILL_MAP_DIR}/${
|
|
4209
|
+
`${SKILL_MAP_DIR}/${LOCAL_SETTINGS_FILENAME2}`,
|
|
4194
4210
|
`${SKILL_MAP_DIR}/${DB_FILENAME}`
|
|
4195
4211
|
];
|
|
4196
4212
|
function resolveDbPath(options) {
|
|
@@ -4207,23 +4223,23 @@ function defaultProjectPluginsDir(ctx) {
|
|
|
4207
4223
|
return resolve6(ctx.cwd, SKILL_MAP_DIR, PLUGINS_DIRNAME);
|
|
4208
4224
|
}
|
|
4209
4225
|
function defaultDbPath(scopeRoot) {
|
|
4210
|
-
return
|
|
4226
|
+
return join2(scopeRoot, SKILL_MAP_DIR, DB_FILENAME);
|
|
4211
4227
|
}
|
|
4212
4228
|
function defaultSettingsPath(scopeRoot) {
|
|
4213
|
-
return
|
|
4229
|
+
return join2(scopeRoot, SKILL_MAP_DIR, SETTINGS_FILENAME2);
|
|
4214
4230
|
}
|
|
4215
4231
|
function defaultLocalSettingsPath(scopeRoot) {
|
|
4216
|
-
return
|
|
4232
|
+
return join2(scopeRoot, SKILL_MAP_DIR, LOCAL_SETTINGS_FILENAME2);
|
|
4217
4233
|
}
|
|
4218
4234
|
function defaultIgnoreFilePath(scopeRoot) {
|
|
4219
|
-
return
|
|
4235
|
+
return join2(scopeRoot, IGNORE_FILENAME);
|
|
4220
4236
|
}
|
|
4221
4237
|
|
|
4222
4238
|
// cli/util/user-settings-store.ts
|
|
4223
4239
|
var FILENAME = "settings.json";
|
|
4224
4240
|
var SCHEMA_VERSION = 1;
|
|
4225
4241
|
function userSettingsFilePath() {
|
|
4226
|
-
return
|
|
4242
|
+
return join3(homedir(), SKILL_MAP_DIR, FILENAME);
|
|
4227
4243
|
}
|
|
4228
4244
|
function defaultSettings() {
|
|
4229
4245
|
return { schemaVersion: SCHEMA_VERSION, updateCheck: {}, telemetry: {} };
|
|
@@ -4262,7 +4278,7 @@ function backfillSubObjects(settings) {
|
|
|
4262
4278
|
};
|
|
4263
4279
|
}
|
|
4264
4280
|
function writeUserSettings(patch) {
|
|
4265
|
-
const dir =
|
|
4281
|
+
const dir = join3(homedir(), SKILL_MAP_DIR);
|
|
4266
4282
|
const path = userSettingsFilePath();
|
|
4267
4283
|
try {
|
|
4268
4284
|
const current = readUserSettings();
|
|
@@ -5359,18 +5375,6 @@ var CONFIG_LOADER_TEXTS = {
|
|
|
5359
5375
|
projectLocalOnlyStripped: "[config:{{layer}}] key {{key}} is project-local only; stripped from the committed project layer. Move it to .skill-map/settings.local.json (gitignored, per-checkout)."
|
|
5360
5376
|
};
|
|
5361
5377
|
|
|
5362
|
-
// kernel/util/skill-map-paths.ts
|
|
5363
|
-
import { join as join3 } from "path";
|
|
5364
|
-
var KERNEL_SKILL_MAP_DIR = SKILL_MAP_DIR;
|
|
5365
|
-
var SETTINGS_FILENAME2 = "settings.json";
|
|
5366
|
-
var LOCAL_SETTINGS_FILENAME2 = "settings.local.json";
|
|
5367
|
-
function kernelSettingsPath(scopeRoot) {
|
|
5368
|
-
return join3(scopeRoot, KERNEL_SKILL_MAP_DIR, SETTINGS_FILENAME2);
|
|
5369
|
-
}
|
|
5370
|
-
function kernelLocalSettingsPath(scopeRoot) {
|
|
5371
|
-
return join3(scopeRoot, KERNEL_SKILL_MAP_DIR, LOCAL_SETTINGS_FILENAME2);
|
|
5372
|
-
}
|
|
5373
|
-
|
|
5374
5378
|
// config/defaults.json
|
|
5375
5379
|
var defaults_default = {
|
|
5376
5380
|
schemaVersion: 1,
|
|
@@ -5828,11 +5832,20 @@ var FilesystemSidecarStore = class {
|
|
|
5828
5832
|
* files in the repo and entries are tiny).
|
|
5829
5833
|
*/
|
|
5830
5834
|
#locks = /* @__PURE__ */ new Map();
|
|
5835
|
+
/** Injected consent gate, see {@link TSidecarConsentGate}. */
|
|
5836
|
+
#consentGate;
|
|
5837
|
+
/**
|
|
5838
|
+
* @param consentGate the write-consent gate, invoked first inside
|
|
5839
|
+
* `applyPatch`. Production wires
|
|
5840
|
+
* `core/config/sidecar-consent.ts:ensureSidecarWritesAllowed`; tests
|
|
5841
|
+
* wire the same function (to exercise the real config-backed gate)
|
|
5842
|
+
* or a stub.
|
|
5843
|
+
*/
|
|
5844
|
+
constructor(consentGate) {
|
|
5845
|
+
this.#consentGate = consentGate;
|
|
5846
|
+
}
|
|
5831
5847
|
async applyPatch(sidecarAbsPath, changes, consent) {
|
|
5832
|
-
|
|
5833
|
-
confirm: consent.confirm,
|
|
5834
|
-
cwd: consent.cwd
|
|
5835
|
-
});
|
|
5848
|
+
this.#consentGate(consent);
|
|
5836
5849
|
const prev = this.#locks.get(sidecarAbsPath) ?? Promise.resolve();
|
|
5837
5850
|
let release;
|
|
5838
5851
|
const settled = new Promise((res) => {
|
|
@@ -7856,7 +7869,7 @@ function rowToContribution(row) {
|
|
|
7856
7869
|
};
|
|
7857
7870
|
}
|
|
7858
7871
|
|
|
7859
|
-
//
|
|
7872
|
+
// kernel/adapters/sqlite/schema-fingerprint.ts
|
|
7860
7873
|
import { createHash } from "crypto";
|
|
7861
7874
|
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
7862
7875
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
@@ -9332,7 +9345,7 @@ var BumpCommand = class extends SmCommand {
|
|
|
9332
9345
|
* the staging missed).
|
|
9333
9346
|
*/
|
|
9334
9347
|
async #executePending(plan, cwd, ansi) {
|
|
9335
|
-
const store = new FilesystemSidecarStore();
|
|
9348
|
+
const store = new FilesystemSidecarStore(ensureSidecarWritesAllowed);
|
|
9336
9349
|
const ctx = defaultRuntimeContext();
|
|
9337
9350
|
const consent = {
|
|
9338
9351
|
confirm: this.yes,
|
|
@@ -9478,7 +9491,7 @@ function buildBumpedOutcome(item, sidecarPath) {
|
|
|
9478
9491
|
if (item.report.createdSidecar === true) outcome.createdSidecar = true;
|
|
9479
9492
|
return outcome;
|
|
9480
9493
|
}
|
|
9481
|
-
async function applyBumpWrites(item, consent, store = new FilesystemSidecarStore()) {
|
|
9494
|
+
async function applyBumpWrites(item, consent, store = new FilesystemSidecarStore(ensureSidecarWritesAllowed)) {
|
|
9482
9495
|
let sidecarPath;
|
|
9483
9496
|
try {
|
|
9484
9497
|
for (const w of item.writes) {
|
|
@@ -11421,20 +11434,9 @@ function trimRedundantPath(message, primary) {
|
|
|
11421
11434
|
import { existsSync as existsSync16 } from "fs";
|
|
11422
11435
|
import { Command as Command4, Option as Option4 } from "clipanion";
|
|
11423
11436
|
|
|
11424
|
-
//
|
|
11437
|
+
// kernel/scan/detect-providers.ts
|
|
11425
11438
|
import { existsSync as existsSync15 } from "fs";
|
|
11426
11439
|
import { join as join10 } from "path";
|
|
11427
|
-
function resolveActiveProvider(cwd, providers = []) {
|
|
11428
|
-
const detected = detectProvidersFromFilesystem(cwd, providers);
|
|
11429
|
-
const fromConfig = readConfigValue("activeProvider", { cwd });
|
|
11430
|
-
if (typeof fromConfig === "string" && fromConfig.length > 0) {
|
|
11431
|
-
return { resolved: fromConfig, source: "config", detected };
|
|
11432
|
-
}
|
|
11433
|
-
if (detected.length > 0) {
|
|
11434
|
-
return { resolved: detected[0], source: "autodetect", detected };
|
|
11435
|
-
}
|
|
11436
|
-
return { resolved: null, source: "none", detected };
|
|
11437
|
-
}
|
|
11438
11440
|
function detectProvidersFromFilesystem(cwd, providers) {
|
|
11439
11441
|
const seen = /* @__PURE__ */ new Set();
|
|
11440
11442
|
const out = [];
|
|
@@ -11449,6 +11451,19 @@ function detectProvidersFromFilesystem(cwd, providers) {
|
|
|
11449
11451
|
return out;
|
|
11450
11452
|
}
|
|
11451
11453
|
|
|
11454
|
+
// core/config/active-provider.ts
|
|
11455
|
+
function resolveActiveProvider(cwd, providers = []) {
|
|
11456
|
+
const detected = detectProvidersFromFilesystem(cwd, providers);
|
|
11457
|
+
const fromConfig = readConfigValue("activeProvider", { cwd });
|
|
11458
|
+
if (typeof fromConfig === "string" && fromConfig.length > 0) {
|
|
11459
|
+
return { resolved: fromConfig, source: "config", detected };
|
|
11460
|
+
}
|
|
11461
|
+
if (detected.length > 0) {
|
|
11462
|
+
return { resolved: detected[0], source: "autodetect", detected };
|
|
11463
|
+
}
|
|
11464
|
+
return { resolved: null, source: "none", detected };
|
|
11465
|
+
}
|
|
11466
|
+
|
|
11452
11467
|
// cli/util/path-display.ts
|
|
11453
11468
|
import { isAbsolute as isAbsolute4, relative as pathRelative } from "path";
|
|
11454
11469
|
function relativeIfBelow(path, cwd) {
|
|
@@ -16980,7 +16995,7 @@ function resolveActiveProviderOption(optionValue, roots, providers) {
|
|
|
16980
16995
|
for (const root of roots) {
|
|
16981
16996
|
const absRoot = isAbsolute7(root) ? root : resolve28(root);
|
|
16982
16997
|
if (!existsSync23(absRoot)) continue;
|
|
16983
|
-
const detected =
|
|
16998
|
+
const detected = detectProvidersFromFilesystem(absRoot, providers)[0] ?? null;
|
|
16984
16999
|
if (detected !== null) return detected;
|
|
16985
17000
|
}
|
|
16986
17001
|
return null;
|
|
@@ -22270,7 +22285,7 @@ var IntentionalFailCommand = class extends SmCommand {
|
|
|
22270
22285
|
throw new Error(INTENTIONAL_FAIL_TEXTS.errorMessage);
|
|
22271
22286
|
}, 0);
|
|
22272
22287
|
await new Promise((resolve40) => setTimeout(resolve40, 5e3));
|
|
22273
|
-
return
|
|
22288
|
+
return ExitCode.Issues;
|
|
22274
22289
|
}
|
|
22275
22290
|
};
|
|
22276
22291
|
|
|
@@ -22339,6 +22354,25 @@ var SCAN_TEXTS = {
|
|
|
22339
22354
|
persistedTo: " {{dbPath}}\n",
|
|
22340
22355
|
/** Body line for dry-run mode, same indent, marker tail. */
|
|
22341
22356
|
wouldPersist: " would persist to {{dbPath}} (dry-run)\n",
|
|
22357
|
+
/**
|
|
22358
|
+
* Count-row nouns for the `{{counts}}` block in `scannedSummary`.
|
|
22359
|
+
* The caller selects the singular / plural form on `count === 1`
|
|
22360
|
+
* (English plural rule), so both forms live in the catalog instead of
|
|
22361
|
+
* being hand-suffixed with `s` at the call site (per the i18n
|
|
22362
|
+
* contract: catalog strings, no `${word}s` interpolation). `info` is
|
|
22363
|
+
* uncountable in English (no `infos`), so it carries a single form;
|
|
22364
|
+
* `countNoIssues` is the all-clean placeholder.
|
|
22365
|
+
*/
|
|
22366
|
+
countNodeNounSingular: "node",
|
|
22367
|
+
countNodeNounPlural: "nodes",
|
|
22368
|
+
countLinkNounSingular: "link",
|
|
22369
|
+
countLinkNounPlural: "links",
|
|
22370
|
+
countErrorNounSingular: "error",
|
|
22371
|
+
countErrorNounPlural: "errors",
|
|
22372
|
+
countWarningNounSingular: "warning",
|
|
22373
|
+
countWarningNounPlural: "warnings",
|
|
22374
|
+
countInfoNoun: "info",
|
|
22375
|
+
countNoIssues: "0 issues",
|
|
22342
22376
|
/**
|
|
22343
22377
|
* Cap-hit notice, printed when the walker stopped accepting nodes
|
|
22344
22378
|
* because `--max-nodes` (or the `scan.maxNodes` setting) was reached.
|
|
@@ -23420,27 +23454,29 @@ function fillSeverityBucket(bucket, nodeIds) {
|
|
|
23420
23454
|
function formatScanCounts(opts) {
|
|
23421
23455
|
const { nodes, links, severities, ansi } = opts;
|
|
23422
23456
|
const parts = [
|
|
23423
|
-
`${nodes} ${
|
|
23424
|
-
`${links} ${
|
|
23457
|
+
`${nodes} ${countNoun(nodes, SCAN_TEXTS.countNodeNounSingular, SCAN_TEXTS.countNodeNounPlural)}`,
|
|
23458
|
+
`${links} ${countNoun(links, SCAN_TEXTS.countLinkNounSingular, SCAN_TEXTS.countLinkNounPlural)}`
|
|
23425
23459
|
];
|
|
23426
23460
|
const total = severities.errors + severities.warns + severities.info;
|
|
23427
23461
|
if (total === 0) {
|
|
23428
|
-
parts.push(ansi.dim(
|
|
23462
|
+
parts.push(ansi.dim(SCAN_TEXTS.countNoIssues));
|
|
23429
23463
|
} else {
|
|
23430
23464
|
if (severities.errors > 0) {
|
|
23431
|
-
|
|
23465
|
+
const noun = countNoun(severities.errors, SCAN_TEXTS.countErrorNounSingular, SCAN_TEXTS.countErrorNounPlural);
|
|
23466
|
+
parts.push(ansi.red(`${severities.errors} ${noun}`));
|
|
23432
23467
|
}
|
|
23433
23468
|
if (severities.warns > 0) {
|
|
23434
|
-
|
|
23469
|
+
const noun = countNoun(severities.warns, SCAN_TEXTS.countWarningNounSingular, SCAN_TEXTS.countWarningNounPlural);
|
|
23470
|
+
parts.push(ansi.yellow(`${severities.warns} ${noun}`));
|
|
23435
23471
|
}
|
|
23436
23472
|
if (severities.info > 0) {
|
|
23437
|
-
parts.push(ansi.dim(`${severities.info}
|
|
23473
|
+
parts.push(ansi.dim(`${severities.info} ${SCAN_TEXTS.countInfoNoun}`));
|
|
23438
23474
|
}
|
|
23439
23475
|
}
|
|
23440
23476
|
return parts.join(" \xB7 ");
|
|
23441
23477
|
}
|
|
23442
|
-
function
|
|
23443
|
-
return count === 1 ?
|
|
23478
|
+
function countNoun(count, singular, plural) {
|
|
23479
|
+
return count === 1 ? singular : plural;
|
|
23444
23480
|
}
|
|
23445
23481
|
|
|
23446
23482
|
// cli/commands/scan-compare.ts
|
|
@@ -23886,11 +23922,10 @@ var SERVER_TEXTS = {
|
|
|
23886
23922
|
// here (after static + SPA fallback have had their turn).
|
|
23887
23923
|
unknownPath: "Not found: {{path}}.",
|
|
23888
23924
|
// ---- sidecar bump route (routes/sidecar.ts) ------------------------------
|
|
23889
|
-
// 409 refusal when a fresh node is bumped without `force`.
|
|
23890
|
-
// `sidecar-fresh
|
|
23891
|
-
//
|
|
23892
|
-
//
|
|
23893
|
-
// affinity with the CLI's bump verb).
|
|
23925
|
+
// 409 refusal when a fresh node is bumped without `force`. Dispatch
|
|
23926
|
+
// is via the typed `ConflictError` (`code: 'sidecar-fresh'`), so the
|
|
23927
|
+
// `sidecar-fresh:` prefix is NOT load-bearing; it stays only for
|
|
23928
|
+
// log-grep affinity with the CLI's bump verb.
|
|
23894
23929
|
sidecarFreshRefusal: "sidecar-fresh: Node is fresh; pass force:true to bump anyway.",
|
|
23895
23930
|
// 400 envelopes thrown by `parseBody` when the request payload is
|
|
23896
23931
|
// malformed. Each branch has its own key so the UI / log can
|
|
@@ -23918,9 +23953,9 @@ var SERVER_TEXTS = {
|
|
|
23918
23953
|
// dropped half the pipeline. Same gate the `?fresh=1` GET applies.
|
|
23919
23954
|
scanPostRequiresFullPipeline: "POST /api/scan cannot run while the server was started with --no-built-ins or --no-plugins (would persist a partial DB).",
|
|
23920
23955
|
// 409, another scan (watcher batch or another POST) is in flight.
|
|
23921
|
-
//
|
|
23922
|
-
// `scan-busy
|
|
23923
|
-
//
|
|
23956
|
+
// Dispatch is via the typed `ConflictError` (`code: 'scan-busy'`), so
|
|
23957
|
+
// the `scan-busy:` prefix is NOT load-bearing; it stays only for
|
|
23958
|
+
// log-grep affinity with the CLI's `sm scan` verb.
|
|
23924
23959
|
scanPostBusy: "scan-busy: Another scan is already in flight; retry once it finishes.",
|
|
23925
23960
|
// 500, DB missing on a write path. Read paths degrade to empty
|
|
23926
23961
|
// shapes; mutations cannot persist without a DB so they fail fast.
|
|
@@ -24533,6 +24568,7 @@ function registerHealthRoute(app, deps) {
|
|
|
24533
24568
|
var DEFAULT_LIMIT = 100;
|
|
24534
24569
|
var MAX_LIMIT = 1e3;
|
|
24535
24570
|
var BFF_MAX_BULK_CONTRIBUTIONS = 200;
|
|
24571
|
+
var MAX_WS_CLIENTS = 64;
|
|
24536
24572
|
|
|
24537
24573
|
// server/routes/issues.ts
|
|
24538
24574
|
function registerIssuesRoute(app, deps) {
|
|
@@ -24765,7 +24801,7 @@ function registerNodesRoutes(app, deps) {
|
|
|
24765
24801
|
const tags = result?.tags ?? [];
|
|
24766
24802
|
if (!bundle) {
|
|
24767
24803
|
throw new HTTPException7(404, {
|
|
24768
|
-
message: tx(SERVER_TEXTS.nodeNotFound, { path: nodePath })
|
|
24804
|
+
message: tx(SERVER_TEXTS.nodeNotFound, { path: sanitizeForTerminal(nodePath) })
|
|
24769
24805
|
});
|
|
24770
24806
|
}
|
|
24771
24807
|
const decoratedNode = { ...bundle.node, isFavorite, contributions, tags };
|
|
@@ -26055,7 +26091,7 @@ async function runPersistedScan(c, deps) {
|
|
|
26055
26091
|
});
|
|
26056
26092
|
} catch (err) {
|
|
26057
26093
|
if (err instanceof ScanBusyError) {
|
|
26058
|
-
throw new
|
|
26094
|
+
throw new ConflictError({ code: "scan-busy", message: SERVER_TEXTS.scanPostBusy });
|
|
26059
26095
|
}
|
|
26060
26096
|
throw err;
|
|
26061
26097
|
}
|
|
@@ -26248,7 +26284,7 @@ function registerSidecarRoutes(app, deps) {
|
|
|
26248
26284
|
}
|
|
26249
26285
|
const result = invokeBump2(node, absPath, body);
|
|
26250
26286
|
if (result.report.ok === false && result.report.reason === "fresh") {
|
|
26251
|
-
throw new
|
|
26287
|
+
throw new ConflictError({ code: "sidecar-fresh", message: SERVER_TEXTS.sidecarFreshRefusal });
|
|
26252
26288
|
}
|
|
26253
26289
|
if (result.report.ok === true && result.report.noop === true) {
|
|
26254
26290
|
const envelope2 = {
|
|
@@ -26263,7 +26299,7 @@ function registerSidecarRoutes(app, deps) {
|
|
|
26263
26299
|
};
|
|
26264
26300
|
return c.json(envelope2);
|
|
26265
26301
|
}
|
|
26266
|
-
const store = new FilesystemSidecarStore();
|
|
26302
|
+
const store = new FilesystemSidecarStore(ensureSidecarWritesAllowed);
|
|
26267
26303
|
try {
|
|
26268
26304
|
for (const w of result.writes ?? []) {
|
|
26269
26305
|
if (w.kind === "sidecar") {
|
|
@@ -26531,6 +26567,14 @@ var LoopbackGateError = class extends HTTPException16 {
|
|
|
26531
26567
|
this.code = init.code;
|
|
26532
26568
|
}
|
|
26533
26569
|
};
|
|
26570
|
+
var ConflictError = class extends HTTPException16 {
|
|
26571
|
+
code;
|
|
26572
|
+
constructor(init) {
|
|
26573
|
+
super(409, { message: init.message });
|
|
26574
|
+
this.name = "ConflictError";
|
|
26575
|
+
this.code = init.code;
|
|
26576
|
+
}
|
|
26577
|
+
};
|
|
26534
26578
|
function createApp(deps) {
|
|
26535
26579
|
const app = new Hono();
|
|
26536
26580
|
const configService = new ConfigService({
|
|
@@ -26607,16 +26651,12 @@ function createApp(deps) {
|
|
|
26607
26651
|
});
|
|
26608
26652
|
return app;
|
|
26609
26653
|
}
|
|
26610
|
-
function codeForStatus(status
|
|
26654
|
+
function codeForStatus(status) {
|
|
26611
26655
|
if (status === 404) return "not-found";
|
|
26612
26656
|
if (status === 400) return "bad-query";
|
|
26613
26657
|
if (status === 403) return "locked";
|
|
26614
26658
|
if (status === 412) return "confirm-required";
|
|
26615
26659
|
if (status === 413) return "payload-too-large";
|
|
26616
|
-
if (status === 409) {
|
|
26617
|
-
if (message.startsWith("scan-busy:")) return "scan-busy";
|
|
26618
|
-
return "sidecar-fresh";
|
|
26619
|
-
}
|
|
26620
26660
|
return "internal";
|
|
26621
26661
|
}
|
|
26622
26662
|
function formatError2(err, c) {
|
|
@@ -26653,12 +26693,23 @@ function formatError2(err, c) {
|
|
|
26653
26693
|
};
|
|
26654
26694
|
return c.json(envelope, 403);
|
|
26655
26695
|
}
|
|
26696
|
+
if (err instanceof ConflictError) {
|
|
26697
|
+
const envelope = {
|
|
26698
|
+
ok: false,
|
|
26699
|
+
error: {
|
|
26700
|
+
code: err.code,
|
|
26701
|
+
message: err.message,
|
|
26702
|
+
details: null
|
|
26703
|
+
}
|
|
26704
|
+
};
|
|
26705
|
+
return c.json(envelope, 409);
|
|
26706
|
+
}
|
|
26656
26707
|
if (err instanceof HTTPException16) {
|
|
26657
26708
|
const status = err.status;
|
|
26658
26709
|
const envelope = {
|
|
26659
26710
|
ok: false,
|
|
26660
26711
|
error: {
|
|
26661
|
-
code: codeForStatus(status
|
|
26712
|
+
code: codeForStatus(status),
|
|
26662
26713
|
message: err.message,
|
|
26663
26714
|
details: null
|
|
26664
26715
|
}
|
|
@@ -26709,6 +26760,7 @@ function formatInternalErrorFallThrough(err, c) {
|
|
|
26709
26760
|
var MAX_BUFFERED_BYTES = 4 * 1024 * 1024;
|
|
26710
26761
|
var CLOSE_CODE_GOING_AWAY = 1001;
|
|
26711
26762
|
var CLOSE_CODE_MESSAGE_TOO_BIG = 1009;
|
|
26763
|
+
var CLOSE_CODE_TRY_AGAIN_LATER = 1013;
|
|
26712
26764
|
var READY_STATE_OPEN = 1;
|
|
26713
26765
|
var WsBroadcaster = class {
|
|
26714
26766
|
#clients = /* @__PURE__ */ new Set();
|
|
@@ -26731,6 +26783,13 @@ var WsBroadcaster = class {
|
|
|
26731
26783
|
}
|
|
26732
26784
|
return;
|
|
26733
26785
|
}
|
|
26786
|
+
if (this.#clients.size >= MAX_WS_CLIENTS) {
|
|
26787
|
+
try {
|
|
26788
|
+
ws.close(CLOSE_CODE_TRY_AGAIN_LATER, "too many connections");
|
|
26789
|
+
} catch {
|
|
26790
|
+
}
|
|
26791
|
+
return;
|
|
26792
|
+
}
|
|
26734
26793
|
this.#clients.add(ws);
|
|
26735
26794
|
}
|
|
26736
26795
|
/**
|
|
@@ -26977,14 +27036,19 @@ function validatePort(port) {
|
|
|
26977
27036
|
return null;
|
|
26978
27037
|
}
|
|
26979
27038
|
function validateHost(host, devCors) {
|
|
26980
|
-
if (
|
|
27039
|
+
if (isLoopbackHost(host)) return null;
|
|
27040
|
+
if (devCors) {
|
|
26981
27041
|
return {
|
|
26982
27042
|
code: "host-dev-cors-rejected",
|
|
26983
27043
|
message: `--dev-cors requires a loopback --host (got ${host})`,
|
|
26984
27044
|
value: host
|
|
26985
27045
|
};
|
|
26986
27046
|
}
|
|
26987
|
-
return
|
|
27047
|
+
return {
|
|
27048
|
+
code: "host-not-loopback",
|
|
27049
|
+
message: `--host must be a loopback address; multi-host serve is not supported pre-1.0 (got ${host})`,
|
|
27050
|
+
value: host
|
|
27051
|
+
};
|
|
26988
27052
|
}
|
|
26989
27053
|
function validateWatcher(noWatcher, noBuiltIns, _noPlugins) {
|
|
26990
27054
|
if (noWatcher) return null;
|
|
@@ -27272,6 +27336,14 @@ var SERVE_TEXTS = {
|
|
|
27272
27336
|
*/
|
|
27273
27337
|
hostDevCorsRejected: "{{glyph}} sm serve: --dev-cors requires a loopback --host (got {{host}}).\n {{hint}}\n",
|
|
27274
27338
|
hostDevCorsRejectedHint: "Use --host 127.0.0.1 (or ::1) when --dev-cors is set. Multi-host serve reopens after v0.6.0 (Decision #119).",
|
|
27339
|
+
/**
|
|
27340
|
+
* §3.1b error block when `--host` is any non-loopback address (without
|
|
27341
|
+
* `--dev-cors`). The BFF is loopback-only and unauthenticated pre-1.0
|
|
27342
|
+
* (Decision #119), so binding off-loopback is refused outright rather
|
|
27343
|
+
* than relying on the DNS-rebinding gate as the sole control.
|
|
27344
|
+
*/
|
|
27345
|
+
hostNotLoopback: "{{glyph}} sm serve: --host must be a loopback address (got {{host}}).\n {{hint}}\n",
|
|
27346
|
+
hostNotLoopbackHint: "Use --host 127.0.0.1 (or ::1). The server has no auth and is loopback-only; multi-host serve reopens after v0.6.0 (Decision #119).",
|
|
27275
27347
|
/**
|
|
27276
27348
|
* §3.1b error block when `--port` falls outside the [0, 65535] range.
|
|
27277
27349
|
* Hint names the accepted range so the operator can re-run.
|
|
@@ -27820,6 +27892,12 @@ function formatValidationError(err, ansi) {
|
|
|
27820
27892
|
host: sanitizeForTerminal(err.value),
|
|
27821
27893
|
hint: ansi.dim(SERVE_TEXTS.hostDevCorsRejectedHint)
|
|
27822
27894
|
});
|
|
27895
|
+
case "host-not-loopback":
|
|
27896
|
+
return tx(SERVE_TEXTS.hostNotLoopback, {
|
|
27897
|
+
glyph: errGlyph,
|
|
27898
|
+
host: sanitizeForTerminal(err.value),
|
|
27899
|
+
hint: ansi.dim(SERVE_TEXTS.hostNotLoopbackHint)
|
|
27900
|
+
});
|
|
27823
27901
|
case "port-out-of-range":
|
|
27824
27902
|
return tx(SERVE_TEXTS.portOutOfRange, {
|
|
27825
27903
|
glyph: errGlyph,
|
|
@@ -28412,7 +28490,7 @@ var SidecarRefreshCommand = class extends SmCommand {
|
|
|
28412
28490
|
);
|
|
28413
28491
|
return ExitCode.Ok;
|
|
28414
28492
|
}
|
|
28415
|
-
const store = new FilesystemSidecarStore();
|
|
28493
|
+
const store = new FilesystemSidecarStore(ensureSidecarWritesAllowed);
|
|
28416
28494
|
try {
|
|
28417
28495
|
await store.applyPatch(
|
|
28418
28496
|
sidecarAbsPath,
|
|
@@ -28699,7 +28777,7 @@ var SidecarAnnotateCommand = class extends SmCommand {
|
|
|
28699
28777
|
return ExitCode.Error;
|
|
28700
28778
|
}
|
|
28701
28779
|
}
|
|
28702
|
-
const store = new FilesystemSidecarStore();
|
|
28780
|
+
const store = new FilesystemSidecarStore(ensureSidecarWritesAllowed);
|
|
28703
28781
|
try {
|
|
28704
28782
|
await store.applyPatch(
|
|
28705
28783
|
sidecarAbsPath,
|
|
@@ -29488,4 +29566,4 @@ function resolveBareDefault() {
|
|
|
29488
29566
|
process.exit(ExitCode.Error);
|
|
29489
29567
|
}
|
|
29490
29568
|
//# sourceMappingURL=cli.js.map
|
|
29491
|
-
//# debugId=
|
|
29569
|
+
//# debugId=1a42a4ca-6765-5a66-abc9-6b57464bc9c6
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// conformance/index.ts
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cc85d6cc-8968-5fbd-b7b7-eab3d298263d")}catch(e){}}();
|
|
4
4
|
import { spawnSync } from "child_process";
|
|
5
5
|
import { cpSync, existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from "fs";
|
|
6
6
|
import { tmpdir } from "os";
|
|
7
|
-
import { isAbsolute, join as
|
|
7
|
+
import { isAbsolute, join as join2, relative, resolve } from "path";
|
|
8
8
|
|
|
9
9
|
// kernel/util/format-error.ts
|
|
10
10
|
function formatErrorMessage(err) {
|
|
@@ -12,20 +12,8 @@ function formatErrorMessage(err) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// kernel/util/skill-map-paths.ts
|
|
15
|
-
import { join
|
|
16
|
-
|
|
17
|
-
// core/paths/db-path.ts
|
|
18
|
-
import { join, resolve } from "path";
|
|
15
|
+
import { join } from "path";
|
|
19
16
|
var SKILL_MAP_DIR = ".skill-map";
|
|
20
|
-
var DB_FILENAME = "skill-map.db";
|
|
21
|
-
var LOCAL_SETTINGS_FILENAME = "settings.local.json";
|
|
22
|
-
var DEFAULT_DB_REL = `${SKILL_MAP_DIR}/${DB_FILENAME}`;
|
|
23
|
-
var GITIGNORE_ENTRIES = [
|
|
24
|
-
`${SKILL_MAP_DIR}/${LOCAL_SETTINGS_FILENAME}`,
|
|
25
|
-
`${SKILL_MAP_DIR}/${DB_FILENAME}`
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
// kernel/util/skill-map-paths.ts
|
|
29
17
|
var KERNEL_SKILL_MAP_DIR = SKILL_MAP_DIR;
|
|
30
18
|
|
|
31
19
|
// kernel/util/tx.ts
|
|
@@ -127,9 +115,9 @@ function pickSafeEnv(source) {
|
|
|
127
115
|
function runConformanceCase(options) {
|
|
128
116
|
const raw = readFileSync(options.casePath, "utf8");
|
|
129
117
|
const c = JSON.parse(raw);
|
|
130
|
-
const fixturesRoot = options.fixturesRoot ??
|
|
118
|
+
const fixturesRoot = options.fixturesRoot ?? join2(options.specRoot, "conformance", "fixtures");
|
|
131
119
|
const safeId = c.id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 32);
|
|
132
|
-
const scope = mkdtempSync(
|
|
120
|
+
const scope = mkdtempSync(join2(tmpdir(), `sm-conformance-${safeId}-`));
|
|
133
121
|
const setupEnv = disableEnv(c.setup);
|
|
134
122
|
try {
|
|
135
123
|
const priorFailure = runPriorScansSetup(c, options, scope, fixturesRoot, setupEnv);
|
|
@@ -201,9 +189,9 @@ function replaceFixture(scope, fixturesRoot, fixture) {
|
|
|
201
189
|
assertContained(fixturesRoot, fixture, "fixture");
|
|
202
190
|
for (const entry of readdirSync(scope)) {
|
|
203
191
|
if (entry === KERNEL_SKILL_MAP_DIR) continue;
|
|
204
|
-
rmSync(
|
|
192
|
+
rmSync(join2(scope, entry), { recursive: true, force: true });
|
|
205
193
|
}
|
|
206
|
-
const src =
|
|
194
|
+
const src = join2(fixturesRoot, fixture);
|
|
207
195
|
cpSync(src, scope, { recursive: true });
|
|
208
196
|
}
|
|
209
197
|
function assertContained(root, rel, label) {
|
|
@@ -212,7 +200,7 @@ function assertContained(root, rel, label) {
|
|
|
212
200
|
tx(CONFORMANCE_RUNNER_TEXTS.pathMustBeRelative, { label, path: rel, anchor: root })
|
|
213
201
|
);
|
|
214
202
|
}
|
|
215
|
-
const abs =
|
|
203
|
+
const abs = resolve(root, rel);
|
|
216
204
|
const r = relative(root, abs);
|
|
217
205
|
if (r.startsWith("..") || isAbsolute(r)) {
|
|
218
206
|
throw new Error(
|
|
@@ -239,7 +227,7 @@ function evaluateAssertion(a, ctx) {
|
|
|
239
227
|
} catch (err) {
|
|
240
228
|
return { ok: false, type: a.type, reason: formatErrorMessage(err) };
|
|
241
229
|
}
|
|
242
|
-
const abs =
|
|
230
|
+
const abs = resolve(ctx.scope, a.path);
|
|
243
231
|
return existsSync(abs) ? { ok: true, type: a.type } : {
|
|
244
232
|
ok: false,
|
|
245
233
|
type: a.type,
|
|
@@ -253,8 +241,8 @@ function evaluateAssertion(a, ctx) {
|
|
|
253
241
|
} catch (err) {
|
|
254
242
|
return { ok: false, type: a.type, reason: formatErrorMessage(err) };
|
|
255
243
|
}
|
|
256
|
-
const fixturePath =
|
|
257
|
-
const targetPath =
|
|
244
|
+
const fixturePath = join2(ctx.fixturesRoot, a.fixture);
|
|
245
|
+
const targetPath = resolve(ctx.scope, a.path);
|
|
258
246
|
if (!existsSync(targetPath)) {
|
|
259
247
|
return {
|
|
260
248
|
ok: false,
|
|
@@ -415,7 +403,7 @@ function deepEqual(a, b) {
|
|
|
415
403
|
return false;
|
|
416
404
|
}
|
|
417
405
|
function assertSpecRoot(specRoot) {
|
|
418
|
-
const indexPath =
|
|
406
|
+
const indexPath = join2(specRoot, "index.json");
|
|
419
407
|
if (!existsSync(indexPath) || !statSync(indexPath).isFile()) {
|
|
420
408
|
throw new Error(tx(CONFORMANCE_RUNNER_TEXTS.specRootMissingIndex, { specRoot }));
|
|
421
409
|
}
|
|
@@ -425,4 +413,4 @@ export {
|
|
|
425
413
|
runConformanceCase
|
|
426
414
|
};
|
|
427
415
|
//# sourceMappingURL=index.js.map
|
|
428
|
-
//# debugId=
|
|
416
|
+
//# debugId=cc85d6cc-8968-5fbd-b7b7-eab3d298263d
|