@sentropic/h2a 0.90.2 → 0.91.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/cli-command-map.d.ts.map +1 -1
- package/dist/cli-command-map.js +1 -0
- package/dist/cli-command-map.js.map +1 -1
- package/dist/cli-contract.js +1 -1
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +39 -8
- package/dist/cli.js.map +1 -1
- package/dist/hosts/installation-doctor-contract.d.ts +9 -0
- package/dist/hosts/installation-doctor-contract.d.ts.map +1 -0
- package/dist/hosts/installation-doctor-contract.js +9 -0
- package/dist/hosts/installation-doctor-contract.js.map +1 -0
- package/dist/hosts/installation-doctor.d.ts +5 -0
- package/dist/hosts/installation-doctor.d.ts.map +1 -1
- package/dist/hosts/installation-doctor.js +111 -2
- package/dist/hosts/installation-doctor.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/focus/serve.d.ts +1 -0
- package/dist/runtime/focus/serve.d.ts.map +1 -1
- package/dist/runtime/focus/serve.js +1 -1
- package/dist/runtime/focus/serve.js.map +1 -1
- package/dist/runtime/identity/bindings.d.ts +6 -0
- package/dist/runtime/identity/bindings.d.ts.map +1 -1
- package/dist/runtime/identity/bindings.js +15 -0
- package/dist/runtime/identity/bindings.js.map +1 -1
- package/dist/runtime/local-files/locks.d.ts +15 -0
- package/dist/runtime/local-files/locks.d.ts.map +1 -1
- package/dist/runtime/local-files/locks.js +13 -6
- package/dist/runtime/local-files/locks.js.map +1 -1
- package/dist/runtime/loop/engine/adapters.d.ts.map +1 -1
- package/dist/runtime/loop/engine/adapters.js +115 -4
- package/dist/runtime/loop/engine/adapters.js.map +1 -1
- package/dist/runtime/loop/engine/decision.d.ts.map +1 -1
- package/dist/runtime/loop/engine/decision.js +21 -1
- package/dist/runtime/loop/engine/decision.js.map +1 -1
- package/dist/runtime/loop/engine/execute.d.ts +1 -1
- package/dist/runtime/loop/engine/execute.d.ts.map +1 -1
- package/dist/runtime/loop/engine/execute.js +5 -5
- package/dist/runtime/loop/engine/execute.js.map +1 -1
- package/dist/runtime/loop/index.d.ts +43 -0
- package/dist/runtime/loop/index.d.ts.map +1 -1
- package/dist/runtime/loop/index.js.map +1 -1
- package/focus-app/client/_app/immutable/chunks/Bu0ELCga.js +2 -0
- package/focus-app/client/_app/immutable/chunks/Bu0ELCga.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/Bu0ELCga.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/{app.C1sDdCg5.js → app.AqxlGh9f.js} +2 -2
- package/focus-app/client/_app/immutable/entry/app.AqxlGh9f.js.br +0 -0
- package/focus-app/client/_app/immutable/entry/app.AqxlGh9f.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/start.B0poRaV0.js +1 -0
- package/focus-app/client/_app/immutable/entry/start.B0poRaV0.js.br +2 -0
- package/focus-app/client/_app/immutable/entry/start.B0poRaV0.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/{1.DUrghq2x.js → 1.BEBTHieI.js} +1 -1
- package/focus-app/client/_app/immutable/nodes/1.BEBTHieI.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/1.BEBTHieI.js.gz +0 -0
- package/focus-app/client/_app/version.json +1 -1
- package/focus-app/client/_app/version.json.br +0 -0
- package/focus-app/client/_app/version.json.gz +0 -0
- package/focus-app/h2a-focus.json +29 -29
- package/focus-app/handler.js +4 -4
- package/focus-app/index.js +4 -4
- package/focus-app/server/chunks/chunks/{internal.js-C6T8nHkl.js → internal.js-CuLFYCp-.js} +2 -2
- package/focus-app/server/chunks/chunks/{internal.js-C6T8nHkl.js.map → internal.js-CuLFYCp-.js.map} +1 -1
- package/focus-app/server/chunks/{handler-Be3dyNi0.js → handler-Cc1mhJFj.js} +3 -3
- package/focus-app/server/chunks/{handler-Be3dyNi0.js.map → handler-Cc1mhJFj.js.map} +1 -1
- package/focus-app/server/chunks/{index.js-siUxMMnK.js → index.js-D_qPV3oX.js} +2 -2
- package/focus-app/server/chunks/{index.js-siUxMMnK.js.map → index.js-D_qPV3oX.js.map} +1 -1
- package/focus-app/server/chunks/{manifest.js-CXJqSHHn.js → manifest.js-Bdra0QyV.js} +3 -3
- package/focus-app/server/chunks/{manifest.js-CXJqSHHn.js.map → manifest.js-Bdra0QyV.js.map} +1 -1
- package/focus-app/server/chunks/nodes/{1.js-os6QXm6B.js → 1.js-urHS3uQJ.js} +2 -2
- package/focus-app/server/chunks/nodes/{1.js-os6QXm6B.js.map → 1.js-urHS3uQJ.js.map} +1 -1
- package/package.json +2 -2
- package/focus-app/client/_app/immutable/chunks/iXQate3J.js +0 -2
- package/focus-app/client/_app/immutable/chunks/iXQate3J.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/iXQate3J.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js.br +0 -0
- package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js +0 -1
- package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js.br +0 -2
- package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js.gz +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root keys in Claude's native JSON configuration that installation-doctor can
|
|
3
|
+
* rewrite itself. The owner UAT imports this exact contract before taking its
|
|
4
|
+
* snapshot, so its relevance boundary evolves with doctor rather than with an
|
|
5
|
+
* observation of volatile Claude session state.
|
|
6
|
+
*/
|
|
7
|
+
export const CLAUDE_NATIVE_MCP_ROOT_KEY: "mcpServers";
|
|
8
|
+
export const CLAUDE_NATIVE_REPAIRABLE_ROOT_KEYS: readonly string[];
|
|
9
|
+
//# sourceMappingURL=installation-doctor-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation-doctor-contract.d.ts","sourceRoot":"","sources":["../../src/hosts/installation-doctor-contract.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,yCAA0C,YAAY,CAAC;AACvD,mEAA8F"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root keys in Claude's native JSON configuration that installation-doctor can
|
|
3
|
+
* rewrite itself. The owner UAT imports this exact contract before taking its
|
|
4
|
+
* snapshot, so its relevance boundary evolves with doctor rather than with an
|
|
5
|
+
* observation of volatile Claude session state.
|
|
6
|
+
*/
|
|
7
|
+
export const CLAUDE_NATIVE_MCP_ROOT_KEY = "mcpServers";
|
|
8
|
+
export const CLAUDE_NATIVE_REPAIRABLE_ROOT_KEYS = Object.freeze([CLAUDE_NATIVE_MCP_ROOT_KEY]);
|
|
9
|
+
//# sourceMappingURL=installation-doctor-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation-doctor-contract.js","sourceRoot":"","sources":["../../src/hosts/installation-doctor-contract.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,YAAY,CAAC;AACvD,MAAM,CAAC,MAAM,kCAAkC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC"}
|
|
@@ -40,6 +40,11 @@ export interface HostInstallationDoctorOptions {
|
|
|
40
40
|
readonly knownGood: HostCommandResult;
|
|
41
41
|
readonly candidate: HostCommandResult;
|
|
42
42
|
};
|
|
43
|
+
/** Test-only responses from the known-good and candidate Claude configuration probes. */
|
|
44
|
+
readonly testClaudeConfigurationOracle?: {
|
|
45
|
+
readonly knownGood: HostCommandResult;
|
|
46
|
+
readonly candidate: HostCommandResult;
|
|
47
|
+
};
|
|
43
48
|
/** Injectable for hermetic tests; production writes the durable repair marker. */
|
|
44
49
|
readonly writeRepairMarker?: (path: string, content: string) => void;
|
|
45
50
|
/** Report host repair findings and planned actions without mutating the host. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installation-doctor.d.ts","sourceRoot":"","sources":["../../src/hosts/installation-doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAuBH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"installation-doctor.d.ts","sourceRoot":"","sources":["../../src/hosts/installation-doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAuBH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKhD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAChD,eAAO,MAAM,0BAA0B,eAAe,CAAC;AACvD,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAC3E,eAAO,MAAM,+BAA+B,+LACkJ,CAAC;AAC/L,eAAO,MAAM,wCAAwC,gbAC0X,CAAC;AAEhb,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,iBAAiB,GAAG,CAC9B,OAAO,EAAE,QAAQ,GAAG,OAAO,EAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB,iBAAiB,CAAC;AAEvB,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,CAAC,EAAE,iBAAiB,CAAC;IAC5C,oGAAoG;IACpG,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;IACxD,wFAAwF;IACxF,QAAQ,CAAC,4BAA4B,CAAC,EAAE;QACtC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;QACtC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;KACvC,CAAC;IACF,yFAAyF;IACzF,QAAQ,CAAC,6BAA6B,CAAC,EAAE;QACvC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;QACtC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;KACvC,CAAC;IACF,kFAAkF;IAClF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,0BAA0B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,CAAC,sBAAsB,CAAC,EAAE;QAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;QAC9F,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;QACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;KACjE,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EACT,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,mBAAmB,GACnB,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,cAAc,GACd,oBAAoB,GACpB,sBAAsB,GACtB,qBAAqB,GACrB,sBAAsB,GACtB,0BAA0B,GAC1B,sBAAsB,GACtB,sBAAsB,GACtB,yBAAyB,GACzB,0BAA0B,GAC1B,oBAAoB,GACpB,sBAAsB,GACtB,2BAA2B,GAC3B,4BAA4B,GAC5B,8BAA8B,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,uFAAuF;IACvF,QAAQ,CAAC,WAAW,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACzD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,oFAAoF;IACpF,QAAQ,CAAC,SAAS,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACvD,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,4GAA4G;IAC5G,QAAQ,CAAC,YAAY,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC1D,iFAAiF;IACjF,QAAQ,CAAC,UAAU,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACxD,oGAAoG;IACpG,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,2FAA2F;IAC3F,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,uEAAuE;IACvE,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;CAC1C;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,4DAA4D;IAC5D,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC;IAC3C,iEAAiE;IACjE,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACnD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AA00ED,0FAA0F;AAC1F,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,6BAAkC,GAC1C,4BAA4B,CA+E9B;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,QAAQ,EAAE,SAAS,UAAU,EAAE,EAC/B,KAAK,EAAE,SAAS,sBAAsB,EAAE,GACvC,sBAAsB,EAAE,CA4D1B"}
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
import { spawnSync } from "node:child_process";
|
|
16
16
|
import { closeSync, existsSync, fsyncSync, lstatSync, mkdtempSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { homedir, tmpdir } from "node:os";
|
|
18
|
-
import { delimiter, dirname, join } from "node:path";
|
|
18
|
+
import { delimiter, dirname, join, relative } from "node:path";
|
|
19
19
|
import { resolveHostConfigCompanionBase, resolveHostConfigRoot } from "../runtime/host-config-root.js";
|
|
20
20
|
import { currentCliVersion } from "../runtime/upgrade/index.js";
|
|
21
|
+
import { CLAUDE_NATIVE_MCP_ROOT_KEY } from "./installation-doctor-contract.js";
|
|
21
22
|
export const H2A_PLUGIN_SELECTOR = "h2a@sentropic";
|
|
22
23
|
export const H2A_MARKETPLACE_NAME = "sentropic";
|
|
23
24
|
export const H2A_MARKETPLACE_REPOSITORY = "rhanka/h2a";
|
|
@@ -1222,7 +1223,7 @@ function jsonObjectProperties(raw, objectStart) {
|
|
|
1222
1223
|
}
|
|
1223
1224
|
function removeOwnedJsonMcpEntries(raw) {
|
|
1224
1225
|
const root = jsonObjectProperties(raw, skipJsonWhitespace(raw, 0));
|
|
1225
|
-
const mcpServers = root?.find((property) => property.key ===
|
|
1226
|
+
const mcpServers = root?.find((property) => property.key === CLAUDE_NATIVE_MCP_ROOT_KEY);
|
|
1226
1227
|
if (!mcpServers || raw[mcpServers.valueStart] !== "{")
|
|
1227
1228
|
return raw;
|
|
1228
1229
|
const servers = jsonObjectProperties(raw, mcpServers.valueStart);
|
|
@@ -1709,6 +1710,106 @@ function verifyCodexConfiguration(home, report, nativeCliReachable, testOracle)
|
|
|
1709
1710
|
report.unrepaired.push(finding("config-invalid", `Codex rejected its configuration while running codex mcp list: ${result.message ?? "unknown error"}`, configPath));
|
|
1710
1711
|
return false;
|
|
1711
1712
|
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Claude rewrites even a valid configuration while listing MCP servers. The
|
|
1715
|
+
* oracle therefore receives a byte-for-byte copy under a disposable home;
|
|
1716
|
+
* the owner's files must never be an argument to the native command.
|
|
1717
|
+
*/
|
|
1718
|
+
function claudeOracleContext(claudeHome) {
|
|
1719
|
+
return {
|
|
1720
|
+
cwd: claudeHome,
|
|
1721
|
+
env: {
|
|
1722
|
+
...process.env,
|
|
1723
|
+
HOME: claudeHome,
|
|
1724
|
+
CLAUDE_CONFIG_DIR: claudeHome,
|
|
1725
|
+
XDG_CONFIG_HOME: join(claudeHome, ".config"),
|
|
1726
|
+
XDG_CACHE_HOME: join(claudeHome, ".cache"),
|
|
1727
|
+
XDG_DATA_HOME: join(claudeHome, ".local", "share")
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
function verifyClaudeOracleKnownGood(testOracle) {
|
|
1732
|
+
if (testOracle)
|
|
1733
|
+
return testOracle.knownGood;
|
|
1734
|
+
let oracleHome;
|
|
1735
|
+
let oracleResult;
|
|
1736
|
+
try {
|
|
1737
|
+
oracleHome = mkdtempSync(join(tmpdir(), "h2a-claude-config-oracle-"));
|
|
1738
|
+
writeFileSync(join(oracleHome, ".claude.json"), "{}\n");
|
|
1739
|
+
oracleResult = defaultHostCommand("claude", ["mcp", "list"], claudeOracleContext(oracleHome));
|
|
1740
|
+
}
|
|
1741
|
+
catch (error) {
|
|
1742
|
+
oracleResult = { ok: false, message: error.message };
|
|
1743
|
+
}
|
|
1744
|
+
if (oracleHome) {
|
|
1745
|
+
try {
|
|
1746
|
+
rmSync(oracleHome, { recursive: true, force: true });
|
|
1747
|
+
}
|
|
1748
|
+
catch (error) {
|
|
1749
|
+
return { ok: false, message: `cannot remove disposable oracle root: ${error.message}` };
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
return oracleResult;
|
|
1753
|
+
}
|
|
1754
|
+
function verifyClaudeConfiguration(home, report, nativeCliReachable, testOracle) {
|
|
1755
|
+
if (!nativeCliReachable)
|
|
1756
|
+
return false;
|
|
1757
|
+
const configPaths = claudeConfigPaths(home);
|
|
1758
|
+
const configBase = resolveHostConfigCompanionBase("claude", home);
|
|
1759
|
+
const configPath = configPaths[0] ?? join(configBase, ".claude.json");
|
|
1760
|
+
const oracleSelfTest = verifyClaudeOracleKnownGood(testOracle);
|
|
1761
|
+
if (!oracleSelfTest.ok) {
|
|
1762
|
+
report.unrepaired.push(finding("host-config-unverifiable", `Claude configuration oracle could not validate a known-good minimal configuration; it did not judge ${configPath}: ${oracleSelfTest.message ?? "unknown error"}`, configPath));
|
|
1763
|
+
return false;
|
|
1764
|
+
}
|
|
1765
|
+
if (testOracle) {
|
|
1766
|
+
if (testOracle.candidate.ok)
|
|
1767
|
+
return true;
|
|
1768
|
+
report.unrepaired.push(finding("config-invalid", `Claude rejected its configuration while running claude mcp list: ${testOracle.candidate.message ?? "unknown error"}`, configPath));
|
|
1769
|
+
return false;
|
|
1770
|
+
}
|
|
1771
|
+
let oracleHome;
|
|
1772
|
+
let oracleResult;
|
|
1773
|
+
let verificationError;
|
|
1774
|
+
const sources = [];
|
|
1775
|
+
try {
|
|
1776
|
+
oracleHome = mkdtempSync(join(tmpdir(), "h2a-claude-config-oracle-"));
|
|
1777
|
+
for (const path of configPaths) {
|
|
1778
|
+
const destination = join(oracleHome, relative(configBase, path));
|
|
1779
|
+
const raw = readFileSync(path);
|
|
1780
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
1781
|
+
writeFileSync(destination, raw);
|
|
1782
|
+
sources.push({ path, raw });
|
|
1783
|
+
}
|
|
1784
|
+
oracleResult = defaultHostCommand("claude", ["mcp", "list"], claudeOracleContext(oracleHome));
|
|
1785
|
+
for (const source of sources) {
|
|
1786
|
+
const current = readFileSync(source.path);
|
|
1787
|
+
if (!current.equals(source.raw)) {
|
|
1788
|
+
verificationError = `configuration changed while the Claude oracle inspected its disposable copy: ${source.path}`;
|
|
1789
|
+
break;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
catch (error) {
|
|
1794
|
+
verificationError = error.message;
|
|
1795
|
+
}
|
|
1796
|
+
if (oracleHome) {
|
|
1797
|
+
try {
|
|
1798
|
+
rmSync(oracleHome, { recursive: true, force: true });
|
|
1799
|
+
}
|
|
1800
|
+
catch (error) {
|
|
1801
|
+
verificationError ??= `cannot remove disposable oracle root: ${error.message}`;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
if (verificationError) {
|
|
1805
|
+
report.unrepaired.push(finding("host-config-unverifiable", `Claude configuration oracle could not safely inspect ${configPath}: ${verificationError}`, configPath));
|
|
1806
|
+
return false;
|
|
1807
|
+
}
|
|
1808
|
+
if (oracleResult?.ok)
|
|
1809
|
+
return true;
|
|
1810
|
+
report.unrepaired.push(finding("config-invalid", `Claude rejected its configuration while running claude mcp list: ${oracleResult?.message ?? "unknown error"}`, configPath));
|
|
1811
|
+
return false;
|
|
1812
|
+
}
|
|
1712
1813
|
function reportAcceptedOpaqueCodexRegions(home, report) {
|
|
1713
1814
|
const path = codexConfigPath(home);
|
|
1714
1815
|
try {
|
|
@@ -1993,6 +2094,14 @@ export function doctorHostInstallations(options = {}) {
|
|
|
1993
2094
|
report = repair
|
|
1994
2095
|
? repairClaude(home, version, runner, writeMarker, dryRun, options.testClaudePluginUninstalls ?? [], options.testConfigurationWrite, cliReachable)
|
|
1995
2096
|
: inspectClaude(home, version);
|
|
2097
|
+
// `testHostCliReachable` deliberately models only CLI presence for
|
|
2098
|
+
// hermetic fixture tests. It must not accidentally query a developer's
|
|
2099
|
+
// configured Claude installation; the production path has no such
|
|
2100
|
+
// override and always asks Claude through a disposable configuration
|
|
2101
|
+
// copy because `claude mcp list` rewrites its input.
|
|
2102
|
+
if (cliReachable && (options.testHostCliReachable === undefined || options.testClaudeConfigurationOracle !== undefined)) {
|
|
2103
|
+
verifyClaudeConfiguration(home, report, cliReachable, options.testClaudeConfigurationOracle);
|
|
2104
|
+
}
|
|
1996
2105
|
}
|
|
1997
2106
|
else {
|
|
1998
2107
|
report = repair
|