agent-trellis 0.14.1 → 0.15.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/dist/adapters/claude-code.js +4 -3
- package/dist/adapters/codex.js +4 -3
- package/dist/adapters/kimi-code.js +4 -3
- package/dist/adapters/kiro.js +5 -4
- package/dist/adapters/pi.js +4 -3
- package/dist/adapters/zcode.d.ts +12 -1
- package/dist/adapters/zcode.js +7 -6
- package/dist/cli.js +38 -5
- package/dist/commands/doctor.d.ts +9 -1
- package/dist/commands/doctor.js +43 -6
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.js +24 -0
- package/dist/commands/mcp.d.ts +44 -1
- package/dist/commands/mcp.js +145 -33
- package/dist/commands/migrate.d.ts +12 -0
- package/dist/commands/migrate.js +8 -4
- package/dist/commands/migrateWorkspace.d.ts +40 -0
- package/dist/commands/migrateWorkspace.js +197 -0
- package/dist/commands/rollback.js +65 -35
- package/dist/commands/skill.d.ts +14 -0
- package/dist/commands/skill.js +71 -0
- package/dist/commands/sync.d.ts +16 -1
- package/dist/commands/sync.js +48 -15
- package/dist/core/adapter.d.ts +14 -0
- package/dist/core/canonical.d.ts +20 -34
- package/dist/core/canonical.js +18 -92
- package/dist/core/mcpServerDef.d.ts +39 -0
- package/dist/core/mcpServerDef.js +93 -0
- package/dist/core/types.d.ts +39 -4
- package/dist/lib/mcpMigrateRead.d.ts +25 -0
- package/dist/lib/mcpMigrateRead.js +9 -2
- package/dist/lib/skillProvider.js +18 -5
- package/dist/lib/workspace.d.ts +39 -0
- package/dist/lib/workspace.js +158 -0
- package/dist/lib/workspaceConfig.d.ts +45 -0
- package/dist/lib/workspaceConfig.js +98 -0
- package/dist/lib/workspaceDoctor.d.ts +44 -0
- package/dist/lib/workspaceDoctor.js +94 -0
- package/dist/lib/workspaceFiles.d.ts +38 -0
- package/dist/lib/workspaceFiles.js +264 -0
- package/dist/lib/workspaceMcp.d.ts +57 -0
- package/dist/lib/workspaceMcp.js +277 -0
- package/dist/lib/workspaceMerge.d.ts +37 -0
- package/dist/lib/workspaceMerge.js +98 -0
- package/dist/lib/workspaceMigrate.d.ts +118 -0
- package/dist/lib/workspaceMigrate.js +423 -0
- package/dist/pi-bridge/bundle.js +258 -96
- package/docs/architecture.md +111 -49
- package/docs/getting-started.md +86 -14
- package/docs/mcp-oauth-matrix.md +12 -1
- package/docs/overview.zh-CN.md +17 -0
- package/docs/research.md +28 -6
- package/docs/roadmap.md +17 -5
- package/package.json +1 -1
- package/docs/implementation-plan.md +0 -341
package/dist/pi-bridge/bundle.js
CHANGED
|
@@ -7463,12 +7463,12 @@ var require_isexe = __commonJS({
|
|
|
7463
7463
|
if (typeof Promise !== "function") {
|
|
7464
7464
|
throw new TypeError("callback not provided");
|
|
7465
7465
|
}
|
|
7466
|
-
return new Promise(function(
|
|
7466
|
+
return new Promise(function(resolve2, reject) {
|
|
7467
7467
|
isexe(path, options || {}, function(er, is) {
|
|
7468
7468
|
if (er) {
|
|
7469
7469
|
reject(er);
|
|
7470
7470
|
} else {
|
|
7471
|
-
|
|
7471
|
+
resolve2(is);
|
|
7472
7472
|
}
|
|
7473
7473
|
});
|
|
7474
7474
|
});
|
|
@@ -7534,27 +7534,27 @@ var require_which = __commonJS({
|
|
|
7534
7534
|
opt = {};
|
|
7535
7535
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
7536
7536
|
const found = [];
|
|
7537
|
-
const step = (i) => new Promise((
|
|
7537
|
+
const step = (i) => new Promise((resolve2, reject) => {
|
|
7538
7538
|
if (i === pathEnv.length)
|
|
7539
|
-
return opt.all && found.length ?
|
|
7539
|
+
return opt.all && found.length ? resolve2(found) : reject(getNotFoundError(cmd));
|
|
7540
7540
|
const ppRaw = pathEnv[i];
|
|
7541
7541
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
7542
7542
|
const pCmd = path.join(pathPart, cmd);
|
|
7543
7543
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
7544
|
-
|
|
7544
|
+
resolve2(subStep(p, i, 0));
|
|
7545
7545
|
});
|
|
7546
|
-
const subStep = (p, i, ii) => new Promise((
|
|
7546
|
+
const subStep = (p, i, ii) => new Promise((resolve2, reject) => {
|
|
7547
7547
|
if (ii === pathExt.length)
|
|
7548
|
-
return
|
|
7548
|
+
return resolve2(step(i + 1));
|
|
7549
7549
|
const ext = pathExt[ii];
|
|
7550
7550
|
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
|
|
7551
7551
|
if (!er && is) {
|
|
7552
7552
|
if (opt.all)
|
|
7553
7553
|
found.push(p + ext);
|
|
7554
7554
|
else
|
|
7555
|
-
return
|
|
7555
|
+
return resolve2(p + ext);
|
|
7556
7556
|
}
|
|
7557
|
-
return
|
|
7557
|
+
return resolve2(subStep(p, i, ii + 1));
|
|
7558
7558
|
});
|
|
7559
7559
|
});
|
|
7560
7560
|
return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
|
|
@@ -7871,9 +7871,9 @@ import { homedir as homedir2 } from "node:os";
|
|
|
7871
7871
|
|
|
7872
7872
|
// src/core/canonical.ts
|
|
7873
7873
|
var import_yaml = __toESM(require_dist(), 1);
|
|
7874
|
-
import { existsSync as
|
|
7874
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2, writeFileSync } from "node:fs";
|
|
7875
7875
|
import { homedir } from "node:os";
|
|
7876
|
-
import { basename, dirname, join } from "node:path";
|
|
7876
|
+
import { basename, dirname as dirname2, join as join2 } from "node:path";
|
|
7877
7877
|
|
|
7878
7878
|
// src/core/types.ts
|
|
7879
7879
|
function isOAuthAuth(auth2) {
|
|
@@ -7936,69 +7936,224 @@ function resolveSecretEnv(names, policy) {
|
|
|
7936
7936
|
return result;
|
|
7937
7937
|
}
|
|
7938
7938
|
|
|
7939
|
-
// src/core/
|
|
7940
|
-
function fromServerDefYaml(serverName, def) {
|
|
7939
|
+
// src/core/mcpServerDef.ts
|
|
7940
|
+
function fromServerDefYaml(serverName, def, source = "mcp/servers.yaml") {
|
|
7941
7941
|
const { static_env, env_aliases, auth: auth2, ...rest } = def;
|
|
7942
7942
|
const out = { ...rest };
|
|
7943
7943
|
if (static_env) out.staticEnv = static_env;
|
|
7944
7944
|
if (env_aliases) out.envAliases = env_aliases;
|
|
7945
|
-
if (auth2 !== void 0) out.auth = fromAuthYaml(serverName, auth2);
|
|
7945
|
+
if (auth2 !== void 0) out.auth = fromAuthYaml(serverName, auth2, source);
|
|
7946
7946
|
return out;
|
|
7947
7947
|
}
|
|
7948
|
-
function fromAuthYaml(serverName, auth2) {
|
|
7948
|
+
function fromAuthYaml(serverName, auth2, source) {
|
|
7949
7949
|
if (auth2 === "oauth") return "oauth";
|
|
7950
7950
|
if (typeof auth2 !== "object" || auth2 === null) {
|
|
7951
|
-
throw new Error(
|
|
7951
|
+
throw new Error(`${source}: "${serverName}" auth must be the scalar "oauth" or { kind: oauth, client_id?, client_secret_env?, client_name? }`);
|
|
7952
7952
|
}
|
|
7953
7953
|
const { kind, owner, client_id, client_secret_env, client_name, ...extra } = auth2;
|
|
7954
7954
|
const unknownKey = Object.keys(extra)[0];
|
|
7955
7955
|
if (unknownKey !== void 0) {
|
|
7956
|
-
throw new Error(
|
|
7956
|
+
throw new Error(`${source}: "${serverName}" auth has unrecognized key "${unknownKey}" \u2014 expected kind, owner, client_id, client_secret_env, client_name`);
|
|
7957
7957
|
}
|
|
7958
7958
|
if (kind !== "oauth") {
|
|
7959
|
-
throw new Error(
|
|
7959
|
+
throw new Error(`${source}: "${serverName}" auth.kind must be "oauth" \u2014 kind is the only recognized discriminator`);
|
|
7960
7960
|
}
|
|
7961
7961
|
if (client_id !== void 0 && typeof client_id !== "string") {
|
|
7962
|
-
throw new Error(
|
|
7962
|
+
throw new Error(`${source}: "${serverName}" auth.client_id must be a string`);
|
|
7963
7963
|
}
|
|
7964
7964
|
if (client_secret_env !== void 0 && (typeof client_secret_env !== "string" || !isValidSecretVarName(client_secret_env))) {
|
|
7965
|
-
throw new Error(
|
|
7965
|
+
throw new Error(`${source}: "${serverName}" auth.client_secret_env must be a variable NAME (e.g. FIGMA_CLIENT_SECRET), never a secret value`);
|
|
7966
7966
|
}
|
|
7967
7967
|
if (client_name !== void 0 && typeof client_name !== "string") {
|
|
7968
|
-
throw new Error(
|
|
7968
|
+
throw new Error(`${source}: "${serverName}" auth.client_name must be a string`);
|
|
7969
7969
|
}
|
|
7970
7970
|
const out = { kind: "oauth" };
|
|
7971
|
-
if (owner !== void 0 && owner !== "agent" && owner !== "trellis") throw new Error(
|
|
7971
|
+
if (owner !== void 0 && owner !== "agent" && owner !== "trellis") throw new Error(`${source}: "${serverName}" auth.owner must be agent or trellis`);
|
|
7972
7972
|
if (owner !== void 0) out.owner = owner;
|
|
7973
7973
|
if (typeof client_id === "string") out.clientId = client_id;
|
|
7974
7974
|
if (typeof client_secret_env === "string") out.clientSecretEnv = client_secret_env;
|
|
7975
7975
|
if (typeof client_name === "string") out.clientName = client_name;
|
|
7976
7976
|
return out;
|
|
7977
7977
|
}
|
|
7978
|
+
|
|
7979
|
+
// src/lib/workspace.ts
|
|
7980
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
|
|
7981
|
+
import { dirname, join, resolve } from "node:path";
|
|
7982
|
+
var WORKSPACE_DIR_NAME = ".agents";
|
|
7983
|
+
var WORKSPACE_CONFIG_VERSION = 1;
|
|
7984
|
+
var CONFIG_SOURCE_LABEL = ".agents/config.json";
|
|
7985
|
+
function isTombstone(def) {
|
|
7986
|
+
return def.enabled === false && def.transport === void 0;
|
|
7987
|
+
}
|
|
7988
|
+
function loadWorkspaceLayer(workspaceDir, policy) {
|
|
7989
|
+
const layerRoot = join(workspaceDir, WORKSPACE_DIR_NAME);
|
|
7990
|
+
const diagnostics = [];
|
|
7991
|
+
const layer = { root: workspaceDir, servers: {}, tombstones: [], skills: [], diagnostics };
|
|
7992
|
+
const configPath = join(layerRoot, "config.json");
|
|
7993
|
+
if (existsSync2(configPath)) {
|
|
7994
|
+
let parsed;
|
|
7995
|
+
try {
|
|
7996
|
+
parsed = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
7997
|
+
} catch (err) {
|
|
7998
|
+
throw new Error(`${CONFIG_SOURCE_LABEL}: invalid JSON \u2014 ${err.message}`);
|
|
7999
|
+
}
|
|
8000
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
8001
|
+
throw new Error(`${CONFIG_SOURCE_LABEL}: top level must be an object { "version", "mcp" }`);
|
|
8002
|
+
}
|
|
8003
|
+
const { version: version2, mcp, ...extra } = parsed;
|
|
8004
|
+
const configVersion = version2 === void 0 ? WORKSPACE_CONFIG_VERSION : version2;
|
|
8005
|
+
if (typeof configVersion !== "number" || !Number.isInteger(configVersion) || configVersion < 1) {
|
|
8006
|
+
throw new Error(`${CONFIG_SOURCE_LABEL}: "version" must be a positive integer, got ${JSON.stringify(version2)}`);
|
|
8007
|
+
}
|
|
8008
|
+
if (configVersion > WORKSPACE_CONFIG_VERSION) {
|
|
8009
|
+
throw new Error(
|
|
8010
|
+
`${CONFIG_SOURCE_LABEL}: schema version ${configVersion} is newer than this Trellis understands (${WORKSPACE_CONFIG_VERSION}) \u2014 upgrade Trellis`
|
|
8011
|
+
);
|
|
8012
|
+
}
|
|
8013
|
+
for (const key of Object.keys(extra)) {
|
|
8014
|
+
diagnostics.push(`${CONFIG_SOURCE_LABEL}: unrecognized top-level key "${key}" \u2014 ignored`);
|
|
8015
|
+
}
|
|
8016
|
+
if (mcp !== void 0) {
|
|
8017
|
+
if (typeof mcp !== "object" || mcp === null || typeof mcp.servers !== "object" || mcp.servers === null || Array.isArray(mcp.servers)) {
|
|
8018
|
+
throw new Error(`${CONFIG_SOURCE_LABEL}: "mcp.servers" must be an object mapping server names to definitions`);
|
|
8019
|
+
}
|
|
8020
|
+
for (const [name, rawDef] of Object.entries(mcp.servers)) {
|
|
8021
|
+
if (typeof rawDef !== "object" || rawDef === null) {
|
|
8022
|
+
throw new Error(`${CONFIG_SOURCE_LABEL}: "${name}" must be a server definition object or { "enabled": false }`);
|
|
8023
|
+
}
|
|
8024
|
+
if (isTombstone(rawDef)) {
|
|
8025
|
+
layer.tombstones.push(name);
|
|
8026
|
+
continue;
|
|
8027
|
+
}
|
|
8028
|
+
if (rawDef.enabled === false) {
|
|
8029
|
+
layer.tombstones.push(name);
|
|
8030
|
+
continue;
|
|
8031
|
+
}
|
|
8032
|
+
layer.servers[name] = fromServerDefYaml(name, rawDef, CONFIG_SOURCE_LABEL);
|
|
8033
|
+
}
|
|
8034
|
+
}
|
|
8035
|
+
}
|
|
8036
|
+
const instructionsPath = join(layerRoot, "AGENTS.md");
|
|
8037
|
+
if (existsSync2(instructionsPath)) {
|
|
8038
|
+
layer.instructionsFile = instructionsPath;
|
|
8039
|
+
}
|
|
8040
|
+
const skillsRoot = join(layerRoot, "skills");
|
|
8041
|
+
let skillEntries = [];
|
|
8042
|
+
try {
|
|
8043
|
+
skillEntries = readdirSync(skillsRoot);
|
|
8044
|
+
} catch {
|
|
8045
|
+
}
|
|
8046
|
+
for (const name of skillEntries) {
|
|
8047
|
+
const dir = join(skillsRoot, name);
|
|
8048
|
+
try {
|
|
8049
|
+
if (statSync(dir).isDirectory()) layer.skills.push({ name, dir });
|
|
8050
|
+
} catch {
|
|
8051
|
+
}
|
|
8052
|
+
}
|
|
8053
|
+
assertWorkspaceSecretsClean(layer.servers, policy);
|
|
8054
|
+
return layer;
|
|
8055
|
+
}
|
|
8056
|
+
var VAR_REF_RE = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/;
|
|
8057
|
+
function assertWorkspaceSecretsClean(servers, policy) {
|
|
8058
|
+
const check2 = (server, field, value) => {
|
|
8059
|
+
if (value === void 0 || VAR_REF_RE.test(value)) return;
|
|
8060
|
+
for (const pattern of policy.rejectPatterns) {
|
|
8061
|
+
if (pattern.test(value)) {
|
|
8062
|
+
throw new Error(
|
|
8063
|
+
`${CONFIG_SOURCE_LABEL}: "${server}" ${field} matches a secrets.policy.yaml reject pattern \u2014 the project layer is committable and must carry only \${VAR} references; move the value to the global secret store (the offending value is intentionally not printed)`
|
|
8064
|
+
);
|
|
8065
|
+
}
|
|
8066
|
+
}
|
|
8067
|
+
};
|
|
8068
|
+
for (const [name, def] of Object.entries(servers)) {
|
|
8069
|
+
for (const entry of def.env ?? []) check2(name, "env", entry);
|
|
8070
|
+
for (const [key, value] of Object.entries(def.staticEnv ?? {})) check2(name, `static_env.${key}`, value);
|
|
8071
|
+
for (const [key, value] of Object.entries(def.headers ?? {})) check2(name, `headers.${key}`, value);
|
|
8072
|
+
const meta3 = oauthClientMetadata(def.auth);
|
|
8073
|
+
check2(name, "auth.client_id", meta3.clientId);
|
|
8074
|
+
check2(name, "auth.client_secret_env", meta3.clientSecretEnv);
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
|
|
8078
|
+
// src/lib/workspaceMerge.ts
|
|
8079
|
+
function mergeWorkspaceLayer(base, layer) {
|
|
8080
|
+
const shadowed = [];
|
|
8081
|
+
const mcpGlobalServers = { ...base.mcp.servers };
|
|
8082
|
+
const servers = { ...base.mcp.servers };
|
|
8083
|
+
const mcpProvenance = Object.fromEntries(
|
|
8084
|
+
Object.keys(base.mcp.servers).map((name) => [name, "global"])
|
|
8085
|
+
);
|
|
8086
|
+
for (const name of layer.tombstones) {
|
|
8087
|
+
if (servers[name] !== void 0) {
|
|
8088
|
+
delete servers[name];
|
|
8089
|
+
delete mcpProvenance[name];
|
|
8090
|
+
shadowed.push(`mcp:${name}`);
|
|
8091
|
+
} else {
|
|
8092
|
+
layer.diagnostics.push(`.agents/config.json: tombstone "${name}" matches no global server \u2014 no-op`);
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
for (const [name, def] of Object.entries(layer.servers)) {
|
|
8096
|
+
if (servers[name] !== void 0) shadowed.push(`mcp:${name}`);
|
|
8097
|
+
servers[name] = def;
|
|
8098
|
+
mcpProvenance[name] = "workspace";
|
|
8099
|
+
}
|
|
8100
|
+
const skills = [...base.skills];
|
|
8101
|
+
const globalSkills = [...base.skills];
|
|
8102
|
+
const skillProvenance = Object.fromEntries(
|
|
8103
|
+
base.skills.map((s) => [s.name, "global"])
|
|
8104
|
+
);
|
|
8105
|
+
for (const wsSkill of layer.skills) {
|
|
8106
|
+
const idx = skills.findIndex((s) => s.name === wsSkill.name);
|
|
8107
|
+
if (idx >= 0) {
|
|
8108
|
+
shadowed.push(`skill:${wsSkill.name}`);
|
|
8109
|
+
skills[idx] = wsSkill;
|
|
8110
|
+
} else {
|
|
8111
|
+
skills.push(wsSkill);
|
|
8112
|
+
}
|
|
8113
|
+
skillProvenance[wsSkill.name] = "workspace";
|
|
8114
|
+
}
|
|
8115
|
+
return {
|
|
8116
|
+
...base,
|
|
8117
|
+
skills,
|
|
8118
|
+
mcp: { ...base.mcp, servers },
|
|
8119
|
+
diagnostics: [...base.diagnostics, ...layer.diagnostics],
|
|
8120
|
+
workspace: {
|
|
8121
|
+
root: layer.root,
|
|
8122
|
+
...layer.instructionsFile !== void 0 ? { instructionsFile: layer.instructionsFile } : {},
|
|
8123
|
+
mcpProvenance,
|
|
8124
|
+
mcpGlobalServers,
|
|
8125
|
+
skillProvenance,
|
|
8126
|
+
globalSkills,
|
|
8127
|
+
shadowed
|
|
8128
|
+
}
|
|
8129
|
+
};
|
|
8130
|
+
}
|
|
8131
|
+
|
|
8132
|
+
// src/core/canonical.ts
|
|
7978
8133
|
function trellisRoot(homeDir) {
|
|
7979
|
-
return
|
|
8134
|
+
return join2(homeDir, ".trellis");
|
|
7980
8135
|
}
|
|
7981
8136
|
function listMarkdownFiles(dir) {
|
|
7982
8137
|
let entries;
|
|
7983
8138
|
try {
|
|
7984
|
-
entries =
|
|
8139
|
+
entries = readdirSync2(dir);
|
|
7985
8140
|
} catch {
|
|
7986
8141
|
return [];
|
|
7987
8142
|
}
|
|
7988
|
-
return entries.filter((name) => name.endsWith(".md")).map((name) => ({ name: basename(name, ".md"), file:
|
|
8143
|
+
return entries.filter((name) => name.endsWith(".md")).map((name) => ({ name: basename(name, ".md"), file: join2(dir, name) }));
|
|
7989
8144
|
}
|
|
7990
8145
|
function listSkillDirs(dir) {
|
|
7991
8146
|
let entries;
|
|
7992
8147
|
try {
|
|
7993
|
-
entries =
|
|
8148
|
+
entries = readdirSync2(dir);
|
|
7994
8149
|
} catch {
|
|
7995
8150
|
return [];
|
|
7996
8151
|
}
|
|
7997
8152
|
const skills = [];
|
|
7998
8153
|
for (const name of entries) {
|
|
7999
|
-
const skillDir =
|
|
8154
|
+
const skillDir = join2(dir, name);
|
|
8000
8155
|
try {
|
|
8001
|
-
if (
|
|
8156
|
+
if (statSync2(skillDir).isDirectory()) {
|
|
8002
8157
|
skills.push({ name, dir: skillDir });
|
|
8003
8158
|
}
|
|
8004
8159
|
} catch {
|
|
@@ -8007,17 +8162,17 @@ function listSkillDirs(dir) {
|
|
|
8007
8162
|
return skills;
|
|
8008
8163
|
}
|
|
8009
8164
|
function loadScopeYaml(path) {
|
|
8010
|
-
if (!
|
|
8165
|
+
if (!existsSync3(path)) {
|
|
8011
8166
|
return {};
|
|
8012
8167
|
}
|
|
8013
|
-
const parsed = (0, import_yaml.parse)(
|
|
8168
|
+
const parsed = (0, import_yaml.parse)(readFileSync3(path, "utf-8"));
|
|
8014
8169
|
return parsed ?? {};
|
|
8015
8170
|
}
|
|
8016
8171
|
function loadServersYaml(path) {
|
|
8017
|
-
if (!
|
|
8172
|
+
if (!existsSync3(path)) {
|
|
8018
8173
|
return { servers: {}, knownHostInjected: [] };
|
|
8019
8174
|
}
|
|
8020
|
-
const parsed = (0, import_yaml.parse)(
|
|
8175
|
+
const parsed = (0, import_yaml.parse)(readFileSync3(path, "utf-8")) ?? {};
|
|
8021
8176
|
const servers = Object.fromEntries(Object.entries(parsed.servers ?? {}).map(([name, def]) => [name, fromServerDefYaml(name, def)]));
|
|
8022
8177
|
return {
|
|
8023
8178
|
servers,
|
|
@@ -8058,10 +8213,10 @@ function fromGatewayYaml(gateway) {
|
|
|
8058
8213
|
return out;
|
|
8059
8214
|
}
|
|
8060
8215
|
function loadSecretsPolicyYaml(path, homeDir) {
|
|
8061
|
-
if (!
|
|
8216
|
+
if (!existsSync3(path)) {
|
|
8062
8217
|
return { allowedVars: [], rejectPatterns: [] };
|
|
8063
8218
|
}
|
|
8064
|
-
const parsed = (0, import_yaml.parse)(
|
|
8219
|
+
const parsed = (0, import_yaml.parse)(readFileSync3(path, "utf-8")) ?? {};
|
|
8065
8220
|
return {
|
|
8066
8221
|
allowedVars: parsed.allowed_vars ?? [],
|
|
8067
8222
|
rejectPatterns: (parsed.reject_patterns ?? []).map((pattern) => new RegExp(pattern)),
|
|
@@ -8069,10 +8224,10 @@ function loadSecretsPolicyYaml(path, homeDir) {
|
|
|
8069
8224
|
};
|
|
8070
8225
|
}
|
|
8071
8226
|
function loadManagedYaml(path, diagnostics) {
|
|
8072
|
-
if (!
|
|
8227
|
+
if (!existsSync3(path)) {
|
|
8073
8228
|
return [];
|
|
8074
8229
|
}
|
|
8075
|
-
const parsed = (0, import_yaml.parse)(
|
|
8230
|
+
const parsed = (0, import_yaml.parse)(readFileSync3(path, "utf-8")) ?? {};
|
|
8076
8231
|
const raw = parsed.agents ?? [];
|
|
8077
8232
|
const valid = [];
|
|
8078
8233
|
for (const id of raw) {
|
|
@@ -8110,27 +8265,29 @@ function assertAuthMetadataClean(mcp, policy) {
|
|
|
8110
8265
|
}
|
|
8111
8266
|
}
|
|
8112
8267
|
}
|
|
8113
|
-
function loadCanonicalSource(
|
|
8268
|
+
function loadCanonicalSource(arg = {}) {
|
|
8269
|
+
const options = typeof arg === "string" ? { homeDir: arg } : arg;
|
|
8270
|
+
const homeDir = options.homeDir ?? homedir();
|
|
8114
8271
|
const root = trellisRoot(homeDir);
|
|
8115
|
-
if (!
|
|
8272
|
+
if (!existsSync3(root)) {
|
|
8116
8273
|
throw new Error(
|
|
8117
8274
|
`No canonical source at ${root}. Run trellis init before trellis sync.`
|
|
8118
8275
|
);
|
|
8119
8276
|
}
|
|
8120
8277
|
const diagnostics = [];
|
|
8121
|
-
const managedAgents = loadManagedYaml(
|
|
8122
|
-
const scopeYaml = loadScopeYaml(
|
|
8123
|
-
const skillDirs = listSkillDirs(
|
|
8278
|
+
const managedAgents = loadManagedYaml(join2(root, "managed.yaml"), diagnostics);
|
|
8279
|
+
const scopeYaml = loadScopeYaml(join2(root, "scope.yaml"));
|
|
8280
|
+
const skillDirs = listSkillDirs(join2(root, "skills"));
|
|
8124
8281
|
const knownSkillNames = new Set(skillDirs.map((s) => s.name));
|
|
8125
8282
|
const skills = skillDirs.map(({ name, dir }) => ({ name, dir, scope: scopeFor(scopeYaml.skills, name) }));
|
|
8126
|
-
const agentFiles = listMarkdownFiles(
|
|
8283
|
+
const agentFiles = listMarkdownFiles(join2(root, "agents"));
|
|
8127
8284
|
const knownAgentProfileNames = new Set(agentFiles.map((a) => a.name));
|
|
8128
8285
|
const agents = agentFiles.map(({ name, file: file2 }) => ({
|
|
8129
8286
|
name,
|
|
8130
8287
|
file: file2,
|
|
8131
8288
|
scope: scopeFor(scopeYaml.agents, name)
|
|
8132
8289
|
}));
|
|
8133
|
-
const memoryFiles = listMarkdownFiles(
|
|
8290
|
+
const memoryFiles = listMarkdownFiles(join2(root, "memories"));
|
|
8134
8291
|
const knownMemoryNames = new Set(memoryFiles.map((m) => m.name));
|
|
8135
8292
|
const memories = memoryFiles.map(({ name, file: file2 }) => ({
|
|
8136
8293
|
name,
|
|
@@ -8151,11 +8308,11 @@ function loadCanonicalSource(homeDir = homedir()) {
|
|
|
8151
8308
|
}
|
|
8152
8309
|
}
|
|
8153
8310
|
}
|
|
8154
|
-
const mcp = loadServersYaml(
|
|
8155
|
-
const secretsPolicy = loadSecretsPolicyYaml(
|
|
8311
|
+
const mcp = loadServersYaml(join2(root, "mcp", "servers.yaml"));
|
|
8312
|
+
const secretsPolicy = loadSecretsPolicyYaml(join2(root, "secrets.policy.yaml"), homeDir);
|
|
8156
8313
|
assertAuthMetadataClean(mcp, secretsPolicy);
|
|
8157
|
-
|
|
8158
|
-
instructionsFile:
|
|
8314
|
+
const source = {
|
|
8315
|
+
instructionsFile: join2(root, "agents.md"),
|
|
8159
8316
|
managedAgents,
|
|
8160
8317
|
skills,
|
|
8161
8318
|
agents,
|
|
@@ -8164,6 +8321,11 @@ function loadCanonicalSource(homeDir = homedir()) {
|
|
|
8164
8321
|
secretsPolicy,
|
|
8165
8322
|
diagnostics
|
|
8166
8323
|
};
|
|
8324
|
+
if (options.workspaceDir) {
|
|
8325
|
+
const layer = loadWorkspaceLayer(options.workspaceDir, secretsPolicy);
|
|
8326
|
+
return mergeWorkspaceLayer(source, layer);
|
|
8327
|
+
}
|
|
8328
|
+
return source;
|
|
8167
8329
|
}
|
|
8168
8330
|
|
|
8169
8331
|
// src/core/adapter.ts
|
|
@@ -13468,7 +13630,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
13468
13630
|
var NONE = 0;
|
|
13469
13631
|
var ASSUMED = 1;
|
|
13470
13632
|
var PROVEN = 2;
|
|
13471
|
-
function isRecursive(inst, stack,
|
|
13633
|
+
function isRecursive(inst, stack, resolve2) {
|
|
13472
13634
|
const cached2 = recursive.get(inst);
|
|
13473
13635
|
if (cached2 !== void 0)
|
|
13474
13636
|
return cached2 ? PROVEN : NONE;
|
|
@@ -13478,7 +13640,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
13478
13640
|
let result = NONE;
|
|
13479
13641
|
const check2 = (child) => {
|
|
13480
13642
|
if (result !== PROVEN && child?._zod) {
|
|
13481
|
-
const answer = isRecursive(child, stack,
|
|
13643
|
+
const answer = isRecursive(child, stack, resolve2);
|
|
13482
13644
|
if (answer > result)
|
|
13483
13645
|
result = answer;
|
|
13484
13646
|
}
|
|
@@ -13489,7 +13651,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
13489
13651
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
13490
13652
|
if (spread && !desc.enumerable)
|
|
13491
13653
|
continue;
|
|
13492
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
13654
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve2) : NONE;
|
|
13493
13655
|
if (child > answer)
|
|
13494
13656
|
answer = child;
|
|
13495
13657
|
}
|
|
@@ -13553,7 +13715,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
13553
13715
|
break;
|
|
13554
13716
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
13555
13717
|
case "lazy": {
|
|
13556
|
-
const inner = def._cachedInner ?? (
|
|
13718
|
+
const inner = def._cachedInner ?? (resolve2 ? inst._zod.innerType : void 0);
|
|
13557
13719
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
13558
13720
|
break;
|
|
13559
13721
|
}
|
|
@@ -32475,14 +32637,14 @@ function inputRequiredRoundsExceededMessage(method, maxRounds) {
|
|
|
32475
32637
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
32476
32638
|
}
|
|
32477
32639
|
function sleep(ms, signal) {
|
|
32478
|
-
return new Promise((
|
|
32640
|
+
return new Promise((resolve2, reject) => {
|
|
32479
32641
|
if (signal?.aborted) {
|
|
32480
32642
|
reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
|
|
32481
32643
|
return;
|
|
32482
32644
|
}
|
|
32483
32645
|
const timer = setTimeout(() => {
|
|
32484
32646
|
signal?.removeEventListener("abort", onAbort);
|
|
32485
|
-
|
|
32647
|
+
resolve2();
|
|
32486
32648
|
}, ms);
|
|
32487
32649
|
const onAbort = () => {
|
|
32488
32650
|
clearTimeout(timer);
|
|
@@ -33326,7 +33488,7 @@ var Protocol = class {
|
|
|
33326
33488
|
const flowStartedAt = Date.now();
|
|
33327
33489
|
let onAbort;
|
|
33328
33490
|
let cleanupMessageId;
|
|
33329
|
-
return new Promise((
|
|
33491
|
+
return new Promise((resolve2, reject) => {
|
|
33330
33492
|
const earlyReject = (error62) => {
|
|
33331
33493
|
reject(error62);
|
|
33332
33494
|
};
|
|
@@ -33395,7 +33557,7 @@ var Protocol = class {
|
|
|
33395
33557
|
}
|
|
33396
33558
|
if (decoded.kind === "invalid") return reject(decoded.error);
|
|
33397
33559
|
if (decoded.kind === "input_required") {
|
|
33398
|
-
if (options?.allowInputRequired === true) return
|
|
33560
|
+
if (options?.allowInputRequired === true) return resolve2(manualInputRequiredValue(decoded));
|
|
33399
33561
|
const flow = {
|
|
33400
33562
|
codec: codec2,
|
|
33401
33563
|
request,
|
|
@@ -33407,11 +33569,11 @@ var Protocol = class {
|
|
|
33407
33569
|
params
|
|
33408
33570
|
}, resultSchema, legOptions)
|
|
33409
33571
|
};
|
|
33410
|
-
return
|
|
33572
|
+
return resolve2(this._resolveNonCompleteResult(decoded, flow));
|
|
33411
33573
|
}
|
|
33412
33574
|
const result = decoded.result;
|
|
33413
33575
|
validateStandardSchema(resultSchema, result).then((parseResult) => {
|
|
33414
|
-
if (parseResult.success)
|
|
33576
|
+
if (parseResult.success) resolve2(parseResult.data);
|
|
33415
33577
|
else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
|
|
33416
33578
|
}, reject);
|
|
33417
33579
|
});
|
|
@@ -36428,7 +36590,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
36428
36590
|
ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
|
|
36429
36591
|
const schOrFunc = root.refs[ref];
|
|
36430
36592
|
if (schOrFunc) return schOrFunc;
|
|
36431
|
-
let _sch =
|
|
36593
|
+
let _sch = resolve2.call(this, root, ref);
|
|
36432
36594
|
if (_sch === void 0) {
|
|
36433
36595
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
36434
36596
|
const { schemaId } = this.opts;
|
|
@@ -36454,7 +36616,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
36454
36616
|
function sameSchemaEnv(s1, s2) {
|
|
36455
36617
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
36456
36618
|
}
|
|
36457
|
-
function
|
|
36619
|
+
function resolve2(root, ref) {
|
|
36458
36620
|
let sch;
|
|
36459
36621
|
while (typeof (sch = this.refs[ref]) == "string") ref = sch;
|
|
36460
36622
|
return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
|
|
@@ -36904,7 +37066,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
36904
37066
|
else if (typeof uri === "object") uri = parse3(serialize(uri, options), options);
|
|
36905
37067
|
return uri;
|
|
36906
37068
|
}
|
|
36907
|
-
function
|
|
37069
|
+
function resolve2(baseURI, relativeURI, options) {
|
|
36908
37070
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
36909
37071
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
36910
37072
|
schemelessOptions.skipEscape = true;
|
|
@@ -37078,7 +37240,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
37078
37240
|
const fastUri = {
|
|
37079
37241
|
SCHEMES,
|
|
37080
37242
|
normalize,
|
|
37081
|
-
resolve,
|
|
37243
|
+
resolve: resolve2,
|
|
37082
37244
|
resolveComponent,
|
|
37083
37245
|
equal,
|
|
37084
37246
|
serialize,
|
|
@@ -42943,14 +43105,14 @@ var ProbeWindow = class ProbeWindow2 {
|
|
|
42943
43105
|
*/
|
|
42944
43106
|
async exchange(buildRequest, timeoutMs) {
|
|
42945
43107
|
const id = `server-discover-probe-${++this._probeCounter}`;
|
|
42946
|
-
return new Promise((
|
|
43108
|
+
return new Promise((resolve2) => {
|
|
42947
43109
|
let settled = false;
|
|
42948
43110
|
const settle2 = (reply) => {
|
|
42949
43111
|
if (settled) return;
|
|
42950
43112
|
settled = true;
|
|
42951
43113
|
clearTimeout(timer);
|
|
42952
43114
|
if (this._pending?.id === id) this._pending = void 0;
|
|
42953
|
-
|
|
43115
|
+
resolve2(reply);
|
|
42954
43116
|
};
|
|
42955
43117
|
const timer = setTimeout(() => settle2({ kind: "timeout" }), timeoutMs);
|
|
42956
43118
|
this._pending = {
|
|
@@ -44164,13 +44326,13 @@ var Client = class extends Protocol {
|
|
|
44164
44326
|
let onCallerAbort;
|
|
44165
44327
|
let resolveOpening;
|
|
44166
44328
|
let rejectOpening;
|
|
44167
|
-
const opening = new Promise((
|
|
44168
|
-
resolveOpening =
|
|
44329
|
+
const opening = new Promise((resolve2, reject) => {
|
|
44330
|
+
resolveOpening = resolve2;
|
|
44169
44331
|
rejectOpening = reject;
|
|
44170
44332
|
});
|
|
44171
44333
|
let resolveClosed;
|
|
44172
|
-
const closed = new Promise((
|
|
44173
|
-
resolveClosed =
|
|
44334
|
+
const closed = new Promise((resolve2) => {
|
|
44335
|
+
resolveClosed = resolve2;
|
|
44174
44336
|
});
|
|
44175
44337
|
const settle2 = (outcome) => {
|
|
44176
44338
|
if (state === "closed") return;
|
|
@@ -44726,7 +44888,7 @@ var SSEClientTransport = class {
|
|
|
44726
44888
|
const eventSourceFetch = this._eventSourceInit?.fetch;
|
|
44727
44889
|
const fetchImpl = this._redirects(eventSourceFetch ? this._dpop?.(eventSourceFetch) ?? eventSourceFetch : this._fetch ?? fetch);
|
|
44728
44890
|
let redirect;
|
|
44729
|
-
return new Promise((
|
|
44891
|
+
return new Promise((resolve2, reject) => {
|
|
44730
44892
|
this._eventSource = new EventSource(this._url.href, {
|
|
44731
44893
|
...this._eventSourceInit,
|
|
44732
44894
|
fetch: async (url2, init) => {
|
|
@@ -44760,7 +44922,7 @@ var SSEClientTransport = class {
|
|
|
44760
44922
|
response,
|
|
44761
44923
|
serverUrl: this._url,
|
|
44762
44924
|
fetchFn: this._fetchWithInit
|
|
44763
|
-
}).then(() => this._startOrAuth().then(
|
|
44925
|
+
}).then(() => this._startOrAuth().then(resolve2, reject), (error$2) => {
|
|
44764
44926
|
this._connectAuthRetried = false;
|
|
44765
44927
|
markAuthSeamEscape(error$2);
|
|
44766
44928
|
this.onerror?.(error$2);
|
|
@@ -44798,7 +44960,7 @@ var SSEClientTransport = class {
|
|
|
44798
44960
|
this.close();
|
|
44799
44961
|
return;
|
|
44800
44962
|
}
|
|
44801
|
-
|
|
44963
|
+
resolve2();
|
|
44802
44964
|
});
|
|
44803
44965
|
this._eventSource.onmessage = (event) => {
|
|
44804
44966
|
const messageEvent = event;
|
|
@@ -45543,7 +45705,7 @@ var StdioClientTransport = class {
|
|
|
45543
45705
|
*/
|
|
45544
45706
|
async start() {
|
|
45545
45707
|
if (this._process) throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
45546
|
-
return new Promise((
|
|
45708
|
+
return new Promise((resolve2, reject) => {
|
|
45547
45709
|
this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
|
|
45548
45710
|
env: {
|
|
45549
45711
|
...getDefaultEnvironment(),
|
|
@@ -45563,7 +45725,7 @@ var StdioClientTransport = class {
|
|
|
45563
45725
|
this.onerror?.(error62);
|
|
45564
45726
|
});
|
|
45565
45727
|
this._process.on("spawn", () => {
|
|
45566
|
-
|
|
45728
|
+
resolve2();
|
|
45567
45729
|
});
|
|
45568
45730
|
this._process.on("close", (_code) => {
|
|
45569
45731
|
this._process = void 0;
|
|
@@ -45628,7 +45790,7 @@ var StdioClientTransport = class {
|
|
|
45628
45790
|
const proc = this._process;
|
|
45629
45791
|
this._process = void 0;
|
|
45630
45792
|
if (proc && proc.exitCode === null && proc.signalCode === null) {
|
|
45631
|
-
const exited = new Promise((
|
|
45793
|
+
const exited = new Promise((resolve2) => proc.once("exit", () => resolve2()));
|
|
45632
45794
|
try {
|
|
45633
45795
|
proc.stdin?.end();
|
|
45634
45796
|
} catch {
|
|
@@ -45637,7 +45799,7 @@ var StdioClientTransport = class {
|
|
|
45637
45799
|
proc.kill("SIGTERM");
|
|
45638
45800
|
} catch {
|
|
45639
45801
|
}
|
|
45640
|
-
await Promise.race([exited, new Promise((
|
|
45802
|
+
await Promise.race([exited, new Promise((resolve2) => setTimeout(resolve2, 1e3).unref())]);
|
|
45641
45803
|
if (proc.exitCode === null && proc.signalCode === null) try {
|
|
45642
45804
|
proc.kill("SIGKILL");
|
|
45643
45805
|
} catch {
|
|
@@ -45662,22 +45824,22 @@ var StdioClientTransport = class {
|
|
|
45662
45824
|
if (this._process) {
|
|
45663
45825
|
const processToClose = this._process;
|
|
45664
45826
|
this._process = void 0;
|
|
45665
|
-
const closePromise = new Promise((
|
|
45827
|
+
const closePromise = new Promise((resolve2) => {
|
|
45666
45828
|
processToClose.once("close", () => {
|
|
45667
|
-
|
|
45829
|
+
resolve2();
|
|
45668
45830
|
});
|
|
45669
45831
|
});
|
|
45670
45832
|
try {
|
|
45671
45833
|
processToClose.stdin?.end();
|
|
45672
45834
|
} catch {
|
|
45673
45835
|
}
|
|
45674
|
-
await Promise.race([closePromise, new Promise((
|
|
45836
|
+
await Promise.race([closePromise, new Promise((resolve2) => setTimeout(resolve2, 2e3).unref())]);
|
|
45675
45837
|
if (processToClose.exitCode === null) {
|
|
45676
45838
|
try {
|
|
45677
45839
|
processToClose.kill("SIGTERM");
|
|
45678
45840
|
} catch {
|
|
45679
45841
|
}
|
|
45680
|
-
await Promise.race([closePromise, new Promise((
|
|
45842
|
+
await Promise.race([closePromise, new Promise((resolve2) => setTimeout(resolve2, 2e3).unref())]);
|
|
45681
45843
|
}
|
|
45682
45844
|
if (processToClose.exitCode === null) try {
|
|
45683
45845
|
processToClose.kill("SIGKILL");
|
|
@@ -45687,11 +45849,11 @@ var StdioClientTransport = class {
|
|
|
45687
45849
|
this._readBuffer.clear();
|
|
45688
45850
|
}
|
|
45689
45851
|
send(message) {
|
|
45690
|
-
return new Promise((
|
|
45852
|
+
return new Promise((resolve2) => {
|
|
45691
45853
|
if (!this._process?.stdin) throw new SdkError(SdkErrorCode.NotConnected, "Not connected");
|
|
45692
45854
|
const json2 = serializeMessage(message);
|
|
45693
|
-
if (this._process.stdin.write(json2))
|
|
45694
|
-
else this._process.stdin.once("drain",
|
|
45855
|
+
if (this._process.stdin.write(json2)) resolve2();
|
|
45856
|
+
else this._process.stdin.once("drain", resolve2);
|
|
45695
45857
|
});
|
|
45696
45858
|
}
|
|
45697
45859
|
};
|
|
@@ -45706,12 +45868,12 @@ function extractTemplateVarNames(value) {
|
|
|
45706
45868
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
45707
45869
|
var FAILED_TRANSPORT_CLEANUP_TIMEOUT_MS = 1e3;
|
|
45708
45870
|
function withTimeout(promise2, timeoutMs, message) {
|
|
45709
|
-
return new Promise((
|
|
45871
|
+
return new Promise((resolve2, reject) => {
|
|
45710
45872
|
const timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
45711
45873
|
promise2.then(
|
|
45712
45874
|
(value) => {
|
|
45713
45875
|
clearTimeout(timer);
|
|
45714
|
-
|
|
45876
|
+
resolve2(value);
|
|
45715
45877
|
},
|
|
45716
45878
|
(err) => {
|
|
45717
45879
|
clearTimeout(timer);
|
|
@@ -45934,18 +46096,18 @@ var McpToolRegistry = class {
|
|
|
45934
46096
|
};
|
|
45935
46097
|
|
|
45936
46098
|
// src/lib/oauth/store.ts
|
|
45937
|
-
import { chmodSync, existsSync as
|
|
45938
|
-
import { join as
|
|
46099
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
46100
|
+
import { join as join3 } from "node:path";
|
|
45939
46101
|
function oauthDir(homeDir) {
|
|
45940
|
-
return
|
|
46102
|
+
return join3(homeDir, ".trellis", "mcp", "oauth");
|
|
45941
46103
|
}
|
|
45942
46104
|
function tokenPath(homeDir, serverName) {
|
|
45943
46105
|
assertSafeServerName(serverName);
|
|
45944
|
-
return
|
|
46106
|
+
return join3(oauthDir(homeDir), `${serverName}.json`);
|
|
45945
46107
|
}
|
|
45946
46108
|
function lockPath(homeDir, serverName) {
|
|
45947
46109
|
assertSafeServerName(serverName);
|
|
45948
|
-
return
|
|
46110
|
+
return join3(oauthDir(homeDir), `${serverName}.lock`);
|
|
45949
46111
|
}
|
|
45950
46112
|
function assertSafeServerName(serverName) {
|
|
45951
46113
|
if (serverName === "" || serverName === "." || serverName === ".." || /[/\\]/.test(serverName) || serverName.startsWith(".")) {
|
|
@@ -45954,9 +46116,9 @@ function assertSafeServerName(serverName) {
|
|
|
45954
46116
|
}
|
|
45955
46117
|
function readToken(homeDir, serverName) {
|
|
45956
46118
|
const path = tokenPath(homeDir, serverName);
|
|
45957
|
-
if (!
|
|
46119
|
+
if (!existsSync4(path)) return void 0;
|
|
45958
46120
|
try {
|
|
45959
|
-
return JSON.parse(
|
|
46121
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
45960
46122
|
} catch {
|
|
45961
46123
|
return void 0;
|
|
45962
46124
|
}
|
|
@@ -45978,8 +46140,8 @@ function isExpired(token, skewMs = 6e4, now = Date.now()) {
|
|
|
45978
46140
|
}
|
|
45979
46141
|
|
|
45980
46142
|
// src/lib/oauth/lock.ts
|
|
45981
|
-
import { existsSync as
|
|
45982
|
-
import { dirname as
|
|
46143
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, openSync, closeSync, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
46144
|
+
import { dirname as dirname3 } from "node:path";
|
|
45983
46145
|
var STALE_AFTER_MS = 6e4;
|
|
45984
46146
|
var POLL_INTERVAL_MS = 50;
|
|
45985
46147
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -45994,7 +46156,7 @@ function processAlive(pid) {
|
|
|
45994
46156
|
function isStale(path, now) {
|
|
45995
46157
|
let contents;
|
|
45996
46158
|
try {
|
|
45997
|
-
contents = JSON.parse(
|
|
46159
|
+
contents = JSON.parse(readFileSync5(path, "utf-8"));
|
|
45998
46160
|
} catch {
|
|
45999
46161
|
return true;
|
|
46000
46162
|
}
|
|
@@ -46007,7 +46169,7 @@ async function withServerLock(homeDir, serverName, fn, opts = {}) {
|
|
|
46007
46169
|
const now = opts.now ?? Date.now;
|
|
46008
46170
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
46009
46171
|
const deadline = now() + timeoutMs;
|
|
46010
|
-
mkdirSync4(
|
|
46172
|
+
mkdirSync4(dirname3(path), { recursive: true, mode: 448 });
|
|
46011
46173
|
for (; ; ) {
|
|
46012
46174
|
try {
|
|
46013
46175
|
const fd = openSync(path, "wx", 384);
|
|
@@ -46019,14 +46181,14 @@ async function withServerLock(homeDir, serverName, fn, opts = {}) {
|
|
|
46019
46181
|
break;
|
|
46020
46182
|
} catch (err) {
|
|
46021
46183
|
if (err.code !== "EEXIST") throw err;
|
|
46022
|
-
if (
|
|
46184
|
+
if (existsSync5(path) && isStale(path, now())) {
|
|
46023
46185
|
rmSync2(path, { force: true });
|
|
46024
46186
|
continue;
|
|
46025
46187
|
}
|
|
46026
46188
|
if (now() >= deadline) {
|
|
46027
46189
|
throw new Error(`timed out waiting for the OAuth refresh lock on "${serverName}" (${path})`);
|
|
46028
46190
|
}
|
|
46029
|
-
await new Promise((
|
|
46191
|
+
await new Promise((resolve2) => setTimeout(resolve2, POLL_INTERVAL_MS));
|
|
46030
46192
|
}
|
|
46031
46193
|
}
|
|
46032
46194
|
try {
|