claude-use 9.5.1 → 9.6.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/README.md +1 -0
- package/dist/cli.cjs +40371 -23055
- package/dist/index.cjs +500 -187
- package/dist/index.mjs +482 -181
- package/dist/types/index.d.ts +836 -232
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -2649,7 +2649,7 @@ var init_package = __esm({
|
|
|
2649
2649
|
"package.json"() {
|
|
2650
2650
|
package_default = {
|
|
2651
2651
|
name: "claude-use",
|
|
2652
|
-
version: "9.
|
|
2652
|
+
version: "9.6.0",
|
|
2653
2653
|
description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
2654
2654
|
license: "MIT",
|
|
2655
2655
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -2700,6 +2700,7 @@ var init_package = __esm({
|
|
|
2700
2700
|
dependencies: {
|
|
2701
2701
|
"@anthropic-ai/claude-agent-sdk": "0.3.292",
|
|
2702
2702
|
"@clack/prompts": "^1.8.0",
|
|
2703
|
+
"@modelcontextprotocol/sdk": "1.32.0",
|
|
2703
2704
|
"@orpc/client": "2.0.0-beta.41",
|
|
2704
2705
|
"@orpc/openapi": "2.0.0-beta.41",
|
|
2705
2706
|
"@orpc/server": "2.0.0-beta.41",
|
|
@@ -5767,7 +5768,7 @@ function cascadeProviderName(cascade) {
|
|
|
5767
5768
|
}
|
|
5768
5769
|
return name;
|
|
5769
5770
|
}
|
|
5770
|
-
function
|
|
5771
|
+
function selectProvider(params) {
|
|
5771
5772
|
const cliName = params.cliProvider !== void 0 && params.cliProvider !== "" ? params.cliProvider : void 0;
|
|
5772
5773
|
const name = cliName ?? (params.cascade === void 0 ? void 0 : cascadeProviderName(params.cascade));
|
|
5773
5774
|
if (name === void 0) {
|
|
@@ -5782,6 +5783,14 @@ function resolveProvider(params) {
|
|
|
5782
5783
|
message: `agent-shim: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `agent-shim provider add`.")
|
|
5783
5784
|
};
|
|
5784
5785
|
}
|
|
5786
|
+
return { ok: true, provider: { name, definition } };
|
|
5787
|
+
}
|
|
5788
|
+
function resolveProvider(params) {
|
|
5789
|
+
const selection = selectProvider(params);
|
|
5790
|
+
if (selection?.ok !== true) {
|
|
5791
|
+
return selection;
|
|
5792
|
+
}
|
|
5793
|
+
const { name, definition } = selection.provider;
|
|
5785
5794
|
if (params.credentials === void 0) {
|
|
5786
5795
|
return { ok: false, status: 1, message: `agent-shim: provider ${name} needs its credential resolved, but this launcher has no credential port wired` };
|
|
5787
5796
|
}
|
|
@@ -6064,6 +6073,51 @@ var init_claudeShim = __esm({
|
|
|
6064
6073
|
}
|
|
6065
6074
|
});
|
|
6066
6075
|
|
|
6076
|
+
// src/update/update.ts
|
|
6077
|
+
function compareVersions3(left, right) {
|
|
6078
|
+
const parse = (version) => {
|
|
6079
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
6080
|
+
if (match === null) {
|
|
6081
|
+
throw new Error(`not a plain release version: ${version}`);
|
|
6082
|
+
}
|
|
6083
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
6084
|
+
};
|
|
6085
|
+
const leftParts = parse(left);
|
|
6086
|
+
const rightParts = parse(right);
|
|
6087
|
+
return leftParts.map((part, index) => part - (rightParts[index] ?? 0)).find((difference) => difference !== 0) ?? 0;
|
|
6088
|
+
}
|
|
6089
|
+
function releaseTagFromUrl(url) {
|
|
6090
|
+
const segment = url.split("?")[0]?.split("/").at(-1);
|
|
6091
|
+
const candidate = segment?.startsWith("v") === true ? segment.slice(1) : void 0;
|
|
6092
|
+
return candidate !== void 0 && /^\d+\.\d+\.\d+$/.test(candidate) ? candidate : void 0;
|
|
6093
|
+
}
|
|
6094
|
+
var LATEST_RELEASE_URL, UpdateChannelError, UpdateConflictError, UpdateDownloadError;
|
|
6095
|
+
var init_update = __esm({
|
|
6096
|
+
"src/update/update.ts"() {
|
|
6097
|
+
"use strict";
|
|
6098
|
+
init_cliError();
|
|
6099
|
+
LATEST_RELEASE_URL = "https://github.com/ExaDev/agent-shim/releases/latest";
|
|
6100
|
+
UpdateChannelError = class extends CliError {
|
|
6101
|
+
constructor(message) {
|
|
6102
|
+
super(message);
|
|
6103
|
+
this.name = "UpdateChannelError";
|
|
6104
|
+
}
|
|
6105
|
+
};
|
|
6106
|
+
UpdateConflictError = class extends CliError {
|
|
6107
|
+
constructor(message) {
|
|
6108
|
+
super(message);
|
|
6109
|
+
this.name = "UpdateConflictError";
|
|
6110
|
+
}
|
|
6111
|
+
};
|
|
6112
|
+
UpdateDownloadError = class extends CliError {
|
|
6113
|
+
constructor(message) {
|
|
6114
|
+
super(message);
|
|
6115
|
+
this.name = "UpdateDownloadError";
|
|
6116
|
+
}
|
|
6117
|
+
};
|
|
6118
|
+
}
|
|
6119
|
+
});
|
|
6120
|
+
|
|
6067
6121
|
// src/frontdoor/ensure.ts
|
|
6068
6122
|
function ensureFrontDoor(params) {
|
|
6069
6123
|
const { paths, ports } = params;
|
|
@@ -6499,7 +6553,7 @@ function buildEnv(params) {
|
|
|
6499
6553
|
const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
|
|
6500
6554
|
let providerCustomHeaders;
|
|
6501
6555
|
if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
|
|
6502
|
-
env.CLAUDE_CONFIG_DIR =
|
|
6556
|
+
env.CLAUDE_CONFIG_DIR = import_node_path32.default.join(params.identitiesDir, params.resolvedIdentityName);
|
|
6503
6557
|
}
|
|
6504
6558
|
if (params.provider !== void 0) {
|
|
6505
6559
|
const providerEnv = params.provider.definition.env ?? {};
|
|
@@ -6543,11 +6597,11 @@ function buildEnv(params) {
|
|
|
6543
6597
|
}
|
|
6544
6598
|
return env;
|
|
6545
6599
|
}
|
|
6546
|
-
var
|
|
6600
|
+
var import_node_path32, LOOPBACK_HOSTS;
|
|
6547
6601
|
var init_flags = __esm({
|
|
6548
6602
|
"src/launcher/flags.ts"() {
|
|
6549
6603
|
"use strict";
|
|
6550
|
-
|
|
6604
|
+
import_node_path32 = __toESM(require("node:path"), 1);
|
|
6551
6605
|
init_envBool();
|
|
6552
6606
|
init_credential();
|
|
6553
6607
|
init_headers();
|
|
@@ -6623,7 +6677,9 @@ function resolvePoolLaunch(params) {
|
|
|
6623
6677
|
}
|
|
6624
6678
|
const { pick, earliestReturn, movedOff } = graph.ranking;
|
|
6625
6679
|
if (pick !== void 0) {
|
|
6626
|
-
|
|
6680
|
+
if (params.recordPick) {
|
|
6681
|
+
recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
|
|
6682
|
+
}
|
|
6627
6683
|
const move = movedOff === void 0 ? "" : `moved off ${movedOff.identity} (${movedOff.reason}); `;
|
|
6628
6684
|
return {
|
|
6629
6685
|
ok: true,
|
|
@@ -6689,33 +6745,6 @@ var init_spawn = __esm({
|
|
|
6689
6745
|
}
|
|
6690
6746
|
});
|
|
6691
6747
|
|
|
6692
|
-
// src/update/update.ts
|
|
6693
|
-
function compareVersions3(left, right) {
|
|
6694
|
-
const parse = (version) => {
|
|
6695
|
-
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
6696
|
-
if (match === null) {
|
|
6697
|
-
throw new Error(`not a plain release version: ${version}`);
|
|
6698
|
-
}
|
|
6699
|
-
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
6700
|
-
};
|
|
6701
|
-
const leftParts = parse(left);
|
|
6702
|
-
const rightParts = parse(right);
|
|
6703
|
-
return leftParts.map((part, index) => part - (rightParts[index] ?? 0)).find((difference) => difference !== 0) ?? 0;
|
|
6704
|
-
}
|
|
6705
|
-
function releaseTagFromUrl(url) {
|
|
6706
|
-
const segment = url.split("?")[0]?.split("/").at(-1);
|
|
6707
|
-
const candidate = segment?.startsWith("v") === true ? segment.slice(1) : void 0;
|
|
6708
|
-
return candidate !== void 0 && /^\d+\.\d+\.\d+$/.test(candidate) ? candidate : void 0;
|
|
6709
|
-
}
|
|
6710
|
-
var LATEST_RELEASE_URL;
|
|
6711
|
-
var init_update = __esm({
|
|
6712
|
-
"src/update/update.ts"() {
|
|
6713
|
-
"use strict";
|
|
6714
|
-
init_cliError();
|
|
6715
|
-
LATEST_RELEASE_URL = "https://github.com/ExaDev/agent-shim/releases/latest";
|
|
6716
|
-
}
|
|
6717
|
-
});
|
|
6718
|
-
|
|
6719
6748
|
// src/update/launchHook.ts
|
|
6720
6749
|
function resolveUpdateMode(globalConfig) {
|
|
6721
6750
|
return globalConfig?.update?.mode ?? "off";
|
|
@@ -6793,7 +6822,7 @@ function resolveIdentityCredential(identity, credential, env, port) {
|
|
|
6793
6822
|
const resolution = resolveCredential({ credential, env, port, subject: `identity ${identity}` });
|
|
6794
6823
|
return resolution.ok ? resolution : { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
|
|
6795
6824
|
}
|
|
6796
|
-
function pickFromPool(decided, params, parsedArgv) {
|
|
6825
|
+
function pickFromPool(decided, params, parsedArgv, readOnly) {
|
|
6797
6826
|
const { paths, fs: fs12, proc, log } = params;
|
|
6798
6827
|
if (decided.pool === void 0) {
|
|
6799
6828
|
return { identityDecision: decided };
|
|
@@ -6814,7 +6843,9 @@ function pickFromPool(decided, params, parsedArgv) {
|
|
|
6814
6843
|
now: farmRuntime.now,
|
|
6815
6844
|
sleep: farmRuntime.lock.sleep,
|
|
6816
6845
|
passthrough: parsedArgv.rest,
|
|
6817
|
-
|
|
6846
|
+
// A read-only decision never sleeps for a refused pool and never records its pick, so asking what a launch would pick leaves the next real launch's keep-warm preference as it was.
|
|
6847
|
+
wait: !readOnly && parsedArgv.wait === true,
|
|
6848
|
+
recordPick: !readOnly,
|
|
6818
6849
|
log
|
|
6819
6850
|
});
|
|
6820
6851
|
if (!resolution.ok) {
|
|
@@ -6827,7 +6858,7 @@ function pickFromPool(decided, params, parsedArgv) {
|
|
|
6827
6858
|
poolPick: { name: decided.pool, reasons: resolution.reasons, ...resolution.movedOff === void 0 ? {} : { movedOff: resolution.movedOff } }
|
|
6828
6859
|
};
|
|
6829
6860
|
}
|
|
6830
|
-
function
|
|
6861
|
+
function decideLaunch(params, readOnly) {
|
|
6831
6862
|
const { paths, fs: fs12, proc, log } = params;
|
|
6832
6863
|
const { env, argv } = proc;
|
|
6833
6864
|
const parsedArgv = parseLauncherArgv(argv);
|
|
@@ -6851,10 +6882,10 @@ function prepareLaunch(params) {
|
|
|
6851
6882
|
return trimmed === "" ? void 0 : trimmed;
|
|
6852
6883
|
}
|
|
6853
6884
|
});
|
|
6854
|
-
const { identityDecision, poolExplanation, poolPick } = pickFromPool(decidedIdentity, params, parsedArgv);
|
|
6885
|
+
const { identityDecision, poolExplanation, poolPick } = pickFromPool(decidedIdentity, params, parsedArgv, readOnly);
|
|
6855
6886
|
const farmIdentity = configDirEscapeHatchApplies ? void 0 : identityDecision.name;
|
|
6856
6887
|
const farm = farmIdentity === void 0 ? void 0 : params.farm;
|
|
6857
|
-
if (farm !== void 0 && farmIdentity !== void 0) {
|
|
6888
|
+
if (!readOnly && farm !== void 0 && farmIdentity !== void 0) {
|
|
6858
6889
|
let recovery;
|
|
6859
6890
|
try {
|
|
6860
6891
|
recovery = recoverFarm({
|
|
@@ -6893,33 +6924,44 @@ function prepareLaunch(params) {
|
|
|
6893
6924
|
identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
|
|
6894
6925
|
globalDefaultConfigProfile: params.globalDefaultConfigProfile
|
|
6895
6926
|
});
|
|
6896
|
-
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(
|
|
6927
|
+
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path33.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
|
|
6897
6928
|
log.error(
|
|
6898
6929
|
`agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
|
|
6899
6930
|
);
|
|
6900
6931
|
proc.exit(1);
|
|
6901
6932
|
}
|
|
6902
6933
|
const farmContext = farm !== void 0 && farmIdentity !== void 0 ? { farm, identity: farmIdentity, cascade: farm.loadCascade(configProfileDecision.name, cliOverride) } : void 0;
|
|
6903
|
-
const
|
|
6934
|
+
const providerParams = {
|
|
6904
6935
|
paths,
|
|
6905
6936
|
port: fs12,
|
|
6906
|
-
|
|
6907
|
-
...params.credentials === void 0 ? {} : { credentials: params.credentials },
|
|
6908
|
-
...parsedArgv.provider === void 0 ? {} : { cliProvider: parsedArgv.provider },
|
|
6937
|
+
...parsedArgv.provider === void 0 || parsedArgv.provider === false ? {} : { cliProvider: parsedArgv.provider },
|
|
6909
6938
|
...farmContext === void 0 ? {} : { cascade: farmContext.cascade }
|
|
6910
|
-
}
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6939
|
+
};
|
|
6940
|
+
let selectedProvider;
|
|
6941
|
+
let resolvedProvider;
|
|
6942
|
+
if (parsedArgv.provider !== false && readOnly) {
|
|
6943
|
+
const selection = selectProvider(providerParams);
|
|
6944
|
+
if (selection !== void 0 && !selection.ok) {
|
|
6945
|
+
log.error(selection.message);
|
|
6946
|
+
proc.exit(selection.status);
|
|
6947
|
+
}
|
|
6948
|
+
selectedProvider = selection?.ok === true ? selection.provider : void 0;
|
|
6949
|
+
} else if (parsedArgv.provider !== false) {
|
|
6950
|
+
const provider = resolveProvider({ ...providerParams, env, ...params.credentials === void 0 ? {} : { credentials: params.credentials } });
|
|
6951
|
+
if (provider !== void 0 && !provider.ok) {
|
|
6952
|
+
log.error(provider.message);
|
|
6953
|
+
proc.exit(provider.status);
|
|
6954
|
+
}
|
|
6955
|
+
resolvedProvider = provider?.ok === true ? provider.provider : void 0;
|
|
6956
|
+
selectedProvider = resolvedProvider;
|
|
6957
|
+
for (const warning of provider?.ok === true ? provider.warnings : []) {
|
|
6958
|
+
log.warn(warning);
|
|
6959
|
+
}
|
|
6918
6960
|
}
|
|
6919
6961
|
if (farm !== void 0 && farmIdentity !== void 0) {
|
|
6920
6962
|
try {
|
|
6921
6963
|
const snapshot = readUsageSnapshot(farm.fs, paths.usageSnapshotsDir, farmIdentity);
|
|
6922
|
-
for (const warning of quotaWarnings(snapshot,
|
|
6964
|
+
for (const warning of quotaWarnings(snapshot, selectedProvider?.name ?? ANTHROPIC_PROVIDER, farm.now())) {
|
|
6923
6965
|
log.warn(warning);
|
|
6924
6966
|
}
|
|
6925
6967
|
} catch (error) {
|
|
@@ -6929,8 +6971,8 @@ function prepareLaunch(params) {
|
|
|
6929
6971
|
log.warn(`agent-shim: ${error.message}`);
|
|
6930
6972
|
}
|
|
6931
6973
|
}
|
|
6932
|
-
const identityCredentialBlock = loadedIdentity?.config.credential;
|
|
6933
|
-
const identityResolution =
|
|
6974
|
+
const identityCredentialBlock = selectedProvider === void 0 && farmIdentity !== void 0 ? loadedIdentity?.config.credential : void 0;
|
|
6975
|
+
const identityResolution = !readOnly && identityCredentialBlock !== void 0 && farmIdentity !== void 0 ? resolveIdentityCredential(farmIdentity, identityCredentialBlock, env, params.credentials) : void 0;
|
|
6934
6976
|
if (identityResolution !== void 0 && !identityResolution.ok) {
|
|
6935
6977
|
log.error(identityResolution.message);
|
|
6936
6978
|
proc.exit(identityResolution.status);
|
|
@@ -6944,25 +6986,97 @@ function prepareLaunch(params) {
|
|
|
6944
6986
|
allowAmbientCredential: loadedIdentity?.config.allowAmbientCredential ?? false,
|
|
6945
6987
|
allowAmbientCredentialOverride: parseEnvBool("AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL", env.AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL) === true,
|
|
6946
6988
|
identityName: identityDecision.name,
|
|
6947
|
-
providerSelected:
|
|
6989
|
+
providerSelected: selectedProvider !== void 0,
|
|
6948
6990
|
...identityCredential === void 0 ? {} : { injectedCredential: { variable: CREDENTIAL_TARGET_VARS[identityCredential.target], token: identityCredential.token } }
|
|
6949
6991
|
});
|
|
6950
6992
|
if (!guardResult.ok) {
|
|
6951
|
-
|
|
6952
|
-
|
|
6993
|
+
if (readOnly && identityCredentialBlock !== void 0) {
|
|
6994
|
+
log.warn(`${guardResult.message} (not resolved here: the launch proceeds only if that value is the identity's own injected credential)`);
|
|
6995
|
+
} else {
|
|
6996
|
+
log.error(guardResult.message);
|
|
6997
|
+
proc.exit(1);
|
|
6998
|
+
}
|
|
6953
6999
|
}
|
|
7000
|
+
const launchCascade = farmContext?.cascade ?? (params.farm === void 0 ? void 0 : params.farm.loadCascade(configProfileDecision.name, cliOverride));
|
|
7001
|
+
let cascadeLaunch;
|
|
7002
|
+
if (launchCascade !== void 0 && params.farm !== void 0) {
|
|
7003
|
+
const assembled = assembleCascade(launchCascade);
|
|
7004
|
+
const flattened = flattenLayers(assembled.layers, { home: params.farm.home });
|
|
7005
|
+
cascadeLaunch = flattened.launch;
|
|
7006
|
+
if (readOnly) {
|
|
7007
|
+
for (const diagnostic of [...assembled.diagnostics, ...flattened.diagnostics]) {
|
|
7008
|
+
if (diagnostic.severity !== "info") {
|
|
7009
|
+
log.warn(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
|
|
7010
|
+
}
|
|
7011
|
+
}
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
const pinnedVersion = resolveClaudeVersion({ env, ...parsedArgv.claudeVersion === void 0 ? {} : { flag: parsedArgv.claudeVersion }, ...cascadeLaunch?.claudeVersion === void 0 ? {} : { cascade: cascadeLaunch.claudeVersion } });
|
|
7015
|
+
const discovered = params.resolveClaudeBinary(pinnedVersion === void 0 ? void 0 : { version: pinnedVersion.version });
|
|
7016
|
+
const flags = resolveLaunchFlags({
|
|
7017
|
+
env,
|
|
7018
|
+
// A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.
|
|
7019
|
+
...poolExplanation === void 0 ? {} : { trackUsageDefault: true },
|
|
7020
|
+
...cascadeLaunch === void 0 ? {} : { cascade: cascadeLaunch },
|
|
7021
|
+
flags: {
|
|
7022
|
+
...parsedArgv.skipPermissions === void 0 ? {} : { skipPermissions: parsedArgv.skipPermissions },
|
|
7023
|
+
...parsedArgv.remoteControl === void 0 ? {} : { remoteControl: parsedArgv.remoteControl },
|
|
7024
|
+
...parsedArgv.headroom === void 0 ? {} : { headroom: parsedArgv.headroom },
|
|
7025
|
+
...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage }
|
|
7026
|
+
}
|
|
7027
|
+
});
|
|
7028
|
+
const args = buildArgv({
|
|
7029
|
+
toolFlags: buildFlagArgs(flags),
|
|
7030
|
+
extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
|
|
7031
|
+
passthrough: parsedArgv.rest
|
|
7032
|
+
});
|
|
7033
|
+
const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR : import_node_path33.default.join(paths.identitiesDir, identityDecision.name);
|
|
7034
|
+
const decision = {
|
|
7035
|
+
identitySource: identityDecision.source,
|
|
7036
|
+
configDirEscapeHatch: identityDecision.configDirEscapeHatch,
|
|
7037
|
+
configProfileSource: configProfileDecision.source,
|
|
7038
|
+
...identityDecision.name === void 0 ? {} : { identity: identityDecision.name },
|
|
7039
|
+
...poolPick === void 0 ? {} : { pool: poolPick },
|
|
7040
|
+
...configDir === void 0 || configDir === "" ? {} : { configDir },
|
|
7041
|
+
...configProfileDecision.name === void 0 ? {} : { configProfile: configProfileDecision.name },
|
|
7042
|
+
...selectedProvider === void 0 ? {} : { provider: selectedProvider.name }
|
|
7043
|
+
};
|
|
7044
|
+
return {
|
|
7045
|
+
parsedArgv,
|
|
7046
|
+
identityDecision,
|
|
7047
|
+
poolExplanation,
|
|
7048
|
+
poolPick,
|
|
7049
|
+
configDirEscapeHatch: configDirEscapeHatchApplies,
|
|
7050
|
+
farmIdentity,
|
|
7051
|
+
farmContext,
|
|
7052
|
+
configProfileDecision,
|
|
7053
|
+
provider: selectedProvider,
|
|
7054
|
+
resolvedProvider,
|
|
7055
|
+
identityCredentialBlock,
|
|
7056
|
+
identityCredential,
|
|
7057
|
+
pinnedVersion,
|
|
7058
|
+
flags,
|
|
7059
|
+
bin: discovered.path,
|
|
7060
|
+
args,
|
|
7061
|
+
decision
|
|
7062
|
+
};
|
|
7063
|
+
}
|
|
7064
|
+
function prepareLaunch(params) {
|
|
7065
|
+
const { paths, proc, log } = params;
|
|
7066
|
+
const { env } = proc;
|
|
7067
|
+
const decided = decideLaunch(params, false);
|
|
7068
|
+
const { identityDecision, configProfileDecision, resolvedProvider, identityCredential, poolExplanation, flags: resolvedFlags, args: finalArgv, configDirEscapeHatch: configDirEscapeHatchApplies, decision } = decided;
|
|
6954
7069
|
log.info(
|
|
6955
7070
|
`agent-shim: identity ${identityDecision.name ?? "(none)"} (${identityDecision.source}${poolExplanation === void 0 ? "" : `, ${poolExplanation}`}), config profile ${configProfileDecision.name ?? "(none)"} (${configProfileDecision.source})` + (resolvedProvider === void 0 ? "" : `, provider ${resolvedProvider.name} (credential ${resolvedProvider.credential.target} from ${describeSource(resolvedProvider.credential.source)})`) + (identityCredential === void 0 ? "" : `, identity credential ${identityCredential.target} from ${describeSource(identityCredential.source)}`)
|
|
6956
7071
|
);
|
|
6957
7072
|
const updateCheck = runLaunchUpdateCheck({
|
|
6958
7073
|
mode: params.updateMode ?? "off",
|
|
6959
|
-
checkPath:
|
|
7074
|
+
checkPath: import_node_path33.default.join(paths.root, "update.check"),
|
|
6960
7075
|
currentVersion: package_default.version,
|
|
6961
7076
|
port: params.update
|
|
6962
7077
|
});
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = farmContext;
|
|
7078
|
+
if (decided.farmContext !== void 0) {
|
|
7079
|
+
const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = decided.farmContext;
|
|
6966
7080
|
let result;
|
|
6967
7081
|
try {
|
|
6968
7082
|
result = resyncFarm({
|
|
@@ -6999,27 +7113,10 @@ function prepareLaunch(params) {
|
|
|
6999
7113
|
log.info(
|
|
7000
7114
|
result.noOp ? `agent-shim: farm at ${result.farmRoot} already matches the resolved cascade` : `agent-shim: farm at ${result.farmRoot} resynced (${String(result.manifest.links.length)} link(s), ${String(result.manifest.materialised.length)} built director(ies)${result.adopted.length === 0 ? "" : `, ${String(result.adopted.length)} adopted into ${resyncFarmRuntime.claudeHome}`})`
|
|
7001
7115
|
);
|
|
7002
|
-
cascadeLaunch = result.resolved.flattened.launch;
|
|
7003
|
-
} else if (params.farm !== void 0) {
|
|
7004
|
-
cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
|
|
7005
7116
|
}
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
if (pinnedVersion !== void 0) {
|
|
7009
|
-
log.info(`agent-shim: Claude Code ${pinnedVersion.version} (pinned by ${pinnedVersion.source})`);
|
|
7117
|
+
if (decided.pinnedVersion !== void 0) {
|
|
7118
|
+
log.info(`agent-shim: Claude Code ${decided.pinnedVersion.version} (pinned by ${decided.pinnedVersion.source})`);
|
|
7010
7119
|
}
|
|
7011
|
-
const resolvedFlags = resolveLaunchFlags({
|
|
7012
|
-
env,
|
|
7013
|
-
// A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.
|
|
7014
|
-
...poolExplanation === void 0 ? {} : { trackUsageDefault: true },
|
|
7015
|
-
...cascadeLaunch === void 0 ? {} : { cascade: cascadeLaunch },
|
|
7016
|
-
flags: {
|
|
7017
|
-
...parsedArgv.skipPermissions === void 0 ? {} : { skipPermissions: parsedArgv.skipPermissions },
|
|
7018
|
-
...parsedArgv.remoteControl === void 0 ? {} : { remoteControl: parsedArgv.remoteControl },
|
|
7019
|
-
...parsedArgv.headroom === void 0 ? {} : { headroom: parsedArgv.headroom },
|
|
7020
|
-
...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage }
|
|
7021
|
-
}
|
|
7022
|
-
});
|
|
7023
7120
|
const frontDoorPort = params.frontdoor;
|
|
7024
7121
|
const frontDoorEngaged = resolvedProvider !== void 0 || resolvedFlags.headroom || resolvedFlags.trackUsage;
|
|
7025
7122
|
if (frontDoorEngaged && frontDoorPort === void 0) {
|
|
@@ -7043,11 +7140,6 @@ function prepareLaunch(params) {
|
|
|
7043
7140
|
log.info(`agent-shim: routing through the front door on 127.0.0.1:${String(frontDoor.port)}${resolvedProvider === void 0 ? ` (OAuth via the door's CONNECT surface on 127.0.0.1:${String(frontDoor.connectPort)}, usage recorded)` : ` (provider ${resolvedProvider.name})`}`);
|
|
7044
7141
|
}
|
|
7045
7142
|
const frontDoorRelease = frontDoor === void 0 ? void 0 : frontDoorPort?.release;
|
|
7046
|
-
const finalArgv = buildArgv({
|
|
7047
|
-
toolFlags: buildFlagArgs(resolvedFlags),
|
|
7048
|
-
extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
|
|
7049
|
-
passthrough: parsedArgv.rest
|
|
7050
|
-
});
|
|
7051
7143
|
const finalEnv = buildEnv({
|
|
7052
7144
|
baseEnv: env,
|
|
7053
7145
|
configDirEscapeHatch: configDirEscapeHatchApplies,
|
|
@@ -7065,18 +7157,35 @@ function prepareLaunch(params) {
|
|
|
7065
7157
|
registered();
|
|
7066
7158
|
}
|
|
7067
7159
|
};
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7160
|
+
return { bin: decided.bin, args: finalArgv, env: finalEnv, release, markChildStarted: updateCheck.markChildStarted, decision };
|
|
7161
|
+
}
|
|
7162
|
+
function resolveLaunch(params) {
|
|
7163
|
+
const decided = decideLaunch(params, true);
|
|
7164
|
+
const { env } = params.proc;
|
|
7165
|
+
const frontDoor = decided.provider !== void 0 || decided.flags.headroom || decided.flags.trackUsage;
|
|
7166
|
+
const built = buildEnv({
|
|
7167
|
+
baseEnv: env,
|
|
7168
|
+
configDirEscapeHatch: decided.configDirEscapeHatch,
|
|
7169
|
+
resolvedIdentityName: decided.identityDecision.name,
|
|
7170
|
+
identitiesDir: params.paths.identitiesDir,
|
|
7171
|
+
...decided.provider === void 0 ? {} : { provider: decided.provider },
|
|
7172
|
+
...frontDoor ? { frontdoor: { port: 0, connectPort: 0, trustBundlePath: "", sessionToken: "" } } : {},
|
|
7173
|
+
...decided.flags.headroom ? { headroom: { socketPath: "", projectId: "" } } : {},
|
|
7174
|
+
sessionId: ""
|
|
7175
|
+
});
|
|
7176
|
+
const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
|
|
7177
|
+
const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
|
|
7178
|
+
const credential = decided.provider !== void 0 ? { subject: "provider", name: decided.provider.name, summary: summariseCredential(decided.provider.definition.credential) } : decided.identityCredentialBlock !== void 0 && decided.farmIdentity !== void 0 ? { subject: "identity", name: decided.farmIdentity, summary: summariseCredential(decided.identityCredentialBlock) } : void 0;
|
|
7179
|
+
return {
|
|
7180
|
+
decision: decided.decision,
|
|
7181
|
+
flags: decided.flags,
|
|
7182
|
+
...decided.pinnedVersion === void 0 ? {} : { claudeVersion: decided.pinnedVersion },
|
|
7183
|
+
bin: decided.bin,
|
|
7184
|
+
args: decided.args,
|
|
7185
|
+
...credential === void 0 ? {} : { credential },
|
|
7186
|
+
routing: { frontDoor, headroom: decided.flags.headroom },
|
|
7187
|
+
environment
|
|
7078
7188
|
};
|
|
7079
|
-
return { bin: discovered.path, args: finalArgv, env: finalEnv, release, markChildStarted: updateCheck.markChildStarted, decision };
|
|
7080
7189
|
}
|
|
7081
7190
|
function runLaunchPlan(plan, spawn2) {
|
|
7082
7191
|
try {
|
|
@@ -7093,12 +7202,12 @@ function runLaunchPlan(plan, spawn2) {
|
|
|
7093
7202
|
function runLauncher(params) {
|
|
7094
7203
|
params.proc.exit(runLaunchPlan(prepareLaunch(params), params.spawn));
|
|
7095
7204
|
}
|
|
7096
|
-
var import_node_crypto10,
|
|
7205
|
+
var import_node_crypto10, import_node_path33;
|
|
7097
7206
|
var init_launcher = __esm({
|
|
7098
7207
|
"src/launcher.ts"() {
|
|
7099
7208
|
"use strict";
|
|
7100
7209
|
import_node_crypto10 = require("node:crypto");
|
|
7101
|
-
|
|
7210
|
+
import_node_path33 = __toESM(require("node:path"), 1);
|
|
7102
7211
|
init_package();
|
|
7103
7212
|
init_envBool();
|
|
7104
7213
|
init_argv();
|
|
@@ -7129,13 +7238,13 @@ function agentShimCliPath(distDir = typeof __AGENT_SHIM_DIST_DIR__ === "string"
|
|
|
7129
7238
|
if (distDir === void 0) {
|
|
7130
7239
|
throw new OwnCliPathUnknownError();
|
|
7131
7240
|
}
|
|
7132
|
-
return
|
|
7241
|
+
return import_node_path34.default.join(distDir, OWN_CLI_FILE_NAME);
|
|
7133
7242
|
}
|
|
7134
|
-
var
|
|
7243
|
+
var import_node_path34, OWN_CLI_FILE_NAME, OwnCliPathUnknownError;
|
|
7135
7244
|
var init_ownCli = __esm({
|
|
7136
7245
|
"src/ownCli.ts"() {
|
|
7137
7246
|
"use strict";
|
|
7138
|
-
|
|
7247
|
+
import_node_path34 = __toESM(require("node:path"), 1);
|
|
7139
7248
|
init_cliError();
|
|
7140
7249
|
OWN_CLI_FILE_NAME = "cli.cjs";
|
|
7141
7250
|
OwnCliPathUnknownError = class extends CliError {
|
|
@@ -7220,7 +7329,7 @@ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " :
|
|
|
7220
7329
|
// src/frontdoor/trust.ts
|
|
7221
7330
|
function resolveTrustBundle(params) {
|
|
7222
7331
|
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
7223
|
-
if (inherited === void 0 || inherited === "" ||
|
|
7332
|
+
if (inherited === void 0 || inherited === "" || import_node_path35.default.resolve(inherited) === import_node_path35.default.resolve(caCertFile)) {
|
|
7224
7333
|
return { path: caCertFile };
|
|
7225
7334
|
}
|
|
7226
7335
|
const caPem = fs12.readFileUtf8(caCertFile);
|
|
@@ -7238,19 +7347,19 @@ function resolveTrustBundle(params) {
|
|
|
7238
7347
|
}
|
|
7239
7348
|
const combined = `${inheritedPem.trimEnd()}
|
|
7240
7349
|
${caPem}`;
|
|
7241
|
-
const bundle =
|
|
7350
|
+
const bundle = import_node_path35.default.join(bundlesDir, `${(0, import_node_crypto11.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
7242
7351
|
if (!fs12.exists(bundle)) {
|
|
7243
7352
|
fs12.mkdirp(bundlesDir);
|
|
7244
7353
|
fs12.writeFileAtomic(bundle, combined);
|
|
7245
7354
|
}
|
|
7246
7355
|
return { path: bundle };
|
|
7247
7356
|
}
|
|
7248
|
-
var import_node_crypto11,
|
|
7357
|
+
var import_node_crypto11, import_node_path35, BUNDLE_NAME_HEX_DIGITS;
|
|
7249
7358
|
var init_trust = __esm({
|
|
7250
7359
|
"src/frontdoor/trust.ts"() {
|
|
7251
7360
|
"use strict";
|
|
7252
7361
|
import_node_crypto11 = require("node:crypto");
|
|
7253
|
-
|
|
7362
|
+
import_node_path35 = __toESM(require("node:path"), 1);
|
|
7254
7363
|
BUNDLE_NAME_HEX_DIGITS = 16;
|
|
7255
7364
|
}
|
|
7256
7365
|
});
|
|
@@ -7395,6 +7504,31 @@ function prepareClaudeLaunch(options) {
|
|
|
7395
7504
|
const spawnDaemon = daemonSpawnerFor(options.agentShim);
|
|
7396
7505
|
return prepareLaunch(realPrepareLaunchParams(paths, { proc, log, spawnDaemon, farm: buildFarmRuntime(paths, options.cwd) }));
|
|
7397
7506
|
}
|
|
7507
|
+
function resolveClaudeLaunch(options) {
|
|
7508
|
+
const paths = options.paths ?? resolveLayoutPaths();
|
|
7509
|
+
const refusals = [];
|
|
7510
|
+
const warnings = [];
|
|
7511
|
+
const log = {
|
|
7512
|
+
info: () => void 0,
|
|
7513
|
+
warn: (message) => {
|
|
7514
|
+
warnings.push(message);
|
|
7515
|
+
},
|
|
7516
|
+
error: (message) => {
|
|
7517
|
+
refusals.push(message);
|
|
7518
|
+
}
|
|
7519
|
+
};
|
|
7520
|
+
const proc = {
|
|
7521
|
+
env: options.env,
|
|
7522
|
+
argv: options.argv,
|
|
7523
|
+
exit: (code) => {
|
|
7524
|
+
throw new LaunchRefusedError(refusals.join("\n") || `the launch was refused (exit ${String(code)})`, code);
|
|
7525
|
+
}
|
|
7526
|
+
};
|
|
7527
|
+
const spawnDaemon = () => {
|
|
7528
|
+
throw new Error("resolving a launch starts no daemon");
|
|
7529
|
+
};
|
|
7530
|
+
return { resolution: resolveLaunch(realPrepareLaunchParams(paths, { proc, log, spawnDaemon, farm: buildFarmRuntime(paths, options.cwd) })), warnings };
|
|
7531
|
+
}
|
|
7398
7532
|
var import_node_os7, import_node_crypto12, LaunchRefusedError;
|
|
7399
7533
|
var init_launchWiring = __esm({
|
|
7400
7534
|
"src/launchWiring.ts"() {
|
|
@@ -7563,11 +7697,11 @@ var init_anthropicUsageRefresh = __esm({
|
|
|
7563
7697
|
});
|
|
7564
7698
|
|
|
7565
7699
|
// src/usage/providerQuota.ts
|
|
7566
|
-
var
|
|
7700
|
+
var import_zod22, MS_PER_SECOND7, SECONDS_PER_HOUR, HOURS_PER_DAY3, DAYS_PER_MONTH, ZAI_HOST, ZAI_QUOTA_URL, ZAI_UNIT_HOURS, ZAI_UNIT_MONTHS, ZAI_UNIT_MS, ZaiLimitSchema, ZaiResponseSchema, OPENROUTER_HOST, OPENROUTER_KEY_URL, OPENROUTER_CREDITS_URL, MS_PER_DAY3, OpenRouterKeySchema, OpenRouterCreditsSchema;
|
|
7567
7701
|
var init_providerQuota = __esm({
|
|
7568
7702
|
"src/usage/providerQuota.ts"() {
|
|
7569
7703
|
"use strict";
|
|
7570
|
-
|
|
7704
|
+
import_zod22 = require("zod");
|
|
7571
7705
|
init_schema2();
|
|
7572
7706
|
MS_PER_SECOND7 = 1e3;
|
|
7573
7707
|
SECONDS_PER_HOUR = 3600;
|
|
@@ -7581,35 +7715,35 @@ var init_providerQuota = __esm({
|
|
|
7581
7715
|
[ZAI_UNIT_HOURS, SECONDS_PER_HOUR * MS_PER_SECOND7],
|
|
7582
7716
|
[ZAI_UNIT_MONTHS, DAYS_PER_MONTH * HOURS_PER_DAY3 * SECONDS_PER_HOUR * MS_PER_SECOND7]
|
|
7583
7717
|
]);
|
|
7584
|
-
ZaiLimitSchema =
|
|
7585
|
-
type:
|
|
7586
|
-
unit:
|
|
7587
|
-
number:
|
|
7588
|
-
percentage:
|
|
7589
|
-
nextResetTime:
|
|
7590
|
-
usage:
|
|
7591
|
-
currentValue:
|
|
7592
|
-
remaining:
|
|
7718
|
+
ZaiLimitSchema = import_zod22.z.object({
|
|
7719
|
+
type: import_zod22.z.string(),
|
|
7720
|
+
unit: import_zod22.z.number().int(),
|
|
7721
|
+
number: import_zod22.z.number().int().positive(),
|
|
7722
|
+
percentage: import_zod22.z.number().nonnegative(),
|
|
7723
|
+
nextResetTime: import_zod22.z.number().positive().optional(),
|
|
7724
|
+
usage: import_zod22.z.number().nonnegative().optional(),
|
|
7725
|
+
currentValue: import_zod22.z.number().nonnegative().optional(),
|
|
7726
|
+
remaining: import_zod22.z.number().nonnegative().optional()
|
|
7593
7727
|
});
|
|
7594
|
-
ZaiResponseSchema =
|
|
7595
|
-
success:
|
|
7596
|
-
msg:
|
|
7597
|
-
data:
|
|
7728
|
+
ZaiResponseSchema = import_zod22.z.object({
|
|
7729
|
+
success: import_zod22.z.boolean(),
|
|
7730
|
+
msg: import_zod22.z.string().optional(),
|
|
7731
|
+
data: import_zod22.z.object({ level: import_zod22.z.string().optional(), limits: import_zod22.z.array(ZaiLimitSchema) })
|
|
7598
7732
|
});
|
|
7599
7733
|
OPENROUTER_HOST = "openrouter.ai";
|
|
7600
7734
|
OPENROUTER_KEY_URL = `https://${OPENROUTER_HOST}/api/v1/key`;
|
|
7601
7735
|
OPENROUTER_CREDITS_URL = `https://${OPENROUTER_HOST}/api/v1/credits`;
|
|
7602
7736
|
MS_PER_DAY3 = HOURS_PER_DAY3 * SECONDS_PER_HOUR * MS_PER_SECOND7;
|
|
7603
|
-
OpenRouterKeySchema =
|
|
7604
|
-
data:
|
|
7605
|
-
limit:
|
|
7606
|
-
limit_remaining:
|
|
7607
|
-
limit_reset:
|
|
7608
|
-
is_free_tier:
|
|
7609
|
-
free_model_daily_requests:
|
|
7737
|
+
OpenRouterKeySchema = import_zod22.z.object({
|
|
7738
|
+
data: import_zod22.z.object({
|
|
7739
|
+
limit: import_zod22.z.number().nonnegative().nullable(),
|
|
7740
|
+
limit_remaining: import_zod22.z.number().nullable(),
|
|
7741
|
+
limit_reset: import_zod22.z.string().nullable(),
|
|
7742
|
+
is_free_tier: import_zod22.z.boolean().optional(),
|
|
7743
|
+
free_model_daily_requests: import_zod22.z.object({ used: import_zod22.z.number().nonnegative(), limit: import_zod22.z.number().nonnegative(), remaining: import_zod22.z.number() }).optional()
|
|
7610
7744
|
})
|
|
7611
7745
|
});
|
|
7612
|
-
OpenRouterCreditsSchema =
|
|
7746
|
+
OpenRouterCreditsSchema = import_zod22.z.object({ data: import_zod22.z.object({ total_credits: import_zod22.z.number().nonnegative(), total_usage: import_zod22.z.number().nonnegative() }) });
|
|
7613
7747
|
}
|
|
7614
7748
|
});
|
|
7615
7749
|
|
|
@@ -7741,6 +7875,9 @@ __export(index_exports, {
|
|
|
7741
7875
|
CheckReportJsonSchema: () => CheckReportJsonSchema,
|
|
7742
7876
|
CheckRunInputSchema: () => CheckRunInputSchema,
|
|
7743
7877
|
CliError: () => CliError,
|
|
7878
|
+
CodexLogoutOutputSchema: () => CodexLogoutOutputSchema,
|
|
7879
|
+
CodexSignInSchema: () => CodexSignInSchema,
|
|
7880
|
+
CodexStatusOutputSchema: () => CodexStatusOutputSchema,
|
|
7744
7881
|
ConfigProfileSchema: () => ConfigProfileSchema,
|
|
7745
7882
|
CredentialCacheSchema: () => CredentialCacheSchema,
|
|
7746
7883
|
CredentialSchema: () => CredentialSchema,
|
|
@@ -7765,6 +7902,7 @@ __export(index_exports, {
|
|
|
7765
7902
|
FARM_MANIFEST_FILENAME: () => FARM_MANIFEST_FILENAME,
|
|
7766
7903
|
FrontDoorControlMaterialError: () => FrontDoorControlMaterialError,
|
|
7767
7904
|
FrontDoorNotServingError: () => FrontDoorNotServingError,
|
|
7905
|
+
FrontDoorRestartOutputSchema: () => FrontDoorRestartOutputSchema,
|
|
7768
7906
|
FrontDoorSessionStatusSchema: () => FrontDoorSessionStatusSchema,
|
|
7769
7907
|
FrontDoorSessionsOutputSchema: () => FrontDoorSessionsOutputSchema,
|
|
7770
7908
|
FrontDoorStartError: () => FrontDoorStartError,
|
|
@@ -7782,6 +7920,8 @@ __export(index_exports, {
|
|
|
7782
7920
|
LAUNCH_EVENT_SOURCE: () => LAUNCH_EVENT_SOURCE,
|
|
7783
7921
|
LaunchLifecycleEventSchema: () => LaunchLifecycleEventSchema,
|
|
7784
7922
|
LaunchRefusedError: () => LaunchRefusedError,
|
|
7923
|
+
LaunchResolveInputSchema: () => LaunchResolveInputSchema,
|
|
7924
|
+
LaunchResolveOutputSchema: () => LaunchResolveOutputSchema,
|
|
7785
7925
|
LegacyProviderFileError: () => LegacyProviderFileError,
|
|
7786
7926
|
OWN_CLI_FILE_NAME: () => OWN_CLI_FILE_NAME,
|
|
7787
7927
|
PROMPT_CACHE_TTL_MS: () => PROMPT_CACHE_TTL_MS,
|
|
@@ -7828,6 +7968,7 @@ __export(index_exports, {
|
|
|
7828
7968
|
RcStreamEnvelopeSchema: () => RcStreamEnvelopeSchema,
|
|
7829
7969
|
RcStreamEventSchema: () => RcStreamEventSchema,
|
|
7830
7970
|
USAGE_EVENT_SOURCE: () => USAGE_EVENT_SOURCE,
|
|
7971
|
+
UpdateCheckOutputSchema: () => UpdateCheckOutputSchema,
|
|
7831
7972
|
UsageError: () => UsageError,
|
|
7832
7973
|
UsageListOutputSchema: () => UsageListOutputSchema,
|
|
7833
7974
|
UsageLiveOutputSchema: () => UsageLiveOutputSchema,
|
|
@@ -7870,14 +8011,17 @@ __export(index_exports, {
|
|
|
7870
8011
|
collectDoctorReport: () => collectDoctorReport,
|
|
7871
8012
|
collectFrontDoorStatus: () => collectFrontDoorStatus,
|
|
7872
8013
|
collectPoolPick: () => collectPoolPick,
|
|
8014
|
+
createCodexApiRouter: () => createCodexApiRouter,
|
|
7873
8015
|
createControlApiRouter: () => createControlApiRouter,
|
|
7874
8016
|
createDoorApiNodeHandler: () => createDoorApiNodeHandler,
|
|
7875
8017
|
createDoorApiRouter: () => createDoorApiRouter,
|
|
7876
8018
|
createDoorEventHub: () => createDoorEventHub,
|
|
7877
8019
|
createDoorHealthPublisher: () => createDoorHealthPublisher,
|
|
7878
8020
|
createEventsApiRouter: () => createEventsApiRouter,
|
|
8021
|
+
createLaunchApiRouter: () => createLaunchApiRouter,
|
|
7879
8022
|
createLaunchEventPublisher: () => createLaunchEventPublisher,
|
|
7880
8023
|
createLeafCache: () => createLeafCache,
|
|
8024
|
+
createLifecycleApiRouter: () => createLifecycleApiRouter,
|
|
7881
8025
|
createProfile: () => createProfile,
|
|
7882
8026
|
createQuotaExpiringPublisher: () => createQuotaExpiringPublisher,
|
|
7883
8027
|
createRcApiNodeHandler: () => createRcApiNodeHandler,
|
|
@@ -7985,7 +8129,9 @@ __export(index_exports, {
|
|
|
7985
8129
|
requirePool: () => requirePool,
|
|
7986
8130
|
resolveAgentShimHome: () => resolveAgentShimHome,
|
|
7987
8131
|
resolveClaudeHome: () => resolveClaudeHome,
|
|
8132
|
+
resolveClaudeLaunch: () => resolveClaudeLaunch,
|
|
7988
8133
|
resolveDecisions: () => resolveDecisions,
|
|
8134
|
+
resolveLaunch: () => resolveLaunch,
|
|
7989
8135
|
resolveLaunchSelection: () => resolveLaunchSelection,
|
|
7990
8136
|
resolveLayoutPaths: () => resolveLayoutPaths,
|
|
7991
8137
|
resolveSupervisorConfig: () => resolveSupervisorConfig,
|
|
@@ -8522,8 +8668,8 @@ function parseConnectTarget(authority) {
|
|
|
8522
8668
|
function isInterceptedHost(host, interceptHosts) {
|
|
8523
8669
|
return interceptHosts.includes(host);
|
|
8524
8670
|
}
|
|
8525
|
-
function servedByPipeline(
|
|
8526
|
-
return
|
|
8671
|
+
function servedByPipeline(path36) {
|
|
8672
|
+
return path36?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
8527
8673
|
}
|
|
8528
8674
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
8529
8675
|
"connection",
|
|
@@ -9057,11 +9203,11 @@ function createRcSessionTracker(deps) {
|
|
|
9057
9203
|
};
|
|
9058
9204
|
const observeExchange = (request4) => {
|
|
9059
9205
|
const method = (request4.method ?? "").toUpperCase();
|
|
9060
|
-
const
|
|
9061
|
-
if (!
|
|
9206
|
+
const path36 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
|
|
9207
|
+
if (!path36.startsWith(RC_SESSIONS_PATH_PREFIX)) {
|
|
9062
9208
|
return void 0;
|
|
9063
9209
|
}
|
|
9064
|
-
const tail =
|
|
9210
|
+
const tail = path36.slice(RC_SESSIONS_PATH_PREFIX.length);
|
|
9065
9211
|
const facts = {
|
|
9066
9212
|
oauthAuthorization: oauthAuthorizationOf(request4.headers),
|
|
9067
9213
|
anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
|
|
@@ -9443,8 +9589,8 @@ var RC_READ_FILE_ENCODINGS = ["utf-8", "base64"];
|
|
|
9443
9589
|
function isRcReadFileEncoding(value) {
|
|
9444
9590
|
return RC_READ_FILE_ENCODINGS.some((encoding) => encoding === value);
|
|
9445
9591
|
}
|
|
9446
|
-
function buildRcReadFilePayload(requestId,
|
|
9447
|
-
return buildRcControlRequestPayload(requestId, { subtype: "read_file", path:
|
|
9592
|
+
function buildRcReadFilePayload(requestId, path36, options) {
|
|
9593
|
+
return buildRcControlRequestPayload(requestId, { subtype: "read_file", path: path36, ...options?.maxBytes === void 0 ? {} : { max_bytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } });
|
|
9448
9594
|
}
|
|
9449
9595
|
function buildRcFileSuggestionsPayload(requestId, query) {
|
|
9450
9596
|
return buildRcControlRequestPayload(requestId, { subtype: "file_suggestions", query });
|
|
@@ -9546,15 +9692,15 @@ async function getRcSessionContextUsage(deps, sessionId, detail) {
|
|
|
9546
9692
|
const result = await deliverRcClientPayload(deps, sessionId, buildRcGetContextUsagePayload(requestId, detail), `request the context usage of session ${sessionId}`);
|
|
9547
9693
|
return result.ok ? { ...result, requestId } : result;
|
|
9548
9694
|
}
|
|
9549
|
-
async function readRcSessionFile(deps, sessionId,
|
|
9550
|
-
if (
|
|
9695
|
+
async function readRcSessionFile(deps, sessionId, path36, options) {
|
|
9696
|
+
if (path36 === "") {
|
|
9551
9697
|
return { ok: false, message: "a read-file write needs a non-empty path: the SDK's own field names the file the worker resolves against the session's cwd, and an empty string names none" };
|
|
9552
9698
|
}
|
|
9553
9699
|
if (options?.maxBytes !== void 0 && (!Number.isInteger(options.maxBytes) || options.maxBytes <= 0)) {
|
|
9554
9700
|
return { ok: false, message: "a read-file write's max-bytes is a positive whole number of bytes: the SDK's own field caps the read, and a zero or negative cap reads nothing" };
|
|
9555
9701
|
}
|
|
9556
9702
|
const requestId = deps.newUuid();
|
|
9557
|
-
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId,
|
|
9703
|
+
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path36, options), `read ${path36} from session ${sessionId}`);
|
|
9558
9704
|
return result.ok ? { ...result, requestId } : result;
|
|
9559
9705
|
}
|
|
9560
9706
|
async function suggestRcSessionFiles(deps, sessionId, query) {
|
|
@@ -9723,11 +9869,11 @@ function createRcControlHandler(deps) {
|
|
|
9723
9869
|
path: "read-file",
|
|
9724
9870
|
read: (body) => {
|
|
9725
9871
|
const session = bodyString(body, "session");
|
|
9726
|
-
const
|
|
9872
|
+
const path36 = bodyString(body, "path");
|
|
9727
9873
|
const maxBytes = "maxBytes" in body ? bodyPositiveInteger(body, "maxBytes") : void 0;
|
|
9728
9874
|
const encoding = "encoding" in body && isRcReadFileEncoding(body.encoding) ? body.encoding : void 0;
|
|
9729
|
-
const refused2 = session === void 0 ||
|
|
9730
|
-
return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session,
|
|
9875
|
+
const refused2 = session === void 0 || path36 === void 0 || "maxBytes" in body && maxBytes === void 0 || "encoding" in body && encoding === void 0;
|
|
9876
|
+
return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session, path36, { ...maxBytes === void 0 ? {} : { maxBytes }, ...encoding === void 0 ? {} : { encoding } }) };
|
|
9731
9877
|
}
|
|
9732
9878
|
},
|
|
9733
9879
|
{
|
|
@@ -10037,9 +10183,9 @@ function requestIdOfBody(body) {
|
|
|
10037
10183
|
}
|
|
10038
10184
|
function frontDoorRcControl(transport, token) {
|
|
10039
10185
|
const headers = { authorization: `Bearer ${token}` };
|
|
10040
|
-
const listAnswerOf = async (
|
|
10186
|
+
const listAnswerOf = async (path36, what) => {
|
|
10041
10187
|
try {
|
|
10042
|
-
return await transport.request({ method: "GET", path:
|
|
10188
|
+
return await transport.request({ method: "GET", path: path36, headers });
|
|
10043
10189
|
} catch (error) {
|
|
10044
10190
|
throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
10045
10191
|
}
|
|
@@ -10111,10 +10257,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
10111
10257
|
}
|
|
10112
10258
|
return pending;
|
|
10113
10259
|
};
|
|
10114
|
-
const writeOf = async (
|
|
10260
|
+
const writeOf = async (path36, body, describeFailure) => {
|
|
10115
10261
|
let answer;
|
|
10116
10262
|
try {
|
|
10117
|
-
answer = await transport.request({ method: "POST", path:
|
|
10263
|
+
answer = await transport.request({ method: "POST", path: path36, headers: { ...headers, "content-type": "application/json" }, body });
|
|
10118
10264
|
} catch (error) {
|
|
10119
10265
|
return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
|
|
10120
10266
|
}
|
|
@@ -10145,10 +10291,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
10145
10291
|
endSession: async (sessionId, reason) => await writeOf(`${CONTROL_PATH_PREFIX}/end-session`, JSON.stringify({ session: sessionId, ...reason === void 0 ? {} : { reason } }), (status, message) => `ending ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10146
10292
|
getUsage: async (sessionId, skipBehaviors) => await writeOf(`${CONTROL_PATH_PREFIX}/get-usage`, JSON.stringify({ session: sessionId, ...skipBehaviors === void 0 ? {} : { skipBehaviors } }), (status, message) => `requesting the usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10147
10293
|
getContextUsage: async (sessionId, detail) => await writeOf(`${CONTROL_PATH_PREFIX}/get-context-usage`, JSON.stringify({ session: sessionId, ...detail === void 0 ? {} : { detail } }), (status, message) => `requesting the context usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10148
|
-
readFile: async (sessionId,
|
|
10294
|
+
readFile: async (sessionId, path36, options) => await writeOf(
|
|
10149
10295
|
`${CONTROL_PATH_PREFIX}/read-file`,
|
|
10150
|
-
JSON.stringify({ session: sessionId, path:
|
|
10151
|
-
(status, message) => `reading ${
|
|
10296
|
+
JSON.stringify({ session: sessionId, path: path36, ...options?.maxBytes === void 0 ? {} : { maxBytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } }),
|
|
10297
|
+
(status, message) => `reading ${path36} from ${sessionId} failed (HTTP ${String(status)}): ${message}`
|
|
10152
10298
|
),
|
|
10153
10299
|
fileSuggestions: async (sessionId, query) => await writeOf(`${CONTROL_PATH_PREFIX}/file-suggestions`, JSON.stringify({ session: sessionId, query }), (status, message) => `requesting file suggestions from ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10154
10300
|
keepAlive: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/keep-alive`, JSON.stringify({ session: sessionId }), (status, message) => `keeping ${sessionId} alive failed (HTTP ${String(status)}): ${message}`),
|
|
@@ -10307,12 +10453,12 @@ function tlsFacts(options) {
|
|
|
10307
10453
|
}
|
|
10308
10454
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
10309
10455
|
const agent = new ExemptTlsAgent();
|
|
10310
|
-
const post = async (
|
|
10456
|
+
const post = async (path36, headers, body) => await new Promise((resolve, reject) => {
|
|
10311
10457
|
const options = {
|
|
10312
10458
|
host: target.host,
|
|
10313
10459
|
port: target.port,
|
|
10314
10460
|
method: "POST",
|
|
10315
|
-
path:
|
|
10461
|
+
path: path36,
|
|
10316
10462
|
// The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
|
|
10317
10463
|
headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
|
|
10318
10464
|
agent
|
|
@@ -10377,12 +10523,12 @@ function lateRcStreamDial(resolve) {
|
|
|
10377
10523
|
}
|
|
10378
10524
|
function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
10379
10525
|
const agent = new ExemptTlsAgent();
|
|
10380
|
-
const request4 = async (method,
|
|
10526
|
+
const request4 = async (method, path36, headers, body, signal) => await new Promise((resolve, reject) => {
|
|
10381
10527
|
const options = {
|
|
10382
10528
|
host: target.host,
|
|
10383
10529
|
port: target.port,
|
|
10384
10530
|
method,
|
|
10385
|
-
path:
|
|
10531
|
+
path: path36,
|
|
10386
10532
|
// The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
|
|
10387
10533
|
headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
|
|
10388
10534
|
agent,
|
|
@@ -10424,9 +10570,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
|
|
|
10424
10570
|
return { status, body: await readAll(response) };
|
|
10425
10571
|
},
|
|
10426
10572
|
openStream: async (sessionId, headers, resume, signal) => {
|
|
10427
|
-
const
|
|
10573
|
+
const path36 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
|
|
10428
10574
|
const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
|
|
10429
|
-
const { status, response } = await request4("GET",
|
|
10575
|
+
const { status, response } = await request4("GET", path36, streamHeaders, void 0, signal);
|
|
10430
10576
|
if (!isSuccessful2(status)) {
|
|
10431
10577
|
await readAll(response);
|
|
10432
10578
|
return { status, chunks: NO_CHUNKS };
|
|
@@ -11025,11 +11171,15 @@ function doorApiNodeHandlerOf(router, expectedToken) {
|
|
|
11025
11171
|
}
|
|
11026
11172
|
return { matched: true };
|
|
11027
11173
|
}
|
|
11028
|
-
const rest = await restHandler.handle(request4, response, { context: { headers: request4.headers
|
|
11174
|
+
const rest = await restHandler.handle(request4, response, { context: { headers: request4.headers, afterResponse: (action) => {
|
|
11175
|
+
response.once("finish", action);
|
|
11176
|
+
} }, prefix: RC_ORPC_PATH_PREFIX });
|
|
11029
11177
|
if (rest.matched) {
|
|
11030
11178
|
return rest;
|
|
11031
11179
|
}
|
|
11032
|
-
return await rpcHandler.handle(request4, response, { context: { headers: request4.headers
|
|
11180
|
+
return await rpcHandler.handle(request4, response, { context: { headers: request4.headers, afterResponse: (action) => {
|
|
11181
|
+
response.once("finish", action);
|
|
11182
|
+
} }, prefix: RC_ORPC_PATH_PREFIX });
|
|
11033
11183
|
}
|
|
11034
11184
|
};
|
|
11035
11185
|
}
|
|
@@ -11066,8 +11216,8 @@ init_cliError();
|
|
|
11066
11216
|
init_realPorts();
|
|
11067
11217
|
|
|
11068
11218
|
// src/frontdoor/controlApi.ts
|
|
11069
|
-
var
|
|
11070
|
-
var
|
|
11219
|
+
var import_client5 = require("@orpc/client");
|
|
11220
|
+
var import_openapi6 = require("@orpc/openapi");
|
|
11071
11221
|
|
|
11072
11222
|
// src/checkReport.ts
|
|
11073
11223
|
var import_node_os5 = __toESM(require("node:os"), 1);
|
|
@@ -11294,19 +11444,19 @@ function writePools(paths, pools) {
|
|
|
11294
11444
|
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
|
|
11295
11445
|
}
|
|
11296
11446
|
function poolCycleOf(pools, name) {
|
|
11297
|
-
const walk = (current,
|
|
11447
|
+
const walk = (current, path36) => {
|
|
11298
11448
|
for (const entry of pools[current]?.identities ?? []) {
|
|
11299
11449
|
const nested = poolNameOf(poolMemberIdentity(entry));
|
|
11300
11450
|
if (nested === void 0) {
|
|
11301
11451
|
continue;
|
|
11302
11452
|
}
|
|
11303
11453
|
if (nested === name) {
|
|
11304
|
-
return [...
|
|
11454
|
+
return [...path36, nested];
|
|
11305
11455
|
}
|
|
11306
|
-
if (
|
|
11456
|
+
if (path36.includes(nested)) {
|
|
11307
11457
|
continue;
|
|
11308
11458
|
}
|
|
11309
|
-
const found = walk(nested, [...
|
|
11459
|
+
const found = walk(nested, [...path36, nested]);
|
|
11310
11460
|
if (found !== void 0) {
|
|
11311
11461
|
return found;
|
|
11312
11462
|
}
|
|
@@ -12877,10 +13027,48 @@ var DoctorRunOutputSchema = import_zod19.z.strictObject({
|
|
|
12877
13027
|
ok: import_zod19.z.boolean(),
|
|
12878
13028
|
findings: import_zod19.z.readonly(import_zod19.z.array(DoctorFindingSchema))
|
|
12879
13029
|
});
|
|
13030
|
+
var FrontDoorRestartOutputSchema = import_zod19.z.strictObject({
|
|
13031
|
+
action: import_zod19.z.literal("restarting"),
|
|
13032
|
+
previousPid: import_zod19.z.int().positive()
|
|
13033
|
+
});
|
|
13034
|
+
var UpdateCheckOutputSchema = import_zod19.z.strictObject({
|
|
13035
|
+
current: import_zod19.z.string(),
|
|
13036
|
+
latest: import_zod19.z.string(),
|
|
13037
|
+
action: import_zod19.z.enum(["current", "available", "updated"])
|
|
13038
|
+
});
|
|
13039
|
+
var CodexSignInSchema = import_zod19.z.discriminatedUnion("state", [
|
|
13040
|
+
import_zod19.z.strictObject({ state: import_zod19.z.literal("none") }),
|
|
13041
|
+
import_zod19.z.strictObject({ state: import_zod19.z.literal("signed-in"), email: import_zod19.z.string().optional(), planScope: import_zod19.z.boolean(), accessTokenExpiresAt: import_zod19.z.number() }),
|
|
13042
|
+
import_zod19.z.strictObject({ state: import_zod19.z.literal("unreadable"), message: import_zod19.z.string() })
|
|
13043
|
+
]);
|
|
13044
|
+
var CodexStatusOutputSchema = import_zod19.z.strictObject({
|
|
13045
|
+
signIn: CodexSignInSchema,
|
|
13046
|
+
codexProviders: import_zod19.z.readonly(import_zod19.z.array(import_zod19.z.string()))
|
|
13047
|
+
});
|
|
13048
|
+
var CodexLogoutOutputSchema = import_zod19.z.strictObject({
|
|
13049
|
+
hadGrant: import_zod19.z.boolean(),
|
|
13050
|
+
revoked: import_zod19.z.boolean()
|
|
13051
|
+
});
|
|
13052
|
+
|
|
13053
|
+
// src/frontdoor/codexApi.ts
|
|
13054
|
+
var import_openapi2 = require("@orpc/openapi");
|
|
13055
|
+
var CODEX_API_TAG = "codex";
|
|
13056
|
+
function createCodexApiRouter(deps) {
|
|
13057
|
+
const authed = doorApiAuth(deps.expectedToken);
|
|
13058
|
+
return {
|
|
13059
|
+
codex: {
|
|
13060
|
+
status: authed.meta((0, import_openapi2.openapi)({ method: "GET", path: "/rest/codex/status", summary: "Read the Codex sign-in and the codex providers", tags: [CODEX_API_TAG] })).output(CodexStatusOutputSchema).handler(() => {
|
|
13061
|
+
const status = deps.codexStatus();
|
|
13062
|
+
return { signIn: status.signIn, codexProviders: status.codexProviders };
|
|
13063
|
+
}),
|
|
13064
|
+
logout: authed.meta((0, import_openapi2.openapi)({ method: "POST", path: "/rest/codex/logout", summary: "Revoke the Sign in with ChatGPT login and remove it", tags: [CODEX_API_TAG] })).output(CodexLogoutOutputSchema).handler(async () => await deps.codexLogout())
|
|
13065
|
+
}
|
|
13066
|
+
};
|
|
13067
|
+
}
|
|
12880
13068
|
|
|
12881
13069
|
// src/frontdoor/eventsApi.ts
|
|
12882
13070
|
var import_client2 = require("@orpc/client");
|
|
12883
|
-
var
|
|
13071
|
+
var import_openapi3 = require("@orpc/openapi");
|
|
12884
13072
|
var import_server3 = require("@orpc/server");
|
|
12885
13073
|
|
|
12886
13074
|
// src/frontdoor/eventSchemas.ts
|
|
@@ -12927,7 +13115,7 @@ function createEventsApiRouter(deps) {
|
|
|
12927
13115
|
const authed = doorApiAuth(deps.expectedToken);
|
|
12928
13116
|
return {
|
|
12929
13117
|
events: {
|
|
12930
|
-
subscribe: authed.meta((0,
|
|
13118
|
+
subscribe: authed.meta((0, import_openapi3.openapi)({ method: "GET", path: "/rest/events", summary: "Stream the door's every event source (SSE)", tags: [EVENTS_API_TAG] })).input(DoorEventSourceQuerySchema).output((0, import_server3.eventIterator)(DoorEventSchema)).handler(async function* ({ input, signal }) {
|
|
12931
13119
|
if (input.sources !== void 0) {
|
|
12932
13120
|
const live = deps.events.sources();
|
|
12933
13121
|
const unknown = input.sources.filter((source) => !live.includes(source));
|
|
@@ -12959,9 +13147,120 @@ function createEventsApiRouter(deps) {
|
|
|
12959
13147
|
};
|
|
12960
13148
|
}
|
|
12961
13149
|
|
|
13150
|
+
// src/frontdoor/lifecycleApi.ts
|
|
13151
|
+
var import_client3 = require("@orpc/client");
|
|
13152
|
+
var import_openapi4 = require("@orpc/openapi");
|
|
13153
|
+
init_update();
|
|
13154
|
+
var FRONTDOOR_API_TAG = "frontdoor";
|
|
13155
|
+
var UPDATE_API_TAG = "update";
|
|
13156
|
+
function createLifecycleApiRouter(deps) {
|
|
13157
|
+
const authed = doorApiAuth(deps.expectedToken);
|
|
13158
|
+
return {
|
|
13159
|
+
frontdoor: {
|
|
13160
|
+
restart: authed.meta((0, import_openapi4.openapi)({ method: "POST", path: "/rest/frontdoor/restart", summary: "Replace the serving front door in place", description: "Answers with the pid of the door being replaced, then replaces it. The replacement is a new generation with its own control token: the caller reopens its client from the state root once the door's supervisor pid differs from the one returned.", tags: [FRONTDOOR_API_TAG] })).output(FrontDoorRestartOutputSchema).handler(({ context }) => {
|
|
13161
|
+
context.afterResponse(deps.restartDoor);
|
|
13162
|
+
return { action: "restarting", previousPid: deps.doorPid };
|
|
13163
|
+
})
|
|
13164
|
+
},
|
|
13165
|
+
update: {
|
|
13166
|
+
check: authed.meta((0, import_openapi4.openapi)({ method: "GET", path: "/rest/update/check", summary: "Check whether a newer release exists", tags: [UPDATE_API_TAG] })).output(UpdateCheckOutputSchema).handler(async () => {
|
|
13167
|
+
try {
|
|
13168
|
+
return await deps.checkForUpdate();
|
|
13169
|
+
} catch (error) {
|
|
13170
|
+
if (error instanceof UpdateChannelError) {
|
|
13171
|
+
throw new import_client3.ORPCError("PRECONDITION_FAILED", { message: error.message });
|
|
13172
|
+
}
|
|
13173
|
+
if (error instanceof UpdateConflictError) {
|
|
13174
|
+
throw new import_client3.ORPCError("CONFLICT", { message: error.message });
|
|
13175
|
+
}
|
|
13176
|
+
if (error instanceof UpdateDownloadError) {
|
|
13177
|
+
throw new import_client3.ORPCError("BAD_GATEWAY", { message: error.message });
|
|
13178
|
+
}
|
|
13179
|
+
throw error;
|
|
13180
|
+
}
|
|
13181
|
+
})
|
|
13182
|
+
}
|
|
13183
|
+
};
|
|
13184
|
+
}
|
|
13185
|
+
|
|
13186
|
+
// src/frontdoor/launchApi.ts
|
|
13187
|
+
var import_client4 = require("@orpc/client");
|
|
13188
|
+
var import_openapi5 = require("@orpc/openapi");
|
|
13189
|
+
init_cliError();
|
|
13190
|
+
|
|
13191
|
+
// src/frontdoor/launchSchemas.ts
|
|
13192
|
+
var import_node_path30 = __toESM(require("node:path"), 1);
|
|
13193
|
+
var import_zod21 = require("zod");
|
|
13194
|
+
init_claudeVersion();
|
|
13195
|
+
init_identity();
|
|
13196
|
+
var LaunchResolveInputSchema = import_zod21.z.strictObject({
|
|
13197
|
+
path: import_zod21.z.string().min(1),
|
|
13198
|
+
/** `@name`, launch flags, then the arguments for `claude`; empty for a bare launch. */
|
|
13199
|
+
argv: import_zod21.z.readonly(import_zod21.z.array(import_zod21.z.string())).optional(),
|
|
13200
|
+
/** The launch's inherited environment. Absent means an empty one: the door's own environment is never a substitute for the caller's, so a caller that wants `AGENT_SHIM_*` switches or a `CLAUDE_CONFIG_DIR` considered names them here. Values are read, never reported. */
|
|
13201
|
+
env: import_zod21.z.record(import_zod21.z.string(), import_zod21.z.string()).optional()
|
|
13202
|
+
}).refine((input) => import_node_path30.default.isAbsolute(input.path), { message: "path must be absolute: the door cannot resolve a relative path against the caller's working directory" });
|
|
13203
|
+
var LaunchPoolDecisionSchema = import_zod21.z.strictObject({
|
|
13204
|
+
name: import_zod21.z.string(),
|
|
13205
|
+
reasons: import_zod21.z.readonly(import_zod21.z.array(import_zod21.z.string())),
|
|
13206
|
+
movedOff: import_zod21.z.strictObject({ identity: import_zod21.z.string(), reason: import_zod21.z.string() }).optional()
|
|
13207
|
+
});
|
|
13208
|
+
var LaunchDecisionSchema = import_zod21.z.strictObject({
|
|
13209
|
+
identity: import_zod21.z.string().optional(),
|
|
13210
|
+
identitySource: import_zod21.z.enum(IDENTITY_DECISION_SOURCES),
|
|
13211
|
+
pool: LaunchPoolDecisionSchema.optional(),
|
|
13212
|
+
configDirEscapeHatch: import_zod21.z.boolean(),
|
|
13213
|
+
configDir: import_zod21.z.string().optional(),
|
|
13214
|
+
configProfile: import_zod21.z.string().optional(),
|
|
13215
|
+
configProfileSource: import_zod21.z.enum(CONFIG_PROFILE_DECISION_SOURCES),
|
|
13216
|
+
provider: import_zod21.z.string().optional()
|
|
13217
|
+
});
|
|
13218
|
+
var LaunchFlagsSchema = import_zod21.z.strictObject({
|
|
13219
|
+
skipPermissions: import_zod21.z.boolean(),
|
|
13220
|
+
remoteControl: import_zod21.z.boolean(),
|
|
13221
|
+
headroom: import_zod21.z.boolean(),
|
|
13222
|
+
trackUsage: import_zod21.z.boolean()
|
|
13223
|
+
});
|
|
13224
|
+
var LaunchResolveOutputSchema = import_zod21.z.strictObject({
|
|
13225
|
+
decision: LaunchDecisionSchema,
|
|
13226
|
+
flags: LaunchFlagsSchema,
|
|
13227
|
+
claudeVersion: import_zod21.z.strictObject({ version: import_zod21.z.string(), source: import_zod21.z.enum(CLAUDE_VERSION_SOURCES) }).optional(),
|
|
13228
|
+
/** The real `claude` binary the launch would spawn, on the door's host. */
|
|
13229
|
+
bin: import_zod21.z.string(),
|
|
13230
|
+
/** The arguments the launch would pass it: the tool's own flags, then `CLAUDE_EXTRA_FLAGS`, then the caller's own. */
|
|
13231
|
+
args: import_zod21.z.readonly(import_zod21.z.array(import_zod21.z.string())),
|
|
13232
|
+
/** The credential the launch would authenticate with, by target and source kinds. Absent when none applies. */
|
|
13233
|
+
credential: import_zod21.z.strictObject({ subject: import_zod21.z.enum(["provider", "identity"]), name: import_zod21.z.string(), summary: CredentialSummarySchema }).optional(),
|
|
13234
|
+
routing: import_zod21.z.strictObject({ frontDoor: import_zod21.z.boolean(), headroom: import_zod21.z.boolean() }),
|
|
13235
|
+
/** The names of the environment variables the launch would set or unset, sorted. Values are not reported. */
|
|
13236
|
+
environment: import_zod21.z.readonly(import_zod21.z.array(import_zod21.z.string())),
|
|
13237
|
+
warnings: import_zod21.z.readonly(import_zod21.z.array(import_zod21.z.string()))
|
|
13238
|
+
});
|
|
13239
|
+
|
|
13240
|
+
// src/frontdoor/launchApi.ts
|
|
13241
|
+
var LAUNCH_API_TAG = "launch";
|
|
13242
|
+
function createLaunchApiRouter(deps) {
|
|
13243
|
+
const authed = doorApiAuth(deps.expectedToken);
|
|
13244
|
+
return {
|
|
13245
|
+
launch: {
|
|
13246
|
+
resolve: authed.meta((0, import_openapi5.openapi)({ method: "POST", path: "/rest/launch/resolve", summary: "Resolve what a launch from one directory would do, without performing it", tags: [LAUNCH_API_TAG] })).input(LaunchResolveInputSchema).output(LaunchResolveOutputSchema).handler(({ input }) => {
|
|
13247
|
+
try {
|
|
13248
|
+
const { resolution, warnings } = deps.resolveLaunch({ path: input.path, argv: input.argv ?? [], env: input.env ?? {} });
|
|
13249
|
+
return { ...resolution, warnings };
|
|
13250
|
+
} catch (error) {
|
|
13251
|
+
if (error instanceof CliError) {
|
|
13252
|
+
throw new import_client4.ORPCError("BAD_REQUEST", { message: error.message });
|
|
13253
|
+
}
|
|
13254
|
+
throw error;
|
|
13255
|
+
}
|
|
13256
|
+
})
|
|
13257
|
+
}
|
|
13258
|
+
};
|
|
13259
|
+
}
|
|
13260
|
+
|
|
12962
13261
|
// src/frontdoor/controlApi.ts
|
|
12963
13262
|
var USAGE_API_TAG = "usage";
|
|
12964
|
-
var
|
|
13263
|
+
var FRONTDOOR_API_TAG2 = "frontdoor";
|
|
12965
13264
|
var CHECK_API_TAG = "check";
|
|
12966
13265
|
var DOCTOR_API_TAG = "doctor";
|
|
12967
13266
|
var POOL_API_TAG = "pool";
|
|
@@ -12969,11 +13268,11 @@ function createControlApiRouter(deps) {
|
|
|
12969
13268
|
const authed = doorApiAuth(deps.expectedToken);
|
|
12970
13269
|
return {
|
|
12971
13270
|
usage: {
|
|
12972
|
-
list: authed.meta((0,
|
|
12973
|
-
effectiveWindow: authed.meta((0,
|
|
13271
|
+
list: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/usage/snapshots", summary: "List every identity's usage snapshot", tags: [USAGE_API_TAG] })).output(UsageListOutputSchema).handler(() => ({ snapshots: deps.usageSnapshots() })),
|
|
13272
|
+
effectiveWindow: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/usage/windows", summary: "Read one identity's effective quota windows", tags: [USAGE_API_TAG] })).input(UsageWindowsInputSchema).output(UsageWindowsOutputSchema).handler(({ input }) => {
|
|
12974
13273
|
const snapshot = deps.usageSnapshotOf(input.identity);
|
|
12975
13274
|
if (snapshot === void 0) {
|
|
12976
|
-
throw new
|
|
13275
|
+
throw new import_client5.ORPCError("NOT_FOUND", { message: `identity ${input.identity} has no usage snapshot yet, so no quota window has been observed for it` });
|
|
12977
13276
|
}
|
|
12978
13277
|
const provider = input.provider ?? ANTHROPIC_PROVIDER;
|
|
12979
13278
|
const rateLimit = snapshot.providers[provider]?.rateLimit;
|
|
@@ -12987,34 +13286,34 @@ function createControlApiRouter(deps) {
|
|
|
12987
13286
|
...unified?.sevenDay === void 0 ? {} : { sevenDay: effectiveWindow(unified.sevenDay, now) }
|
|
12988
13287
|
};
|
|
12989
13288
|
}),
|
|
12990
|
-
live: authed.meta((0,
|
|
13289
|
+
live: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/usage/live", summary: "Read the live rate-limit observations the event backbone files", tags: [USAGE_API_TAG] })).input(RcSessionQuerySchema).output(UsageLiveOutputSchema).handler(({ input }) => {
|
|
12991
13290
|
const sessions = deps.liveRateLimits(input.session);
|
|
12992
13291
|
if (input.session !== void 0 && sessions.length === 0) {
|
|
12993
13292
|
if (deps.list().some((session) => session.id === input.session)) {
|
|
12994
|
-
throw new
|
|
13293
|
+
throw new import_client5.ORPCError("NOT_FOUND", { message: `session ${input.session} has filed no rate_limit_event on its stream yet: the worker emits one only once a turn has completed, so retry after this session's next turn` });
|
|
12995
13294
|
}
|
|
12996
|
-
throw new
|
|
13295
|
+
throw new import_client5.ORPCError("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
|
|
12997
13296
|
}
|
|
12998
13297
|
return { latest: deps.latestRateLimit(), sessions };
|
|
12999
13298
|
})
|
|
13000
13299
|
},
|
|
13001
13300
|
frontdoor: {
|
|
13002
|
-
status: authed.meta((0,
|
|
13003
|
-
sessions: authed.meta((0,
|
|
13301
|
+
status: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/frontdoor/status", summary: "Read the front door's status", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorStatusOutputSchema).handler(() => deps.frontDoorStatus()),
|
|
13302
|
+
sessions: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/frontdoor/sessions", summary: "Read the front door's session registry", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorSessionsOutputSchema).handler(() => ({ sessions: deps.frontDoorStatus().sessions }))
|
|
13004
13303
|
},
|
|
13005
13304
|
check: {
|
|
13006
13305
|
// The report's own JSON shape is the contract (the same one `check --json` prints and `checkReportSchema.ts` defines), so the procedure returns exactly that conversion.
|
|
13007
|
-
run: authed.meta((0,
|
|
13306
|
+
run: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/check", summary: "Run the check report for one directory", tags: [CHECK_API_TAG] })).input(CheckRunInputSchema).output(CheckReportJsonSchema).handler(({ input }) => checkReportToJson(deps.checkReport(input.path, input.identity)))
|
|
13008
13307
|
},
|
|
13009
13308
|
doctor: {
|
|
13010
|
-
run: authed.meta((0,
|
|
13309
|
+
run: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/doctor", summary: "Run the doctor report", tags: [DOCTOR_API_TAG] })).output(DoctorRunOutputSchema).handler(() => deps.doctorReport())
|
|
13011
13310
|
},
|
|
13012
13311
|
pool: {
|
|
13013
|
-
pick: authed.meta((0,
|
|
13312
|
+
pick: authed.meta((0, import_openapi6.openapi)({ method: "GET", path: "/rest/pool/pick", summary: "Rank one pool exactly as a launch from a directory would right now", tags: [POOL_API_TAG] })).input(PoolPickInputSchema).output(PoolPickReportSchema).handler(({ input }) => {
|
|
13014
13313
|
const report = deps.poolPick(input.pool, input.path);
|
|
13015
13314
|
if (report === void 0) {
|
|
13016
13315
|
const live = deps.poolNames();
|
|
13017
|
-
throw new
|
|
13316
|
+
throw new import_client5.ORPCError("NOT_FOUND", {
|
|
13018
13317
|
message: live.length === 0 ? `no pools are configured, so none is named ${input.pool}` : `no pool is named ${input.pool}; the live pools are ${live.map((name) => `"${name}"`).join(", ")}`
|
|
13019
13318
|
});
|
|
13020
13319
|
}
|
|
@@ -13024,13 +13323,15 @@ function createControlApiRouter(deps) {
|
|
|
13024
13323
|
};
|
|
13025
13324
|
}
|
|
13026
13325
|
function createDoorApiRouter(deps) {
|
|
13027
|
-
|
|
13326
|
+
const control = createControlApiRouter(deps);
|
|
13327
|
+
const lifecycle = createLifecycleApiRouter(deps);
|
|
13328
|
+
return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
|
|
13028
13329
|
}
|
|
13029
13330
|
function createDoorApiNodeHandler(deps) {
|
|
13030
13331
|
return doorApiNodeHandlerOf(createDoorApiRouter(deps), deps.expectedToken);
|
|
13031
13332
|
}
|
|
13032
13333
|
function frontDoorApiClient(port, ca, token) {
|
|
13033
|
-
return (0,
|
|
13334
|
+
return (0, import_client5.createORPCClient)(frontDoorApiLink(port, ca, token));
|
|
13034
13335
|
}
|
|
13035
13336
|
|
|
13036
13337
|
// src/frontdoor/doorClient.ts
|
|
@@ -14984,7 +15285,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
14984
15285
|
}
|
|
14985
15286
|
|
|
14986
15287
|
// src/frontdoor/rcSelfHostMint.ts
|
|
14987
|
-
var
|
|
15288
|
+
var import_node_path31 = __toESM(require("node:path"), 1);
|
|
14988
15289
|
init_account();
|
|
14989
15290
|
var CREDENTIALS_FILE = ".credentials.json";
|
|
14990
15291
|
var CLAUDE_JSON2 = ".claude.json";
|
|
@@ -15009,7 +15310,7 @@ function readJsonObject(fs12, file) {
|
|
|
15009
15310
|
return isRecord11(parsed) ? parsed : void 0;
|
|
15010
15311
|
}
|
|
15011
15312
|
function readRcSelfHostRecord(fs12, frontdoorDir) {
|
|
15012
|
-
const parsed = readJsonObject(fs12,
|
|
15313
|
+
const parsed = readJsonObject(fs12, import_node_path31.default.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
|
|
15013
15314
|
if (parsed === void 0) {
|
|
15014
15315
|
return void 0;
|
|
15015
15316
|
}
|
|
@@ -15023,11 +15324,11 @@ function mintRcSelfHostCredential(deps) {
|
|
|
15023
15324
|
if (!isIdentityName(deps.identity)) {
|
|
15024
15325
|
throw new Error(`"${deps.identity}" is not a valid identity name.`);
|
|
15025
15326
|
}
|
|
15026
|
-
const identityDir =
|
|
15027
|
-
const credentialsFile =
|
|
15028
|
-
const claudeJsonFile =
|
|
15029
|
-
const recordDir =
|
|
15030
|
-
const recordFile =
|
|
15327
|
+
const identityDir = import_node_path31.default.join(deps.identitiesDir, deps.identity);
|
|
15328
|
+
const credentialsFile = import_node_path31.default.join(identityDir, CREDENTIALS_FILE);
|
|
15329
|
+
const claudeJsonFile = import_node_path31.default.join(identityDir, CLAUDE_JSON2);
|
|
15330
|
+
const recordDir = import_node_path31.default.join(deps.frontdoorDir, RC_SELF_HOST_RECORD_DIR);
|
|
15331
|
+
const recordFile = import_node_path31.default.join(recordDir, RC_SELF_HOST_RECORD_FILE);
|
|
15031
15332
|
const previousRecord = readRcSelfHostRecord(deps.fs, deps.frontdoorDir);
|
|
15032
15333
|
const existingCredentials = readJsonObject(deps.fs, credentialsFile);
|
|
15033
15334
|
const existingOauth = isRecord11(existingCredentials?.claudeAiOauth) ? existingCredentials.claudeAiOauth : void 0;
|
|
@@ -15043,7 +15344,7 @@ function mintRcSelfHostCredential(deps) {
|
|
|
15043
15344
|
const organizationUuid = deps.newUuid();
|
|
15044
15345
|
const accountUuid = deps.newUuid();
|
|
15045
15346
|
const mintedAt = new Date(deps.now()).toISOString();
|
|
15046
|
-
deps.fs.mkdirPrivate(
|
|
15347
|
+
deps.fs.mkdirPrivate(import_node_path31.default.dirname(credentialsFile));
|
|
15047
15348
|
deps.fs.writeFilePrivate(credentialsFile, `${JSON.stringify({ ...existingCredentials, claudeAiOauth: { accessToken, refreshToken, expiresAt: null, scopes: [...RC_SELF_HOST_SCOPE_LIST], subscriptionType: SELF_HOST_SUBSCRIPTION_TYPE, rateLimitTier: null } }, null, 2)}
|
|
15048
15349
|
`);
|
|
15049
15350
|
const claudeJson = readJsonObject(deps.fs, claudeJsonFile) ?? {};
|
|
@@ -15298,6 +15599,9 @@ init_ownCli();
|
|
|
15298
15599
|
CheckReportJsonSchema,
|
|
15299
15600
|
CheckRunInputSchema,
|
|
15300
15601
|
CliError,
|
|
15602
|
+
CodexLogoutOutputSchema,
|
|
15603
|
+
CodexSignInSchema,
|
|
15604
|
+
CodexStatusOutputSchema,
|
|
15301
15605
|
ConfigProfileSchema,
|
|
15302
15606
|
CredentialCacheSchema,
|
|
15303
15607
|
CredentialSchema,
|
|
@@ -15322,6 +15626,7 @@ init_ownCli();
|
|
|
15322
15626
|
FARM_MANIFEST_FILENAME,
|
|
15323
15627
|
FrontDoorControlMaterialError,
|
|
15324
15628
|
FrontDoorNotServingError,
|
|
15629
|
+
FrontDoorRestartOutputSchema,
|
|
15325
15630
|
FrontDoorSessionStatusSchema,
|
|
15326
15631
|
FrontDoorSessionsOutputSchema,
|
|
15327
15632
|
FrontDoorStartError,
|
|
@@ -15339,6 +15644,8 @@ init_ownCli();
|
|
|
15339
15644
|
LAUNCH_EVENT_SOURCE,
|
|
15340
15645
|
LaunchLifecycleEventSchema,
|
|
15341
15646
|
LaunchRefusedError,
|
|
15647
|
+
LaunchResolveInputSchema,
|
|
15648
|
+
LaunchResolveOutputSchema,
|
|
15342
15649
|
LegacyProviderFileError,
|
|
15343
15650
|
OWN_CLI_FILE_NAME,
|
|
15344
15651
|
PROMPT_CACHE_TTL_MS,
|
|
@@ -15385,6 +15692,7 @@ init_ownCli();
|
|
|
15385
15692
|
RcStreamEnvelopeSchema,
|
|
15386
15693
|
RcStreamEventSchema,
|
|
15387
15694
|
USAGE_EVENT_SOURCE,
|
|
15695
|
+
UpdateCheckOutputSchema,
|
|
15388
15696
|
UsageError,
|
|
15389
15697
|
UsageListOutputSchema,
|
|
15390
15698
|
UsageLiveOutputSchema,
|
|
@@ -15427,14 +15735,17 @@ init_ownCli();
|
|
|
15427
15735
|
collectDoctorReport,
|
|
15428
15736
|
collectFrontDoorStatus,
|
|
15429
15737
|
collectPoolPick,
|
|
15738
|
+
createCodexApiRouter,
|
|
15430
15739
|
createControlApiRouter,
|
|
15431
15740
|
createDoorApiNodeHandler,
|
|
15432
15741
|
createDoorApiRouter,
|
|
15433
15742
|
createDoorEventHub,
|
|
15434
15743
|
createDoorHealthPublisher,
|
|
15435
15744
|
createEventsApiRouter,
|
|
15745
|
+
createLaunchApiRouter,
|
|
15436
15746
|
createLaunchEventPublisher,
|
|
15437
15747
|
createLeafCache,
|
|
15748
|
+
createLifecycleApiRouter,
|
|
15438
15749
|
createProfile,
|
|
15439
15750
|
createQuotaExpiringPublisher,
|
|
15440
15751
|
createRcApiNodeHandler,
|
|
@@ -15542,7 +15853,9 @@ init_ownCli();
|
|
|
15542
15853
|
requirePool,
|
|
15543
15854
|
resolveAgentShimHome,
|
|
15544
15855
|
resolveClaudeHome,
|
|
15856
|
+
resolveClaudeLaunch,
|
|
15545
15857
|
resolveDecisions,
|
|
15858
|
+
resolveLaunch,
|
|
15546
15859
|
resolveLaunchSelection,
|
|
15547
15860
|
resolveLayoutPaths,
|
|
15548
15861
|
resolveSupervisorConfig,
|