blun-king-cli 9.1.597 → 9.1.600
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/CHANGELOG.md +39 -0
- package/README.md +17 -1
- package/agent-spine-plugin/CHANGELOG.md +1 -1
- package/agent-spine-plugin/docs/host-integration.md +1 -15
- package/agent-spine-plugin/docs/preflight-recall.md +1 -1
- package/agent-spine-plugin/scripts/check-install.js +1 -6
- package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
- package/agent-spine-plugin/scripts/release-check.js +2 -3
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
- package/agent-spine-plugin/src/hook.js +40 -40
- package/agent-spine-plugin/src/lib/briefing.js +6 -3
- package/agent-spine-plugin/src/lib/hook-context.js +63 -64
- package/agent-spine-plugin/src/lib/hook-output.js +115 -94
- package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
- package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
- package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
- package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
- package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
- package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
- package/agent-spine-plugin/src/lib/source-roots.js +26 -16
- package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
- package/bin/core-bootstrap.js +18 -10
- package/bin/launcher-mode.js +5 -0
- package/bin/launcher-runtime.js +27 -0
- package/bin/verify-bundled-agent-sources.cjs +28 -2
- package/blun.mjs +798 -143
- package/bundled-agent-sources.json +192 -155
- package/package.json +1 -1
- package/standard-skills/translate-native/README.md +1334 -1
- package/standard-skills/translate-native/SKILL.md +1 -1
- package/standard-skills/translate-native/VERSION +1 -1
- package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
- package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
- package/standard-skills/translate-native/integrations/website_localization.py +234 -10
- package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
- package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
- package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
- package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
- package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
- package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
- package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
- package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
- package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
- package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
- package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
- package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
- package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
- package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
- package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
- package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
- package/standard-skills/translate-native/provenance.json +2 -2
- package/standard-skills/translate-native/references/commercial-localization.md +96 -17
- package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
- package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
- package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/VERSION +1 -1
- package/standard-tools/language-guard/blun_language_guard.py +3 -1
- package/standard-tools/language-guard/check_commercial_review.py +69 -9
- package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/provenance.json +2 -2
- package/standard-tools/manifest.json +1 -1
- package/worker-host.mjs +215 -82
- package/agent-spine-plugin/scripts/check-install-king.js +0 -37
|
@@ -8,7 +8,7 @@ import { isFileLockContention, replaceFileWithRetry } from "./filesystem-retry.j
|
|
|
8
8
|
import { purgeIndexedMemoryCache, resolveIndexedMemory } from "./indexed-memory.js";
|
|
9
9
|
import { hookMemoryQuery, loadLessonRecallSelection, rememberLessonRecallSelection } from "./lesson-recall-session.js";
|
|
10
10
|
import { catalogScanPolicy } from "./catalog.js";
|
|
11
|
-
import { isKingHost,
|
|
11
|
+
import { isKingHost, KING_SOURCE_BYTES } from "./host-instruction-budget.js";
|
|
12
12
|
import {
|
|
13
13
|
SOURCE_SCAN_INCOMPLETE, boundedMarkdownTree, existingDirectory, existingRegular, sourceScanError
|
|
14
14
|
} from "./source-tree-scan.js";
|
|
@@ -25,6 +25,20 @@ const SOURCE_RESOLUTION_MS = 2000;
|
|
|
25
25
|
const SAFE_NAME = /^[A-Za-z0-9._-]{1,128}$/;
|
|
26
26
|
|
|
27
27
|
function digest(value) { return createHash("sha256").update(value).digest("hex"); }
|
|
28
|
+
async function partitionSources(sources, env) {
|
|
29
|
+
if (!isKingHost(env)) return { sources, unverified: [] };
|
|
30
|
+
const loaded = [], unverified = []; let used = 0;
|
|
31
|
+
for (const source of sources) {
|
|
32
|
+
if (!source.id.startsWith("codex:")) { loaded.push(source); continue; }
|
|
33
|
+
const bytes = (await lstat(source.path)).size, limit = source.maxBytes || KING_SOURCE_BYTES;
|
|
34
|
+
const total = bytes <= limit && used + bytes > MAX_TOTAL_SOURCE_BYTES;
|
|
35
|
+
if (bytes <= limit && !total) { loaded.push(source); used += bytes; continue; }
|
|
36
|
+
const ceiling = total ? MAX_TOTAL_SOURCE_BYTES : limit;
|
|
37
|
+
const message = `King rule ${source.id} (${bytes} bytes) exceeds AgentSpine's ${ceiling}-byte ${total ? "total " : ""}reader budget; AgentSpine did not load or verify it. Native rules apply. Continue; no retry.`;
|
|
38
|
+
unverified.push({ id: source.id, path: source.path, bytes, message });
|
|
39
|
+
}
|
|
40
|
+
return { sources: loaded, unverified };
|
|
41
|
+
}
|
|
28
42
|
function registryPath(env = process.env) { return join(stateRoot(env), "source-roots.json"); }
|
|
29
43
|
function emptyRegistry() { return { schema: SOURCE_REGISTRY_SCHEMA, revision: 0, bindings: [], history: [] }; }
|
|
30
44
|
|
|
@@ -354,7 +368,7 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
354
368
|
const { registry } = await readRegistry(env);
|
|
355
369
|
let hostHome;
|
|
356
370
|
let projectRoot;
|
|
357
|
-
let sources;
|
|
371
|
+
let sources, unverified;
|
|
358
372
|
let skipped = [];
|
|
359
373
|
let hostDetails = {};
|
|
360
374
|
let rootResolution = "explicit-root";
|
|
@@ -362,7 +376,7 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
362
376
|
const codexHome = isKingHost(env) ? env.BLUN_HOME : env.CODEX_HOME || env.BLUN_HOME || join(homedir(), ".codex");
|
|
363
377
|
hostHome = await existingDirectory(resolve(codexHome)) || resolve(codexHome);
|
|
364
378
|
const config = await codexConfig(hostHome);
|
|
365
|
-
if (isKingHost(env)) config.maxBytes =
|
|
379
|
+
if (isKingHost(env)) config.maxBytes = KING_SOURCE_BYTES;
|
|
366
380
|
if (env.AGENTSPINE_ROOT) projectRoot = await canonicalPath(env.AGENTSPINE_ROOT);
|
|
367
381
|
else ({ root: projectRoot, resolution: rootResolution } = await findRoot(canonicalCwd, config.rootMarkers));
|
|
368
382
|
sources = await codexSources({ cwd: canonicalCwd, projectRoot, codexHome: hostHome, config });
|
|
@@ -378,7 +392,6 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
378
392
|
hostDetails = { memoryRoot: result.memoryRoot, memoryProvenance: result.memoryProvenance,
|
|
379
393
|
memoryDiagnostics: result.memoryDiagnostics };
|
|
380
394
|
} else {
|
|
381
|
-
// Generic hosts get project sources, never another provider's profile.
|
|
382
395
|
hostHome = await canonicalPath(homedir());
|
|
383
396
|
if (env.AGENTSPINE_ROOT) projectRoot = await canonicalPath(env.AGENTSPINE_ROOT);
|
|
384
397
|
else ({ root: projectRoot, resolution: rootResolution } = await findRoot(canonicalCwd, [".git"]));
|
|
@@ -394,6 +407,7 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
394
407
|
}
|
|
395
408
|
sources = [...new Map(sources.map((item) => [item.path, item])).values()];
|
|
396
409
|
if (sources.length > MAX_SOURCES) throw new Error(`host-native required source set exceeds ${MAX_SOURCES} files`);
|
|
410
|
+
({ sources, unverified } = await partitionSources(sources, env));
|
|
397
411
|
const nativeNames = new Set(host === "codex"
|
|
398
412
|
? ["AGENTS.override.md", "AGENTS.md", ...(hostDetails.fallbackNames || [])]
|
|
399
413
|
: host === "claude" ? ["CLAUDE.md", "CLAUDE.local.md"] : ["AGENTS.md", "SOUL.md", "MEMORY.md"]);
|
|
@@ -410,10 +424,6 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
410
424
|
}
|
|
411
425
|
sources = [...new Map(sources.map((item) => [item.path, item])).values()];
|
|
412
426
|
if (sources.length > MAX_SOURCES) throw new Error(`host-native source set exceeds ${MAX_SOURCES} files`);
|
|
413
|
-
const projectScanIncomplete = skipped.some((item) => item.code === SOURCE_SCAN_INCOMPLETE);
|
|
414
|
-
if (Date.now() > deadline && !projectScanIncomplete) {
|
|
415
|
-
throw new Error(`host-native source resolution exceeded ${SOURCE_RESOLUTION_MS} ms`);
|
|
416
|
-
}
|
|
417
427
|
let documents;
|
|
418
428
|
try {
|
|
419
429
|
documents = await indexExplicitDocuments(sources);
|
|
@@ -421,25 +431,25 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
421
431
|
if (typeof error?.code === "string" && (error.path || error.syscall)) throw sourceScanError(error);
|
|
422
432
|
throw error;
|
|
423
433
|
}
|
|
424
|
-
if (Date.now() > deadline && !projectScanIncomplete) {
|
|
425
|
-
throw new Error(`host-native source resolution exceeded ${SOURCE_RESOLUTION_MS} ms`);
|
|
426
|
-
}
|
|
427
434
|
const totalBytes = documents.reduce((sum, document) => sum + document.bytes, 0);
|
|
428
435
|
if (totalBytes > MAX_TOTAL_SOURCE_BYTES) throw new Error("host-native source set exceeds 8 MiB");
|
|
429
436
|
const activeUserState = activeBinding(registry, host, hostHome, projectRoot, "state-user");
|
|
430
437
|
const orderedSkipped = skipped.sort((a, b) => a.path.localeCompare(b.path) || a.operation.localeCompare(b.operation));
|
|
431
438
|
const warnings = orderedSkipped.filter((item) => item.code === SOURCE_SCAN_INCOMPLETE);
|
|
439
|
+
const unverifiedWarning = unverified.length > 1
|
|
440
|
+
? `${unverified.length} King rules exceed AgentSpine reader budgets; none were loaded or verified. Native rules apply. Continue; no retry.`
|
|
441
|
+
: unverified[0]?.message;
|
|
432
442
|
const diagnostics = {
|
|
433
|
-
schema: SOURCE_REGISTRY_SCHEMA, host, status: documents.length ? "loaded" : "empty", projectRoot,
|
|
443
|
+
schema: SOURCE_REGISTRY_SCHEMA, host, status: unverified.length ? "incomplete" : documents.length ? "loaded" : "empty", projectRoot,
|
|
434
444
|
hostHomeDigest: digest(hostHome).slice(0, 16), checked: ["host-profile", "project-chain", ...(host === "claude" ? ["project-memory"] : [])],
|
|
435
445
|
scopes: Object.fromEntries(["user", "project", "project-memory"].map((scope) => [scope, documents.filter((item) => item.sourceScope === scope).length])),
|
|
436
|
-
reason: documents.length ? null : "No regular, non-symlink host-native Markdown source exists in the checked scope.",
|
|
446
|
+
reason: unverifiedWarning || (documents.length ? null : "No regular, non-symlink host-native Markdown source exists in the checked scope."),
|
|
437
447
|
personalContinuityLoaded: documents.some((item) => item.sourceScope === "user") || Boolean(activeUserState),
|
|
438
448
|
broadHomeScan: false, projectTreeScan: skippedFallbackHomeTree ? "skipped-unmarked-home"
|
|
439
449
|
: skippedHomeTree ? "skipped-home-root" : skippedProfileTree ? "skipped-profile-root"
|
|
440
450
|
: warnings.length ? "bounded-truncated" : "bounded",
|
|
441
|
-
incomplete:
|
|
442
|
-
warning: warnings[0]?.message || null,
|
|
451
|
+
incomplete: Boolean(unverified.length || warnings.length),
|
|
452
|
+
warning: unverifiedWarning || warnings[0]?.message || null,
|
|
443
453
|
warnings,
|
|
444
454
|
skipped: orderedSkipped,
|
|
445
455
|
rootResolution, registryRevision: registry.revision,
|
|
@@ -460,6 +470,6 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
460
470
|
summary: { total: documents.length, protected: documents.filter((item) => item.protected).length, conflicts: 0,
|
|
461
471
|
byLayer: Object.fromEntries([...new Set(documents.map((item) => item.layer))].sort().map((layer) => [layer, documents.filter((item) => item.layer === layer).length])) }
|
|
462
472
|
};
|
|
463
|
-
return { host, hostHome, projectRoot, cwd: canonicalCwd, catalog, diagnostics,
|
|
473
|
+
return { host, hostHome, projectRoot, cwd: canonicalCwd, catalog, diagnostics, unverified,
|
|
464
474
|
userStateRoot: activeUserState?.sourceRoot || null, memoryRoot: hostDetails.memoryRoot || null };
|
|
465
475
|
}
|
|
@@ -69,7 +69,6 @@ function validateInterpretation(input, value) {
|
|
|
69
69
|
return true;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// Provenance only.
|
|
73
72
|
export function validateUserFeedback(input, value) {
|
|
74
73
|
if (validateInterpretation(input, value)) return;
|
|
75
74
|
if (input.evidenceKind !== KIND && value?.schema !== USER_FEEDBACK_SCHEMA) return;
|
package/bin/core-bootstrap.js
CHANGED
|
@@ -7,12 +7,16 @@ const { pathToFileURL } = require('node:url');
|
|
|
7
7
|
const { acquireSharedRuntimeLease } = require('./update-lease');
|
|
8
8
|
const { installWindowsNodeCrashDump } = require('./windows-node-crash-dump.cjs');
|
|
9
9
|
const { recordRuntimeExit } = require('./runtime-exit-ledger.cjs');
|
|
10
|
+
const { isStandaloneHelpRequest } = require('./launcher-mode');
|
|
10
11
|
|
|
11
12
|
const CORE_LOADED_MESSAGE = 'blun-core-bootstrap-loaded';
|
|
12
13
|
|
|
13
14
|
async function runCoreBootstrap() {
|
|
15
|
+
const informational = isStandaloneHelpRequest(process.argv.slice(2));
|
|
14
16
|
let diagnostics;
|
|
15
|
-
|
|
17
|
+
if (!informational) {
|
|
18
|
+
try { diagnostics = installWindowsNodeCrashDump({ homeDir: process.env.BLUN_HOME }); } catch {}
|
|
19
|
+
}
|
|
16
20
|
const packageRoot = path.resolve(__dirname, '..');
|
|
17
21
|
const mainPath = path.join(packageRoot, 'blun.mjs');
|
|
18
22
|
let leaseResult;
|
|
@@ -25,18 +29,22 @@ async function runCoreBootstrap() {
|
|
|
25
29
|
await import(pathToFileURL(mainPath).href);
|
|
26
30
|
leaseResult.lease.assertOwned();
|
|
27
31
|
} catch (error) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
if (!informational) {
|
|
33
|
+
try {
|
|
34
|
+
if (diagnostics?.enabled) diagnostics.write(error, 'bootstrap-failure');
|
|
35
|
+
else recordRuntimeExit({ homeDir: process.env.BLUN_HOME, source: 'bootstrap',
|
|
36
|
+
kind: 'bootstrap-failure', phase: 'startup', error });
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
33
39
|
try { diagnostics?.dispose(); } catch {}
|
|
34
40
|
try { await leaseResult?.lease?.release(); }
|
|
35
41
|
catch (leaseError) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
if (!informational) {
|
|
43
|
+
try {
|
|
44
|
+
recordRuntimeExit({ homeDir: process.env.BLUN_HOME, source: 'bootstrap',
|
|
45
|
+
kind: 'lease-release-failure', phase: 'cleanup', error: leaseError });
|
|
46
|
+
} catch {}
|
|
47
|
+
}
|
|
40
48
|
}
|
|
41
49
|
throw error;
|
|
42
50
|
}
|
package/bin/launcher-mode.js
CHANGED
|
@@ -75,6 +75,10 @@ function isNpmPackageUpdateRequest(args) {
|
|
|
75
75
|
return command === 'update' || command === 'upgrade';
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
function isStandaloneHelpRequest(args) {
|
|
79
|
+
return Array.isArray(args) && args.length === 1 && (args[0] === '--help' || args[0] === '-h');
|
|
80
|
+
}
|
|
81
|
+
|
|
78
82
|
function launcherHelpText() {
|
|
79
83
|
return LAUNCHER_HELP_TEXT;
|
|
80
84
|
}
|
|
@@ -83,6 +87,7 @@ module.exports = {
|
|
|
83
87
|
LAUNCHER_MODES,
|
|
84
88
|
createLauncherEnvironment,
|
|
85
89
|
isNpmPackageUpdateRequest,
|
|
90
|
+
isStandaloneHelpRequest,
|
|
86
91
|
launcherHelpText,
|
|
87
92
|
launcherModeFromArgv,
|
|
88
93
|
};
|
package/bin/launcher-runtime.js
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
LAUNCHER_MODES,
|
|
13
13
|
createLauncherEnvironment,
|
|
14
14
|
isNpmPackageUpdateRequest,
|
|
15
|
+
isStandaloneHelpRequest,
|
|
15
16
|
launcherHelpText,
|
|
16
17
|
launcherModeFromArgv,
|
|
17
18
|
} = require('./launcher-mode');
|
|
@@ -28,6 +29,7 @@ const {
|
|
|
28
29
|
} = require('./launcher-restart-policy.cjs');
|
|
29
30
|
const { recordRuntimeExit } = require('./runtime-exit-ledger.cjs');
|
|
30
31
|
const { prepareManagedNodeRuntime } = require('./node-runtime');
|
|
32
|
+
const { unsupportedNodeMessage } = require('./node-version');
|
|
31
33
|
const { repairConfiguredNativeModules } = require('./native-module-repair');
|
|
32
34
|
const { acquireSharedRuntimeLease, tryAcquireUpdateLease } = require('./update-lease');
|
|
33
35
|
const { runExplicitUpdate, runUpdateNotice } = require('./update-notice');
|
|
@@ -160,6 +162,15 @@ function spawnProtectedCore(args, env, cwd) {
|
|
|
160
162
|
return { child, completed, loaded };
|
|
161
163
|
}
|
|
162
164
|
|
|
165
|
+
async function runInformationalCore(args, env, cwd, releaseNotice) {
|
|
166
|
+
const core = spawnProtectedCore(args, env, cwd);
|
|
167
|
+
await core.loaded;
|
|
168
|
+
await releaseNotice();
|
|
169
|
+
const result = await core.completed;
|
|
170
|
+
if (result.error) throw result.error;
|
|
171
|
+
return Number.isInteger(result.code) ? result.code : exitCodeForChild(result, false);
|
|
172
|
+
}
|
|
173
|
+
|
|
163
174
|
async function superviseProtectedCore(args, env, cwd, releaseNotice) {
|
|
164
175
|
let noticeReleased = false;
|
|
165
176
|
for (;;) {
|
|
@@ -347,6 +358,22 @@ async function runLauncher(options = {}) {
|
|
|
347
358
|
return;
|
|
348
359
|
}
|
|
349
360
|
|
|
361
|
+
if (isStandaloneHelpRequest(ARGS)) {
|
|
362
|
+
const compatibilityError = unsupportedNodeMessage(process.versions.node, process.platform);
|
|
363
|
+
if (compatibilityError !== null) {
|
|
364
|
+
process.stderr.write(`${compatibilityError}\n`);
|
|
365
|
+
process.exitCode = 1;
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
process.stdout.write(launcherHelpText());
|
|
369
|
+
const env = createLauncherEnvironment(process.env, mode, readPackageVersion());
|
|
370
|
+
const informationalEnv = { ...process.env };
|
|
371
|
+
delete informationalEnv.BLUN_HOME;
|
|
372
|
+
env.BLUN_HOME = resolveLauncherPrivatePaths({ env: informationalEnv }).blunHome;
|
|
373
|
+
process.exitCode = await runInformationalCore(ARGS, env, callerCwd, releaseNotice);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
350
377
|
let privatePaths;
|
|
351
378
|
const getPrivatePaths = () => {
|
|
352
379
|
privatePaths ||= resolveLauncherPrivatePaths();
|
|
@@ -5,10 +5,20 @@ const { createHash } = require('node:crypto');
|
|
|
5
5
|
const RECEIPT = 'bundled-agent-sources.json';
|
|
6
6
|
const SCHEMA = 'blun.bundled-agent-sources/v1';
|
|
7
7
|
const PREFIXES = ['agent-spine-plugin/', 'standard-skills/translate-native/', 'standard-tools/language-guard/'];
|
|
8
|
+
const GUARD_RESPONSE_PROFILE = Object.freeze({
|
|
9
|
+
schema: 'blun.language-guard-response-profile/v1',
|
|
10
|
+
file: 'translate-native/scripts/blun_language_guard.py',
|
|
11
|
+
beforeSha256: '837361690535ded4251ca23fbab313f5c3a7005472c259aa8fc51ebf7ecb9cb9',
|
|
12
|
+
afterSha256: '1e21b570259de0145ace2abf55fb82bf8896c90aaae93839c97fff36a01731f2',
|
|
13
|
+
});
|
|
14
|
+
const GUARD_RESPONSE_PAYLOADS = Object.freeze([
|
|
15
|
+
'standard-skills/translate-native/scripts/blun_language_guard.py',
|
|
16
|
+
'standard-tools/language-guard/blun_language_guard.py',
|
|
17
|
+
]);
|
|
8
18
|
const REQUIRED = [
|
|
9
19
|
'agent-spine-plugin/blun.plugin.json', 'agent-spine-plugin/src/hook.js',
|
|
10
20
|
'agent-spine-plugin/src/mcp.js', 'agent-spine-plugin/skills/agent-spine/SKILL.md',
|
|
11
|
-
'standard-skills/translate-native/SKILL.md',
|
|
21
|
+
'standard-skills/translate-native/SKILL.md', ...GUARD_RESPONSE_PAYLOADS,
|
|
12
22
|
'standard-tools/language-guard/check_diacritics.py', 'standard-tools/language-guard/language_quality.py',
|
|
13
23
|
'standard-tools/language-guard/guard_service_client.py', 'standard-tools/language-guard/translation_guard.py',
|
|
14
24
|
];
|
|
@@ -46,6 +56,21 @@ function verifyBundledAgentSources(root, pins) {
|
|
|
46
56
|
for (const file of expectedNames) {
|
|
47
57
|
if (!/^[a-f0-9]{64}$/.test(receipt.files[file]) || actual[file] !== receipt.files[file]) throw new Error('Bundled source digest mismatch: ' + file);
|
|
48
58
|
}
|
|
59
|
+
// Bind the semantic repair independently of the self-reported file inventory.
|
|
60
|
+
const patch = receipt.localPatches?.guardResponseProfile;
|
|
61
|
+
if (!patch || typeof patch !== 'object' || Array.isArray(patch)
|
|
62
|
+
|| Object.keys(patch).length !== Object.keys(GUARD_RESPONSE_PROFILE).length
|
|
63
|
+
|| Object.entries(GUARD_RESPONSE_PROFILE).some(([key, value]) => patch[key] !== value)) {
|
|
64
|
+
throw new Error('Invalid language guard response profile repair receipt');
|
|
65
|
+
}
|
|
66
|
+
if (receipt.sourceDigests?.translateNative?.[GUARD_RESPONSE_PROFILE.file] !== GUARD_RESPONSE_PROFILE.beforeSha256) {
|
|
67
|
+
throw new Error('Invalid language guard response profile source digest');
|
|
68
|
+
}
|
|
69
|
+
for (const file of GUARD_RESPONSE_PAYLOADS) {
|
|
70
|
+
if (actual[file] !== GUARD_RESPONSE_PROFILE.afterSha256) {
|
|
71
|
+
throw new Error('Invalid language guard response profile payload: ' + file);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
49
74
|
return receipt;
|
|
50
75
|
}
|
|
51
76
|
|
|
@@ -54,4 +79,5 @@ if (require.main === module) {
|
|
|
54
79
|
console.log(JSON.stringify({ verified: true, sources: receipt.sources, files: Object.keys(receipt.files).length }));
|
|
55
80
|
} catch (error) { console.error(error.message); process.exitCode = 1; }
|
|
56
81
|
}
|
|
57
|
-
module.exports = { verifyBundledAgentSources, payloadInventory, sha256, RECEIPT, SCHEMA, PREFIXES, REQUIRED
|
|
82
|
+
module.exports = { verifyBundledAgentSources, payloadInventory, sha256, RECEIPT, SCHEMA, PREFIXES, REQUIRED,
|
|
83
|
+
GUARD_RESPONSE_PROFILE, GUARD_RESPONSE_PAYLOADS };
|