@mesh-tech/mesh-cli 0.39.0 → 0.40.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/bin/{mesh.auth-preflight-JO5G7SOF.js → mesh.auth-preflight-AUFQ2FGD.js} +1 -1
- package/dist/bin/{mesh.chunk-CNLSVKYY.js → mesh.chunk-2ASXJ5DO.js} +233 -581
- package/dist/bin/mesh.chunk-2ASXJ5DO.js.map +6 -0
- package/dist/bin/{mesh.chunk-WODQO6TP.js → mesh.chunk-6AIG5OJM.js} +3 -3
- package/dist/bin/{mesh.chunk-OSV3EZQ3.js → mesh.chunk-6SSOVZOI.js} +1 -1
- package/dist/bin/{mesh.chunk-2ZJR5LGN.js → mesh.chunk-7HTKSUWR.js} +1507 -548
- package/dist/bin/mesh.chunk-7HTKSUWR.js.map +6 -0
- package/dist/bin/{mesh.chunk-UI6EFAMD.js → mesh.chunk-F44A3ACW.js} +2 -2
- package/dist/bin/{mesh.chunk-C2TKCYHP.js → mesh.chunk-HJGMOEUG.js} +1 -1
- package/dist/bin/{mesh.chunk-O6WRZU4X.js → mesh.chunk-NSQJEX36.js} +1 -1
- package/dist/bin/{mesh.chunk-C4ZM7DM2.js → mesh.chunk-PZVI7V3J.js} +1 -1
- package/dist/bin/mesh.chunk-TDCH4SFQ.js +419 -0
- package/dist/bin/mesh.chunk-TDCH4SFQ.js.map +6 -0
- package/dist/bin/mesh.chunk-YE2WIY3Y.js +473 -0
- package/dist/bin/mesh.chunk-YE2WIY3Y.js.map +6 -0
- package/dist/bin/{mesh.create-app-SOHBL75U.js → mesh.create-app-Z3RKSTBO.js} +3 -3
- package/dist/bin/{mesh.dev-token-server-SS7QEQOQ.js → mesh.dev-token-server-XG26C6IQ.js} +2 -2
- package/dist/bin/mesh.generate-XSM4C6FQ.js +10 -0
- package/dist/bin/mesh.js +9 -8
- package/dist/bin/mesh.js.map +1 -1
- package/dist/bin/{mesh.login-6VPMWHHU.js → mesh.login-3AWVGPCM.js} +2 -2
- package/dist/bin/{mesh.platform-setup-DJJB2PWL.js → mesh.platform-setup-2ZDMHRCI.js} +1 -1
- package/dist/bin/{mesh.program-Y4HUNBFP.js → mesh.program-K5JQXEHX.js} +9 -8
- package/dist/bin/{mesh.registry-5P4ZLFLJ.js → mesh.registry-JLQYFUNN.js} +4 -4
- package/dist/bin/{mesh.registry-identity-ONGUJQAY.js → mesh.registry-identity-3AR27UGO.js} +3 -3
- package/dist/bin/mesh.registry-identity-3AR27UGO.js.map +6 -0
- package/dist/bin/mesh.review-command-LUVZQN2T.js +238 -0
- package/dist/bin/mesh.review-command-LUVZQN2T.js.map +6 -0
- package/dist/bin/{mesh.start-5CPWOHDJ.js → mesh.start-KZ5L6SOJ.js} +2 -2
- package/dist/bin/{mesh.wizard-FNRTSGVN.js → mesh.wizard-FCTT55KI.js} +7 -7
- package/dist/bin/mesh.workspace-membership-DI3YQGEK.js +65 -0
- package/dist/bin/mesh.workspace-membership-DI3YQGEK.js.map +6 -0
- package/dist/build-info.json +2 -2
- package/dist/src/commands/dev-doctor.d.ts +22 -0
- package/dist/src/commands/dev-doctor.js +149 -0
- package/dist/src/commands/dev-env-leaks.d.ts +24 -0
- package/dist/src/commands/dev-env-leaks.js +178 -0
- package/dist/src/commands/dev-launch.d.ts +17 -1
- package/dist/src/commands/dev-launch.js +130 -5
- package/dist/src/commands/dev-readiness.d.ts +49 -0
- package/dist/src/commands/dev-readiness.js +78 -0
- package/dist/src/commands/dev.d.ts +60 -0
- package/dist/src/commands/dev.js +539 -140
- package/dist/src/commands/hub/index.js +10 -7
- package/dist/src/commands/mcp/generate.d.ts +11 -0
- package/dist/src/commands/mcp/generate.js +78 -0
- package/dist/src/commands/mcp/index.d.ts +2 -0
- package/dist/src/commands/mcp/index.js +70 -0
- package/dist/src/commands/mcp/manifest-file.d.ts +5 -0
- package/dist/src/commands/mcp/manifest-file.js +24 -0
- package/dist/src/commands/mcp/review-command.d.ts +24 -0
- package/dist/src/commands/mcp/review-command.js +66 -0
- package/dist/src/commands/mcp/review.d.ts +41 -0
- package/dist/src/commands/mcp/review.js +140 -0
- package/dist/src/commands/mcp/workspace-membership.d.ts +7 -0
- package/dist/src/commands/mcp/workspace-membership.js +77 -0
- package/dist/src/commands/secrets/reindex.js +2 -7
- package/dist/src/commands/secrets/set.d.ts +22 -1
- package/dist/src/commands/secrets/set.js +31 -8
- package/dist/src/commands/temporal.js +35 -4
- package/dist/src/commands/temporal.js.map +2 -2
- package/dist/src/program.js +2 -0
- package/dist/src/utils/aws-auth.d.ts +4 -0
- package/dist/src/utils/aws-auth.js +7 -3
- package/dist/src/utils/dev-sessions-root.d.ts +3 -0
- package/dist/src/utils/dev-sessions-root.js +45 -0
- package/dist/src/utils/kubeconfig.js +2 -2
- package/dist/src/utils/tailscale.js +7 -1
- package/dist/src/utils/temporal-auth.js +2 -1
- package/dist/src/utils/workflow-fingerprint.js +23 -12
- package/fragments/base/index.ts.hbs +3 -0
- package/package.json +7 -5
- package/skills/mesh/SKILL.md +10 -6
- package/templates/api-auth/index.ts.hbs +1 -0
- package/templates/api-role-gating/index.ts.hbs +1 -0
- package/templates/external-service/index.ts.hbs +1 -0
- package/templates/workflow/index.ts.hbs +2 -0
- package/dist/bin/mesh.chunk-2ZJR5LGN.js.map +0 -6
- package/dist/bin/mesh.chunk-CNLSVKYY.js.map +0 -6
- /package/dist/bin/{mesh.auth-preflight-JO5G7SOF.js.map → mesh.auth-preflight-AUFQ2FGD.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-WODQO6TP.js.map → mesh.chunk-6AIG5OJM.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-OSV3EZQ3.js.map → mesh.chunk-6SSOVZOI.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-UI6EFAMD.js.map → mesh.chunk-F44A3ACW.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-C2TKCYHP.js.map → mesh.chunk-HJGMOEUG.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-O6WRZU4X.js.map → mesh.chunk-NSQJEX36.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-C4ZM7DM2.js.map → mesh.chunk-PZVI7V3J.js.map} +0 -0
- /package/dist/bin/{mesh.create-app-SOHBL75U.js.map → mesh.create-app-Z3RKSTBO.js.map} +0 -0
- /package/dist/bin/{mesh.dev-token-server-SS7QEQOQ.js.map → mesh.dev-token-server-XG26C6IQ.js.map} +0 -0
- /package/dist/bin/{mesh.login-6VPMWHHU.js.map → mesh.generate-XSM4C6FQ.js.map} +0 -0
- /package/dist/bin/{mesh.platform-setup-DJJB2PWL.js.map → mesh.login-3AWVGPCM.js.map} +0 -0
- /package/dist/bin/{mesh.program-Y4HUNBFP.js.map → mesh.platform-setup-2ZDMHRCI.js.map} +0 -0
- /package/dist/bin/{mesh.registry-5P4ZLFLJ.js.map → mesh.program-K5JQXEHX.js.map} +0 -0
- /package/dist/bin/{mesh.registry-identity-ONGUJQAY.js.map → mesh.registry-JLQYFUNN.js.map} +0 -0
- /package/dist/bin/{mesh.start-5CPWOHDJ.js.map → mesh.start-KZ5L6SOJ.js.map} +0 -0
- /package/dist/bin/{mesh.wizard-FNRTSGVN.js.map → mesh.wizard-FCTT55KI.js.map} +0 -0
|
@@ -15,13 +15,13 @@ import {
|
|
|
15
15
|
registrySessionCandidates,
|
|
16
16
|
registryTokenRoles,
|
|
17
17
|
resolveRegistryIdentity
|
|
18
|
-
} from "./mesh.chunk-
|
|
19
|
-
import "./mesh.chunk-
|
|
18
|
+
} from "./mesh.chunk-HJGMOEUG.js";
|
|
19
|
+
import "./mesh.chunk-7HTKSUWR.js";
|
|
20
20
|
import "./mesh.chunk-2QIVBQX5.js";
|
|
21
21
|
import "./mesh.chunk-MCBMHWXP.js";
|
|
22
22
|
import "./mesh.chunk-WFFDF346.js";
|
|
23
23
|
import "./mesh.chunk-IQOBTL42.js";
|
|
24
|
-
import "./mesh.chunk-
|
|
24
|
+
import "./mesh.chunk-6SSOVZOI.js";
|
|
25
25
|
export {
|
|
26
26
|
REGISTRY_ALIAS,
|
|
27
27
|
REGISTRY_CREDENTIAL_KEY,
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
classifyMcpTools,
|
|
3
|
+
defaultServeDir,
|
|
4
|
+
generateMcpServeDir,
|
|
5
|
+
mcpAuthHeaders,
|
|
6
|
+
parseMcpToolSnapshot,
|
|
7
|
+
readMcpManifestFile
|
|
8
|
+
} from "./mesh.chunk-TDCH4SFQ.js";
|
|
9
|
+
import {
|
|
10
|
+
discoverStackExternalServices,
|
|
11
|
+
ensureAwsCredentialsForStack,
|
|
12
|
+
resolveExternalServiceScope
|
|
13
|
+
} from "./mesh.chunk-YE2WIY3Y.js";
|
|
14
|
+
import "./mesh.chunk-7HTKSUWR.js";
|
|
15
|
+
import "./mesh.chunk-2QIVBQX5.js";
|
|
16
|
+
import "./mesh.chunk-MCBMHWXP.js";
|
|
17
|
+
import {
|
|
18
|
+
logInfo
|
|
19
|
+
} from "./mesh.chunk-WFFDF346.js";
|
|
20
|
+
import "./mesh.chunk-IQOBTL42.js";
|
|
21
|
+
import "./mesh.chunk-6SSOVZOI.js";
|
|
22
|
+
|
|
23
|
+
// packages/mesh-cli/src/commands/mcp/review-command.ts
|
|
24
|
+
import { SSMClient } from "@aws-sdk/client-ssm";
|
|
25
|
+
import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
|
|
26
|
+
import confirm from "@inquirer/confirm";
|
|
27
|
+
|
|
28
|
+
// packages/mesh-cli/src/commands/mcp/review.ts
|
|
29
|
+
import * as fs from "node:fs";
|
|
30
|
+
function canonical(tool) {
|
|
31
|
+
return JSON.stringify(tool, Object.keys(tool).sort());
|
|
32
|
+
}
|
|
33
|
+
function describeChange(before, after) {
|
|
34
|
+
const parts = [];
|
|
35
|
+
if (before.description !== after.description) parts.push("description");
|
|
36
|
+
if (JSON.stringify(before.inputSchema) !== JSON.stringify(after.inputSchema))
|
|
37
|
+
parts.push("input schema");
|
|
38
|
+
if (JSON.stringify(before.outputSchema) !== JSON.stringify(after.outputSchema))
|
|
39
|
+
parts.push("output schema");
|
|
40
|
+
if (JSON.stringify(before.annotations) !== JSON.stringify(after.annotations))
|
|
41
|
+
parts.push("annotations (read/write classification)");
|
|
42
|
+
return parts.length > 0 ? parts.join(", ") : "other fields";
|
|
43
|
+
}
|
|
44
|
+
function diffSnapshot(current, fetched, enabledOps = [], classification = {}) {
|
|
45
|
+
const before = new Map(current.map((t) => [t.name, t]));
|
|
46
|
+
const after = new Map(fetched.map((t) => [t.name, t]));
|
|
47
|
+
const classified = {
|
|
48
|
+
...classifyMcpTools(current, classification),
|
|
49
|
+
...classifyMcpTools(fetched, classification)
|
|
50
|
+
};
|
|
51
|
+
const accessOf = (name) => {
|
|
52
|
+
const entry = classified[name];
|
|
53
|
+
return { access: entry.access, ...entry.suggested ? { suggested: entry.suggested } : {} };
|
|
54
|
+
};
|
|
55
|
+
const entries = [];
|
|
56
|
+
for (const tool of fetched) {
|
|
57
|
+
const prior = before.get(tool.name);
|
|
58
|
+
if (!prior) {
|
|
59
|
+
entries.push({ name: tool.name, status: "added", ...accessOf(tool.name) });
|
|
60
|
+
} else if (canonical(prior) !== canonical(tool)) {
|
|
61
|
+
entries.push({
|
|
62
|
+
name: tool.name,
|
|
63
|
+
status: "changed",
|
|
64
|
+
...accessOf(tool.name),
|
|
65
|
+
detail: describeChange(prior, tool)
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
entries.push({ name: tool.name, status: "unchanged", ...accessOf(tool.name) });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const tool of current) {
|
|
72
|
+
if (!after.has(tool.name)) {
|
|
73
|
+
entries.push({ name: tool.name, status: "removed", ...accessOf(tool.name) });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const pick = (status) => entries.filter((e) => e.status === status).map((e) => e.name);
|
|
77
|
+
const removed = pick("removed");
|
|
78
|
+
return {
|
|
79
|
+
entries,
|
|
80
|
+
added: pick("added"),
|
|
81
|
+
changed: pick("changed"),
|
|
82
|
+
removed,
|
|
83
|
+
removedEnabled: enabledOps.filter((op) => removed.includes(op)),
|
|
84
|
+
clean: pick("added").length === 0 && pick("changed").length === 0 && removed.length === 0,
|
|
85
|
+
next: [...fetched]
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function reviewMcpCatalog(opts) {
|
|
89
|
+
const loaded = readMcpManifestFile(opts.manifestPath);
|
|
90
|
+
const { manifest } = loaded;
|
|
91
|
+
const report = opts.report ?? ((line) => console.log(line));
|
|
92
|
+
const snapshotPath = loaded.toolsPath;
|
|
93
|
+
const headers = mcpAuthHeaders(manifest, opts.credentials);
|
|
94
|
+
const fetched = parseMcpToolSnapshot(
|
|
95
|
+
await opts.fetchTools({
|
|
96
|
+
serverUrl: manifest.serverUrl,
|
|
97
|
+
headers,
|
|
98
|
+
timeoutMs: manifest.timeoutMs ?? 3e4
|
|
99
|
+
}),
|
|
100
|
+
`${manifest.serverUrl} tools/list`
|
|
101
|
+
);
|
|
102
|
+
if (fetched.length === 0) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`${manifest.name}: the server answered tools/list with an empty catalog \u2014 refusing to replace a reviewed snapshot with nothing`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const enabled = manifest.enabledOps ?? loaded.tools.map((t) => t.name);
|
|
108
|
+
const diff = diffSnapshot(loaded.tools, fetched, enabled, manifest.classification ?? {});
|
|
109
|
+
report(`${manifest.name} \u2014 ${manifest.serverUrl}`);
|
|
110
|
+
report(` snapshot: ${snapshotPath}`);
|
|
111
|
+
for (const entry of diff.entries) {
|
|
112
|
+
const mark = entry.status === "added" ? "+" : entry.status === "removed" ? "-" : entry.status === "changed" ? "~" : " ";
|
|
113
|
+
const enabledMark = enabled.includes(entry.name) ? "enabled" : "not enabled";
|
|
114
|
+
const suggestion = entry.suggested ? ", vendor suggests read" : "";
|
|
115
|
+
report(
|
|
116
|
+
` ${mark} ${entry.name} [${entry.access}${suggestion}, ${enabledMark}]${entry.detail ? ` \u2014 ${entry.detail}` : ""}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
const suggestedReads = diff.entries.filter((entry) => entry.suggested === "read" && entry.status !== "removed").map((entry) => entry.name);
|
|
120
|
+
if (suggestedReads.length > 0) {
|
|
121
|
+
report(
|
|
122
|
+
` the vendor marks ${suggestedReads.join(", ")} read-only (readOnlyHint). They stay unknown and need approval until the manifest's "classification" names them "read".`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
if (diff.added.length > 0) {
|
|
126
|
+
report(
|
|
127
|
+
` ${diff.added.length} new upstream tool(s) will be recorded but NOT enabled: add them to enabledOps deliberately.`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
if (diff.removedEnabled.length > 0) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`${manifest.name}: the server no longer offers enabled operation(s) ${diff.removedEnabled.join(", ")} \u2014 remove them from enabledOps first, then re-review`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (diff.clean) {
|
|
136
|
+
report(" no changes \u2014 the reviewed snapshot still matches the server.");
|
|
137
|
+
return { diff, manifest, snapshotPath, written: false };
|
|
138
|
+
}
|
|
139
|
+
if (opts.dryRun) {
|
|
140
|
+
report(" --dry-run: nothing written.");
|
|
141
|
+
return { diff, manifest, snapshotPath, written: false };
|
|
142
|
+
}
|
|
143
|
+
const approved = opts.yes === true || await (opts.confirm ?? (async () => false))(`Write the new snapshot to ${snapshotPath}?`);
|
|
144
|
+
if (!approved) {
|
|
145
|
+
report(" not written.");
|
|
146
|
+
return { diff, manifest, snapshotPath, written: false };
|
|
147
|
+
}
|
|
148
|
+
fs.writeFileSync(snapshotPath, `${JSON.stringify(diff.next, null, 2)}
|
|
149
|
+
`);
|
|
150
|
+
report(` wrote ${diff.next.length} reviewed tool(s).`);
|
|
151
|
+
const serveDir = defaultServeDir(opts.manifestPath, manifest.name);
|
|
152
|
+
if (fs.existsSync(serveDir)) {
|
|
153
|
+
const generated = generateMcpServeDir(opts.manifestPath);
|
|
154
|
+
report(` regenerated ${generated.written.join(", ") || "nothing"} in ${generated.serveDir}.`);
|
|
155
|
+
} else {
|
|
156
|
+
report(` run \`mesh mcp generate ${opts.manifestPath}\` to write the worker package.`);
|
|
157
|
+
}
|
|
158
|
+
return { diff, manifest, snapshotPath, written: true };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// packages/mesh-cli/src/commands/mcp/review-command.ts
|
|
162
|
+
async function resolveIntegrationCredentials(name, opts, clients = {}) {
|
|
163
|
+
const region = opts.region ?? process.env.AWS_REGION ?? "us-east-2";
|
|
164
|
+
let secretId = opts.secret;
|
|
165
|
+
if (secretId) {
|
|
166
|
+
const ensure = clients.ensureCredentials ?? ensureAwsCredentialsForStack;
|
|
167
|
+
await ensure(resolveExternalServiceScope(opts).stack);
|
|
168
|
+
} else {
|
|
169
|
+
const { scope, services } = await discoverStackExternalServices(
|
|
170
|
+
opts,
|
|
171
|
+
clients.ssm ?? new SSMClient({ region }),
|
|
172
|
+
clients.ensureCredentials ? { ensureCredentials: clients.ensureCredentials } : {}
|
|
173
|
+
);
|
|
174
|
+
const service = services.get(name);
|
|
175
|
+
if (!service?.meta?.secretPrefix) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`No deployed ExternalService named "${name}" in ${scope.context.tenant}/${scope.platformEnv} (stack ${scope.stack ?? "unknown"}). Deploy the Integration first, or pass --secret <id>.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
secretId = service.meta.secretPrefix;
|
|
181
|
+
}
|
|
182
|
+
const response = await (clients.secretsManager ?? new SecretsManagerClient({ region })).send(
|
|
183
|
+
new GetSecretValueCommand({ SecretId: secretId })
|
|
184
|
+
);
|
|
185
|
+
if (!response.SecretString) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`The Integration credential at "${secretId}" is empty \u2014 populate it with \`mesh secrets set external/${name}\``
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return JSON.parse(response.SecretString);
|
|
191
|
+
}
|
|
192
|
+
var fetchMcpToolsOverHttp = async ({ serverUrl, headers, timeoutMs }) => {
|
|
193
|
+
const { Client, StreamableHTTPClientTransport } = await import("@modelcontextprotocol/client");
|
|
194
|
+
const client = new Client(
|
|
195
|
+
{ name: "mesh-mcp-review", version: "1.0.0" },
|
|
196
|
+
{ capabilities: {}, versionNegotiation: { mode: "auto" } }
|
|
197
|
+
);
|
|
198
|
+
const transport = new StreamableHTTPClientTransport(new URL(serverUrl), {
|
|
199
|
+
requestInit: { headers, redirect: "error" }
|
|
200
|
+
});
|
|
201
|
+
try {
|
|
202
|
+
await client.connect(transport, { timeout: timeoutMs });
|
|
203
|
+
const result = await client.listTools(void 0, { timeout: timeoutMs });
|
|
204
|
+
return result.tools;
|
|
205
|
+
} finally {
|
|
206
|
+
if (transport.sessionId) await transport.terminateSession().catch(() => {
|
|
207
|
+
});
|
|
208
|
+
await client.close().catch(() => {
|
|
209
|
+
});
|
|
210
|
+
await transport.close().catch(() => {
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
async function runMcpReviewCommand(manifestPath, opts) {
|
|
215
|
+
const { manifest } = readMcpManifestFile(manifestPath);
|
|
216
|
+
const credentials = manifest.auth.kind === "shared-header" ? await resolveIntegrationCredentials(manifest.name, opts) : {};
|
|
217
|
+
if (manifest.auth.kind === "none") {
|
|
218
|
+
logInfo(`${manifest.name} declares no authentication; connecting unauthenticated.`);
|
|
219
|
+
}
|
|
220
|
+
const result = await reviewMcpCatalog({
|
|
221
|
+
manifestPath,
|
|
222
|
+
credentials,
|
|
223
|
+
fetchTools: fetchMcpToolsOverHttp,
|
|
224
|
+
...opts.yes ? { yes: true } : {},
|
|
225
|
+
...opts.dryRun ? { dryRun: true } : {},
|
|
226
|
+
confirm: (question) => confirm({ message: question, default: false })
|
|
227
|
+
});
|
|
228
|
+
if (result.written) {
|
|
229
|
+
logInfo(
|
|
230
|
+
"Commit the snapshot with the regenerated worker package; McpIntegration refuses a package that does not match its manifest."
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export {
|
|
235
|
+
fetchMcpToolsOverHttp,
|
|
236
|
+
resolveIntegrationCredentials,
|
|
237
|
+
runMcpReviewCommand
|
|
238
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/mcp/review-command.ts", "../../src/commands/mcp/review.ts"],
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
reportAssembly,
|
|
5
5
|
resolveCliRuntime,
|
|
6
6
|
runAssemble
|
|
7
|
-
} from "./mesh.chunk-
|
|
7
|
+
} from "./mesh.chunk-PZVI7V3J.js";
|
|
8
8
|
import {
|
|
9
9
|
logError,
|
|
10
10
|
logInfo,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
homeNpmrcPath,
|
|
15
15
|
parseNpmrcRegistryAuth
|
|
16
|
-
} from "./mesh.chunk-
|
|
16
|
+
} from "./mesh.chunk-6SSOVZOI.js";
|
|
17
17
|
|
|
18
18
|
// packages/mesh-cli/src/docs/start.ts
|
|
19
19
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
@@ -2,24 +2,24 @@ import {
|
|
|
2
2
|
bootstrapAppsRepo,
|
|
3
3
|
isInsidePlatformMonorepo,
|
|
4
4
|
shouldBootstrapAppsRepo
|
|
5
|
-
} from "./mesh.chunk-
|
|
5
|
+
} from "./mesh.chunk-F44A3ACW.js";
|
|
6
6
|
import {
|
|
7
7
|
PLATFORM_SETUP_DEFAULTS,
|
|
8
8
|
ensureStateBucket,
|
|
9
9
|
renderPlatformNextSteps,
|
|
10
10
|
resolvePlatformSetup,
|
|
11
11
|
scaffoldPlatformRepo
|
|
12
|
-
} from "./mesh.chunk-
|
|
12
|
+
} from "./mesh.chunk-NSQJEX36.js";
|
|
13
13
|
import {
|
|
14
14
|
RegistryNotAuthorizedError
|
|
15
|
-
} from "./mesh.chunk-
|
|
15
|
+
} from "./mesh.chunk-6AIG5OJM.js";
|
|
16
16
|
import {
|
|
17
17
|
resolveTargetRoot,
|
|
18
18
|
syncSkills
|
|
19
19
|
} from "./mesh.chunk-F4654EPX.js";
|
|
20
20
|
import {
|
|
21
21
|
readRegistrySession
|
|
22
|
-
} from "./mesh.chunk-
|
|
22
|
+
} from "./mesh.chunk-HJGMOEUG.js";
|
|
23
23
|
import {
|
|
24
24
|
detectLocalTenant,
|
|
25
25
|
discoverConfigForContext,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
runLoginFlow,
|
|
32
32
|
tokenStillValid,
|
|
33
33
|
writeMeshJson
|
|
34
|
-
} from "./mesh.chunk-
|
|
34
|
+
} from "./mesh.chunk-7HTKSUWR.js";
|
|
35
35
|
import "./mesh.chunk-2QIVBQX5.js";
|
|
36
36
|
import "./mesh.chunk-MCBMHWXP.js";
|
|
37
37
|
import {
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
} from "./mesh.chunk-IQOBTL42.js";
|
|
45
45
|
import {
|
|
46
46
|
probeRegistryToken
|
|
47
|
-
} from "./mesh.chunk-
|
|
47
|
+
} from "./mesh.chunk-6SSOVZOI.js";
|
|
48
48
|
|
|
49
49
|
// packages/mesh-cli/src/commands/init/wizard.ts
|
|
50
50
|
import * as fs from "fs";
|
|
@@ -157,7 +157,7 @@ var registryStep = {
|
|
|
157
157
|
try {
|
|
158
158
|
logInfo(REGISTRY_WHY);
|
|
159
159
|
const login = ctx.seams?.runRegistryLogin ?? (async (opts) => {
|
|
160
|
-
const { runRegistryLogin } = await import("./mesh.registry-
|
|
160
|
+
const { runRegistryLogin } = await import("./mesh.registry-JLQYFUNN.js");
|
|
161
161
|
await runRegistryLogin(void 0, opts);
|
|
162
162
|
});
|
|
163
163
|
await login({ device: ctx.device, profile: ctx.profile });
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// packages/mesh-cli/src/commands/mcp/workspace-membership.ts
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
function findWorkspaceFile(from) {
|
|
6
|
+
let dir = from;
|
|
7
|
+
for (; ; ) {
|
|
8
|
+
const file = path.join(dir, "pnpm-workspace.yaml");
|
|
9
|
+
if (fs.existsSync(file)) return file;
|
|
10
|
+
const parent = path.dirname(dir);
|
|
11
|
+
if (parent === dir) return void 0;
|
|
12
|
+
dir = parent;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function segmentPattern(segment) {
|
|
16
|
+
const body = segment.split("").map(
|
|
17
|
+
(ch) => ch === "*" ? "[^/]*" : ch === "?" ? "[^/]" : ch.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
18
|
+
).join("");
|
|
19
|
+
return new RegExp(segment.startsWith(".") ? `^${body}$` : `^(?!\\.)${body}$`);
|
|
20
|
+
}
|
|
21
|
+
function matchSegments(pattern, target) {
|
|
22
|
+
if (pattern.length === 0) return target.length === 0;
|
|
23
|
+
const [head, ...rest] = pattern;
|
|
24
|
+
if (head === "**") {
|
|
25
|
+
for (let i = 0; i <= target.length; i++) {
|
|
26
|
+
if (target.slice(0, i).some((s) => s.startsWith("."))) break;
|
|
27
|
+
if (matchSegments(rest, target.slice(i))) return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (target.length === 0) return false;
|
|
32
|
+
return segmentPattern(head).test(target[0]) && matchSegments(rest, target.slice(1));
|
|
33
|
+
}
|
|
34
|
+
function matchesWorkspaceGlob(pattern, relDir) {
|
|
35
|
+
const clean = (p) => p.replace(/^\.\//, "").replace(/\/+$/, "").split("/").filter((s) => s.length > 0 && s !== ".");
|
|
36
|
+
return matchSegments(clean(pattern), clean(relDir.split(path.sep).join("/")));
|
|
37
|
+
}
|
|
38
|
+
function workspaceMembership(dir) {
|
|
39
|
+
const abs = path.resolve(dir);
|
|
40
|
+
const workspaceFile = findWorkspaceFile(abs);
|
|
41
|
+
if (!workspaceFile) return { member: false };
|
|
42
|
+
const root = path.dirname(workspaceFile);
|
|
43
|
+
const rel = path.relative(root, abs).split(path.sep).join("/");
|
|
44
|
+
const suggestedGlob = `${path.posix.dirname(rel)}/*`;
|
|
45
|
+
let globs;
|
|
46
|
+
try {
|
|
47
|
+
globs = parse(fs.readFileSync(workspaceFile, "utf8"))?.packages;
|
|
48
|
+
} catch {
|
|
49
|
+
return { workspaceFile, member: false, suggestedGlob };
|
|
50
|
+
}
|
|
51
|
+
let member = false;
|
|
52
|
+
for (const glob of Array.isArray(globs) ? globs : []) {
|
|
53
|
+
if (typeof glob !== "string") continue;
|
|
54
|
+
if (glob.startsWith("!")) {
|
|
55
|
+
if (matchesWorkspaceGlob(glob.slice(1), rel)) member = false;
|
|
56
|
+
} else if (matchesWorkspaceGlob(glob, rel)) {
|
|
57
|
+
member = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { workspaceFile, member, suggestedGlob };
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
matchesWorkspaceGlob,
|
|
64
|
+
workspaceMembership
|
|
65
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/mcp/workspace-membership.ts"],
|
|
4
|
+
"mappings": ";AASA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,aAAa;AAetB,SAAS,kBAAkB,MAAkC;AAC3D,MAAI,MAAM;AACV,aAAS;AACP,UAAM,OAAY,UAAK,KAAK,qBAAqB;AACjD,QAAO,cAAW,IAAI,EAAG,QAAO;AAChC,UAAM,SAAc,aAAQ,GAAG;AAC/B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAEA,SAAS,eAAe,SAAyB;AAC/C,QAAM,OAAO,QACV,MAAM,EAAE,EACR;AAAA,IAAI,CAAC,OACJ,OAAO,MAAM,UAAU,OAAO,MAAM,SAAS,GAAG,QAAQ,qBAAqB,MAAM;AAAA,EACrF,EACC,KAAK,EAAE;AAGV,SAAO,IAAI,OAAO,QAAQ,WAAW,GAAG,IAAI,IAAI,IAAI,MAAM,WAAW,IAAI,GAAG;AAC9E;AAEA,SAAS,cAAc,SAAmB,QAA2B;AACnE,MAAI,QAAQ,WAAW,EAAG,QAAO,OAAO,WAAW;AACnD,QAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AACxB,MAAI,SAAS,MAAM;AACjB,aAAS,IAAI,GAAG,KAAK,OAAO,QAAQ,KAAK;AACvC,UAAI,OAAO,MAAM,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,CAAC,EAAG;AACvD,UAAI,cAAc,MAAM,OAAO,MAAM,CAAC,CAAC,EAAG,QAAO;AAAA,IACnD;AACA,WAAO;AAAA,EACT;AACA,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,SAAO,eAAe,IAAK,EAAE,KAAK,OAAO,CAAC,CAAE,KAAK,cAAc,MAAM,OAAO,MAAM,CAAC,CAAC;AACtF;AAWO,SAAS,qBAAqB,SAAiB,QAAyB;AAC7E,QAAM,QAAQ,CAAC,MACb,EACG,QAAQ,SAAS,EAAE,EACnB,QAAQ,QAAQ,EAAE,EAClB,MAAM,GAAG,EACT,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,MAAM,GAAG;AAC5C,SAAO,cAAc,MAAM,OAAO,GAAG,MAAM,OAAO,MAAW,QAAG,EAAE,KAAK,GAAG,CAAC,CAAC;AAC9E;AAWO,SAAS,oBAAoB,KAAkC;AACpE,QAAM,MAAW,aAAQ,GAAG;AAC5B,QAAM,gBAAgB,kBAAkB,GAAG;AAC3C,MAAI,CAAC,cAAe,QAAO,EAAE,QAAQ,MAAM;AAC3C,QAAM,OAAY,aAAQ,aAAa;AACvC,QAAM,MAAW,cAAS,MAAM,GAAG,EAAE,MAAW,QAAG,EAAE,KAAK,GAAG;AAC7D,QAAM,gBAAgB,GAAQ,WAAM,QAAQ,GAAG,CAAC;AAChD,MAAI;AACJ,MAAI;AACF,YAAS,MAAS,gBAAa,eAAe,MAAM,CAAC,GACjD;AAAA,EACN,QAAQ;AACN,WAAO,EAAE,eAAe,QAAQ,OAAO,cAAc;AAAA,EACvD;AACA,MAAI,SAAS;AACb,aAAW,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,GAAG;AACpD,QAAI,OAAO,SAAS,SAAU;AAC9B,QAAI,KAAK,WAAW,GAAG,GAAG;AACxB,UAAI,qBAAqB,KAAK,MAAM,CAAC,GAAG,GAAG,EAAG,UAAS;AAAA,IACzD,WAAW,qBAAqB,MAAM,GAAG,GAAG;AAC1C,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO,EAAE,eAAe,QAAQ,cAAc;AAChD;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
package/dist/build-info.json
CHANGED
|
@@ -57,6 +57,28 @@ export declare function sharesWorktreeRoot(serviceSrc: string, repoRoot: string)
|
|
|
57
57
|
export type PortOwnership = "owned" | "foreign" | "dead";
|
|
58
58
|
export declare function classifyPortListener(listenerPid: number | null, sessionPids: ReadonlySet<number>): PortOwnership;
|
|
59
59
|
export declare function collectSessionPids(panePids: number[], psOut: string): Set<number>;
|
|
60
|
+
export type PaneLiveness = {
|
|
61
|
+
state: "running";
|
|
62
|
+
} | {
|
|
63
|
+
state: "exited";
|
|
64
|
+
exitCode: number | null;
|
|
65
|
+
lastActivityEpoch: number | null;
|
|
66
|
+
} | {
|
|
67
|
+
state: "unknown";
|
|
68
|
+
reason: string;
|
|
69
|
+
};
|
|
70
|
+
export type PaneProcessQuery = (command: string, args: string[]) => string;
|
|
71
|
+
export declare function paneProcessQuery(command: string, args: string[]): string;
|
|
72
|
+
export declare function listSessionWindowNames(sessionName: string, query: PaneProcessQuery): Set<string> | null;
|
|
73
|
+
export declare function classifyPaneLiveness(target: string, query: PaneProcessQuery): PaneLiveness;
|
|
74
|
+
export declare function classifySessionServices(sessionName: string, services: Record<string, {
|
|
75
|
+
command: string[];
|
|
76
|
+
}>, query: PaneProcessQuery): Map<string, PaneLiveness>;
|
|
77
|
+
export declare function describePaneExit(liveness: Extract<PaneLiveness, {
|
|
78
|
+
state: "exited";
|
|
79
|
+
}>): string;
|
|
80
|
+
export declare function servicesLivenessToResult(liveness: ReadonlyMap<string, PaneLiveness>): CheckResult;
|
|
81
|
+
export declare const servicesCheck: Check;
|
|
60
82
|
export declare const tmuxCheck: Check;
|
|
61
83
|
export declare const portsCheck: Check;
|
|
62
84
|
export declare function isConfigStale(configMtimeMs: number, startedAtIso: string): boolean;
|
|
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
|
|
5
5
|
import { isLinkedDependencyDir, isPortFree } from "./dev.js";
|
|
6
6
|
import { appUsesMeshPackages, probeRegistryToken, registryLoginFix, } from "../utils/auth-preflight.js";
|
|
7
7
|
import { probeCredentials, isRemoteEnvironment } from "./login.js";
|
|
8
|
+
import { envLeaksCheck } from "./dev-env-leaks.js";
|
|
8
9
|
export function aggregateStatus(results) {
|
|
9
10
|
if (results.some((r) => r.status === "error"))
|
|
10
11
|
return "error";
|
|
@@ -262,6 +263,152 @@ function sessionProcessTree(sessionName) {
|
|
|
262
263
|
}
|
|
263
264
|
return collectSessionPids(panePids, psOut);
|
|
264
265
|
}
|
|
266
|
+
export function paneProcessQuery(command, args) {
|
|
267
|
+
return execFileSync(command, args, {
|
|
268
|
+
encoding: "utf8",
|
|
269
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
export function listSessionWindowNames(sessionName, query) {
|
|
273
|
+
try {
|
|
274
|
+
const raw = query("tmux", ["list-windows", "-t", sessionName, "-F", "#{window_name}"]);
|
|
275
|
+
return new Set(raw
|
|
276
|
+
.trim()
|
|
277
|
+
.split("\n")
|
|
278
|
+
.map((line) => line.trim())
|
|
279
|
+
.filter(Boolean));
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function parseOptionalNumber(field) {
|
|
286
|
+
if (field === undefined || field === "")
|
|
287
|
+
return null;
|
|
288
|
+
const n = Number(field);
|
|
289
|
+
return Number.isFinite(n) ? n : null;
|
|
290
|
+
}
|
|
291
|
+
export function classifyPaneLiveness(target, query) {
|
|
292
|
+
let raw;
|
|
293
|
+
try {
|
|
294
|
+
raw = query("tmux", [
|
|
295
|
+
"display",
|
|
296
|
+
"-p",
|
|
297
|
+
"-t",
|
|
298
|
+
target,
|
|
299
|
+
"#{pane_dead}|#{pane_dead_status}|#{pane_pid}|#{window_activity}",
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return { state: "unknown", reason: `tmux could not report the pane at '${target}'` };
|
|
304
|
+
}
|
|
305
|
+
const [dead, deadStatus, pidStr, activityStr] = raw.trim().split("|");
|
|
306
|
+
const lastActivityEpoch = parseOptionalNumber(activityStr);
|
|
307
|
+
if (dead === "1") {
|
|
308
|
+
return { state: "exited", exitCode: parseOptionalNumber(deadStatus), lastActivityEpoch };
|
|
309
|
+
}
|
|
310
|
+
const pid = Number(pidStr);
|
|
311
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
312
|
+
return { state: "unknown", reason: `tmux reported no pane pid for '${target}'` };
|
|
313
|
+
}
|
|
314
|
+
let psOut;
|
|
315
|
+
try {
|
|
316
|
+
psOut = query("ps", ["-eo", "pid=,ppid="]);
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
return paneChildrenViaPgrep(pid, lastActivityEpoch, query);
|
|
320
|
+
}
|
|
321
|
+
return collectSessionPids([pid], psOut).size > 1
|
|
322
|
+
? { state: "running" }
|
|
323
|
+
: { state: "exited", exitCode: null, lastActivityEpoch };
|
|
324
|
+
}
|
|
325
|
+
function paneChildrenViaPgrep(pid, lastActivityEpoch, query) {
|
|
326
|
+
try {
|
|
327
|
+
return query("pgrep", ["-P", String(pid)]).trim().length > 0
|
|
328
|
+
? { state: "running" }
|
|
329
|
+
: { state: "exited", exitCode: null, lastActivityEpoch };
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
if (err.status === 1) {
|
|
333
|
+
return { state: "exited", exitCode: null, lastActivityEpoch };
|
|
334
|
+
}
|
|
335
|
+
return { state: "unknown", reason: "could not read the process table (ps, pgrep)" };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
export function classifySessionServices(sessionName, services, query) {
|
|
339
|
+
const windows = listSessionWindowNames(sessionName, query);
|
|
340
|
+
const result = new Map();
|
|
341
|
+
for (const [name, svc] of Object.entries(services)) {
|
|
342
|
+
if (!svc.command || svc.command.length === 0)
|
|
343
|
+
continue;
|
|
344
|
+
if (windows === null) {
|
|
345
|
+
result.set(name, {
|
|
346
|
+
state: "unknown",
|
|
347
|
+
reason: `could not list the windows of session '${sessionName}' (tmux)`,
|
|
348
|
+
});
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (!windows.has(name)) {
|
|
352
|
+
result.set(name, { state: "exited", exitCode: null, lastActivityEpoch: null });
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
result.set(name, classifyPaneLiveness(`${sessionName}:${name}`, query));
|
|
356
|
+
}
|
|
357
|
+
return result;
|
|
358
|
+
}
|
|
359
|
+
export function describePaneExit(liveness) {
|
|
360
|
+
if (liveness.exitCode !== null)
|
|
361
|
+
return `exit ${liveness.exitCode}`;
|
|
362
|
+
if (liveness.lastActivityEpoch !== null) {
|
|
363
|
+
return `no live process (last output ${new Date(liveness.lastActivityEpoch * 1000).toISOString()})`;
|
|
364
|
+
}
|
|
365
|
+
return "no live process";
|
|
366
|
+
}
|
|
367
|
+
export function servicesLivenessToResult(liveness) {
|
|
368
|
+
const total = liveness.size;
|
|
369
|
+
const dead = [];
|
|
370
|
+
const unknown = [];
|
|
371
|
+
for (const [name, l] of liveness.entries()) {
|
|
372
|
+
if (l.state === "exited")
|
|
373
|
+
dead.push([name, l]);
|
|
374
|
+
else if (l.state === "unknown")
|
|
375
|
+
unknown.push([name, l]);
|
|
376
|
+
}
|
|
377
|
+
if (dead.length === 0 && unknown.length === 0) {
|
|
378
|
+
return { status: "ok", summary: `all ${total} service process(es) running` };
|
|
379
|
+
}
|
|
380
|
+
if (dead.length > 0) {
|
|
381
|
+
return {
|
|
382
|
+
status: "error",
|
|
383
|
+
summary: `${dead.length} of ${total} service process(es) not running`,
|
|
384
|
+
detail: dead.map(([name, l]) => `${name} — ${describePaneExit(l)}`).join("; "),
|
|
385
|
+
remediation: dead.length === 1
|
|
386
|
+
? `mesh dev logs ${dead[0][0]}`
|
|
387
|
+
: "mesh dev logs <svc> for each service above, then mesh dev restart <svc>",
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
status: "warn",
|
|
392
|
+
summary: `could not determine liveness for ${unknown.length} of ${total} service(s)`,
|
|
393
|
+
detail: unknown.map(([name, l]) => `${name} — ${l.reason}`).join("; "),
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
export const servicesCheck = {
|
|
397
|
+
id: "services",
|
|
398
|
+
title: "Service processes",
|
|
399
|
+
phases: ["ondemand"],
|
|
400
|
+
async run(ctx) {
|
|
401
|
+
const services = ctx.sessionState?.devOutput.services;
|
|
402
|
+
if (!services || Object.keys(services).length === 0) {
|
|
403
|
+
return { status: "ok", summary: "no session — services start at launch" };
|
|
404
|
+
}
|
|
405
|
+
const liveness = classifySessionServices(ctx.sessionName, services, paneProcessQuery);
|
|
406
|
+
if (liveness.size === 0) {
|
|
407
|
+
return { status: "ok", summary: "no locally-run services in this session" };
|
|
408
|
+
}
|
|
409
|
+
return servicesLivenessToResult(liveness);
|
|
410
|
+
},
|
|
411
|
+
};
|
|
265
412
|
export const tmuxCheck = {
|
|
266
413
|
id: "tmux",
|
|
267
414
|
title: "tmux",
|
|
@@ -533,9 +680,11 @@ export const ALL_CHECKS = [
|
|
|
533
680
|
registryCheck,
|
|
534
681
|
configStalenessCheck,
|
|
535
682
|
portsCheck,
|
|
683
|
+
servicesCheck,
|
|
536
684
|
worktreeCheck,
|
|
537
685
|
tunnelsCheck,
|
|
538
686
|
temporalCheck,
|
|
687
|
+
envLeaksCheck,
|
|
539
688
|
];
|
|
540
689
|
export async function runDoctor(ctx, opts) {
|
|
541
690
|
const results = await runChecks(ctx, "ondemand", ALL_CHECKS);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Check } from "./dev-doctor.js";
|
|
2
|
+
export declare const LEAK_NAME_PATTERNS: ReadonlyArray<RegExp>;
|
|
3
|
+
export declare function matchesLeakPattern(name: string): boolean;
|
|
4
|
+
export declare function parseTmuxEnvironment(text: string): Record<string, string>;
|
|
5
|
+
export type LeakSource = "tmux-global" | "shell";
|
|
6
|
+
export type LeakFate = "reaches" | "shadowed" | "dropped" | "partial";
|
|
7
|
+
export interface LeakCandidate {
|
|
8
|
+
name: string;
|
|
9
|
+
sources: LeakSource[];
|
|
10
|
+
fate: LeakFate;
|
|
11
|
+
shadowedIn: string[];
|
|
12
|
+
unshadowedIn: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface ClassifyInput {
|
|
15
|
+
tmuxGlobal: Record<string, string>;
|
|
16
|
+
shell: Record<string, string | undefined>;
|
|
17
|
+
envFileKeysByService: Record<string, string[]>;
|
|
18
|
+
cleanLaunch: boolean | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function classifyLeak(name: string, envFileKeysByService: Record<string, string[]>, cleanLaunch: boolean | null): Pick<LeakCandidate, "fate" | "shadowedIn" | "unshadowedIn">;
|
|
21
|
+
export declare function collectLeakCandidates(input: ClassifyInput): LeakCandidate[];
|
|
22
|
+
export declare function redactValue(value: string): string;
|
|
23
|
+
export declare function renderLeakLines(candidates: LeakCandidate[], input: ClassifyInput): string[];
|
|
24
|
+
export declare const envLeaksCheck: Check;
|