token-harness 0.1.2 → 0.1.3
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/README.md +34 -10
- package/package.json +1 -1
- package/sbom.json +2 -2
- package/token-harness.mjs +737 -214
package/token-harness.mjs
CHANGED
|
@@ -97,18 +97,18 @@ function compareVersions(a, b) {
|
|
|
97
97
|
return comparePrerelease(a.prerelease, b.prerelease);
|
|
98
98
|
}
|
|
99
99
|
function classifyVersion(observed, range) {
|
|
100
|
-
const
|
|
100
|
+
const version3 = parseSemanticVersion(observed);
|
|
101
101
|
const minimum = parseSemanticVersion(range.minimum);
|
|
102
|
-
if (
|
|
102
|
+
if (version3 === null || minimum === null)
|
|
103
103
|
return "unparseable";
|
|
104
|
-
if (compareVersions(
|
|
104
|
+
if (compareVersions(version3, minimum) < 0)
|
|
105
105
|
return "below-range";
|
|
106
106
|
if (range.maximum === null)
|
|
107
107
|
return "in-range";
|
|
108
108
|
const maximum = parseSemanticVersion(range.maximum);
|
|
109
109
|
if (maximum === null)
|
|
110
110
|
return "unparseable";
|
|
111
|
-
return compareVersions(
|
|
111
|
+
return compareVersions(version3, maximum) > 0 ? "unknown-newer" : "in-range";
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
// packages/core/dist/src/domain/compatibility-rows.js
|
|
@@ -134,6 +134,19 @@ var COMPATIBILITY_ROWS = [
|
|
|
134
134
|
configSchema: "claude-skills-directory",
|
|
135
135
|
fixture: "tests/fixtures/rows/harnesstrim-claude-windows",
|
|
136
136
|
verificationTier: "config-only"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
harness: "codex",
|
|
140
|
+
harnessVersion: { minimum: "0.146.0", maximum: "0.146.0" },
|
|
141
|
+
provider: "harnesstrim",
|
|
142
|
+
providerVersion: "0.1.0",
|
|
143
|
+
platform: { os: "windows", wsl: false, supported: true, limitation: null },
|
|
144
|
+
// The same shape as the Claude skills row, and for the same reason: the install writes skill
|
|
145
|
+
// files rather than a document this build parses, so the schema it depends on is the directory
|
|
146
|
+
// layout. A separate id because the directory is `.codex/skills` and the protected paths differ.
|
|
147
|
+
configSchema: "codex-skills-directory",
|
|
148
|
+
fixture: "tests/fixtures/rows/harnesstrim-codex-windows",
|
|
149
|
+
verificationTier: "config-only"
|
|
137
150
|
}
|
|
138
151
|
];
|
|
139
152
|
function classifyRowHarnessVersion(rows, observed) {
|
|
@@ -695,14 +708,14 @@ function resolveOwnership(input) {
|
|
|
695
708
|
});
|
|
696
709
|
continue;
|
|
697
710
|
}
|
|
698
|
-
if (!provider.
|
|
711
|
+
if (!provider.assignableHarnesses.has(harness.id)) {
|
|
699
712
|
const observed = input.observedVersions[provider.id] ?? null;
|
|
700
713
|
exclusions.push({
|
|
701
714
|
scope,
|
|
702
715
|
excluded: provider.id,
|
|
703
716
|
retained: null,
|
|
704
717
|
reason: [
|
|
705
|
-
observed === null ? `${provider.id} implements ${capability} but no installer state this build could observe produces it
|
|
718
|
+
observed === null ? `${provider.id} implements ${capability} on ${harness.id} but no installer state this build could observe produces it there` : `${provider.id} ${observed} implements ${capability} on ${harness.id} but no installer state at that version produces it there`,
|
|
706
719
|
"RFC 0003: a capability the provider has but cannot be asked for is not an assignable capability",
|
|
707
720
|
"It is still detected, adopted, reconciled against the owner, and measured"
|
|
708
721
|
]
|
|
@@ -1026,21 +1039,21 @@ function validateStoredPlan(input) {
|
|
|
1026
1039
|
detail: `the plan was computed for ${stored.projectRoot} and this invocation is in ${input.projectRoot}`
|
|
1027
1040
|
});
|
|
1028
1041
|
}
|
|
1029
|
-
for (const [id,
|
|
1042
|
+
for (const [id, version3] of Object.entries(stored.versions.providers)) {
|
|
1030
1043
|
const current = input.versions.providers[id];
|
|
1031
|
-
if (current !==
|
|
1044
|
+
if (current !== version3) {
|
|
1032
1045
|
rejections.push({
|
|
1033
1046
|
reason: "plan-version-drift",
|
|
1034
|
-
detail: `${id} was ${
|
|
1047
|
+
detail: `${id} was ${version3 ?? "absent"} when the plan was made and is now ${current ?? "absent"}`
|
|
1035
1048
|
});
|
|
1036
1049
|
}
|
|
1037
1050
|
}
|
|
1038
|
-
for (const [id,
|
|
1051
|
+
for (const [id, version3] of Object.entries(stored.versions.harnesses)) {
|
|
1039
1052
|
const current = input.versions.harnesses[id];
|
|
1040
|
-
if (current !==
|
|
1053
|
+
if (current !== version3) {
|
|
1041
1054
|
rejections.push({
|
|
1042
1055
|
reason: "plan-version-drift",
|
|
1043
|
-
detail: `${id} was ${
|
|
1056
|
+
detail: `${id} was ${version3 ?? "absent"} when the plan was made and is now ${current ?? "absent"}`
|
|
1044
1057
|
});
|
|
1045
1058
|
}
|
|
1046
1059
|
}
|
|
@@ -1327,7 +1340,7 @@ function resolveMetricsWindow(input) {
|
|
|
1327
1340
|
var INSTALL_COMMANDS = {
|
|
1328
1341
|
winget: {
|
|
1329
1342
|
executable: "winget",
|
|
1330
|
-
args: (packageName,
|
|
1343
|
+
args: (packageName, version3) => [
|
|
1331
1344
|
"install",
|
|
1332
1345
|
"--id",
|
|
1333
1346
|
packageName,
|
|
@@ -1337,16 +1350,16 @@ var INSTALL_COMMANDS = {
|
|
|
1337
1350
|
"--silent",
|
|
1338
1351
|
"--accept-package-agreements",
|
|
1339
1352
|
"--accept-source-agreements",
|
|
1340
|
-
...
|
|
1353
|
+
...version3 === null ? [] : ["--version", version3]
|
|
1341
1354
|
],
|
|
1342
1355
|
verified: true
|
|
1343
1356
|
},
|
|
1344
1357
|
cargo: {
|
|
1345
1358
|
executable: "cargo",
|
|
1346
|
-
args: (packageName,
|
|
1359
|
+
args: (packageName, version3) => [
|
|
1347
1360
|
"install",
|
|
1348
1361
|
packageName,
|
|
1349
|
-
...
|
|
1362
|
+
...version3 === null ? [] : ["--version", version3]
|
|
1350
1363
|
],
|
|
1351
1364
|
verified: false
|
|
1352
1365
|
}
|
|
@@ -1464,8 +1477,8 @@ async function queryAvailableVersion(input) {
|
|
|
1464
1477
|
}));
|
|
1465
1478
|
return { status: "failed", version: null, destination, diagnostics };
|
|
1466
1479
|
}
|
|
1467
|
-
const
|
|
1468
|
-
if (
|
|
1480
|
+
const version3 = recipe.parse(outcome2.stdout);
|
|
1481
|
+
if (version3 === null) {
|
|
1469
1482
|
diagnostics.push(diagnostic({
|
|
1470
1483
|
severity: "warning",
|
|
1471
1484
|
code: "version-query-unreadable",
|
|
@@ -1474,7 +1487,7 @@ async function queryAvailableVersion(input) {
|
|
|
1474
1487
|
}));
|
|
1475
1488
|
return { status: "unknown", version: null, destination, diagnostics };
|
|
1476
1489
|
}
|
|
1477
|
-
return { status: "found", version:
|
|
1490
|
+
return { status: "found", version: version3, destination, diagnostics };
|
|
1478
1491
|
}
|
|
1479
1492
|
var INVENTORY_COMMANDS = {
|
|
1480
1493
|
/**
|
|
@@ -3133,10 +3146,10 @@ function parsePins(raw, path, diagnostics) {
|
|
|
3133
3146
|
if (typeof entry !== "object" || entry === null)
|
|
3134
3147
|
continue;
|
|
3135
3148
|
const provider = entry.provider;
|
|
3136
|
-
const
|
|
3149
|
+
const version3 = entry.version;
|
|
3137
3150
|
if (typeof provider !== "string" || provider === "")
|
|
3138
3151
|
continue;
|
|
3139
|
-
if (typeof
|
|
3152
|
+
if (typeof version3 !== "string" || parseSemanticVersion(version3) === null) {
|
|
3140
3153
|
diagnostics.push(diagnostic({
|
|
3141
3154
|
severity: "warning",
|
|
3142
3155
|
code: "pin-version-unparseable",
|
|
@@ -3145,7 +3158,7 @@ function parsePins(raw, path, diagnostics) {
|
|
|
3145
3158
|
}));
|
|
3146
3159
|
continue;
|
|
3147
3160
|
}
|
|
3148
|
-
pins.push({ provider, version:
|
|
3161
|
+
pins.push({ provider, version: version3 });
|
|
3149
3162
|
}
|
|
3150
3163
|
return pins;
|
|
3151
3164
|
}
|
|
@@ -5053,8 +5066,8 @@ async function detectVersion2(context) {
|
|
|
5053
5066
|
};
|
|
5054
5067
|
}
|
|
5055
5068
|
const matched = VERSION_PATTERN.exec(outcome2.stdout);
|
|
5056
|
-
const
|
|
5057
|
-
if (
|
|
5069
|
+
const version3 = matched?.[1] ?? null;
|
|
5070
|
+
if (version3 === null) {
|
|
5058
5071
|
return {
|
|
5059
5072
|
version: null,
|
|
5060
5073
|
verdict: null,
|
|
@@ -5068,14 +5081,14 @@ async function detectVersion2(context) {
|
|
|
5068
5081
|
};
|
|
5069
5082
|
}
|
|
5070
5083
|
return {
|
|
5071
|
-
version:
|
|
5072
|
-
verdict: classifyVersion(
|
|
5084
|
+
version: version3,
|
|
5085
|
+
verdict: classifyVersion(version3, MANIFEST.testedVersions),
|
|
5073
5086
|
evidence: [
|
|
5074
5087
|
evidence({
|
|
5075
5088
|
kind: "version-output",
|
|
5076
5089
|
source: command.executable,
|
|
5077
5090
|
path: outcome2.executablePath,
|
|
5078
|
-
detail: `reported ${
|
|
5091
|
+
detail: `reported ${version3}`
|
|
5079
5092
|
})
|
|
5080
5093
|
]
|
|
5081
5094
|
};
|
|
@@ -5083,7 +5096,7 @@ async function detectVersion2(context) {
|
|
|
5083
5096
|
async function detect(context) {
|
|
5084
5097
|
const evidenceItems = [];
|
|
5085
5098
|
const warnings = [];
|
|
5086
|
-
const { version:
|
|
5099
|
+
const { version: version3, verdict, evidence: versionEvidence } = await detectVersion2(context);
|
|
5087
5100
|
evidenceItems.push(...versionEvidence);
|
|
5088
5101
|
const configs = await Promise.all(MANIFEST.configFiles.map((declaration) => resolveConfig(declaration, context)));
|
|
5089
5102
|
const present = configs.filter((config) => config.exists);
|
|
@@ -5106,7 +5119,7 @@ async function detect(context) {
|
|
|
5106
5119
|
remediation: "Repair the JSON syntax, then run the command again"
|
|
5107
5120
|
}));
|
|
5108
5121
|
}
|
|
5109
|
-
if (
|
|
5122
|
+
if (version3 === null && present.length > 0) {
|
|
5110
5123
|
warnings.push(diagnostic({
|
|
5111
5124
|
severity: "warning",
|
|
5112
5125
|
code: "harness-executable-missing",
|
|
@@ -5119,16 +5132,16 @@ async function detect(context) {
|
|
|
5119
5132
|
warnings.push(diagnostic({
|
|
5120
5133
|
severity: "warning",
|
|
5121
5134
|
code: "harness-version-unknown-newer",
|
|
5122
|
-
message: `Claude Code ${String(
|
|
5135
|
+
message: `Claude Code ${String(version3)} is newer than the versions whose configuration schema Token Harness has observed (up to ${String(MANIFEST.testedVersions.maximum)})`,
|
|
5123
5136
|
remediation: "Check the release notes for hook-schema changes before applying a plan"
|
|
5124
5137
|
}));
|
|
5125
5138
|
}
|
|
5126
|
-
const state = unparsed.length > 0 ? "broken" : configured.length > 0 &&
|
|
5139
|
+
const state = unparsed.length > 0 ? "broken" : configured.length > 0 && version3 !== null ? "configured" : version3 !== null || present.length > 0 ? "detected" : "absent";
|
|
5127
5140
|
const primary = present.find((config) => config.declaration.primary) ?? present[0] ?? null;
|
|
5128
5141
|
return {
|
|
5129
5142
|
harnessId: CLAUDE,
|
|
5130
5143
|
state,
|
|
5131
|
-
version:
|
|
5144
|
+
version: version3,
|
|
5132
5145
|
versionVerdict: verdict,
|
|
5133
5146
|
configPath: primary?.path ?? null,
|
|
5134
5147
|
declaredVerificationTier: MANIFEST.verificationTier,
|
|
@@ -5382,22 +5395,22 @@ async function detectVersion3(context) {
|
|
|
5382
5395
|
})
|
|
5383
5396
|
]
|
|
5384
5397
|
};
|
|
5385
|
-
const
|
|
5398
|
+
const version3 = VERSION_PATTERN2.exec(outcome2.stdout)?.[1] ?? null;
|
|
5386
5399
|
return {
|
|
5387
|
-
version:
|
|
5388
|
-
verdict:
|
|
5400
|
+
version: version3,
|
|
5401
|
+
verdict: version3 === null ? null : classifyVersion(version3, MANIFEST2.testedVersions),
|
|
5389
5402
|
evidence: [
|
|
5390
5403
|
evidence({
|
|
5391
5404
|
kind: "version-output",
|
|
5392
5405
|
source: "codex",
|
|
5393
5406
|
path: outcome2.executablePath,
|
|
5394
|
-
detail:
|
|
5407
|
+
detail: version3 === null ? "reported no recognisable semantic version" : `reported ${version3}`
|
|
5395
5408
|
})
|
|
5396
5409
|
]
|
|
5397
5410
|
};
|
|
5398
5411
|
}
|
|
5399
5412
|
async function detect2(context) {
|
|
5400
|
-
const { version:
|
|
5413
|
+
const { version: version3, verdict, evidence: versionEvidence } = await detectVersion3(context);
|
|
5401
5414
|
const configs = await Promise.all(MANIFEST2.configFiles.map((file) => resolveConfig2(file, context)));
|
|
5402
5415
|
const present = configs.filter((config) => config.exists);
|
|
5403
5416
|
const hooks = configs.find((config) => config.declaration.path.endsWith("hooks.json"));
|
|
@@ -5410,7 +5423,7 @@ async function detect2(context) {
|
|
|
5410
5423
|
path: hooks.path,
|
|
5411
5424
|
remediation: "Repair the JSON syntax, then run the command again"
|
|
5412
5425
|
}));
|
|
5413
|
-
if (
|
|
5426
|
+
if (version3 === null && present.length > 0)
|
|
5414
5427
|
warnings.push(diagnostic({
|
|
5415
5428
|
severity: "warning",
|
|
5416
5429
|
code: "harness-executable-missing",
|
|
@@ -5422,15 +5435,15 @@ async function detect2(context) {
|
|
|
5422
5435
|
warnings.push(diagnostic({
|
|
5423
5436
|
severity: "warning",
|
|
5424
5437
|
code: "harness-version-unknown-newer",
|
|
5425
|
-
message: `Codex ${String(
|
|
5438
|
+
message: `Codex ${String(version3)} is newer than the observed hook schema`,
|
|
5426
5439
|
remediation: "Check the release notes for hook-schema changes before applying a plan"
|
|
5427
5440
|
}));
|
|
5428
5441
|
const configured = (hooks?.configuredPoints.length ?? 0) > 0;
|
|
5429
5442
|
const primary = configs.find((config) => config.declaration.primary && config.exists) ?? present[0] ?? null;
|
|
5430
5443
|
return {
|
|
5431
5444
|
harnessId: CODEX,
|
|
5432
|
-
state: hooks?.exists && !hooks.parsed ? "broken" : configured &&
|
|
5433
|
-
version:
|
|
5445
|
+
state: hooks?.exists && !hooks.parsed ? "broken" : configured && version3 !== null ? "configured" : version3 !== null || present.length > 0 ? "detected" : "absent",
|
|
5446
|
+
version: version3,
|
|
5434
5447
|
versionVerdict: verdict,
|
|
5435
5448
|
configPath: primary?.path ?? null,
|
|
5436
5449
|
declaredVerificationTier: MANIFEST2.verificationTier,
|
|
@@ -5547,10 +5560,231 @@ async function verify2(context) {
|
|
|
5547
5560
|
}
|
|
5548
5561
|
var codexAdapter = { manifest: MANIFEST2, detect: detect2, inspect: inspect2, verify: verify2 };
|
|
5549
5562
|
|
|
5550
|
-
// packages/adapters/dist/src/harnesses/
|
|
5551
|
-
var
|
|
5563
|
+
// packages/adapters/dist/src/harnesses/hermes.js
|
|
5564
|
+
var HERMES = harnessId("hermes");
|
|
5552
5565
|
var VERSION_PATTERN3 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
|
|
5566
|
+
var PLUGIN = "harnesstrim";
|
|
5553
5567
|
var MANIFEST3 = {
|
|
5568
|
+
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
5569
|
+
id: HERMES,
|
|
5570
|
+
displayName: "Hermes Agent",
|
|
5571
|
+
homepage: "https://hermes-agent.nousresearch.com/docs/",
|
|
5572
|
+
testedVersions: { minimum: "0.1.0", maximum: "0.1.0" },
|
|
5573
|
+
verificationTier: "config-only",
|
|
5574
|
+
versionCommand: { executable: "hermes", args: ["--version"] },
|
|
5575
|
+
interceptionPoints: [{ scopeId: "transform-tool-result", eventName: "transform_tool_result" }],
|
|
5576
|
+
configFiles: [
|
|
5577
|
+
{
|
|
5578
|
+
path: ".hermes/plugins/harnesstrim/plugin.yaml",
|
|
5579
|
+
scope: "user",
|
|
5580
|
+
parser: "markers",
|
|
5581
|
+
primary: true
|
|
5582
|
+
},
|
|
5583
|
+
{
|
|
5584
|
+
path: ".hermes/plugins/harnesstrim/config.json",
|
|
5585
|
+
scope: "user",
|
|
5586
|
+
parser: "json",
|
|
5587
|
+
primary: false
|
|
5588
|
+
}
|
|
5589
|
+
],
|
|
5590
|
+
toolFamilies: [
|
|
5591
|
+
{ id: "tool.result", platforms: ["windows", "macos", "linux"], executesShellCommands: false }
|
|
5592
|
+
],
|
|
5593
|
+
requiresEnablement: true,
|
|
5594
|
+
enablementNote: "The plugin must be enabled with `hermes plugins enable harnesstrim`.",
|
|
5595
|
+
receiptFamily: "provider-telemetry"
|
|
5596
|
+
};
|
|
5597
|
+
async function resolveConfig3(declaration, context) {
|
|
5598
|
+
const path = resolveConfigPath(declaration, context);
|
|
5599
|
+
const stat3 = await context.fs.stat(path);
|
|
5600
|
+
if (stat3 === null || stat3.kind !== "file") {
|
|
5601
|
+
return {
|
|
5602
|
+
declaration,
|
|
5603
|
+
path,
|
|
5604
|
+
exists: false,
|
|
5605
|
+
parsed: false,
|
|
5606
|
+
configuredPoints: [],
|
|
5607
|
+
matchers: [],
|
|
5608
|
+
commands: []
|
|
5609
|
+
};
|
|
5610
|
+
}
|
|
5611
|
+
const text = new TextDecoder().decode(await context.fs.readFile(path));
|
|
5612
|
+
const parsed = declaration.parser === "json" ? (() => {
|
|
5613
|
+
try {
|
|
5614
|
+
return JSON.parse(text);
|
|
5615
|
+
} catch {
|
|
5616
|
+
return null;
|
|
5617
|
+
}
|
|
5618
|
+
})() : text;
|
|
5619
|
+
const valid = parsed !== null;
|
|
5620
|
+
return {
|
|
5621
|
+
declaration,
|
|
5622
|
+
path,
|
|
5623
|
+
exists: true,
|
|
5624
|
+
parsed: valid,
|
|
5625
|
+
configuredPoints: valid && declaration.path.endsWith("plugin.yaml") ? ["transform-tool-result"] : [],
|
|
5626
|
+
matchers: valid && declaration.path.endsWith("plugin.yaml") ? ["tool.result"] : [],
|
|
5627
|
+
commands: valid && declaration.path.endsWith("plugin.yaml") ? ["hermes plugins enable harnesstrim"] : []
|
|
5628
|
+
};
|
|
5629
|
+
}
|
|
5630
|
+
async function version2(context) {
|
|
5631
|
+
const result = await context.runner.run({
|
|
5632
|
+
executable: "hermes",
|
|
5633
|
+
args: ["--version"],
|
|
5634
|
+
cwd: context.projectRoot,
|
|
5635
|
+
timeoutMs: 2e4
|
|
5636
|
+
});
|
|
5637
|
+
if (result.failure !== null)
|
|
5638
|
+
return {
|
|
5639
|
+
value: null,
|
|
5640
|
+
verdict: null,
|
|
5641
|
+
evidence: [
|
|
5642
|
+
evidence({
|
|
5643
|
+
kind: "absence",
|
|
5644
|
+
source: "hermes",
|
|
5645
|
+
detail: `not runnable: ${result.failure.reason}`
|
|
5646
|
+
})
|
|
5647
|
+
]
|
|
5648
|
+
};
|
|
5649
|
+
const value = VERSION_PATTERN3.exec(result.stdout)?.[1] ?? null;
|
|
5650
|
+
return {
|
|
5651
|
+
value,
|
|
5652
|
+
verdict: value === null ? null : classifyVersion(value, MANIFEST3.testedVersions),
|
|
5653
|
+
evidence: [
|
|
5654
|
+
evidence({
|
|
5655
|
+
kind: "version-output",
|
|
5656
|
+
source: "hermes",
|
|
5657
|
+
path: result.executablePath,
|
|
5658
|
+
detail: value ? `reported ${value}` : "reported no recognisable version"
|
|
5659
|
+
})
|
|
5660
|
+
]
|
|
5661
|
+
};
|
|
5662
|
+
}
|
|
5663
|
+
async function enabled(context) {
|
|
5664
|
+
const result = await context.runner.run({
|
|
5665
|
+
executable: "hermes",
|
|
5666
|
+
args: ["plugins", "list"],
|
|
5667
|
+
cwd: context.projectRoot,
|
|
5668
|
+
timeoutMs: 2e4
|
|
5669
|
+
});
|
|
5670
|
+
if (result.failure !== null || result.exitCode !== 0)
|
|
5671
|
+
return null;
|
|
5672
|
+
const line = result.stdout.split("\n").find((entry) => entry.toLowerCase().includes(PLUGIN));
|
|
5673
|
+
return line === void 0 ? false : /enabled/i.test(line);
|
|
5674
|
+
}
|
|
5675
|
+
async function detect3(context) {
|
|
5676
|
+
const observed = await version2(context);
|
|
5677
|
+
const configs = await Promise.all(MANIFEST3.configFiles.map((file) => resolveConfig3(file, context)));
|
|
5678
|
+
const plugin = configs.find((file) => file.declaration.path.endsWith("plugin.yaml"));
|
|
5679
|
+
const isEnabled = await enabled(context);
|
|
5680
|
+
const warnings = [];
|
|
5681
|
+
if (observed.verdict === "unknown-newer")
|
|
5682
|
+
warnings.push(diagnostic({
|
|
5683
|
+
severity: "warning",
|
|
5684
|
+
code: "harness-version-unknown-newer",
|
|
5685
|
+
message: `Hermes ${observed.value} is newer than the observed plugin contract`,
|
|
5686
|
+
remediation: "Review the transform_tool_result plugin contract before applying changes"
|
|
5687
|
+
}));
|
|
5688
|
+
if (plugin?.exists && isEnabled === false)
|
|
5689
|
+
warnings.push(diagnostic({
|
|
5690
|
+
severity: "warning",
|
|
5691
|
+
code: "plugin-disabled",
|
|
5692
|
+
message: "HarnessTrim is installed in Hermes but is not enabled",
|
|
5693
|
+
path: plugin.path,
|
|
5694
|
+
remediation: "Run `hermes plugins enable harnesstrim`"
|
|
5695
|
+
}));
|
|
5696
|
+
const present = plugin?.exists === true;
|
|
5697
|
+
return {
|
|
5698
|
+
harnessId: HERMES,
|
|
5699
|
+
state: present && isEnabled === true && observed.value !== null ? "configured" : present || observed.value !== null ? "detected" : "absent",
|
|
5700
|
+
version: observed.value,
|
|
5701
|
+
versionVerdict: observed.verdict,
|
|
5702
|
+
configPath: plugin?.path ?? null,
|
|
5703
|
+
declaredVerificationTier: MANIFEST3.verificationTier,
|
|
5704
|
+
evidence: [
|
|
5705
|
+
...observed.evidence,
|
|
5706
|
+
...plugin ? [
|
|
5707
|
+
evidence({
|
|
5708
|
+
kind: "config-entry",
|
|
5709
|
+
source: "Hermes plugin directory",
|
|
5710
|
+
path: plugin.path,
|
|
5711
|
+
detail: plugin.exists ? "HarnessTrim plugin manifest present" : "plugin manifest absent"
|
|
5712
|
+
})
|
|
5713
|
+
] : []
|
|
5714
|
+
],
|
|
5715
|
+
warnings
|
|
5716
|
+
};
|
|
5717
|
+
}
|
|
5718
|
+
async function inspect3(context) {
|
|
5719
|
+
const configs = await Promise.all(MANIFEST3.configFiles.map((file) => resolveConfig3(file, context)));
|
|
5720
|
+
return {
|
|
5721
|
+
harnessId: HERMES,
|
|
5722
|
+
configs,
|
|
5723
|
+
activeToolFamilies: familiesOnThisPlatform(MANIFEST3, context.facts),
|
|
5724
|
+
uncoveredToolFamilies: [],
|
|
5725
|
+
enabled: await enabled(context),
|
|
5726
|
+
diagnostics: [],
|
|
5727
|
+
summaries: configs.filter((config) => config.configuredPoints.length > 0).map((config) => ({
|
|
5728
|
+
harnessId: HERMES,
|
|
5729
|
+
configPath: config.path,
|
|
5730
|
+
scope: config.declaration.scope,
|
|
5731
|
+
interceptionPoints: config.configuredPoints,
|
|
5732
|
+
matchers: config.matchers,
|
|
5733
|
+
commands: config.commands
|
|
5734
|
+
}))
|
|
5735
|
+
};
|
|
5736
|
+
}
|
|
5737
|
+
async function verify3(context) {
|
|
5738
|
+
const detection = await detect3(context);
|
|
5739
|
+
const inspection = await inspect3(context);
|
|
5740
|
+
const plugin = inspection.configs.some((config) => config.configuredPoints.length > 0);
|
|
5741
|
+
const checks = [
|
|
5742
|
+
{
|
|
5743
|
+
id: "executable-resolves",
|
|
5744
|
+
status: detection.version === null ? "fail" : "pass",
|
|
5745
|
+
summary: detection.version === null ? "hermes could not be run" : `Hermes ${detection.version}`,
|
|
5746
|
+
achievedTier: detection.version === null ? null : "presence",
|
|
5747
|
+
evidence: detection.evidence.filter((item) => item.kind === "version-output"),
|
|
5748
|
+
remediation: detection.version === null ? "Install Hermes or add it to PATH" : null
|
|
5749
|
+
},
|
|
5750
|
+
{
|
|
5751
|
+
id: "plugin-installed",
|
|
5752
|
+
status: plugin ? "pass" : "fail",
|
|
5753
|
+
summary: plugin ? "HarnessTrim plugin manifest is installed" : "HarnessTrim plugin manifest is missing",
|
|
5754
|
+
achievedTier: plugin ? "config-only" : null,
|
|
5755
|
+
evidence: [],
|
|
5756
|
+
remediation: plugin ? null : "Run `harnesstrim install hermes --apply`"
|
|
5757
|
+
},
|
|
5758
|
+
{
|
|
5759
|
+
id: "plugin-enabled",
|
|
5760
|
+
status: inspection.enabled === true ? "pass" : inspection.enabled === false ? "fail" : "not-exercised",
|
|
5761
|
+
summary: inspection.enabled === true ? "HarnessTrim is enabled" : inspection.enabled === false ? "HarnessTrim is installed but disabled" : "Hermes plugin state could not be read",
|
|
5762
|
+
achievedTier: inspection.enabled === true ? "config-only" : null,
|
|
5763
|
+
evidence: [],
|
|
5764
|
+
remediation: inspection.enabled === false ? "Run `hermes plugins enable harnesstrim`" : null
|
|
5765
|
+
},
|
|
5766
|
+
{
|
|
5767
|
+
id: "canary-intercepted",
|
|
5768
|
+
status: "not-exercised",
|
|
5769
|
+
summary: "Hermes exposes no independent receipt; HarnessTrim telemetry is verified by the provider adapter",
|
|
5770
|
+
achievedTier: null,
|
|
5771
|
+
evidence: [],
|
|
5772
|
+
remediation: null
|
|
5773
|
+
}
|
|
5774
|
+
];
|
|
5775
|
+
return {
|
|
5776
|
+
harnessId: HERMES,
|
|
5777
|
+
declaredTier: MANIFEST3.verificationTier,
|
|
5778
|
+
achievedTier: checks.some((check) => check.achievedTier === "config-only") ? "config-only" : checks.some((check) => check.achievedTier === "presence") ? "presence" : null,
|
|
5779
|
+
checks
|
|
5780
|
+
};
|
|
5781
|
+
}
|
|
5782
|
+
var hermesAdapter = { manifest: MANIFEST3, detect: detect3, inspect: inspect3, verify: verify3 };
|
|
5783
|
+
|
|
5784
|
+
// packages/adapters/dist/src/harnesses/opencode.js
|
|
5785
|
+
var OPENCODE = harnessId("opencode");
|
|
5786
|
+
var VERSION_PATTERN4 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
|
|
5787
|
+
var MANIFEST4 = {
|
|
5554
5788
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
5555
5789
|
id: OPENCODE,
|
|
5556
5790
|
displayName: "OpenCode",
|
|
@@ -5650,7 +5884,7 @@ async function resolvePluginDirectory(declaration, context) {
|
|
|
5650
5884
|
commands: modules.map((entry) => context.fs.join(path, entry))
|
|
5651
5885
|
};
|
|
5652
5886
|
}
|
|
5653
|
-
async function
|
|
5887
|
+
async function resolveConfig4(declaration, context) {
|
|
5654
5888
|
if (declaration.parser === "markers")
|
|
5655
5889
|
return resolvePluginDirectory(declaration, context);
|
|
5656
5890
|
const path = resolveConfigPath(declaration, context);
|
|
@@ -5711,23 +5945,23 @@ async function detectVersion4(context) {
|
|
|
5711
5945
|
})
|
|
5712
5946
|
]
|
|
5713
5947
|
};
|
|
5714
|
-
const
|
|
5948
|
+
const version3 = VERSION_PATTERN4.exec(outcome2.stdout)?.[1] ?? null;
|
|
5715
5949
|
return {
|
|
5716
|
-
version:
|
|
5717
|
-
verdict:
|
|
5950
|
+
version: version3,
|
|
5951
|
+
verdict: version3 === null ? null : classifyVersion(version3, MANIFEST4.testedVersions),
|
|
5718
5952
|
evidence: [
|
|
5719
5953
|
evidence({
|
|
5720
5954
|
kind: "version-output",
|
|
5721
5955
|
source: "opencode",
|
|
5722
5956
|
path: outcome2.executablePath,
|
|
5723
|
-
detail:
|
|
5957
|
+
detail: version3 === null ? "reported no recognisable semantic version" : `reported ${version3}`
|
|
5724
5958
|
})
|
|
5725
5959
|
]
|
|
5726
5960
|
};
|
|
5727
5961
|
}
|
|
5728
|
-
async function
|
|
5729
|
-
const { version:
|
|
5730
|
-
const configs = await Promise.all(
|
|
5962
|
+
async function detect4(context) {
|
|
5963
|
+
const { version: version3, verdict, evidence: versionEvidence } = await detectVersion4(context);
|
|
5964
|
+
const configs = await Promise.all(MANIFEST4.configFiles.map((file) => resolveConfig4(file, context)));
|
|
5731
5965
|
const present = configs.filter((config) => config.exists);
|
|
5732
5966
|
const configured = present.filter((config) => config.configuredPoints.length > 0);
|
|
5733
5967
|
const warnings = [];
|
|
@@ -5743,17 +5977,17 @@ async function detect3(context) {
|
|
|
5743
5977
|
warnings.push(diagnostic({
|
|
5744
5978
|
severity: "warning",
|
|
5745
5979
|
code: "harness-version-unknown-newer",
|
|
5746
|
-
message: `OpenCode ${String(
|
|
5980
|
+
message: `OpenCode ${String(version3)} is newer than the observed configuration schema`,
|
|
5747
5981
|
remediation: "Check the release notes for plugin-schema changes before applying a plan"
|
|
5748
5982
|
}));
|
|
5749
5983
|
const primary = present.find((config) => config.declaration.primary) ?? present[0] ?? null;
|
|
5750
5984
|
return {
|
|
5751
5985
|
harnessId: OPENCODE,
|
|
5752
|
-
state: present.some((config) => !config.parsed) ? "broken" : configured.length > 0 &&
|
|
5753
|
-
version:
|
|
5986
|
+
state: present.some((config) => !config.parsed) ? "broken" : configured.length > 0 && version3 !== null ? "configured" : version3 !== null || present.length > 0 ? "detected" : "absent",
|
|
5987
|
+
version: version3,
|
|
5754
5988
|
versionVerdict: verdict,
|
|
5755
5989
|
configPath: primary?.path ?? null,
|
|
5756
|
-
declaredVerificationTier:
|
|
5990
|
+
declaredVerificationTier: MANIFEST4.verificationTier,
|
|
5757
5991
|
evidence: [
|
|
5758
5992
|
...versionEvidence,
|
|
5759
5993
|
...present.map((config) => evidence({
|
|
@@ -5766,9 +6000,9 @@ async function detect3(context) {
|
|
|
5766
6000
|
warnings
|
|
5767
6001
|
};
|
|
5768
6002
|
}
|
|
5769
|
-
async function
|
|
5770
|
-
const configs = await Promise.all(
|
|
5771
|
-
const activeToolFamilies = familiesOnThisPlatform(
|
|
6003
|
+
async function inspect4(context) {
|
|
6004
|
+
const configs = await Promise.all(MANIFEST4.configFiles.map((file) => resolveConfig4(file, context)));
|
|
6005
|
+
const activeToolFamilies = familiesOnThisPlatform(MANIFEST4, context.facts);
|
|
5772
6006
|
return {
|
|
5773
6007
|
harnessId: OPENCODE,
|
|
5774
6008
|
configs,
|
|
@@ -5786,9 +6020,9 @@ async function inspect3(context) {
|
|
|
5786
6020
|
}))
|
|
5787
6021
|
};
|
|
5788
6022
|
}
|
|
5789
|
-
async function
|
|
5790
|
-
const detection = await
|
|
5791
|
-
const inspection = await
|
|
6023
|
+
async function verify4(context) {
|
|
6024
|
+
const detection = await detect4(context);
|
|
6025
|
+
const inspection = await inspect4(context);
|
|
5792
6026
|
const configured = inspection.configs.some((config) => config.configuredPoints.length > 0);
|
|
5793
6027
|
const readable = inspection.configs.filter((config) => config.exists).every((config) => config.parsed);
|
|
5794
6028
|
const checks = [
|
|
@@ -5827,15 +6061,226 @@ async function verify3(context) {
|
|
|
5827
6061
|
];
|
|
5828
6062
|
return {
|
|
5829
6063
|
harnessId: OPENCODE,
|
|
5830
|
-
declaredTier:
|
|
6064
|
+
declaredTier: MANIFEST4.verificationTier,
|
|
5831
6065
|
achievedTier: detection.version !== null && configured && readable ? "config-only" : detection.version !== null ? "presence" : null,
|
|
5832
6066
|
checks
|
|
5833
6067
|
};
|
|
5834
6068
|
}
|
|
5835
|
-
var opencodeAdapter = { manifest:
|
|
6069
|
+
var opencodeAdapter = { manifest: MANIFEST4, detect: detect4, inspect: inspect4, verify: verify4 };
|
|
6070
|
+
|
|
6071
|
+
// packages/adapters/dist/src/harnesses/pi.js
|
|
6072
|
+
var PI = harnessId("pi");
|
|
6073
|
+
var VERSION_PATTERN5 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
|
|
6074
|
+
var MANIFEST5 = {
|
|
6075
|
+
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
6076
|
+
id: PI,
|
|
6077
|
+
displayName: "Pi",
|
|
6078
|
+
// The npm package declares no `homepage`; the repository it ships is the documented home.
|
|
6079
|
+
homepage: "https://github.com/earendil-works/pi",
|
|
6080
|
+
// Only the version actually observed — PLAN §15 item 31, "tested range of exactly the observed
|
|
6081
|
+
// version". `pi --version` on the machine this was written against printed `0.83.0`.
|
|
6082
|
+
testedVersions: { minimum: "0.83.0", maximum: "0.83.0" },
|
|
6083
|
+
// RFC 0007: the extension emits no receipt of its own, so nothing above `config-only` is
|
|
6084
|
+
// provable. The configuration is the extension module sitting in an auto-loaded directory.
|
|
6085
|
+
verificationTier: "config-only",
|
|
6086
|
+
versionCommand: { executable: "pi", args: ["--version"] },
|
|
6087
|
+
interceptionPoints: [{ scopeId: "tool-result", eventName: "tool_result" }],
|
|
6088
|
+
// `markers` because there is nothing to parse: Pi auto-loads any module in these directories,
|
|
6089
|
+
// and the presence of the HarnessTrim extension file is the whole configuration.
|
|
6090
|
+
configFiles: [
|
|
6091
|
+
{
|
|
6092
|
+
path: ".pi/agent/extensions/harnesstrim/index.ts",
|
|
6093
|
+
scope: "user",
|
|
6094
|
+
parser: "markers",
|
|
6095
|
+
primary: true
|
|
6096
|
+
},
|
|
6097
|
+
{
|
|
6098
|
+
path: ".pi/extensions/harnesstrim/harnesstrim.ts",
|
|
6099
|
+
scope: "project",
|
|
6100
|
+
parser: "markers",
|
|
6101
|
+
primary: false
|
|
6102
|
+
}
|
|
6103
|
+
],
|
|
6104
|
+
// The extension intercepts `tool_result` and reduces text chunks — a content seam, never a
|
|
6105
|
+
// shell. Mirrors the OpenCode plugin API claim.
|
|
6106
|
+
toolFamilies: [
|
|
6107
|
+
{ id: "tool.result", platforms: ["windows", "macos", "linux"], executesShellCommands: false }
|
|
6108
|
+
],
|
|
6109
|
+
// There is no separate enable state: the module being present in the directory is the load
|
|
6110
|
+
// decision, so the adapter reads presence and nothing else.
|
|
6111
|
+
requiresEnablement: false,
|
|
6112
|
+
enablementNote: null,
|
|
6113
|
+
receiptFamily: "none"
|
|
6114
|
+
};
|
|
6115
|
+
async function resolveConfig5(declaration, context) {
|
|
6116
|
+
const path = resolveConfigPath(declaration, context);
|
|
6117
|
+
const stat3 = await context.fs.stat(path);
|
|
6118
|
+
if (stat3 === null || stat3.kind !== "file") {
|
|
6119
|
+
return {
|
|
6120
|
+
declaration,
|
|
6121
|
+
path,
|
|
6122
|
+
exists: false,
|
|
6123
|
+
parsed: false,
|
|
6124
|
+
configuredPoints: [],
|
|
6125
|
+
matchers: [],
|
|
6126
|
+
commands: []
|
|
6127
|
+
};
|
|
6128
|
+
}
|
|
6129
|
+
const text = new TextDecoder().decode(await context.fs.readFile(path));
|
|
6130
|
+
const isHarnesstrim = /harnesstrim/i.test(text);
|
|
6131
|
+
return {
|
|
6132
|
+
declaration,
|
|
6133
|
+
path,
|
|
6134
|
+
exists: true,
|
|
6135
|
+
parsed: isHarnesstrim,
|
|
6136
|
+
configuredPoints: isHarnesstrim ? ["tool-result"] : [],
|
|
6137
|
+
matchers: isHarnesstrim ? ["tool.result"] : [],
|
|
6138
|
+
// There is no enable command: Pi loads the module from the directory directly.
|
|
6139
|
+
commands: []
|
|
6140
|
+
};
|
|
6141
|
+
}
|
|
6142
|
+
async function detectVersion5(context) {
|
|
6143
|
+
const result = await context.runner.run({
|
|
6144
|
+
executable: "pi",
|
|
6145
|
+
args: ["--version"],
|
|
6146
|
+
cwd: context.projectRoot,
|
|
6147
|
+
timeoutMs: 2e4
|
|
6148
|
+
});
|
|
6149
|
+
if (result.failure !== null)
|
|
6150
|
+
return {
|
|
6151
|
+
value: null,
|
|
6152
|
+
verdict: null,
|
|
6153
|
+
evidence: [
|
|
6154
|
+
evidence({
|
|
6155
|
+
kind: "absence",
|
|
6156
|
+
source: "pi",
|
|
6157
|
+
detail: `not runnable: ${result.failure.reason}`
|
|
6158
|
+
})
|
|
6159
|
+
]
|
|
6160
|
+
};
|
|
6161
|
+
const value = VERSION_PATTERN5.exec(result.stdout)?.[1] ?? null;
|
|
6162
|
+
return {
|
|
6163
|
+
value,
|
|
6164
|
+
verdict: value === null ? null : classifyVersion(value, MANIFEST5.testedVersions),
|
|
6165
|
+
evidence: [
|
|
6166
|
+
evidence({
|
|
6167
|
+
kind: "version-output",
|
|
6168
|
+
source: "pi",
|
|
6169
|
+
path: result.executablePath,
|
|
6170
|
+
detail: value ? `reported ${value}` : "reported no recognisable version"
|
|
6171
|
+
})
|
|
6172
|
+
]
|
|
6173
|
+
};
|
|
6174
|
+
}
|
|
6175
|
+
async function detect5(context) {
|
|
6176
|
+
const observed = await detectVersion5(context);
|
|
6177
|
+
const configs = await Promise.all(MANIFEST5.configFiles.map((file) => resolveConfig5(file, context)));
|
|
6178
|
+
const module = configs.find((file) => file.parsed);
|
|
6179
|
+
const present = module !== void 0;
|
|
6180
|
+
const warnings = [];
|
|
6181
|
+
if (observed.verdict === "unknown-newer")
|
|
6182
|
+
warnings.push(diagnostic({
|
|
6183
|
+
severity: "warning",
|
|
6184
|
+
code: "harness-version-unknown-newer",
|
|
6185
|
+
message: `Pi ${observed.value} is newer than the observed extension contract`,
|
|
6186
|
+
remediation: "Review the tool_result extension contract before applying changes"
|
|
6187
|
+
}));
|
|
6188
|
+
return {
|
|
6189
|
+
harnessId: PI,
|
|
6190
|
+
state: present && observed.value !== null ? "configured" : present || observed.value !== null ? "detected" : "absent",
|
|
6191
|
+
version: observed.value,
|
|
6192
|
+
versionVerdict: observed.verdict,
|
|
6193
|
+
configPath: module?.path ?? null,
|
|
6194
|
+
declaredVerificationTier: MANIFEST5.verificationTier,
|
|
6195
|
+
evidence: [
|
|
6196
|
+
...observed.evidence,
|
|
6197
|
+
...module ? [
|
|
6198
|
+
evidence({
|
|
6199
|
+
kind: "config-entry",
|
|
6200
|
+
source: "HarnessTrim Pi extension",
|
|
6201
|
+
path: module.path,
|
|
6202
|
+
detail: "extension module present in an auto-loaded directory"
|
|
6203
|
+
})
|
|
6204
|
+
] : []
|
|
6205
|
+
],
|
|
6206
|
+
warnings
|
|
6207
|
+
};
|
|
6208
|
+
}
|
|
6209
|
+
async function inspect5(context) {
|
|
6210
|
+
const configs = await Promise.all(MANIFEST5.configFiles.map((file) => resolveConfig5(file, context)));
|
|
6211
|
+
return {
|
|
6212
|
+
harnessId: PI,
|
|
6213
|
+
configs,
|
|
6214
|
+
activeToolFamilies: familiesOnThisPlatform(MANIFEST5, context.facts),
|
|
6215
|
+
uncoveredToolFamilies: [],
|
|
6216
|
+
// No separate enablement exists, so nothing is reported as enabled or disabled.
|
|
6217
|
+
enabled: null,
|
|
6218
|
+
diagnostics: [],
|
|
6219
|
+
summaries: configs.filter((config) => config.configuredPoints.length > 0).map((config) => ({
|
|
6220
|
+
harnessId: PI,
|
|
6221
|
+
configPath: config.path,
|
|
6222
|
+
scope: config.declaration.scope,
|
|
6223
|
+
interceptionPoints: config.configuredPoints,
|
|
6224
|
+
matchers: config.matchers,
|
|
6225
|
+
commands: config.commands
|
|
6226
|
+
}))
|
|
6227
|
+
};
|
|
6228
|
+
}
|
|
6229
|
+
async function verify5(context) {
|
|
6230
|
+
const detection = await detect5(context);
|
|
6231
|
+
const inspection = await inspect5(context);
|
|
6232
|
+
const module = inspection.configs.some((config) => config.configuredPoints.length > 0);
|
|
6233
|
+
const checks = [
|
|
6234
|
+
{
|
|
6235
|
+
id: "executable-resolves",
|
|
6236
|
+
status: detection.version === null ? "fail" : "pass",
|
|
6237
|
+
summary: detection.version === null ? "pi could not be run" : `Pi ${detection.version}`,
|
|
6238
|
+
achievedTier: detection.version === null ? null : "presence",
|
|
6239
|
+
evidence: detection.evidence.filter((item) => item.kind === "version-output"),
|
|
6240
|
+
remediation: detection.version === null ? "Install Pi or add it to PATH" : null
|
|
6241
|
+
},
|
|
6242
|
+
{
|
|
6243
|
+
id: "module-installed",
|
|
6244
|
+
status: module ? "pass" : "fail",
|
|
6245
|
+
summary: module ? "HarnessTrim extension module is installed" : "No HarnessTrim extension module was found in the Pi extension directories",
|
|
6246
|
+
achievedTier: module ? "config-only" : null,
|
|
6247
|
+
evidence: [],
|
|
6248
|
+
remediation: module ? null : "Run `harnesstrim install pi --apply`"
|
|
6249
|
+
},
|
|
6250
|
+
{
|
|
6251
|
+
id: "mode-unreadable",
|
|
6252
|
+
status: "info",
|
|
6253
|
+
summary: "The effective reduction mode (HARNESSTRIM_MODE) defaults to dryrun and is not observable from the extension alone",
|
|
6254
|
+
achievedTier: null,
|
|
6255
|
+
evidence: [],
|
|
6256
|
+
remediation: null
|
|
6257
|
+
},
|
|
6258
|
+
{
|
|
6259
|
+
id: "canary-intercepted",
|
|
6260
|
+
status: "not-exercised",
|
|
6261
|
+
summary: "Pi exposes no independent receipt; HarnessTrim telemetry is verified by the provider adapter",
|
|
6262
|
+
achievedTier: null,
|
|
6263
|
+
evidence: [],
|
|
6264
|
+
remediation: null
|
|
6265
|
+
}
|
|
6266
|
+
];
|
|
6267
|
+
return {
|
|
6268
|
+
harnessId: PI,
|
|
6269
|
+
declaredTier: MANIFEST5.verificationTier,
|
|
6270
|
+
achievedTier: checks.some((check) => check.achievedTier === "config-only") ? "config-only" : checks.some((check) => check.achievedTier === "presence") ? "presence" : null,
|
|
6271
|
+
checks
|
|
6272
|
+
};
|
|
6273
|
+
}
|
|
6274
|
+
var piAdapter = { manifest: MANIFEST5, detect: detect5, inspect: inspect5, verify: verify5 };
|
|
5836
6275
|
|
|
5837
6276
|
// packages/adapters/dist/src/harnesses/index.js
|
|
5838
|
-
var HARNESS_ADAPTERS = [
|
|
6277
|
+
var HARNESS_ADAPTERS = [
|
|
6278
|
+
claudeAdapter,
|
|
6279
|
+
codexAdapter,
|
|
6280
|
+
hermesAdapter,
|
|
6281
|
+
opencodeAdapter,
|
|
6282
|
+
piAdapter
|
|
6283
|
+
];
|
|
5839
6284
|
function listHarnessAdapters() {
|
|
5840
6285
|
return HARNESS_ADAPTERS;
|
|
5841
6286
|
}
|
|
@@ -5843,8 +6288,11 @@ function listHarnessAdapters() {
|
|
|
5843
6288
|
// packages/adapters/dist/src/providers/harnesstrim.js
|
|
5844
6289
|
var HARNESSTRIM2 = providerId("harnesstrim");
|
|
5845
6290
|
var CLAUDE2 = harnessId("claude");
|
|
6291
|
+
var HERMES2 = harnessId("hermes");
|
|
5846
6292
|
var CODEX2 = harnessId("codex");
|
|
5847
|
-
var
|
|
6293
|
+
var PI2 = harnessId("pi");
|
|
6294
|
+
var SKILLS_UPSTREAM = "0.0.7";
|
|
6295
|
+
var SKILL_ARTIFACT_DIGESTS = {
|
|
5848
6296
|
"compact-handoff/SKILL.md": "sha256:0efbf35581c559359e755b204778b64a289dab4d20dadc1cba3d5b5c995b5f01",
|
|
5849
6297
|
"debug-log-slim/SKILL.md": "sha256:17f5ccc34d29d7aba083444e0e4d87fd3d49916ebcb4e6544caf8c89f13f0045",
|
|
5850
6298
|
"delegate-bulk/SKILL.md": "sha256:3753de2ad18271c24832e4cda63115d353620515d5d80f40e93bc07d2a7257d7",
|
|
@@ -5853,16 +6301,18 @@ var CLAUDE_ARTIFACT_DIGESTS = {
|
|
|
5853
6301
|
"review-delta/SKILL.md": "sha256:4dfbf9d6ec08dff27b4759726536b43928370e288706fa01f5b498648e741388",
|
|
5854
6302
|
"scaffold-fast/SKILL.md": "sha256:1a18d52c4d335fbd3f74e2559bc20d6346193a40eef7b85149f51f44f697d182"
|
|
5855
6303
|
};
|
|
6304
|
+
var SKILL_ARTIFACTS = Object.keys(SKILL_ARTIFACT_DIGESTS);
|
|
5856
6305
|
var OPENCODE2 = harnessId("opencode");
|
|
5857
6306
|
var MODE_CARRYING_HARNESSES = /* @__PURE__ */ new Set([
|
|
5858
6307
|
OPENCODE2,
|
|
5859
|
-
|
|
6308
|
+
HERMES2,
|
|
5860
6309
|
harnessId("pi"),
|
|
5861
6310
|
harnessId("omp")
|
|
5862
6311
|
]);
|
|
5863
6312
|
var HOOK_COMMAND_PATTERN = /(^|[\\/\s"'])harnesstrim(\.cmd|\.exe)?([\s"']|$)/i;
|
|
5864
6313
|
var PLUGIN_MODULE_PATTERN2 = /(^|[\\/])harnesstrim\.(ts|js|mjs|cjs|mts|cts)$/i;
|
|
5865
|
-
var
|
|
6314
|
+
var PI_EXTENSION_PATTERN = /(^|[\\/])\.pi[\\/](agent[\\/])?extensions[\\/]harnesstrim[\\/]/i;
|
|
6315
|
+
var MANIFEST6 = {
|
|
5866
6316
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
5867
6317
|
id: HARNESSTRIM2,
|
|
5868
6318
|
displayName: "HarnessTrim",
|
|
@@ -5948,15 +6398,48 @@ var MANIFEST4 = {
|
|
|
5948
6398
|
// names it is not read. Item 30 readmits it together with the adapter and a matrix row; the
|
|
5949
6399
|
// registry assertion in `registries.test.ts` refuses a home-relative location that names a
|
|
5950
6400
|
// harness the registry does not know.
|
|
5951
|
-
locations: [".harnesstrim/metrics.jsonl"]
|
|
6401
|
+
locations: [".harnesstrim/metrics.jsonl", ".hermes/harnesstrim-metrics.jsonl"]
|
|
5952
6402
|
},
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
6403
|
+
/**
|
|
6404
|
+
* One review per harness — PLAN §15 item 46b.
|
|
6405
|
+
*
|
|
6406
|
+
* Codex was observed at `0.1.0`: `harnesstrim install codex <dir> --apply --no-instructions`
|
|
6407
|
+
* writes the same seven skill artifacts as the Claude invocation, byte for byte — the digests
|
|
6408
|
+
* below are shared because the files are the same files — under `.codex/skills/` instead, and
|
|
6409
|
+
* skips `AGENTS.md` exactly as the Claude one skips `CLAUDE.md`. What differs is the boundary and
|
|
6410
|
+
* the protected paths, which is precisely why one review could not describe both.
|
|
6411
|
+
*
|
|
6412
|
+
* OpenCode is absent on purpose. Its installer writes `.opencode/plugin/harnesstrim.ts` and
|
|
6413
|
+
* `.opencode/package.json` *and runs an npm install*, so the containment boundary would hold a
|
|
6414
|
+
* `node_modules` tree: a snapshot question, not another entry in this map.
|
|
6415
|
+
*/
|
|
6416
|
+
delegatedInstallReviews: {
|
|
6417
|
+
claude: {
|
|
6418
|
+
upstreamVersion: SKILLS_UPSTREAM,
|
|
6419
|
+
reviewedWriteSet: SKILL_ARTIFACTS.map((path) => `.claude/skills/${path}`),
|
|
6420
|
+
containmentBoundary: [".claude", "CLAUDE.md"],
|
|
6421
|
+
upstreamUninstallAvailable: true
|
|
6422
|
+
},
|
|
6423
|
+
codex: {
|
|
6424
|
+
upstreamVersion: SKILLS_UPSTREAM,
|
|
6425
|
+
reviewedWriteSet: SKILL_ARTIFACTS.map((path) => `.codex/skills/${path}`),
|
|
6426
|
+
containmentBoundary: [".codex", "AGENTS.md"],
|
|
6427
|
+
upstreamUninstallAvailable: true
|
|
6428
|
+
}
|
|
6429
|
+
}
|
|
6430
|
+
};
|
|
6431
|
+
var SKILLS_INSTALL = {
|
|
6432
|
+
claude: {
|
|
6433
|
+
directory: ".claude",
|
|
6434
|
+
instructions: "CLAUDE.md",
|
|
6435
|
+
hook: "settings.json",
|
|
6436
|
+
args: ["--no-hook", "--no-instructions"]
|
|
6437
|
+
},
|
|
6438
|
+
codex: {
|
|
6439
|
+
directory: ".codex",
|
|
6440
|
+
instructions: "AGENTS.md",
|
|
6441
|
+
hook: "hooks.json",
|
|
6442
|
+
args: ["--no-instructions"]
|
|
5960
6443
|
}
|
|
5961
6444
|
};
|
|
5962
6445
|
var TESTED_UPSTREAM = "0.0.7";
|
|
@@ -6004,9 +6487,9 @@ function parseCapabilities(stdout) {
|
|
|
6004
6487
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
6005
6488
|
return null;
|
|
6006
6489
|
const record = parsed;
|
|
6007
|
-
const
|
|
6490
|
+
const version3 = record["version"];
|
|
6008
6491
|
const harnesses = record["harnesses"];
|
|
6009
|
-
if (typeof
|
|
6492
|
+
if (typeof version3 !== "string" || typeof harnesses !== "object" || harnesses === null) {
|
|
6010
6493
|
return null;
|
|
6011
6494
|
}
|
|
6012
6495
|
const entries = {};
|
|
@@ -6016,7 +6499,7 @@ function parseCapabilities(stdout) {
|
|
|
6016
6499
|
return null;
|
|
6017
6500
|
entries[harness] = entry;
|
|
6018
6501
|
}
|
|
6019
|
-
return { version:
|
|
6502
|
+
return { version: version3, harnesses: entries };
|
|
6020
6503
|
}
|
|
6021
6504
|
async function probeCapabilities(context) {
|
|
6022
6505
|
const outcome2 = await context.runner.run({
|
|
@@ -6095,18 +6578,18 @@ function driftWarning(message, remediation) {
|
|
|
6095
6578
|
function formatSurface(surface) {
|
|
6096
6579
|
return `${surface.toolFamily}/${surface.interceptionPoint}`;
|
|
6097
6580
|
}
|
|
6098
|
-
function
|
|
6099
|
-
if (capabilities === null
|
|
6100
|
-
return
|
|
6101
|
-
const
|
|
6102
|
-
return
|
|
6581
|
+
function assignableOn(capabilities) {
|
|
6582
|
+
if (capabilities === null)
|
|
6583
|
+
return [];
|
|
6584
|
+
const reviews = MANIFEST6.delegatedInstallReviews ?? {};
|
|
6585
|
+
return Object.keys(reviews).filter((harness) => {
|
|
6103
6586
|
const observed = capabilities.harnesses[harness];
|
|
6104
|
-
return observed !== void 0 && observed.narrowing.length > 0;
|
|
6105
|
-
});
|
|
6587
|
+
return observed !== void 0 && observed.narrowing.length > 0 && writeSetStillReviewed(capabilities, harnessId(harness));
|
|
6588
|
+
}).map((harness) => harnessId(harness));
|
|
6106
6589
|
}
|
|
6107
6590
|
function writeSetStillReviewed(capabilities, harness) {
|
|
6108
|
-
const review =
|
|
6109
|
-
if (review ===
|
|
6591
|
+
const review = MANIFEST6.delegatedInstallReviews?.[harness];
|
|
6592
|
+
if (review === void 0 || capabilities === null)
|
|
6110
6593
|
return false;
|
|
6111
6594
|
const observed = capabilities.harnesses[harness];
|
|
6112
6595
|
if (observed === void 0)
|
|
@@ -6132,35 +6615,37 @@ function compareCapabilities(manifest, capabilities) {
|
|
|
6132
6615
|
}
|
|
6133
6616
|
}
|
|
6134
6617
|
}
|
|
6135
|
-
const review
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
const claude = capabilities.harnesses["claude"];
|
|
6139
|
-
if (claude === void 0)
|
|
6140
|
-
return warnings;
|
|
6141
|
-
const declared = claude.writeSet.map(writeSetPath);
|
|
6142
|
-
for (const reviewed of review.reviewedWriteSet) {
|
|
6143
|
-
if (declared.some((entry) => coveredBy(reviewed, entry)))
|
|
6144
|
-
continue;
|
|
6145
|
-
warnings.push(driftWarning(`the reviewed write set records ${reviewed} at ${review.upstreamVersion}, but \`harnesstrim capabilities\` (${capabilities.version}) declares nothing covering it (${declared.length === 0 ? "nothing" : declared.join(", ")})`, `Re-review the write set at the installed version before delegating another install`));
|
|
6146
|
-
}
|
|
6147
|
-
const boundary = review.containmentBoundary.map(writeSetPath);
|
|
6148
|
-
for (const entry of declared) {
|
|
6149
|
-
if (boundary.some((prefix) => coveredBy(entry, prefix)))
|
|
6618
|
+
for (const [harness, review] of Object.entries(manifest.delegatedInstallReviews ?? {})) {
|
|
6619
|
+
const observed = capabilities.harnesses[harness];
|
|
6620
|
+
if (observed === void 0)
|
|
6150
6621
|
continue;
|
|
6151
|
-
|
|
6622
|
+
const declared = observed.writeSet.map(writeSetPath);
|
|
6623
|
+
for (const reviewed of review.reviewedWriteSet) {
|
|
6624
|
+
if (declared.some((entry) => coveredBy(reviewed, entry)))
|
|
6625
|
+
continue;
|
|
6626
|
+
warnings.push(driftWarning(`the reviewed ${harness} write set records ${reviewed} at ${review.upstreamVersion}, but \`harnesstrim capabilities\` (${capabilities.version}) declares nothing covering it (${declared.length === 0 ? "nothing" : declared.join(", ")})`, `Re-review the write set at the installed version before delegating another install`));
|
|
6627
|
+
}
|
|
6628
|
+
const boundary = review.containmentBoundary.map(writeSetPath);
|
|
6629
|
+
for (const entry of declared) {
|
|
6630
|
+
if (boundary.some((prefix) => coveredBy(entry, prefix)))
|
|
6631
|
+
continue;
|
|
6632
|
+
warnings.push(driftWarning(`\`harnesstrim capabilities\` (${capabilities.version}) declares ${entry} for ${harness}, which sits outside the containment boundary recorded at ${review.upstreamVersion} (${boundary.join(", ")})`, "Re-review the write set: rollback restores the boundary, and a path it does not cover would survive a rollback"));
|
|
6633
|
+
}
|
|
6152
6634
|
}
|
|
6153
6635
|
return warnings;
|
|
6154
6636
|
}
|
|
6155
6637
|
function harnessesWiredToHarnessTrim(configs) {
|
|
6156
6638
|
const wired = /* @__PURE__ */ new Set();
|
|
6157
6639
|
for (const config of configs) {
|
|
6158
|
-
|
|
6640
|
+
const hermesPlugin = config.harnessId === HERMES2 && (config.configPath.toLowerCase().includes(".hermes/plugins/harnesstrim") || config.commands.some((command) => /hermes plugins enable harnesstrim/i.test(command)));
|
|
6641
|
+
const piExtension = config.harnessId === PI2 && PI_EXTENSION_PATTERN.test(config.configPath);
|
|
6642
|
+
if (piExtension || hermesPlugin || config.commands.some((command) => identifiesCommand(command))) {
|
|
6159
6643
|
wired.add(config.harnessId);
|
|
6644
|
+
}
|
|
6160
6645
|
}
|
|
6161
6646
|
return [...wired];
|
|
6162
6647
|
}
|
|
6163
|
-
var
|
|
6648
|
+
var VERSION_PATTERN6 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
|
|
6164
6649
|
async function probeExecutable(context) {
|
|
6165
6650
|
const asked = await context.runner.run({
|
|
6166
6651
|
executable: "harnesstrim",
|
|
@@ -6183,17 +6668,17 @@ async function probeExecutable(context) {
|
|
|
6183
6668
|
};
|
|
6184
6669
|
}
|
|
6185
6670
|
if (asked.exitCode === 0) {
|
|
6186
|
-
const
|
|
6671
|
+
const version3 = VERSION_PATTERN6.exec(asked.stdout)?.[1] ?? null;
|
|
6187
6672
|
return {
|
|
6188
6673
|
installed: true,
|
|
6189
|
-
version:
|
|
6674
|
+
version: version3,
|
|
6190
6675
|
path: asked.executablePath,
|
|
6191
6676
|
evidence: [
|
|
6192
6677
|
evidence({
|
|
6193
6678
|
kind: "version-output",
|
|
6194
6679
|
source: "harnesstrim --version",
|
|
6195
6680
|
path: asked.executablePath,
|
|
6196
|
-
detail:
|
|
6681
|
+
detail: version3 === null ? "reported no recognisable version" : `reported ${version3}`
|
|
6197
6682
|
})
|
|
6198
6683
|
]
|
|
6199
6684
|
};
|
|
@@ -6233,16 +6718,19 @@ async function probeExecutable(context) {
|
|
|
6233
6718
|
};
|
|
6234
6719
|
}
|
|
6235
6720
|
function metricsLocations(context) {
|
|
6236
|
-
return [
|
|
6721
|
+
return [
|
|
6722
|
+
context.fs.join(context.projectRoot, ".harnesstrim", "metrics.jsonl"),
|
|
6723
|
+
context.fs.join(context.paths.home, ".hermes", "harnesstrim-metrics.jsonl")
|
|
6724
|
+
];
|
|
6237
6725
|
}
|
|
6238
|
-
async function
|
|
6726
|
+
async function detect6(context) {
|
|
6239
6727
|
const probe = await probeExecutable(context);
|
|
6240
6728
|
const observed = probe.installed ? await probeCapabilities(context) : null;
|
|
6241
6729
|
const configured = harnessesWiredToHarnessTrim(context.harnessConfigs);
|
|
6242
6730
|
const warnings = [];
|
|
6243
6731
|
const evidenceItems = [...probe.evidence, ...observed?.evidence ?? []];
|
|
6244
6732
|
if (observed !== null && observed.capabilities !== null) {
|
|
6245
|
-
warnings.push(...compareCapabilities(
|
|
6733
|
+
warnings.push(...compareCapabilities(MANIFEST6, observed.capabilities));
|
|
6246
6734
|
}
|
|
6247
6735
|
for (const harness of configured) {
|
|
6248
6736
|
evidenceItems.push(evidence({
|
|
@@ -6273,7 +6761,7 @@ async function detect4(context) {
|
|
|
6273
6761
|
// cannot answer.
|
|
6274
6762
|
versionVerdict: probe.version === null ? null : classifyVersion(probe.version, TESTED_VERSIONS),
|
|
6275
6763
|
configuredHarnesses: configured,
|
|
6276
|
-
unmanagedHarnessesConfigured: configured.filter((harness) => !
|
|
6764
|
+
unmanagedHarnessesConfigured: configured.filter((harness) => !MANIFEST6.harnesses.some((entry) => entry.harness === harness)),
|
|
6277
6765
|
// RFC 0002 §Providers may exceed the managed surface: HarnessTrim ships adapters for Hermes and
|
|
6278
6766
|
// Pi as well, which Token Harness does not manage, so a wired one is reported and left alone.
|
|
6279
6767
|
supportsUnmanagedHarnesses: true,
|
|
@@ -6281,10 +6769,9 @@ async function detect4(context) {
|
|
|
6281
6769
|
// circumstantial: PLAN §11 says Token Harness never installs it, so every installation it ever
|
|
6282
6770
|
// sees is the user's.
|
|
6283
6771
|
managedByTokenHarness: false,
|
|
6284
|
-
// PLAN §15 item 46. Decided by the build in front of us
|
|
6285
|
-
//
|
|
6286
|
-
|
|
6287
|
-
assignable: observed?.capabilities === null ? false : narrowable(observed?.capabilities),
|
|
6772
|
+
// PLAN §15 item 46, per harness. Decided by the build in front of us and by which harnesses
|
|
6773
|
+
// carry a reviewed write set: those are the two things that make the assignment producible.
|
|
6774
|
+
assignableHarnesses: assignableOn(observed?.capabilities ?? null),
|
|
6288
6775
|
evidence: evidenceItems,
|
|
6289
6776
|
warnings
|
|
6290
6777
|
};
|
|
@@ -6356,7 +6843,7 @@ function toEvent(event, sourceId, ordinal, line, context) {
|
|
|
6356
6843
|
pipelineId: null,
|
|
6357
6844
|
pipelineOrder: null,
|
|
6358
6845
|
toolFamily: event.tool === "" ? null : event.tool,
|
|
6359
|
-
capability: event.harness === OPENCODE2 ? "tool.output.reduce" : "shell.output.reduce"
|
|
6846
|
+
capability: event.harness === OPENCODE2 || event.harness === HERMES2 || event.harness === PI2 ? "tool.output.reduce" : "shell.output.reduce"
|
|
6360
6847
|
},
|
|
6361
6848
|
measurement: {
|
|
6362
6849
|
class: dryrun || hasUnprovenMode ? "counterfactual" : hasTokens ? "exact-local" : "estimated-local",
|
|
@@ -6389,7 +6876,7 @@ function toEvent(event, sourceId, ordinal, line, context) {
|
|
|
6389
6876
|
source: { nativeEventId: native ? eventId : null, importedAt: context.now() }
|
|
6390
6877
|
};
|
|
6391
6878
|
}
|
|
6392
|
-
async function
|
|
6879
|
+
async function verify6(context) {
|
|
6393
6880
|
const checks = [];
|
|
6394
6881
|
const diagnostics = [];
|
|
6395
6882
|
const probe = await probeExecutable(context);
|
|
@@ -6606,84 +7093,102 @@ async function collectMetrics(context, store) {
|
|
|
6606
7093
|
diagnostics
|
|
6607
7094
|
};
|
|
6608
7095
|
}
|
|
6609
|
-
|
|
6610
|
-
const
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
7096
|
+
function skillArtifacts(context, harness) {
|
|
7097
|
+
const install = SKILLS_INSTALL[harness];
|
|
7098
|
+
if (install === void 0)
|
|
7099
|
+
return [];
|
|
7100
|
+
const skills = context.fs.join(context.projectRoot, install.directory, "skills");
|
|
7101
|
+
return Object.entries(SKILL_ARTIFACT_DIGESTS).map(([path, digest]) => ({
|
|
7102
|
+
path: context.fs.join(skills, ...path.split("/")),
|
|
6614
7103
|
digest
|
|
6615
7104
|
}));
|
|
6616
|
-
|
|
7105
|
+
}
|
|
7106
|
+
async function plan(context, request) {
|
|
7107
|
+
const reviews = MANIFEST6.delegatedInstallReviews ?? {};
|
|
7108
|
+
const targets = request.harnesses.map((harness) => harness.id).filter((harness) => reviews[harness] !== void 0 && SKILLS_INSTALL[harness] !== void 0);
|
|
7109
|
+
if (targets.length === 0) {
|
|
6617
7110
|
return { providerId: HARNESSTRIM2, desiredState: request.desiredState, actions: [] };
|
|
6618
7111
|
}
|
|
6619
7112
|
if (request.desiredState === "absent") {
|
|
6620
|
-
const
|
|
7113
|
+
const actions2 = targets.flatMap((harness) => skillArtifacts(context, harness).map((artifact) => ({
|
|
6621
7114
|
kind: "remove-owned-change",
|
|
6622
|
-
id: `harnesstrim-
|
|
7115
|
+
id: `harnesstrim-${harness}-skill-remove-${digestText(artifact.path).slice(7, 15)}`,
|
|
6623
7116
|
riskClass: "reversible",
|
|
6624
7117
|
requiresNetwork: false,
|
|
6625
7118
|
requiresElevation: false,
|
|
6626
7119
|
affectedPaths: [artifact.path],
|
|
6627
7120
|
affectedProcesses: [],
|
|
6628
|
-
preconditions: [
|
|
7121
|
+
preconditions: [
|
|
7122
|
+
`the HarnessTrim skill still matches the reviewed ${SKILLS_UPSTREAM} artifact`
|
|
7123
|
+
],
|
|
6629
7124
|
postconditions: ["the owned HarnessTrim skill is absent"],
|
|
6630
7125
|
rollbackData: "file-snapshot",
|
|
6631
|
-
explanation: `Remove the owned HarnessTrim
|
|
7126
|
+
explanation: `Remove the owned HarnessTrim ${harness} skill ${context.fs.basename(context.fs.dirname(artifact.path))}`,
|
|
6632
7127
|
path: artifact.path,
|
|
6633
|
-
reverses: `harnesstrim-
|
|
6634
|
-
target: {
|
|
6635
|
-
|
|
6636
|
-
|
|
7128
|
+
reverses: `harnesstrim-${harness}-skills-${digestText(context.projectRoot).slice(7, 15)}`,
|
|
7129
|
+
target: {
|
|
7130
|
+
kind: "owned-file",
|
|
7131
|
+
path: artifact.path,
|
|
7132
|
+
digest: artifact.digest,
|
|
7133
|
+
mode: null
|
|
7134
|
+
}
|
|
7135
|
+
})));
|
|
7136
|
+
return { providerId: HARNESSTRIM2, desiredState: "absent", actions: actions2 };
|
|
6637
7137
|
}
|
|
6638
7138
|
const installed = await probeExecutable(context);
|
|
6639
7139
|
if (!installed.installed) {
|
|
6640
7140
|
return { providerId: HARNESSTRIM2, desiredState: "configured", actions: [] };
|
|
6641
7141
|
}
|
|
6642
7142
|
const observed = await probeCapabilities(context);
|
|
6643
|
-
const
|
|
6644
|
-
|
|
6645
|
-
|
|
7143
|
+
const actions = [];
|
|
7144
|
+
for (const harness of targets) {
|
|
7145
|
+
const review = reviews[harness];
|
|
7146
|
+
const install = SKILLS_INSTALL[harness];
|
|
7147
|
+
if (review === void 0 || install === void 0)
|
|
7148
|
+
continue;
|
|
7149
|
+
const reviewed = observed.capabilities === null ? installed.version === review.upstreamVersion : writeSetStillReviewed(observed.capabilities, harnessId(harness));
|
|
7150
|
+
if (!reviewed)
|
|
7151
|
+
continue;
|
|
7152
|
+
const expectedArtifacts = skillArtifacts(context, harness);
|
|
7153
|
+
actions.push({
|
|
7154
|
+
kind: "delegated-provider-install",
|
|
7155
|
+
id: `harnesstrim-${harness}-skills-${digestText(context.projectRoot).slice(7, 15)}`,
|
|
7156
|
+
riskClass: "delegated",
|
|
7157
|
+
requiresNetwork: false,
|
|
7158
|
+
requiresElevation: false,
|
|
7159
|
+
affectedPaths: expectedArtifacts.map((artifact) => artifact.path),
|
|
7160
|
+
affectedProcesses: ["harnesstrim"],
|
|
7161
|
+
preconditions: [
|
|
7162
|
+
"harnesstrim is installed, on PATH, and declares the reviewed write set",
|
|
7163
|
+
`the reviewed installer writes only the declared ${harness} skill artifacts`
|
|
7164
|
+
],
|
|
7165
|
+
postconditions: [
|
|
7166
|
+
`HarnessTrim ${harness} skills match the reviewed ${review.upstreamVersion} artifacts`,
|
|
7167
|
+
"no HarnessTrim hook or reduce-pipe instruction was added"
|
|
7168
|
+
],
|
|
7169
|
+
rollbackData: "directory-snapshot",
|
|
7170
|
+
explanation: `Install HarnessTrim ${harness} skills without a hook or reduce-pipe instruction`,
|
|
7171
|
+
executable: "harnesstrim",
|
|
7172
|
+
args: ["install", harness, context.projectRoot, "--apply", ...install.args],
|
|
7173
|
+
containmentBoundary: review.containmentBoundary.map((path) => context.fs.join(context.projectRoot, path)),
|
|
7174
|
+
expectedArtifacts,
|
|
7175
|
+
// The two files each installer reports skipping. Named here because they must not appear.
|
|
7176
|
+
protectedPaths: [
|
|
7177
|
+
context.fs.join(context.projectRoot, install.directory, install.hook),
|
|
7178
|
+
context.fs.join(context.projectRoot, install.instructions)
|
|
7179
|
+
],
|
|
7180
|
+
rollbackStrategy: "restore-snapshot",
|
|
7181
|
+
snapshotSizeCapBytes: 1048576,
|
|
7182
|
+
upstreamUninstallAvailable: review.upstreamUninstallAvailable
|
|
7183
|
+
});
|
|
6646
7184
|
}
|
|
6647
|
-
|
|
6648
|
-
if (review === null)
|
|
6649
|
-
throw new Error("HarnessTrim delegated-install review is missing");
|
|
6650
|
-
const action = {
|
|
6651
|
-
kind: "delegated-provider-install",
|
|
6652
|
-
id: `harnesstrim-claude-skills-${digestText(context.projectRoot).slice(7, 15)}`,
|
|
6653
|
-
riskClass: "delegated",
|
|
6654
|
-
requiresNetwork: false,
|
|
6655
|
-
requiresElevation: false,
|
|
6656
|
-
affectedPaths: expectedArtifacts.map((artifact) => artifact.path),
|
|
6657
|
-
affectedProcesses: ["harnesstrim"],
|
|
6658
|
-
preconditions: [
|
|
6659
|
-
"harnesstrim 0.0.7 is installed and on PATH",
|
|
6660
|
-
"the reviewed installer writes only the declared Claude skill artifacts"
|
|
6661
|
-
],
|
|
6662
|
-
postconditions: [
|
|
6663
|
-
"HarnessTrim Claude skills match the reviewed 0.0.7 artifacts",
|
|
6664
|
-
"no HarnessTrim hook or reduce-pipe instruction was added"
|
|
6665
|
-
],
|
|
6666
|
-
rollbackData: "directory-snapshot",
|
|
6667
|
-
explanation: "Install HarnessTrim Claude skills without a hook or reduce-pipe instruction",
|
|
6668
|
-
executable: "harnesstrim",
|
|
6669
|
-
args: ["install", "claude", context.projectRoot, "--apply", "--no-hook", "--no-instructions"],
|
|
6670
|
-
containmentBoundary: review.containmentBoundary.map((path) => context.fs.join(context.projectRoot, path)),
|
|
6671
|
-
expectedArtifacts,
|
|
6672
|
-
protectedPaths: [
|
|
6673
|
-
context.fs.join(claudeDirectory, "settings.json"),
|
|
6674
|
-
context.fs.join(context.projectRoot, "CLAUDE.md")
|
|
6675
|
-
],
|
|
6676
|
-
rollbackStrategy: "restore-snapshot",
|
|
6677
|
-
snapshotSizeCapBytes: 1048576,
|
|
6678
|
-
upstreamUninstallAvailable: review.upstreamUninstallAvailable
|
|
6679
|
-
};
|
|
6680
|
-
return { providerId: HARNESSTRIM2, desiredState: "configured", actions: [action] };
|
|
7185
|
+
return { providerId: HARNESSTRIM2, desiredState: "configured", actions };
|
|
6681
7186
|
}
|
|
6682
7187
|
var harnesstrimAdapter = {
|
|
6683
|
-
manifest:
|
|
6684
|
-
detect:
|
|
7188
|
+
manifest: MANIFEST6,
|
|
7189
|
+
detect: detect6,
|
|
6685
7190
|
identifiesCommand,
|
|
6686
|
-
verify:
|
|
7191
|
+
verify: verify6,
|
|
6687
7192
|
collectMetrics,
|
|
6688
7193
|
plan,
|
|
6689
7194
|
plansWithoutOwnership: true
|
|
@@ -6885,7 +7390,7 @@ function buildRtkPlan(input) {
|
|
|
6885
7390
|
var RTK2 = providerId("rtk");
|
|
6886
7391
|
var CLAUDE3 = harnessId("claude");
|
|
6887
7392
|
var OPENCODE3 = harnessId("opencode");
|
|
6888
|
-
var
|
|
7393
|
+
var MANIFEST7 = {
|
|
6889
7394
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
6890
7395
|
id: RTK2,
|
|
6891
7396
|
displayName: "RTK",
|
|
@@ -7045,10 +7550,10 @@ var MANIFEST5 = {
|
|
|
7045
7550
|
// location differs per platform; `rtkDatabasePath` is the single derivation.
|
|
7046
7551
|
locations: ["<user data directory>/rtk/history.db"]
|
|
7047
7552
|
},
|
|
7048
|
-
|
|
7553
|
+
delegatedInstallReviews: null
|
|
7049
7554
|
};
|
|
7050
7555
|
var TESTED_VERSIONS2 = { minimum: "0.40.0", maximum: "0.44.0" };
|
|
7051
|
-
var
|
|
7556
|
+
var VERSION_PATTERN7 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
|
|
7052
7557
|
var HOOK_COMMAND_PATTERN2 = /(^|[\\/\s"'])rtk(\.exe)?([\s"']|$)/i;
|
|
7053
7558
|
var PLUGIN_MODULE_PATTERN3 = /(^|[\\/])rtk\.(ts|js|mjs|cjs|mts|cts)$/i;
|
|
7054
7559
|
function isRecord4(value) {
|
|
@@ -7120,17 +7625,17 @@ async function readVersion(context) {
|
|
|
7120
7625
|
]
|
|
7121
7626
|
};
|
|
7122
7627
|
}
|
|
7123
|
-
const
|
|
7628
|
+
const version3 = VERSION_PATTERN7.exec(outcome2.stdout)?.[1] ?? null;
|
|
7124
7629
|
return {
|
|
7125
|
-
version:
|
|
7126
|
-
verdict:
|
|
7630
|
+
version: version3,
|
|
7631
|
+
verdict: version3 === null ? null : classifyVersion(version3, TESTED_VERSIONS2),
|
|
7127
7632
|
executable: outcome2.executablePath,
|
|
7128
7633
|
evidence: [
|
|
7129
7634
|
evidence({
|
|
7130
7635
|
kind: "version-output",
|
|
7131
7636
|
source: "rtk --version",
|
|
7132
7637
|
path: outcome2.executablePath,
|
|
7133
|
-
detail:
|
|
7638
|
+
detail: version3 === null ? "reported no recognisable version" : `reported ${version3}`
|
|
7134
7639
|
})
|
|
7135
7640
|
]
|
|
7136
7641
|
};
|
|
@@ -7166,11 +7671,11 @@ async function readAnalytics(context) {
|
|
|
7166
7671
|
]
|
|
7167
7672
|
};
|
|
7168
7673
|
}
|
|
7169
|
-
async function
|
|
7674
|
+
async function detect7(context) {
|
|
7170
7675
|
const evidenceItems = [];
|
|
7171
7676
|
const warnings = [];
|
|
7172
|
-
const
|
|
7173
|
-
evidenceItems.push(...
|
|
7677
|
+
const version3 = await readVersion(context);
|
|
7678
|
+
evidenceItems.push(...version3.evidence);
|
|
7174
7679
|
const configured = harnessesWiredToRtk(context.harnessConfigs);
|
|
7175
7680
|
for (const harness of configured) {
|
|
7176
7681
|
evidenceItems.push(evidence({
|
|
@@ -7180,15 +7685,15 @@ async function detect5(context) {
|
|
|
7180
7685
|
detail: "names rtk in a hook command"
|
|
7181
7686
|
}));
|
|
7182
7687
|
}
|
|
7183
|
-
if (
|
|
7688
|
+
if (version3.verdict === "unknown-newer") {
|
|
7184
7689
|
warnings.push(diagnostic({
|
|
7185
7690
|
severity: "warning",
|
|
7186
7691
|
code: "provider-version-unknown-newer",
|
|
7187
|
-
message: `RTK ${String(
|
|
7692
|
+
message: `RTK ${String(version3.version)} is newer than the versions Token Harness has observed (up to ${TESTED_VERSIONS2.maximum})`,
|
|
7188
7693
|
remediation: "Check the release notes for analytics or hook changes before applying a plan"
|
|
7189
7694
|
}));
|
|
7190
7695
|
}
|
|
7191
|
-
const state =
|
|
7696
|
+
const state = version3.version === null ? configured.length > 0 ? "broken" : "absent" : configured.length > 0 ? "configured" : "installed";
|
|
7192
7697
|
if (state === "broken") {
|
|
7193
7698
|
warnings.push(diagnostic({
|
|
7194
7699
|
severity: "error",
|
|
@@ -7201,12 +7706,12 @@ async function detect5(context) {
|
|
|
7201
7706
|
return {
|
|
7202
7707
|
providerId: RTK2,
|
|
7203
7708
|
state,
|
|
7204
|
-
version:
|
|
7205
|
-
executable:
|
|
7709
|
+
version: version3.version,
|
|
7710
|
+
executable: version3.executable,
|
|
7206
7711
|
// Detection reports what it saw; which channel installed it is an installation-stage
|
|
7207
7712
|
// question and guessing it from a path would be a guess.
|
|
7208
7713
|
installationChannel: null,
|
|
7209
|
-
versionVerdict:
|
|
7714
|
+
versionVerdict: version3.verdict,
|
|
7210
7715
|
configuredHarnesses: configured,
|
|
7211
7716
|
unmanagedHarnessesConfigured: [],
|
|
7212
7717
|
/**
|
|
@@ -7227,29 +7732,35 @@ async function detect5(context) {
|
|
|
7227
7732
|
// every installation it finds is the user's.
|
|
7228
7733
|
managedByTokenHarness: false,
|
|
7229
7734
|
/**
|
|
7230
|
-
*
|
|
7735
|
+
* Claude Code alone, and independent of the observed version.
|
|
7736
|
+
*
|
|
7737
|
+
* RTK's assignment is produced by this build writing the hook itself — `rtk-plan.ts` appends the
|
|
7738
|
+
* entry — so nothing about the installed `rtk` decides whether the state is reachable. What does
|
|
7739
|
+
* decide it is which harness schema that builder knows, and it knows one: `HOOK_LIST_HARNESSES`
|
|
7740
|
+
* holds `claude` and the builder refuses anything else, because a `{matcher, hooks:[…]}` object
|
|
7741
|
+
* at `hooks.<event>` is Claude Code's schema and nothing else's.
|
|
7231
7742
|
*
|
|
7232
|
-
* RTK
|
|
7233
|
-
*
|
|
7234
|
-
*
|
|
7235
|
-
*
|
|
7743
|
+
* RTK claims OpenCode too, from spike 9.1, and that claim is real — detected, adopted, verified
|
|
7744
|
+
* and measured there. It is simply not *written* there: its OpenCode integration is a plugin
|
|
7745
|
+
* module `rtk init -g --opencode` installs globally, which this build has no action for. Saying
|
|
7746
|
+
* so here is what stops the resolver assigning a scope nothing can produce.
|
|
7236
7747
|
*/
|
|
7237
|
-
|
|
7748
|
+
assignableHarnesses: [CLAUDE3],
|
|
7238
7749
|
evidence: evidenceItems,
|
|
7239
7750
|
warnings
|
|
7240
7751
|
};
|
|
7241
7752
|
}
|
|
7242
|
-
async function
|
|
7753
|
+
async function verify7(context) {
|
|
7243
7754
|
const checks = [];
|
|
7244
7755
|
const diagnostics = [];
|
|
7245
|
-
const
|
|
7756
|
+
const version3 = await readVersion(context);
|
|
7246
7757
|
checks.push({
|
|
7247
7758
|
id: "executable-resolves",
|
|
7248
|
-
status:
|
|
7249
|
-
summary:
|
|
7250
|
-
achievedTier:
|
|
7251
|
-
evidence:
|
|
7252
|
-
remediation:
|
|
7759
|
+
status: version3.version === null ? "fail" : "pass",
|
|
7760
|
+
summary: version3.version === null ? "rtk could not be run" : `rtk ${version3.version}`,
|
|
7761
|
+
achievedTier: version3.version === null ? null : "presence",
|
|
7762
|
+
evidence: version3.evidence,
|
|
7763
|
+
remediation: version3.version === null ? "Install RTK, or add it to PATH" : null
|
|
7253
7764
|
});
|
|
7254
7765
|
const configured = harnessesWiredToRtk(context.harnessConfigs);
|
|
7255
7766
|
checks.push({
|
|
@@ -7549,19 +8060,19 @@ function identifiesCommand2(command) {
|
|
|
7549
8060
|
return HOOK_COMMAND_PATTERN2.test(command) || PLUGIN_MODULE_PATTERN3.test(command);
|
|
7550
8061
|
}
|
|
7551
8062
|
async function plan2(context, request) {
|
|
7552
|
-
const
|
|
8063
|
+
const version3 = await readVersion(context);
|
|
7553
8064
|
return buildRtkPlan({
|
|
7554
8065
|
context,
|
|
7555
8066
|
request,
|
|
7556
|
-
installed:
|
|
8067
|
+
installed: version3.version !== null,
|
|
7557
8068
|
identifiesCommand: identifiesCommand2,
|
|
7558
|
-
installationChannels:
|
|
8069
|
+
installationChannels: MANIFEST7.installationChannels
|
|
7559
8070
|
});
|
|
7560
8071
|
}
|
|
7561
8072
|
var rtkAdapter = {
|
|
7562
|
-
manifest:
|
|
7563
|
-
detect:
|
|
7564
|
-
verify:
|
|
8073
|
+
manifest: MANIFEST7,
|
|
8074
|
+
detect: detect7,
|
|
8075
|
+
verify: verify7,
|
|
7565
8076
|
collectMetrics: collectMetrics2,
|
|
7566
8077
|
identifiesCommand: identifiesCommand2,
|
|
7567
8078
|
plan: plan2
|
|
@@ -7613,13 +8124,13 @@ async function computePlan(context) {
|
|
|
7613
8124
|
for (const adapter of providerAdapters) {
|
|
7614
8125
|
const detection = await adapter.detect(providerContext);
|
|
7615
8126
|
versions.providers[adapter.manifest.id] = detection.version;
|
|
7616
|
-
assignable.set(adapter.manifest.id, detection.
|
|
8127
|
+
assignable.set(adapter.manifest.id, new Set(detection.assignableHarnesses));
|
|
7617
8128
|
}
|
|
7618
8129
|
}
|
|
7619
8130
|
const providers = providerAdapters.map((adapter) => ({
|
|
7620
8131
|
id: adapter.manifest.id,
|
|
7621
8132
|
capabilities: adapter.manifest.capabilities,
|
|
7622
|
-
|
|
8133
|
+
assignableHarnesses: assignable.get(adapter.manifest.id) ?? /* @__PURE__ */ new Set()
|
|
7623
8134
|
}));
|
|
7624
8135
|
const resolution = resolveOwnership({
|
|
7625
8136
|
profile,
|
|
@@ -7736,9 +8247,10 @@ async function computePlan(context) {
|
|
|
7736
8247
|
remediation: null
|
|
7737
8248
|
}));
|
|
7738
8249
|
}
|
|
8250
|
+
const refusalIsTheOutcome = actions.length === 0;
|
|
7739
8251
|
for (const entry of blocked) {
|
|
7740
8252
|
diagnostics.push(diagnostic({
|
|
7741
|
-
severity: "error",
|
|
8253
|
+
severity: refusalIsTheOutcome ? "error" : "warning",
|
|
7742
8254
|
code: "managed-mutation-blocked",
|
|
7743
8255
|
message: `plan refuses managed mutation of ${entry.harness} by ${entry.provider}${entry.providerVersion !== null ? ` at ${entry.providerVersion}` : ""}: ${entry.missing}`,
|
|
7744
8256
|
remediation: "Add a compatibility row whose fixture proves this combination, or configure this integration by hand"
|
|
@@ -7777,7 +8289,11 @@ async function runPlan(context) {
|
|
|
7777
8289
|
const computed = await computePlan(context);
|
|
7778
8290
|
const persisted = await persist(context, computed);
|
|
7779
8291
|
const report = { ...computed.report, persisted };
|
|
7780
|
-
const exitCode =
|
|
8292
|
+
const exitCode = planExitCode({
|
|
8293
|
+
blocked: computed.blocked.length,
|
|
8294
|
+
actions: report.actions.length,
|
|
8295
|
+
conflicts: report.conflicts.length
|
|
8296
|
+
});
|
|
7781
8297
|
return commandResult({
|
|
7782
8298
|
command: "plan",
|
|
7783
8299
|
exitCode,
|
|
@@ -7785,6 +8301,13 @@ async function runPlan(context) {
|
|
|
7785
8301
|
diagnostics: computed.diagnostics
|
|
7786
8302
|
});
|
|
7787
8303
|
}
|
|
8304
|
+
function planExitCode(counts) {
|
|
8305
|
+
if (counts.blocked > 0 && counts.actions === 0)
|
|
8306
|
+
return EXIT_CODES["unsupported-environment"];
|
|
8307
|
+
if (counts.conflicts > 0)
|
|
8308
|
+
return EXIT_CODES["blocked-by-conflict"];
|
|
8309
|
+
return EXIT_CODES.ok;
|
|
8310
|
+
}
|
|
7788
8311
|
|
|
7789
8312
|
// apps/cli/dist/src/commands/apply.js
|
|
7790
8313
|
var PLANS_DIRECTORY = "plans";
|
|
@@ -7848,7 +8371,7 @@ async function runApply(context) {
|
|
|
7848
8371
|
const diagnostics = [];
|
|
7849
8372
|
const computed = await computePlan(context);
|
|
7850
8373
|
diagnostics.push(...computed.diagnostics);
|
|
7851
|
-
if (computed.blocked.length > 0) {
|
|
8374
|
+
if (computed.blocked.length > 0 && computed.report.actions.length === 0) {
|
|
7852
8375
|
return finish("rejected", EXIT_CODES["unsupported-environment"], emptyReport("rejected"), diagnostics);
|
|
7853
8376
|
}
|
|
7854
8377
|
if (computed.report.conflicts.length > 0) {
|
|
@@ -8468,7 +8991,7 @@ async function runStatus(context) {
|
|
|
8468
8991
|
providers.push({
|
|
8469
8992
|
id: adapter.manifest.id,
|
|
8470
8993
|
capabilities: adapter.manifest.capabilities,
|
|
8471
|
-
|
|
8994
|
+
assignableHarnesses: new Set(detection.assignableHarnesses)
|
|
8472
8995
|
});
|
|
8473
8996
|
}
|
|
8474
8997
|
const resolution = resolveOwnership({
|
|
@@ -9681,7 +10204,7 @@ function usageText(topic) {
|
|
|
9681
10204
|
}
|
|
9682
10205
|
|
|
9683
10206
|
// apps/cli/dist/src/version.js
|
|
9684
|
-
var TOOL_VERSION = "0.1.
|
|
10207
|
+
var TOOL_VERSION = "0.1.3";
|
|
9685
10208
|
|
|
9686
10209
|
// apps/cli/dist/src/run.js
|
|
9687
10210
|
var DEFAULT_COMMANDS = {
|