token-harness 0.1.16 → 0.1.17
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/package.json +1 -1
- package/sbom.json +3 -3
- package/token-harness.mjs +539 -99
package/package.json
CHANGED
package/sbom.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.5",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:acbec121-baa9-de33-8ab5-e5e88efbd50e",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
7
|
"component": {
|
|
8
8
|
"type": "application",
|
|
9
9
|
"bom-ref": "token-harness",
|
|
10
10
|
"name": "token-harness",
|
|
11
|
-
"version": "0.1.
|
|
11
|
+
"version": "0.1.17",
|
|
12
12
|
"description": "Quota-aware efficiency layer for Claude Code and Codex subscription limits.",
|
|
13
13
|
"licenses": [
|
|
14
14
|
{
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"hashes": [
|
|
21
21
|
{
|
|
22
22
|
"alg": "SHA-256",
|
|
23
|
-
"content": "
|
|
23
|
+
"content": "acbec121baa9de338ab5e5e88efbd50e5c4b3f0a1f2c6f7171f80dd05b12f312"
|
|
24
24
|
}
|
|
25
25
|
]
|
|
26
26
|
},
|
package/token-harness.mjs
CHANGED
|
@@ -6535,12 +6535,33 @@ var init_install = __esm({
|
|
|
6535
6535
|
version3 === null ? packageName : `${packageName}==${version3}`
|
|
6536
6536
|
],
|
|
6537
6537
|
verified: true
|
|
6538
|
+
},
|
|
6539
|
+
uv: {
|
|
6540
|
+
executable: "uv",
|
|
6541
|
+
// Headroom uses uv's isolated tool installer. Token Harness invokes an existing uv only;
|
|
6542
|
+
// it never bootstraps uv, Python, or administrator prerequisites.
|
|
6543
|
+
args: (packageName, version3) => [
|
|
6544
|
+
"tool",
|
|
6545
|
+
"install",
|
|
6546
|
+
"--force",
|
|
6547
|
+
version3 === null ? packageName : `${packageName}==${version3}`
|
|
6548
|
+
],
|
|
6549
|
+
verified: true
|
|
6538
6550
|
}
|
|
6539
6551
|
};
|
|
6540
6552
|
UNINSTALL_COMMANDS = {
|
|
6553
|
+
npm: {
|
|
6554
|
+
executable: "npm",
|
|
6555
|
+
args: (packageName) => ["uninstall", "--global", packageName]
|
|
6556
|
+
},
|
|
6541
6557
|
pipx: {
|
|
6542
6558
|
executable: "pipx",
|
|
6543
6559
|
args: (packageName) => ["uninstall", packageName]
|
|
6560
|
+
},
|
|
6561
|
+
uv: {
|
|
6562
|
+
executable: "uv",
|
|
6563
|
+
// Extras are install-time selectors; uv tool uninstall expects the distribution name.
|
|
6564
|
+
args: (packageName) => ["tool", "uninstall", packageName.replace(/\[.*\]$/, "")]
|
|
6544
6565
|
}
|
|
6545
6566
|
};
|
|
6546
6567
|
QUERY_COMMANDS = {
|
|
@@ -6633,17 +6654,35 @@ var init_install = __esm({
|
|
|
6633
6654
|
},
|
|
6634
6655
|
npm: {
|
|
6635
6656
|
executable: "npm",
|
|
6636
|
-
|
|
6657
|
+
// Listing the global root as JSON proves both presence and absence without depending on
|
|
6658
|
+
// localized human output or npm's exit behavior for a package-name filter.
|
|
6659
|
+
args: () => ["ls", "--global", "--depth=0", "--json"],
|
|
6637
6660
|
parse: (stdout, packageName) => {
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6661
|
+
let parsed;
|
|
6662
|
+
try {
|
|
6663
|
+
parsed = JSON.parse(stdout);
|
|
6664
|
+
} catch {
|
|
6665
|
+
return { status: "unknown", version: null };
|
|
6666
|
+
}
|
|
6667
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
6668
|
+
return { status: "unknown", version: null };
|
|
6669
|
+
}
|
|
6670
|
+
const dependencies = parsed["dependencies"];
|
|
6671
|
+
if (dependencies === void 0)
|
|
6672
|
+
return { status: "absent", version: null };
|
|
6673
|
+
if (typeof dependencies !== "object" || dependencies === null || Array.isArray(dependencies)) {
|
|
6674
|
+
return { status: "unknown", version: null };
|
|
6675
|
+
}
|
|
6676
|
+
const dependency = dependencies[packageName];
|
|
6677
|
+
if (dependency === void 0)
|
|
6678
|
+
return { status: "absent", version: null };
|
|
6679
|
+
const candidate = typeof dependency === "string" ? dependency : typeof dependency === "object" && dependency !== null && !Array.isArray(dependency) ? dependency["version"] : null;
|
|
6680
|
+
if (typeof candidate !== "string" || parseSemanticVersion(candidate) === null) {
|
|
6642
6681
|
return { status: "unknown", version: null };
|
|
6643
6682
|
}
|
|
6644
6683
|
return { status: "captured", version: candidate };
|
|
6645
6684
|
},
|
|
6646
|
-
verified:
|
|
6685
|
+
verified: true
|
|
6647
6686
|
},
|
|
6648
6687
|
pnpm: {
|
|
6649
6688
|
executable: "pnpm",
|
|
@@ -6698,16 +6737,20 @@ var init_install = __esm({
|
|
|
6698
6737
|
executable: "uv",
|
|
6699
6738
|
args: () => ["tool", "list"],
|
|
6700
6739
|
parse: (stdout, packageName) => {
|
|
6701
|
-
const
|
|
6702
|
-
const
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6740
|
+
const distribution = packageName.replace(/\[.*\]$/, "");
|
|
6741
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
6742
|
+
const fields = line.trim().split(/\s+/);
|
|
6743
|
+
if (fields[0] !== distribution)
|
|
6744
|
+
continue;
|
|
6745
|
+
const candidate = (fields[1] ?? "").replace(/^v/i, "");
|
|
6746
|
+
if (parseSemanticVersion(candidate) === null) {
|
|
6747
|
+
return { status: "unknown", version: null };
|
|
6748
|
+
}
|
|
6749
|
+
return { status: "captured", version: candidate };
|
|
6750
|
+
}
|
|
6751
|
+
return { status: "absent", version: null };
|
|
6709
6752
|
},
|
|
6710
|
-
verified:
|
|
6753
|
+
verified: true
|
|
6711
6754
|
},
|
|
6712
6755
|
pipx: {
|
|
6713
6756
|
executable: "pipx",
|
|
@@ -8892,7 +8935,7 @@ var init_snapshots = __esm({
|
|
|
8892
8935
|
* calling a constructor directly.
|
|
8893
8936
|
*/
|
|
8894
8937
|
static create(input) {
|
|
8895
|
-
if (input.fs.isInside(input.backupRoot, input.projectRoot)) {
|
|
8938
|
+
if (input.projectRoot !== null && input.fs.isInside(input.backupRoot, input.projectRoot)) {
|
|
8896
8939
|
return {
|
|
8897
8940
|
ok: false,
|
|
8898
8941
|
diagnostics: [
|
|
@@ -9387,7 +9430,7 @@ var TOOL_VERSION;
|
|
|
9387
9430
|
var init_version2 = __esm({
|
|
9388
9431
|
"apps/cli/dist/src/version.js"() {
|
|
9389
9432
|
"use strict";
|
|
9390
|
-
TOOL_VERSION = "0.1.
|
|
9433
|
+
TOOL_VERSION = "0.1.17";
|
|
9391
9434
|
}
|
|
9392
9435
|
});
|
|
9393
9436
|
|
|
@@ -11189,6 +11232,10 @@ var init_environment = __esm({
|
|
|
11189
11232
|
"HOMEPATH",
|
|
11190
11233
|
"LOCALAPPDATA",
|
|
11191
11234
|
"NUMBER_OF_PROCESSORS",
|
|
11235
|
+
// npm global installs must stay in the same prefix the parent process is using. This value is
|
|
11236
|
+
// a filesystem location, not a credential; dropping it can update a different global npm tree
|
|
11237
|
+
// while PATH continues to resolve the old executable.
|
|
11238
|
+
"NPM_CONFIG_PREFIX",
|
|
11192
11239
|
"PATH",
|
|
11193
11240
|
"PATHEXT",
|
|
11194
11241
|
"PROCESSOR_ARCHITECTURE",
|
|
@@ -11214,6 +11261,10 @@ var init_environment = __esm({
|
|
|
11214
11261
|
"LC_ALL",
|
|
11215
11262
|
"LC_CTYPE",
|
|
11216
11263
|
"LOGNAME",
|
|
11264
|
+
// npm documents config environment variables with the lowercase npm_config_ prefix on POSIX.
|
|
11265
|
+
// Keep both common spellings because POSIX environment names are case-sensitive.
|
|
11266
|
+
"NPM_CONFIG_PREFIX",
|
|
11267
|
+
"npm_config_prefix",
|
|
11217
11268
|
"PATH",
|
|
11218
11269
|
"SHELL",
|
|
11219
11270
|
"TMPDIR",
|
|
@@ -16778,6 +16829,25 @@ function skillArtifacts(context, harness, capabilities = null) {
|
|
|
16778
16829
|
digest
|
|
16779
16830
|
}));
|
|
16780
16831
|
}
|
|
16832
|
+
function skillInstallContainmentBoundary(context, harness, capabilities, protectedPaths) {
|
|
16833
|
+
const install = SKILLS_INSTALL[harness];
|
|
16834
|
+
if (install === void 0)
|
|
16835
|
+
return [...protectedPaths];
|
|
16836
|
+
const prefix = `${install.directory}/skills/`;
|
|
16837
|
+
const relativeArtifacts = capabilities === null ? [] : publishedSkillArtifactDigests(capabilities, harness).map(([path]) => path);
|
|
16838
|
+
const fallbackArtifacts = Object.keys(SKILL_ARTIFACT_DIGESTS).map((path) => `${install.directory}/skills/${path}`);
|
|
16839
|
+
const contract = relativeArtifacts.length > 0 ? relativeArtifacts : capabilities !== null && requiresRuntimeSkillDigests(capabilities) ? [] : fallbackArtifacts;
|
|
16840
|
+
const skillRoots = /* @__PURE__ */ new Set();
|
|
16841
|
+
for (const relative of contract) {
|
|
16842
|
+
if (!relative.startsWith(prefix))
|
|
16843
|
+
continue;
|
|
16844
|
+
const first = relative.slice(prefix.length).split("/")[0];
|
|
16845
|
+
if (first) {
|
|
16846
|
+
skillRoots.add(context.fs.join(context.projectRoot, install.directory, "skills", first));
|
|
16847
|
+
}
|
|
16848
|
+
}
|
|
16849
|
+
return [...skillRoots, ...protectedPaths];
|
|
16850
|
+
}
|
|
16781
16851
|
async function harnessTrimSkillsConfigured(context, harness, capabilities) {
|
|
16782
16852
|
const artifacts = skillArtifacts(context, harness, capabilities);
|
|
16783
16853
|
if (artifacts.length === 0)
|
|
@@ -16866,6 +16936,11 @@ async function plan(context, request) {
|
|
|
16866
16936
|
const expectedArtifacts = skillArtifacts(context, harness, currentCapabilities);
|
|
16867
16937
|
if (expectedArtifacts.length === 0)
|
|
16868
16938
|
continue;
|
|
16939
|
+
const protectedPaths = [
|
|
16940
|
+
context.fs.join(context.projectRoot, install.directory, install.hook),
|
|
16941
|
+
context.fs.join(context.projectRoot, install.instructions)
|
|
16942
|
+
];
|
|
16943
|
+
const containmentBoundary = skillInstallContainmentBoundary(context, harness, currentCapabilities, protectedPaths);
|
|
16869
16944
|
actions.push({
|
|
16870
16945
|
kind: "delegated-provider-install",
|
|
16871
16946
|
id: `harnesstrim-${harness}-skills-${digestText(context.projectRoot).slice(7, 15)}`,
|
|
@@ -16886,13 +16961,10 @@ async function plan(context, request) {
|
|
|
16886
16961
|
explanation: `Install HarnessTrim ${harness} skills without a hook or reduce-pipe instruction`,
|
|
16887
16962
|
executable: "harnesstrim",
|
|
16888
16963
|
args: ["install", harness, context.projectRoot, "--apply", ...install.args],
|
|
16889
|
-
containmentBoundary
|
|
16964
|
+
containmentBoundary,
|
|
16890
16965
|
expectedArtifacts,
|
|
16891
16966
|
// The two files each installer reports skipping. Named here because they must not appear.
|
|
16892
|
-
protectedPaths
|
|
16893
|
-
context.fs.join(context.projectRoot, install.directory, install.hook),
|
|
16894
|
-
context.fs.join(context.projectRoot, install.instructions)
|
|
16895
|
-
],
|
|
16967
|
+
protectedPaths,
|
|
16896
16968
|
rollbackStrategy: "restore-snapshot",
|
|
16897
16969
|
snapshotSizeCapBytes: 1048576,
|
|
16898
16970
|
upstreamUninstallAvailable: review.upstreamUninstallAvailable
|
|
@@ -16917,7 +16989,7 @@ var init_harnesstrim = __esm({
|
|
|
16917
16989
|
CODEX2 = harnessId("codex");
|
|
16918
16990
|
PI2 = harnessId("pi");
|
|
16919
16991
|
SKILLS_UPSTREAM = "0.0.7";
|
|
16920
|
-
RUNTIME_SKILL_DIGESTS_MINIMUM = "0.
|
|
16992
|
+
RUNTIME_SKILL_DIGESTS_MINIMUM = "0.2.0";
|
|
16921
16993
|
SKILL_ARTIFACT_DIGESTS = {
|
|
16922
16994
|
"compact-handoff/SKILL.md": "sha256:0efbf35581c559359e755b204778b64a289dab4d20dadc1cba3d5b5c995b5f01",
|
|
16923
16995
|
"debug-log-slim/SKILL.md": "sha256:17f5ccc34d29d7aba083444e0e4d87fd3d49916ebcb4e6544caf8c89f13f0045",
|
|
@@ -18224,6 +18296,29 @@ function prerequisiteDiagnostic(harness, detail2) {
|
|
|
18224
18296
|
remediation: `Install or update GitNexus to ${GITNEXUS_REVIEWED_MCP_VERSION} or newer with the MCP command, then refresh Token Harness`
|
|
18225
18297
|
});
|
|
18226
18298
|
}
|
|
18299
|
+
function gitnexusInstallAction() {
|
|
18300
|
+
return {
|
|
18301
|
+
kind: "package-manager-install",
|
|
18302
|
+
id: `gitnexus:install:${GITNEXUS_REVIEWED_MCP_VERSION}`,
|
|
18303
|
+
riskClass: "delegated",
|
|
18304
|
+
requiresNetwork: true,
|
|
18305
|
+
requiresElevation: false,
|
|
18306
|
+
affectedPaths: [],
|
|
18307
|
+
affectedProcesses: ["npm"],
|
|
18308
|
+
preconditions: [
|
|
18309
|
+
"npm remains runnable",
|
|
18310
|
+
`the reviewed GitNexus ${GITNEXUS_REVIEWED_MCP_VERSION} package remains installable`
|
|
18311
|
+
],
|
|
18312
|
+
postconditions: [
|
|
18313
|
+
`GitNexus ${GITNEXUS_REVIEWED_MCP_VERSION} is installed and exposes the mcp command`
|
|
18314
|
+
],
|
|
18315
|
+
rollbackData: "package-inventory",
|
|
18316
|
+
explanation: `Install the reviewed GitNexus ${GITNEXUS_REVIEWED_MCP_VERSION} CLI through npm`,
|
|
18317
|
+
packageManager: "npm",
|
|
18318
|
+
packageName: "gitnexus",
|
|
18319
|
+
version: GITNEXUS_REVIEWED_MCP_VERSION
|
|
18320
|
+
};
|
|
18321
|
+
}
|
|
18227
18322
|
async function planGitNexusManagedMcpActivation(context, harness) {
|
|
18228
18323
|
if (harness !== "claude") {
|
|
18229
18324
|
return {
|
|
@@ -18242,13 +18337,39 @@ async function planGitNexusManagedMcpActivation(context, harness) {
|
|
|
18242
18337
|
};
|
|
18243
18338
|
}
|
|
18244
18339
|
const observation = await observeGitNexusManagedRuntime(context);
|
|
18340
|
+
const installActions = [];
|
|
18245
18341
|
if (!observation.ready) {
|
|
18246
|
-
|
|
18247
|
-
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18342
|
+
if (!observation.absent) {
|
|
18343
|
+
return {
|
|
18344
|
+
harness,
|
|
18345
|
+
target: null,
|
|
18346
|
+
actions: [],
|
|
18347
|
+
diagnostics: [prerequisiteDiagnostic(harness, observation.detail)]
|
|
18348
|
+
};
|
|
18349
|
+
}
|
|
18350
|
+
const npm = await context.runner.run({
|
|
18351
|
+
executable: "npm",
|
|
18352
|
+
args: ["--version"],
|
|
18353
|
+
cwd: context.projectRoot,
|
|
18354
|
+
timeoutMs: 2e4
|
|
18355
|
+
});
|
|
18356
|
+
if (npm.failure !== null || npm.exitCode !== 0) {
|
|
18357
|
+
return {
|
|
18358
|
+
harness,
|
|
18359
|
+
target: null,
|
|
18360
|
+
actions: [],
|
|
18361
|
+
diagnostics: [
|
|
18362
|
+
diagnostic({
|
|
18363
|
+
severity: "warning",
|
|
18364
|
+
code: "gitnexus-npm-unavailable",
|
|
18365
|
+
subject: harness,
|
|
18366
|
+
message: "GitNexus is absent and npm is not available in this terminal",
|
|
18367
|
+
remediation: "Make npm available on PATH, then refresh Token Harness. Token Harness will not bootstrap Node.js or administrator prerequisites."
|
|
18368
|
+
})
|
|
18369
|
+
]
|
|
18370
|
+
};
|
|
18371
|
+
}
|
|
18372
|
+
installActions.push(gitnexusInstallAction());
|
|
18252
18373
|
}
|
|
18253
18374
|
const target = claudeTarget(context);
|
|
18254
18375
|
if (!context.fs.isInside(target, context.paths.home)) {
|
|
@@ -18366,7 +18487,7 @@ async function planGitNexusManagedMcpActivation(context, harness) {
|
|
|
18366
18487
|
],
|
|
18367
18488
|
createIfMissing: true
|
|
18368
18489
|
};
|
|
18369
|
-
return { harness, target, actions: [action], diagnostics: [] };
|
|
18490
|
+
return { harness, target, actions: [...installActions, action], diagnostics: [] };
|
|
18370
18491
|
}
|
|
18371
18492
|
function planGitNexusManagedMcpRemoval(context, ownership) {
|
|
18372
18493
|
const harness = "claude";
|
|
@@ -19179,7 +19300,22 @@ async function mcptoonDetection(context) {
|
|
|
19179
19300
|
configuredHarnesses.push(harness);
|
|
19180
19301
|
}
|
|
19181
19302
|
}
|
|
19182
|
-
const
|
|
19303
|
+
const pipx = observation.absent ? await context.runner.run({
|
|
19304
|
+
executable: "pipx",
|
|
19305
|
+
args: ["--version"],
|
|
19306
|
+
cwd: context.projectRoot,
|
|
19307
|
+
timeoutMs: 2e4
|
|
19308
|
+
}) : null;
|
|
19309
|
+
const canInstall = observation.absent && pipx !== null && pipx.failure === null && pipx.exitCode === 0;
|
|
19310
|
+
const warnings = observation.absent && !canInstall ? [
|
|
19311
|
+
diagnostic({
|
|
19312
|
+
severity: "warning",
|
|
19313
|
+
code: "mcptoon-pipx-unavailable",
|
|
19314
|
+
subject: "mcptoon",
|
|
19315
|
+
message: "mcptoon is not installed and pipx is not available in this terminal",
|
|
19316
|
+
remediation: "Install pipx or make it available on PATH, then refresh. Token Harness will use it to install the reviewed mcptoon build."
|
|
19317
|
+
})
|
|
19318
|
+
] : !observation.absent && !observation.ready ? [warning("mcptoon-provider-capability-unavailable", "mcptoon", observation.detail)] : [];
|
|
19183
19319
|
return {
|
|
19184
19320
|
providerId: MCPTOON,
|
|
19185
19321
|
state: observation.absent ? "absent" : configuredHarnesses.length > 0 ? "configured" : "installed",
|
|
@@ -19191,7 +19327,7 @@ async function mcptoonDetection(context) {
|
|
|
19191
19327
|
unmanagedHarnessesConfigured: [],
|
|
19192
19328
|
supportsUnmanagedHarnesses: false,
|
|
19193
19329
|
managedByTokenHarness: false,
|
|
19194
|
-
assignableHarnesses: observation.ready ? [CLAUDE5, CODEX3] : [],
|
|
19330
|
+
assignableHarnesses: observation.ready || canInstall ? [CLAUDE5, CODEX3] : [],
|
|
19195
19331
|
evidence: [],
|
|
19196
19332
|
warnings
|
|
19197
19333
|
};
|
|
@@ -19200,7 +19336,22 @@ async function gitnexusDetection(context) {
|
|
|
19200
19336
|
const observation = await observeGitNexusManagedRuntime(context);
|
|
19201
19337
|
const verification = observation.ready ? await verifyGitNexusManagedMcpActivation(context, CLAUDE5) : null;
|
|
19202
19338
|
const configuredHarnesses = verification?.state === "verified" ? [CLAUDE5] : [];
|
|
19203
|
-
const
|
|
19339
|
+
const npm = observation.absent ? await context.runner.run({
|
|
19340
|
+
executable: "npm",
|
|
19341
|
+
args: ["--version"],
|
|
19342
|
+
cwd: context.projectRoot,
|
|
19343
|
+
timeoutMs: 2e4
|
|
19344
|
+
}) : null;
|
|
19345
|
+
const canInstall = observation.absent && npm !== null && npm.failure === null && npm.exitCode === 0;
|
|
19346
|
+
const warnings = observation.absent && !canInstall ? [
|
|
19347
|
+
diagnostic({
|
|
19348
|
+
severity: "warning",
|
|
19349
|
+
code: "gitnexus-npm-unavailable",
|
|
19350
|
+
subject: "gitnexus",
|
|
19351
|
+
message: "GitNexus is not installed and npm is not available in this terminal",
|
|
19352
|
+
remediation: "Make npm available on PATH, then refresh. Token Harness can install the reviewed GitNexus build after explicit approval."
|
|
19353
|
+
})
|
|
19354
|
+
] : !observation.absent && !observation.ready ? [warning("gitnexus-provider-capability-unavailable", "gitnexus", observation.detail)] : [];
|
|
19204
19355
|
return {
|
|
19205
19356
|
providerId: GITNEXUS,
|
|
19206
19357
|
state: observation.absent ? "absent" : configuredHarnesses.length > 0 ? "configured" : "installed",
|
|
@@ -19212,7 +19363,7 @@ async function gitnexusDetection(context) {
|
|
|
19212
19363
|
unmanagedHarnessesConfigured: [],
|
|
19213
19364
|
supportsUnmanagedHarnesses: false,
|
|
19214
19365
|
managedByTokenHarness: false,
|
|
19215
|
-
assignableHarnesses: observation.ready ? [CLAUDE5] : [],
|
|
19366
|
+
assignableHarnesses: observation.ready || canInstall ? [CLAUDE5] : [],
|
|
19216
19367
|
evidence: [],
|
|
19217
19368
|
warnings
|
|
19218
19369
|
};
|
|
@@ -19544,6 +19695,30 @@ async function headroomManagedMcpRuntime(context) {
|
|
|
19544
19695
|
detail: `Headroom ${observation.version} exposes the local MCP server required by the managed integration`
|
|
19545
19696
|
};
|
|
19546
19697
|
}
|
|
19698
|
+
function headroomInstallAction() {
|
|
19699
|
+
return {
|
|
19700
|
+
kind: "package-manager-install",
|
|
19701
|
+
id: `headroom:install:${HEADROOM_REVIEWED_MCP_VERSION}`,
|
|
19702
|
+
riskClass: "delegated",
|
|
19703
|
+
requiresNetwork: true,
|
|
19704
|
+
requiresElevation: false,
|
|
19705
|
+
affectedPaths: [],
|
|
19706
|
+
affectedProcesses: ["uv"],
|
|
19707
|
+
preconditions: [
|
|
19708
|
+
"uv remains runnable",
|
|
19709
|
+
`the reviewed Headroom ${HEADROOM_REVIEWED_MCP_VERSION} MCP package remains installable`
|
|
19710
|
+
],
|
|
19711
|
+
postconditions: [
|
|
19712
|
+
`Headroom ${HEADROOM_REVIEWED_MCP_VERSION} is installed with the MCP extra`,
|
|
19713
|
+
"headroom mcp serve --help succeeds"
|
|
19714
|
+
],
|
|
19715
|
+
rollbackData: "package-inventory",
|
|
19716
|
+
explanation: `Install reviewed Headroom ${HEADROOM_REVIEWED_MCP_VERSION} with its MCP extra through uv`,
|
|
19717
|
+
packageManager: "uv",
|
|
19718
|
+
packageName: "headroom-ai[mcp]",
|
|
19719
|
+
version: HEADROOM_REVIEWED_MCP_VERSION
|
|
19720
|
+
};
|
|
19721
|
+
}
|
|
19547
19722
|
function prerequisite(harness, detail2) {
|
|
19548
19723
|
return {
|
|
19549
19724
|
harness,
|
|
@@ -19841,9 +20016,24 @@ async function planHeadroomManagedMcpActivation(context, harness) {
|
|
|
19841
20016
|
};
|
|
19842
20017
|
}
|
|
19843
20018
|
const cli = await headroomManagedMcpRuntime(context);
|
|
19844
|
-
|
|
19845
|
-
|
|
19846
|
-
|
|
20019
|
+
const installActions = [];
|
|
20020
|
+
if (!cli.ok) {
|
|
20021
|
+
const observation = await observeHeadroomCandidate(context);
|
|
20022
|
+
if (observation.state !== "absent")
|
|
20023
|
+
return prerequisite(harness, cli.detail);
|
|
20024
|
+
const uv = await context.runner.run({
|
|
20025
|
+
executable: "uv",
|
|
20026
|
+
args: ["--version"],
|
|
20027
|
+
cwd: context.projectRoot,
|
|
20028
|
+
timeoutMs: 2e4
|
|
20029
|
+
});
|
|
20030
|
+
if (uv.failure !== null || uv.exitCode !== 0) {
|
|
20031
|
+
return prerequisite(harness, "Headroom is absent and uv is not available in this terminal. Install uv or make it available on PATH; Token Harness will not bootstrap Python or uv itself.");
|
|
20032
|
+
}
|
|
20033
|
+
installActions.push(headroomInstallAction());
|
|
20034
|
+
}
|
|
20035
|
+
const activation = harness === "claude" ? await planClaude(context, harness) : await planCodex(context, harness);
|
|
20036
|
+
return { ...activation, actions: [...installActions, ...activation.actions] };
|
|
19847
20037
|
}
|
|
19848
20038
|
function headroomOwnedArtifact(context, harness) {
|
|
19849
20039
|
if (harness === "claude") {
|
|
@@ -19972,10 +20162,17 @@ async function detect8(context) {
|
|
|
19972
20162
|
configuredHarnesses.push(harness);
|
|
19973
20163
|
}
|
|
19974
20164
|
}
|
|
20165
|
+
const uv = observation.state === "absent" ? await context.runner.run({
|
|
20166
|
+
executable: "uv",
|
|
20167
|
+
args: ["--version"],
|
|
20168
|
+
cwd: context.projectRoot,
|
|
20169
|
+
timeoutMs: 2e4
|
|
20170
|
+
}) : null;
|
|
20171
|
+
const canInstall = observation.state === "absent" && uv !== null && uv.failure === null && uv.exitCode === 0;
|
|
19975
20172
|
const warnings = [];
|
|
19976
|
-
if (observation.state === "absent")
|
|
20173
|
+
if (observation.state === "absent" && !canInstall)
|
|
19977
20174
|
warnings.push(manualInstallWarning());
|
|
19978
|
-
else if (!runtime.ok) {
|
|
20175
|
+
else if (!runtime.ok && observation.state !== "absent") {
|
|
19979
20176
|
warnings.push(diagnostic({
|
|
19980
20177
|
severity: "warning",
|
|
19981
20178
|
code: "headroom-provider-capability-unavailable",
|
|
@@ -19998,7 +20195,7 @@ async function detect8(context) {
|
|
|
19998
20195
|
unmanagedHarnessesConfigured: [],
|
|
19999
20196
|
supportsUnmanagedHarnesses: false,
|
|
20000
20197
|
managedByTokenHarness: false,
|
|
20001
|
-
assignableHarnesses: runtime.ok ? [CLAUDE7, CODEX4] : [],
|
|
20198
|
+
assignableHarnesses: runtime.ok || canInstall ? [CLAUDE7, CODEX4] : [],
|
|
20002
20199
|
evidence: [],
|
|
20003
20200
|
warnings
|
|
20004
20201
|
};
|
|
@@ -21449,6 +21646,33 @@ var init_candidate_campaign_surface = __esm({
|
|
|
21449
21646
|
}
|
|
21450
21647
|
});
|
|
21451
21648
|
|
|
21649
|
+
// apps/cli/dist/src/commands/snapshot-safety.js
|
|
21650
|
+
async function repositoryRootForBackupSafety(context) {
|
|
21651
|
+
const adapters = context.adapters;
|
|
21652
|
+
if (adapters === null)
|
|
21653
|
+
return context.projectRoot;
|
|
21654
|
+
const fs = adapters.fs;
|
|
21655
|
+
let current = context.projectRoot;
|
|
21656
|
+
while (true) {
|
|
21657
|
+
for (const marker of [".git", ".hg", ".svn"]) {
|
|
21658
|
+
if (await fs.stat(fs.join(current, marker)) !== null)
|
|
21659
|
+
return current;
|
|
21660
|
+
}
|
|
21661
|
+
if (context.home !== null && fs.isInside(current, context.home) && fs.isInside(context.home, current)) {
|
|
21662
|
+
return null;
|
|
21663
|
+
}
|
|
21664
|
+
const parent = fs.dirname(current);
|
|
21665
|
+
if (parent === current)
|
|
21666
|
+
return null;
|
|
21667
|
+
current = parent;
|
|
21668
|
+
}
|
|
21669
|
+
}
|
|
21670
|
+
var init_snapshot_safety = __esm({
|
|
21671
|
+
"apps/cli/dist/src/commands/snapshot-safety.js"() {
|
|
21672
|
+
"use strict";
|
|
21673
|
+
}
|
|
21674
|
+
});
|
|
21675
|
+
|
|
21452
21676
|
// apps/cli/dist/src/commands/gitnexus-candidate-lifecycle.js
|
|
21453
21677
|
function emptyReport(outcome2, requestedStateVerified = false) {
|
|
21454
21678
|
return {
|
|
@@ -21510,7 +21734,7 @@ function selectorProblem(context, command) {
|
|
|
21510
21734
|
}
|
|
21511
21735
|
return null;
|
|
21512
21736
|
}
|
|
21513
|
-
function stores(context, id) {
|
|
21737
|
+
async function stores(context, id) {
|
|
21514
21738
|
if (context.adapters === null || context.stateRoot === null)
|
|
21515
21739
|
return null;
|
|
21516
21740
|
const fs = context.adapters.fs;
|
|
@@ -21518,7 +21742,7 @@ function stores(context, id) {
|
|
|
21518
21742
|
fs,
|
|
21519
21743
|
backupRoot: fs.join(context.stateRoot, "backups"),
|
|
21520
21744
|
transactionId: id,
|
|
21521
|
-
projectRoot: context
|
|
21745
|
+
projectRoot: await repositoryRootForBackupSafety(context),
|
|
21522
21746
|
now: context.now
|
|
21523
21747
|
});
|
|
21524
21748
|
if (!creation.ok)
|
|
@@ -21711,7 +21935,7 @@ async function runGitNexusCandidateApply(context) {
|
|
|
21711
21935
|
return finish("apply", EXIT_CODES["confirmation-required"], emptyReport("confirmation-required"), diagnostics);
|
|
21712
21936
|
}
|
|
21713
21937
|
const id = transactionId("gitnexus-activate-claude", context);
|
|
21714
|
-
const built = stores(context, id);
|
|
21938
|
+
const built = await stores(context, id);
|
|
21715
21939
|
if (built === null || !("snapshots" in built)) {
|
|
21716
21940
|
diagnostics.push(...built?.failure ?? []);
|
|
21717
21941
|
return finish("apply", EXIT_CODES["unsupported-environment"], emptyReport("rejected"), diagnostics);
|
|
@@ -21817,7 +22041,7 @@ async function runGitNexusCandidateUninstall(context) {
|
|
|
21817
22041
|
return finish("uninstall", EXIT_CODES["confirmation-required"], emptyReport("confirmation-required"), diagnostics);
|
|
21818
22042
|
}
|
|
21819
22043
|
const id = transactionId("gitnexus-deactivate-claude", context);
|
|
21820
|
-
const built = stores(context, id);
|
|
22044
|
+
const built = await stores(context, id);
|
|
21821
22045
|
if (built === null || !("snapshots" in built)) {
|
|
21822
22046
|
diagnostics.push(...built?.failure ?? []);
|
|
21823
22047
|
return finish("uninstall", EXIT_CODES["unsupported-environment"], emptyReport("rejected"), diagnostics);
|
|
@@ -21857,6 +22081,7 @@ var init_gitnexus_candidate_lifecycle = __esm({
|
|
|
21857
22081
|
init_src3();
|
|
21858
22082
|
init_src();
|
|
21859
22083
|
init_candidate_campaign_surface();
|
|
22084
|
+
init_snapshot_safety();
|
|
21860
22085
|
ACTIVATION_ACTION_ID = "gitnexus:claude:mcp-server";
|
|
21861
22086
|
REMOVAL_ACTION_ID = "gitnexus:claude:mcp-server:remove";
|
|
21862
22087
|
REVIEWED_VALUE_DIGEST = jsonValueDigest(GITNEXUS_MCP_SERVER);
|
|
@@ -21934,7 +22159,7 @@ function selectorProblem2(context, command) {
|
|
|
21934
22159
|
}
|
|
21935
22160
|
return null;
|
|
21936
22161
|
}
|
|
21937
|
-
function stores2(context, transactionId2) {
|
|
22162
|
+
async function stores2(context, transactionId2) {
|
|
21938
22163
|
if (context.adapters === null || context.stateRoot === null)
|
|
21939
22164
|
return null;
|
|
21940
22165
|
const fs = context.adapters.fs;
|
|
@@ -21942,7 +22167,7 @@ function stores2(context, transactionId2) {
|
|
|
21942
22167
|
fs,
|
|
21943
22168
|
backupRoot: fs.join(context.stateRoot, "backups"),
|
|
21944
22169
|
transactionId: transactionId2,
|
|
21945
|
-
projectRoot: context
|
|
22170
|
+
projectRoot: await repositoryRootForBackupSafety(context),
|
|
21946
22171
|
now: context.now
|
|
21947
22172
|
});
|
|
21948
22173
|
if (!creation.ok)
|
|
@@ -22033,7 +22258,7 @@ async function runCandidateApply(context) {
|
|
|
22033
22258
|
return finish2("apply", EXIT_CODES["confirmation-required"], emptyReport2("confirmation-required"), diagnostics);
|
|
22034
22259
|
}
|
|
22035
22260
|
const transactionId2 = candidateTransactionId(`mcptoon-activate-${harness}`, context);
|
|
22036
|
-
const built = stores2(context, transactionId2);
|
|
22261
|
+
const built = await stores2(context, transactionId2);
|
|
22037
22262
|
if (built === null || !("snapshots" in built)) {
|
|
22038
22263
|
diagnostics.push(...built?.failure ?? []);
|
|
22039
22264
|
return finish2("apply", EXIT_CODES["unsupported-environment"], emptyReport2("rejected"), diagnostics);
|
|
@@ -22178,7 +22403,7 @@ async function runCandidateUninstall(context) {
|
|
|
22178
22403
|
return finish2("uninstall", EXIT_CODES["confirmation-required"], emptyReport2("confirmation-required"), diagnostics);
|
|
22179
22404
|
}
|
|
22180
22405
|
const transactionId2 = candidateTransactionId(`mcptoon-deactivate-${harness}`, context);
|
|
22181
|
-
const built = stores2(context, transactionId2);
|
|
22406
|
+
const built = await stores2(context, transactionId2);
|
|
22182
22407
|
if (built === null || !("snapshots" in built)) {
|
|
22183
22408
|
diagnostics.push(...built?.failure ?? []);
|
|
22184
22409
|
return finish2("uninstall", EXIT_CODES["unsupported-environment"], emptyReport2("rejected"), diagnostics);
|
|
@@ -22223,6 +22448,7 @@ var init_mcptoon_candidate_lifecycle = __esm({
|
|
|
22223
22448
|
init_src3();
|
|
22224
22449
|
init_src();
|
|
22225
22450
|
init_candidate_campaign_surface();
|
|
22451
|
+
init_snapshot_safety();
|
|
22226
22452
|
}
|
|
22227
22453
|
});
|
|
22228
22454
|
|
|
@@ -24539,6 +24765,73 @@ var init_plan2 = __esm({
|
|
|
24539
24765
|
});
|
|
24540
24766
|
|
|
24541
24767
|
// apps/cli/dist/src/commands/apply.js
|
|
24768
|
+
async function verifyManagedIntegrationPostconditions(context, integrations) {
|
|
24769
|
+
if (integrations.length === 0)
|
|
24770
|
+
return [];
|
|
24771
|
+
if (context.adapters === null) {
|
|
24772
|
+
return [
|
|
24773
|
+
diagnostic({
|
|
24774
|
+
severity: "error",
|
|
24775
|
+
code: "managed-setup-postcondition-unavailable",
|
|
24776
|
+
message: "The managed integration could not be re-observed because platform adapters are unavailable",
|
|
24777
|
+
remediation: "Refresh the current setup before retrying"
|
|
24778
|
+
})
|
|
24779
|
+
];
|
|
24780
|
+
}
|
|
24781
|
+
const detectionContext = {
|
|
24782
|
+
fs: context.adapters.fs,
|
|
24783
|
+
runner: context.adapters.runner,
|
|
24784
|
+
facts: context.platform,
|
|
24785
|
+
paths: context.adapters.paths,
|
|
24786
|
+
projectRoot: context.projectRoot
|
|
24787
|
+
};
|
|
24788
|
+
const harnessConfigs = (await Promise.all(listHarnessAdapters().map(async (adapter) => (await adapter.inspect(detectionContext)).summaries))).flat();
|
|
24789
|
+
const providerContext4 = {
|
|
24790
|
+
...detectionContext,
|
|
24791
|
+
harnessConfigs,
|
|
24792
|
+
now: context.now,
|
|
24793
|
+
localDatabase: context.adapters.localDatabase,
|
|
24794
|
+
projectIdFor: context.adapters.projectIdFor
|
|
24795
|
+
};
|
|
24796
|
+
const adapters = new Map(listProviderAdapters().map((adapter) => [adapter.manifest.id, adapter]));
|
|
24797
|
+
const diagnostics = [];
|
|
24798
|
+
for (const integration of integrations) {
|
|
24799
|
+
const adapter = adapters.get(integration.providerId);
|
|
24800
|
+
if (adapter === void 0) {
|
|
24801
|
+
diagnostics.push(diagnostic({
|
|
24802
|
+
severity: "error",
|
|
24803
|
+
code: "managed-setup-postcondition-unavailable",
|
|
24804
|
+
subject: integration.providerId,
|
|
24805
|
+
message: `The provider adapter disappeared before ${integration.harnessId} setup could be verified`,
|
|
24806
|
+
remediation: "Refresh Token Harness and review a new setup preview"
|
|
24807
|
+
}));
|
|
24808
|
+
continue;
|
|
24809
|
+
}
|
|
24810
|
+
try {
|
|
24811
|
+
const detection = await adapter.detect(providerContext4);
|
|
24812
|
+
if (!detection.configuredHarnesses.some((harness) => harness === integration.harnessId)) {
|
|
24813
|
+
const runtimeProblem = detection.warnings.find((entry) => entry.severity === "error" || entry.severity === "warning");
|
|
24814
|
+
diagnostics.push(diagnostic({
|
|
24815
|
+
severity: "error",
|
|
24816
|
+
code: "managed-setup-postcondition-unmet",
|
|
24817
|
+
subject: integration.providerId,
|
|
24818
|
+
message: `${adapter.manifest.displayName} setup did not become active for ${integration.harnessId} after the approved actions` + (runtimeProblem === void 0 ? "" : `: ${runtimeProblem.message}`),
|
|
24819
|
+
path: detection.executable,
|
|
24820
|
+
remediation: runtimeProblem?.remediation ?? "Check that the newly installed provider executable is on PATH, then review a fresh setup preview"
|
|
24821
|
+
}));
|
|
24822
|
+
}
|
|
24823
|
+
} catch (error) {
|
|
24824
|
+
diagnostics.push(diagnostic({
|
|
24825
|
+
severity: "error",
|
|
24826
|
+
code: "managed-setup-postcondition-unavailable",
|
|
24827
|
+
subject: integration.providerId,
|
|
24828
|
+
message: `The provider could not be re-observed after setup: ${error instanceof Error ? error.message : String(error)}`,
|
|
24829
|
+
remediation: "Refresh and inspect the provider runtime before retrying"
|
|
24830
|
+
}));
|
|
24831
|
+
}
|
|
24832
|
+
}
|
|
24833
|
+
return diagnostics;
|
|
24834
|
+
}
|
|
24542
24835
|
function transactionIdFor(planId, at) {
|
|
24543
24836
|
const digest = digestText(`${planId} ${at}`);
|
|
24544
24837
|
return digest.slice(digest.indexOf(":") + 1, digest.indexOf(":") + 13);
|
|
@@ -24758,7 +25051,7 @@ async function runApply(context) {
|
|
|
24758
25051
|
fs,
|
|
24759
25052
|
backupRoot: fs.join(context.stateRoot, "backups"),
|
|
24760
25053
|
transactionId: transactionId2,
|
|
24761
|
-
projectRoot: context
|
|
25054
|
+
projectRoot: await repositoryRootForBackupSafety(context),
|
|
24762
25055
|
now: context.now
|
|
24763
25056
|
});
|
|
24764
25057
|
if (!creation.ok) {
|
|
@@ -24788,7 +25081,8 @@ async function runApply(context) {
|
|
|
24788
25081
|
journal,
|
|
24789
25082
|
// RFC 0004 §Process policy: an installer reaches the machine through the runner or not at all.
|
|
24790
25083
|
runner: context.adapters.runner,
|
|
24791
|
-
now: context.now
|
|
25084
|
+
now: context.now,
|
|
25085
|
+
verifyPostconditions: async () => verifyManagedIntegrationPostconditions(context, computed.managedIntegrations)
|
|
24792
25086
|
});
|
|
24793
25087
|
diagnostics.push(...transaction.diagnostics);
|
|
24794
25088
|
const report = {
|
|
@@ -24823,8 +25117,10 @@ var init_apply = __esm({
|
|
|
24823
25117
|
"apps/cli/dist/src/commands/apply.js"() {
|
|
24824
25118
|
"use strict";
|
|
24825
25119
|
init_src();
|
|
25120
|
+
init_src3();
|
|
24826
25121
|
init_candidate_lifecycle();
|
|
24827
25122
|
init_plan2();
|
|
25123
|
+
init_snapshot_safety();
|
|
24828
25124
|
PLANS_DIRECTORY = "plans";
|
|
24829
25125
|
}
|
|
24830
25126
|
});
|
|
@@ -27573,7 +27869,7 @@ function finish4(exitCode, command, data, diagnostics) {
|
|
|
27573
27869
|
diagnostics
|
|
27574
27870
|
});
|
|
27575
27871
|
}
|
|
27576
|
-
function stores3(context, transactionId2) {
|
|
27872
|
+
async function stores3(context, transactionId2) {
|
|
27577
27873
|
if (context.adapters === null || context.stateRoot === null)
|
|
27578
27874
|
return null;
|
|
27579
27875
|
const fs = context.adapters.fs;
|
|
@@ -27581,7 +27877,7 @@ function stores3(context, transactionId2) {
|
|
|
27581
27877
|
fs,
|
|
27582
27878
|
backupRoot: fs.join(context.stateRoot, "backups"),
|
|
27583
27879
|
transactionId: transactionId2,
|
|
27584
|
-
projectRoot: context
|
|
27880
|
+
projectRoot: await repositoryRootForBackupSafety(context),
|
|
27585
27881
|
now: context.now
|
|
27586
27882
|
});
|
|
27587
27883
|
if (!creation.ok)
|
|
@@ -27656,7 +27952,7 @@ async function runRollback(context) {
|
|
|
27656
27952
|
}));
|
|
27657
27953
|
return finish4(EXIT_CODES["confirmation-required"], "rollback", empty("confirmation-required"), diagnostics);
|
|
27658
27954
|
}
|
|
27659
|
-
const built = stores3(context, target.transactionId);
|
|
27955
|
+
const built = await stores3(context, target.transactionId);
|
|
27660
27956
|
if (built === null || built.store === void 0) {
|
|
27661
27957
|
diagnostics.push(...built?.failure ?? []);
|
|
27662
27958
|
return finish4(EXIT_CODES["unsupported-environment"], "rollback", empty("rejected"), diagnostics);
|
|
@@ -27784,7 +28080,7 @@ async function runUninstall(context) {
|
|
|
27784
28080
|
}
|
|
27785
28081
|
const fs = context.adapters.fs;
|
|
27786
28082
|
const transactionId2 = `uninstall-${context.now().replace(/[^0-9]/g, "").slice(0, 14)}`;
|
|
27787
|
-
const built = stores3(context, transactionId2);
|
|
28083
|
+
const built = await stores3(context, transactionId2);
|
|
27788
28084
|
if (built === null || built.store === void 0) {
|
|
27789
28085
|
diagnostics.push(...built?.failure ?? []);
|
|
27790
28086
|
return finish4(EXIT_CODES["unsupported-environment"], "uninstall", empty("rejected"), diagnostics);
|
|
@@ -27820,6 +28116,7 @@ var init_rollback = __esm({
|
|
|
27820
28116
|
init_src();
|
|
27821
28117
|
init_candidate_lifecycle();
|
|
27822
28118
|
init_plan2();
|
|
28119
|
+
init_snapshot_safety();
|
|
27823
28120
|
}
|
|
27824
28121
|
});
|
|
27825
28122
|
|
|
@@ -28430,6 +28727,8 @@ async function runPackageChannelUpdate(context, options = {}) {
|
|
|
28430
28727
|
updateTargets.set(action.id, {
|
|
28431
28728
|
providerId: adapter.manifest.id,
|
|
28432
28729
|
target: query.version,
|
|
28730
|
+
channel: channel.id,
|
|
28731
|
+
packageName,
|
|
28433
28732
|
adapter
|
|
28434
28733
|
});
|
|
28435
28734
|
}
|
|
@@ -28491,7 +28790,7 @@ async function runPackageChannelUpdate(context, options = {}) {
|
|
|
28491
28790
|
fs,
|
|
28492
28791
|
backupRoot: fs.join(context.stateRoot, "backups"),
|
|
28493
28792
|
transactionId: transactionId2,
|
|
28494
|
-
projectRoot: context
|
|
28793
|
+
projectRoot: await repositoryRootForBackupSafety(context),
|
|
28495
28794
|
now: context.now
|
|
28496
28795
|
});
|
|
28497
28796
|
if (!creation.ok) {
|
|
@@ -28526,13 +28825,27 @@ async function runPackageChannelUpdate(context, options = {}) {
|
|
|
28526
28825
|
const expected = parseSemanticVersion(target.target);
|
|
28527
28826
|
const exactTarget = observed !== null && expected !== null && compareVersions(observed, expected) === 0;
|
|
28528
28827
|
if (!exactTarget) {
|
|
28828
|
+
const inventory = await queryPackageInventory({
|
|
28829
|
+
channel: target.channel,
|
|
28830
|
+
packageName: target.packageName,
|
|
28831
|
+
runner: adapters.runner,
|
|
28832
|
+
cwd: context.projectRoot
|
|
28833
|
+
});
|
|
28834
|
+
const inventoryDetail = inventory.status === "captured" && inventory.version !== null ? ` The ${target.channel} global inventory reports ${inventory.version}.` : ` The ${target.channel} inventory could not confirm the installed target (status: ${inventory.status}).`;
|
|
28835
|
+
const prefix = target.channel === "npm" ? await adapters.runner.run({
|
|
28836
|
+
executable: "npm",
|
|
28837
|
+
args: ["config", "get", "prefix"],
|
|
28838
|
+
cwd: context.projectRoot,
|
|
28839
|
+
timeoutMs: 2e4
|
|
28840
|
+
}) : null;
|
|
28841
|
+
const prefixDetail = prefix !== null && prefix.failure === null && prefix.exitCode === 0 ? ` npm prefix: ${prefix.stdout.trim() || "(empty)"}.` : "";
|
|
28529
28842
|
postconditions.push(diagnostic({
|
|
28530
28843
|
severity: "error",
|
|
28531
28844
|
code: "provider-update-version-not-observed",
|
|
28532
28845
|
subject: target.adapter.manifest.id,
|
|
28533
|
-
message: `${target.providerId} update did not become active: requested ${target.target}, but the executable currently resolved on PATH reports ${detection.version ?? "no readable version"}
|
|
28846
|
+
message: `${target.providerId} update did not become active: requested ${target.target}, but the executable currently resolved on PATH reports ${detection.version ?? "no readable version"}.` + inventoryDetail + prefixDetail,
|
|
28534
28847
|
path: detection.executable,
|
|
28535
|
-
remediation: "Review duplicate PATH installations. Token Harness will not report this update as successful while the
|
|
28848
|
+
remediation: "Review duplicate PATH installations and the package-manager global prefix. Token Harness will not report this update as successful while the requested runtime is not the one being resolved."
|
|
28536
28849
|
}));
|
|
28537
28850
|
continue;
|
|
28538
28851
|
}
|
|
@@ -28604,6 +28917,7 @@ var init_update_base = __esm({
|
|
|
28604
28917
|
"use strict";
|
|
28605
28918
|
init_src();
|
|
28606
28919
|
init_src3();
|
|
28920
|
+
init_snapshot_safety();
|
|
28607
28921
|
}
|
|
28608
28922
|
});
|
|
28609
28923
|
|
|
@@ -28864,7 +29178,7 @@ async function runUpdate(context) {
|
|
|
28864
29178
|
fs,
|
|
28865
29179
|
backupRoot: fs.join(context.stateRoot, "backups"),
|
|
28866
29180
|
transactionId: transactionId2,
|
|
28867
|
-
projectRoot: context
|
|
29181
|
+
projectRoot: await repositoryRootForBackupSafety(context),
|
|
28868
29182
|
now: context.now
|
|
28869
29183
|
});
|
|
28870
29184
|
if (!snapshotCreation.ok) {
|
|
@@ -29147,6 +29461,7 @@ var init_update = __esm({
|
|
|
29147
29461
|
"use strict";
|
|
29148
29462
|
init_src();
|
|
29149
29463
|
init_src2();
|
|
29464
|
+
init_snapshot_safety();
|
|
29150
29465
|
init_update_base();
|
|
29151
29466
|
init_rtk_release_update();
|
|
29152
29467
|
}
|
|
@@ -32299,11 +32614,20 @@ function guideSetupTarget(report, harness, provider) {
|
|
|
32299
32614
|
};
|
|
32300
32615
|
}
|
|
32301
32616
|
if (detection.state === "absent" || detection.state === "available") {
|
|
32617
|
+
if (detection.assignableHarnesses.includes(harnessDetection.harnessId)) {
|
|
32618
|
+
return {
|
|
32619
|
+
providerId: provider,
|
|
32620
|
+
provider: label,
|
|
32621
|
+
state: "actionable",
|
|
32622
|
+
reason: `${label} is not installed yet, but Token Harness has a reviewed automatic install + ${name(harness)} setup path. The exact package and configuration changes are shown before approval.`
|
|
32623
|
+
};
|
|
32624
|
+
}
|
|
32625
|
+
const prerequisite2 = detection.warnings.find((entry) => entry.severity === "warning" || entry.severity === "error");
|
|
32302
32626
|
return {
|
|
32303
32627
|
providerId: provider,
|
|
32304
32628
|
provider: label,
|
|
32305
32629
|
state: "unavailable",
|
|
32306
|
-
reason: `${label} is not installed in
|
|
32630
|
+
reason: prerequisite2 === void 0 ? `${label} is not installed and no automatic installer prerequisite is available in this terminal.` : `${prerequisite2.message}${prerequisite2.remediation === null ? "" : ` ${prerequisite2.remediation}`}`
|
|
32307
32631
|
};
|
|
32308
32632
|
}
|
|
32309
32633
|
if (detection.state === "broken") {
|
|
@@ -32315,11 +32639,12 @@ function guideSetupTarget(report, harness, provider) {
|
|
|
32315
32639
|
};
|
|
32316
32640
|
}
|
|
32317
32641
|
if (!detection.assignableHarnesses.includes(harnessDetection.harnessId)) {
|
|
32642
|
+
const capability = detection.warnings.find((entry) => entry.severity === "warning" || entry.severity === "error");
|
|
32318
32643
|
return {
|
|
32319
32644
|
providerId: provider,
|
|
32320
32645
|
provider: label,
|
|
32321
32646
|
state: "not-applicable",
|
|
32322
|
-
reason: `The installed ${label} build does not expose an automatic ${name(harness)} setup surface.`
|
|
32647
|
+
reason: capability === void 0 ? `The installed ${label} build does not expose an automatic ${name(harness)} setup surface.` : `${capability.message}${capability.remediation === null ? "" : ` ${capability.remediation}`}`
|
|
32323
32648
|
};
|
|
32324
32649
|
}
|
|
32325
32650
|
return {
|
|
@@ -32364,7 +32689,7 @@ function stackFingerprint(report) {
|
|
|
32364
32689
|
function createGuideCall(base) {
|
|
32365
32690
|
return async (args) => {
|
|
32366
32691
|
const savings = args[0] === "savings";
|
|
32367
|
-
const updateCheck = args[0] === "update";
|
|
32692
|
+
const updateCheck = args[0] === "update" && !args.includes("--yes");
|
|
32368
32693
|
const translated = savings ? ["metrics", ...args.slice(1)] : [...args];
|
|
32369
32694
|
let stdout = "";
|
|
32370
32695
|
await run({
|
|
@@ -32575,7 +32900,7 @@ function describeChange(action, harness) {
|
|
|
32575
32900
|
files: action.affectedPaths.length
|
|
32576
32901
|
};
|
|
32577
32902
|
}
|
|
32578
|
-
var GuideError, NAMES, name, GUIDE_MANAGED_PROVIDERS, RECOMMENDED_SETUP_PROVIDERS, TASKS, PERIODS, STACK_COMPONENTS, ISSUE_COPY, EFFORT_LABELS, SAFETY_RULES, TASK_RULES, READ_STAGES, GuideService;
|
|
32903
|
+
var GuideError, NAMES, name, sameGuideVersion, GUIDE_MANAGED_PROVIDERS, RECOMMENDED_SETUP_PROVIDERS, TASKS, PERIODS, STACK_COMPONENTS, ISSUE_COPY, EFFORT_LABELS, SAFETY_RULES, TASK_RULES, READ_STAGES, GuideService;
|
|
32579
32904
|
var init_guided = __esm({
|
|
32580
32905
|
"apps/cli/dist/src/guided.js"() {
|
|
32581
32906
|
"use strict";
|
|
@@ -32603,6 +32928,7 @@ var init_guided = __esm({
|
|
|
32603
32928
|
headroom: "Headroom"
|
|
32604
32929
|
};
|
|
32605
32930
|
name = (id) => NAMES[id] ?? id;
|
|
32931
|
+
sameGuideVersion = (left, right) => left !== null && right !== null && left.replace(/^v/i, "").trim() === right.replace(/^v/i, "").trim();
|
|
32606
32932
|
GUIDE_MANAGED_PROVIDERS = [
|
|
32607
32933
|
"rtk",
|
|
32608
32934
|
"harnesstrim",
|
|
@@ -32654,6 +32980,12 @@ var init_guided = __esm({
|
|
|
32654
32980
|
"codex-native-policy-shadowed": "A project or profile overrides this Codex setting. That setting belongs to you and will not be replaced.",
|
|
32655
32981
|
"no-providers-registered": "No optimization provider was selected for this operation.",
|
|
32656
32982
|
"already-in-desired-state": "The supported integration is already configured. Nothing needs to be changed.",
|
|
32983
|
+
"delegated-install-snapshot-too-large": "The optimizer setup found too much unrelated data inside its rollback boundary. Nothing was changed. Update Token Harness or use a narrower project directory before retrying.",
|
|
32984
|
+
"delegated-install-failed": "The optimizer installer itself did not complete successfully. Nothing was kept from the failed transaction.",
|
|
32985
|
+
"delegated-install-artifact-mismatch": "The optimizer installer completed but did not produce the artifact contract it advertised. The transaction was rolled back.",
|
|
32986
|
+
"delegated-install-protected-path-changed": "The optimizer installer touched a file this setup promised to leave alone. The transaction was rolled back.",
|
|
32987
|
+
"delegated-install-undeclared-write": "The optimizer installer changed a path outside the approved write set. The transaction was rolled back.",
|
|
32988
|
+
"action-precondition-drift": "A file changed after the preview was created. Review a fresh preview before applying anything.",
|
|
32657
32989
|
"managed-mutation-unsupported": "Automatic setup is unavailable because the installed provider does not expose the required managed surface. Existing integrations are left untouched.",
|
|
32658
32990
|
"plan-ownership-drift": "The integration changed after the preview. Review a fresh plan; nothing was forced.",
|
|
32659
32991
|
"plan-version-drift": "An installed version changed after the preview. Review a fresh plan.",
|
|
@@ -33210,49 +33542,137 @@ var init_guided = __esm({
|
|
|
33210
33542
|
throw new GuideError(409, "This preview expired or was already used. Review a fresh preview.");
|
|
33211
33543
|
this.approval = null;
|
|
33212
33544
|
if (approval.operation === "update") {
|
|
33213
|
-
|
|
33214
|
-
|
|
33545
|
+
const approvedUpdates = approval.updateTargets ?? [];
|
|
33546
|
+
if (approvedUpdates.length === 0)
|
|
33547
|
+
throw new GuideError(409, "This update preview contains no concrete provider version. Review it again.");
|
|
33548
|
+
this.record("Re-checking the exact provider versions you approved before installing them.", "working");
|
|
33549
|
+
let fresh;
|
|
33215
33550
|
try {
|
|
33216
|
-
|
|
33551
|
+
fresh = await this.call(["update"]);
|
|
33217
33552
|
} catch {
|
|
33218
33553
|
this.invalidateObservedState();
|
|
33219
|
-
const message = "The update
|
|
33554
|
+
const message = "The update channels could not be re-checked immediately before installation. Nothing was changed. Review a fresh update preview.";
|
|
33220
33555
|
this.record(message, "attention");
|
|
33221
33556
|
return {
|
|
33222
33557
|
ok: false,
|
|
33223
|
-
title: "Update
|
|
33558
|
+
title: "Update preview changed",
|
|
33224
33559
|
messages: [message],
|
|
33225
33560
|
appliedPlans: 0
|
|
33226
33561
|
};
|
|
33227
33562
|
}
|
|
33228
|
-
if (
|
|
33229
|
-
const message = explainGuideIssue(
|
|
33563
|
+
if (fresh.exitCode !== 0 || fresh.data === null) {
|
|
33564
|
+
const message = explainGuideIssue(fresh.diagnostics, "The update channels changed or could not be re-checked after approval. Nothing was changed; review a fresh update preview.");
|
|
33565
|
+
this.invalidateObservedState();
|
|
33566
|
+
this.record(message, "attention");
|
|
33567
|
+
return {
|
|
33568
|
+
ok: false,
|
|
33569
|
+
title: "Update preview changed",
|
|
33570
|
+
messages: [message],
|
|
33571
|
+
appliedPlans: 0
|
|
33572
|
+
};
|
|
33573
|
+
}
|
|
33574
|
+
const approvedByProvider = new Map(approvedUpdates.map((target) => [String(target.provider), target.version]));
|
|
33575
|
+
const freshUpgradable = fresh.data.providers.filter((row2) => row2.verdict === "upgradable");
|
|
33576
|
+
const unexpected = freshUpgradable.find((row2) => {
|
|
33577
|
+
const approved = approvedByProvider.get(String(row2.providerId)) ?? null;
|
|
33578
|
+
return approved === null || !sameGuideVersion(row2.available, approved);
|
|
33579
|
+
});
|
|
33580
|
+
const unresolved = approvedUpdates.find((target) => {
|
|
33581
|
+
const row2 = fresh.data?.providers.find((candidate) => candidate.providerId === target.provider);
|
|
33582
|
+
return !(row2 !== void 0 && (row2.verdict === "upgradable" && sameGuideVersion(row2.available, target.version) || row2.verdict === "current" && sameGuideVersion(row2.installed, target.version)));
|
|
33583
|
+
});
|
|
33584
|
+
if (unexpected !== void 0 || unresolved !== void 0) {
|
|
33585
|
+
const changed = unexpected !== void 0 ? `${name(unexpected.providerId)} now offers ${unexpected.available ?? "a different version"}.` : `${name(unresolved.provider)} no longer reports the approved target ${unresolved.version}.`;
|
|
33586
|
+
const message = changed + " Nothing was installed because the live update state no longer matches the preview. Review a fresh update preview.";
|
|
33230
33587
|
this.invalidateObservedState();
|
|
33231
33588
|
this.record(message, "attention");
|
|
33232
33589
|
return {
|
|
33233
33590
|
ok: false,
|
|
33234
|
-
title: "
|
|
33591
|
+
title: "Update preview changed",
|
|
33235
33592
|
messages: [message],
|
|
33236
33593
|
appliedPlans: 0
|
|
33237
33594
|
};
|
|
33238
33595
|
}
|
|
33239
|
-
const
|
|
33596
|
+
const pending = approvedUpdates.filter((target) => {
|
|
33597
|
+
const row2 = fresh.data?.providers.find((candidate) => candidate.providerId === target.provider);
|
|
33598
|
+
return row2?.verdict === "upgradable";
|
|
33599
|
+
});
|
|
33600
|
+
let appliedCount = 0;
|
|
33601
|
+
if (pending.length > 0) {
|
|
33602
|
+
this.record("Installing the provider versions from the approved preview.", "working");
|
|
33603
|
+
let result6;
|
|
33604
|
+
try {
|
|
33605
|
+
result6 = await this.call(["update", "--yes"]);
|
|
33606
|
+
} catch {
|
|
33607
|
+
this.invalidateObservedState();
|
|
33608
|
+
const message = "The update stopped before its final result could be read. No automatic retry was made. Refresh and inspect the installed optimizer versions before retrying.";
|
|
33609
|
+
this.record(message, "attention");
|
|
33610
|
+
return {
|
|
33611
|
+
ok: false,
|
|
33612
|
+
title: "Update result needs checking",
|
|
33613
|
+
messages: [message],
|
|
33614
|
+
appliedPlans: 0
|
|
33615
|
+
};
|
|
33616
|
+
}
|
|
33617
|
+
if (result6.exitCode !== 0 || result6.data === null) {
|
|
33618
|
+
const message = explainGuideIssue(result6.diagnostics, "The optimizer update was not applied. The installed version, update channel or runtime capability state changed after the preview, so nothing was forced.");
|
|
33619
|
+
this.invalidateObservedState();
|
|
33620
|
+
this.record(message, "attention");
|
|
33621
|
+
return {
|
|
33622
|
+
ok: false,
|
|
33623
|
+
title: "Optimizer update was not applied",
|
|
33624
|
+
messages: [message],
|
|
33625
|
+
appliedPlans: 0
|
|
33626
|
+
};
|
|
33627
|
+
}
|
|
33628
|
+
appliedCount = result6.data.execution?.results.filter((row2) => row2.status === "applied").length ?? 0;
|
|
33629
|
+
}
|
|
33630
|
+
let inventory;
|
|
33631
|
+
try {
|
|
33632
|
+
inventory = await this.call(["doctor"]);
|
|
33633
|
+
} catch {
|
|
33634
|
+
this.invalidateObservedState();
|
|
33635
|
+
const message = "The installer returned, but Token Harness could not re-read the active optimizer runtimes. The update is not being reported as successful. Refresh and inspect the installed versions.";
|
|
33636
|
+
this.record(message, "attention");
|
|
33637
|
+
return {
|
|
33638
|
+
ok: false,
|
|
33639
|
+
title: "Update result needs checking",
|
|
33640
|
+
messages: [message],
|
|
33641
|
+
appliedPlans: appliedCount
|
|
33642
|
+
};
|
|
33643
|
+
}
|
|
33644
|
+
const missing = approvedUpdates.filter((target) => {
|
|
33645
|
+
const detection = inventory.data?.providers.find((candidate) => candidate.providerId === target.provider);
|
|
33646
|
+
return !sameGuideVersion(detection?.version ?? null, target.version);
|
|
33647
|
+
});
|
|
33648
|
+
if (inventory.data === null || missing.length > 0) {
|
|
33649
|
+
const message = missing.length > 0 ? "The approved update target was not observed on the active PATH after installation: " + missing.map((target) => `${name(target.provider)} ${target.version}`).join(", ") + ". This is not being reported as a successful update." : "The active optimizer versions could not be verified after installation. This is not being reported as a successful update.";
|
|
33650
|
+
this.invalidateObservedState();
|
|
33651
|
+
this.record(message, "attention");
|
|
33652
|
+
return {
|
|
33653
|
+
ok: false,
|
|
33654
|
+
title: "Update was not verified",
|
|
33655
|
+
messages: [
|
|
33656
|
+
message,
|
|
33657
|
+
"Refresh after correcting PATH or the package installation; no automatic retry was made."
|
|
33658
|
+
],
|
|
33659
|
+
appliedPlans: appliedCount
|
|
33660
|
+
};
|
|
33661
|
+
}
|
|
33240
33662
|
this.lastApplied = null;
|
|
33241
33663
|
this.invalidateObservedState();
|
|
33242
|
-
const
|
|
33243
|
-
|
|
33244
|
-
|
|
33245
|
-
"
|
|
33246
|
-
|
|
33247
|
-
"No optimizer needed an update by the time the approved action ran.",
|
|
33248
|
-
"Nothing was forced. Choose Refresh to read the current versions."
|
|
33664
|
+
const versions = approvedUpdates.map((target) => `${name(target.provider)} ${target.version}`).join(", ");
|
|
33665
|
+
const messages2 = [
|
|
33666
|
+
appliedCount > 0 ? `Installed and verified the approved optimizer version${approvedUpdates.length === 1 ? "" : "s"}: ${versions}.` : `The approved optimizer version${approvedUpdates.length === 1 ? " was" : "s were"} already active when the final check ran: ${versions}.`,
|
|
33667
|
+
"The active runtime was re-read after the operation; success is shown only because it matches the approved target.",
|
|
33668
|
+
"Reopen a coding agent if the updated optimizer requires it."
|
|
33249
33669
|
];
|
|
33250
|
-
this.record(
|
|
33670
|
+
this.record(appliedCount > 0 ? "Optimizer update installed and verified." : "Approved optimizer version already active and verified.", "success");
|
|
33251
33671
|
return {
|
|
33252
33672
|
ok: true,
|
|
33253
|
-
title:
|
|
33673
|
+
title: appliedCount > 0 ? "Optimizer updated" : "Approved version already active",
|
|
33254
33674
|
messages: messages2,
|
|
33255
|
-
appliedPlans:
|
|
33675
|
+
appliedPlans: appliedCount
|
|
33256
33676
|
};
|
|
33257
33677
|
}
|
|
33258
33678
|
if (approval.operation === "candidate-apply" || approval.operation === "candidate-uninstall") {
|
|
@@ -33451,6 +33871,7 @@ var init_guided = __esm({
|
|
|
33451
33871
|
}
|
|
33452
33872
|
this.updates = { fingerprint, report: updateResult.data };
|
|
33453
33873
|
const available = updateResult.data.providers.filter((row2) => row2.verdict === "upgradable");
|
|
33874
|
+
const updateTargets = available.flatMap((row2) => row2.available === null ? [] : [{ provider: row2.providerId, version: row2.available }]);
|
|
33454
33875
|
const blocked = updateResult.data.providers.filter((row2) => row2.verdict === "blocked-unreviewed");
|
|
33455
33876
|
const messages = [];
|
|
33456
33877
|
if (available.length > 0) {
|
|
@@ -33462,7 +33883,9 @@ var init_guided = __esm({
|
|
|
33462
33883
|
if (available.length === 0 && blocked.length === 0)
|
|
33463
33884
|
messages.push("Your managed optimizers are up to date on their configured channels.");
|
|
33464
33885
|
let ticket = null;
|
|
33465
|
-
if (available.length > 0) {
|
|
33886
|
+
if (available.length > 0 && updateTargets.length !== available.length) {
|
|
33887
|
+
messages.push("An update channel reported an upgradable optimizer without a concrete target version. No install approval was created.");
|
|
33888
|
+
} else if (updateTargets.length > 0) {
|
|
33466
33889
|
ticket = this.random();
|
|
33467
33890
|
const expires = this.now() + 10 * 6e4;
|
|
33468
33891
|
this.approval = {
|
|
@@ -33473,7 +33896,8 @@ var init_guided = __esm({
|
|
|
33473
33896
|
provider: null,
|
|
33474
33897
|
description: "Optimizer updates",
|
|
33475
33898
|
operation: "update",
|
|
33476
|
-
network: updateResult.data.network.length > 0
|
|
33899
|
+
network: updateResult.data.network.length > 0,
|
|
33900
|
+
updateTargets
|
|
33477
33901
|
};
|
|
33478
33902
|
messages.push("Review the versions above, then choose Install updates. Token Harness will re-check the update channels and transaction safety rules before changing software.");
|
|
33479
33903
|
} else {
|
|
@@ -33482,10 +33906,10 @@ var init_guided = __esm({
|
|
|
33482
33906
|
const stack = this.stackSnapshot();
|
|
33483
33907
|
if (this.cached !== null)
|
|
33484
33908
|
this.cached.value = { ...this.cached.value, stack };
|
|
33485
|
-
this.record(
|
|
33909
|
+
this.record(ticket !== null ? "Optimizer update available. Waiting for your approval." : available.length > 0 ? "Provider update check could not produce an exact install target." : "Provider update check completed. No update is pending.", "success");
|
|
33486
33910
|
return {
|
|
33487
33911
|
ok: true,
|
|
33488
|
-
title: available.length > 0 ? "
|
|
33912
|
+
title: ticket !== null ? "Updates available" : available.length > 0 ? "Update check needs attention" : "Optimizers up to date",
|
|
33489
33913
|
messages,
|
|
33490
33914
|
appliedPlans: 0,
|
|
33491
33915
|
stack,
|
|
@@ -35942,16 +36366,21 @@ var init_guided_product_client = __esm({
|
|
|
35942
36366
|
function componentState(id, component) {
|
|
35943
36367
|
if (!component || component.detectedState === 'absent') return { label: 'Not installed', cls: '' };
|
|
35944
36368
|
if (component.health === 'attention') return { label: 'Needs attention', cls: 'warn' };
|
|
35945
|
-
|
|
36369
|
+
const targets = activeAgents().map(agent => setupTarget(agent.id, id)).filter(Boolean);
|
|
36370
|
+
const connectedHere = targets.some(target => target.state === 'connected');
|
|
36371
|
+
const actionableHere = targets.some(target => target.state === 'actionable');
|
|
36372
|
+
if (component.installed && actionableHere && connectedHere)
|
|
36373
|
+
return { label: 'Partially connected · setup available', cls: 'warn' };
|
|
36374
|
+
if (component.installed && actionableHere)
|
|
36375
|
+
return { label: 'Installed · setup available', cls: 'warn' };
|
|
36376
|
+
if (connectedHere)
|
|
35946
36377
|
return {
|
|
35947
36378
|
label: component.verification === 'verified' ? 'Connected · verified' : 'Connected',
|
|
35948
36379
|
cls: 'good',
|
|
35949
36380
|
};
|
|
35950
|
-
const targets = activeAgents().map(agent => setupTarget(agent.id, id)).filter(Boolean);
|
|
35951
|
-
if (component.installed && targets.some(target => target.state === 'actionable'))
|
|
35952
|
-
return { label: 'Installed · setup available', cls: 'warn' };
|
|
35953
36381
|
if (component.installed && targets.some(target => target.state === 'unavailable'))
|
|
35954
36382
|
return { label: 'Installed · no automatic setup', cls: '' };
|
|
36383
|
+
if (component.configured) return { label: 'Connected elsewhere', cls: '' };
|
|
35955
36384
|
if (component.installed) return { label: 'Installed', cls: '' };
|
|
35956
36385
|
return { label: 'Not installed', cls: '' };
|
|
35957
36386
|
}
|
|
@@ -35978,15 +36407,25 @@ var init_guided_product_client = __esm({
|
|
|
35978
36407
|
const actionableFor = providerTargets
|
|
35979
36408
|
.filter(item => item.target.state === 'actionable')
|
|
35980
36409
|
.map(item => item.agent.name);
|
|
35981
|
-
const unavailableFor = providerTargets
|
|
35982
|
-
|
|
35983
|
-
|
|
35984
|
-
|
|
35985
|
-
|
|
35986
|
-
|
|
35987
|
-
|
|
35988
|
-
|
|
35989
|
-
|
|
36410
|
+
const unavailableFor = providerTargets
|
|
36411
|
+
.filter(item => item.target.state === 'unavailable')
|
|
36412
|
+
.map(item => item.agent.name);
|
|
36413
|
+
const notApplicableFor = providerTargets
|
|
36414
|
+
.filter(item => item.target.state === 'not-applicable')
|
|
36415
|
+
.map(item => item.agent.name);
|
|
36416
|
+
const connectedFor = component?.configuredHarnesses?.length
|
|
36417
|
+
? component.configuredHarnesses.map(agentName)
|
|
36418
|
+
: [];
|
|
36419
|
+
if (connectedFor.length)
|
|
36420
|
+
facts.append(node('span', 'Connected to'), node('strong', connectedFor.join(', ')));
|
|
36421
|
+
if (actionableFor.length)
|
|
36422
|
+
facts.append(node('span', 'Setup available'), node('strong', actionableFor.join(', ')));
|
|
36423
|
+
if (unavailableFor.length)
|
|
36424
|
+
facts.append(node('span', 'Automatic setup unavailable'), node('strong', unavailableFor.join(', ')));
|
|
36425
|
+
if (notApplicableFor.length)
|
|
36426
|
+
facts.append(node('span', 'Not applicable'), node('strong', notApplicableFor.join(', ')));
|
|
36427
|
+
if (!connectedFor.length && !actionableFor.length && !unavailableFor.length && !notApplicableFor.length)
|
|
36428
|
+
facts.append(node('span', 'Connection'), node('strong', 'No detected coding agent target'));
|
|
35990
36429
|
if (component?.update === 'available')
|
|
35991
36430
|
facts.append(
|
|
35992
36431
|
node('span', 'Update'),
|
|
@@ -36005,7 +36444,8 @@ var init_guided_product_client = __esm({
|
|
|
36005
36444
|
card.append(
|
|
36006
36445
|
messageBox(
|
|
36007
36446
|
'Why there is no Connect button',
|
|
36008
|
-
|
|
36447
|
+
providerTargets.find(item => item.target.state === 'unavailable')?.target.reason ||
|
|
36448
|
+
'The installed provider does not expose an automatic setup surface for this coding agent.',
|
|
36009
36449
|
),
|
|
36010
36450
|
);
|
|
36011
36451
|
|