@mesh-tech/mesh-cli 0.43.2 → 0.44.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/assets/app-skill/SKILL.md +8 -1
- package/dist/bin/{mesh.chunk-OOWKJR4H.js → mesh.chunk-OQA2UBOD.js} +1 -1
- package/dist/bin/{mesh.chunk-VCQKLVZJ.js → mesh.chunk-XOCERV6F.js} +53 -41
- package/dist/bin/{mesh.chunk-VCQKLVZJ.js.map → mesh.chunk-XOCERV6F.js.map} +1 -1
- package/dist/bin/mesh.js +2 -2
- package/dist/bin/{mesh.program-GEKNV2LY.js → mesh.program-NOBVA3JS.js} +2 -2
- package/dist/bin/{mesh.start-HE6P3TCS.js → mesh.start-JDSYIRZI.js} +1 -1
- package/dist/build-info.json +2 -2
- package/dist/src/commands/workflow.d.ts +14 -0
- package/dist/src/commands/workflow.js +43 -31
- package/package.json +2 -2
- package/skills/mesh/SKILL.md +2 -2
- /package/dist/bin/{mesh.chunk-OOWKJR4H.js.map → mesh.chunk-OQA2UBOD.js.map} +0 -0
- /package/dist/bin/{mesh.program-GEKNV2LY.js.map → mesh.program-NOBVA3JS.js.map} +0 -0
- /package/dist/bin/{mesh.start-HE6P3TCS.js.map → mesh.start-JDSYIRZI.js.map} +0 -0
package/dist/bin/mesh.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createProgram
|
|
4
|
-
} from "./mesh.chunk-
|
|
4
|
+
} from "./mesh.chunk-XOCERV6F.js";
|
|
5
5
|
import "./mesh.chunk-QUKWWFZI.js";
|
|
6
6
|
import {
|
|
7
7
|
formatVersionLine,
|
|
8
8
|
resolveCliRuntime
|
|
9
|
-
} from "./mesh.chunk-
|
|
9
|
+
} from "./mesh.chunk-OQA2UBOD.js";
|
|
10
10
|
import "./mesh.chunk-QE5LUIHN.js";
|
|
11
11
|
import "./mesh.chunk-ZNM3DDAM.js";
|
|
12
12
|
import "./mesh.chunk-PANTMVC3.js";
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
CLI_DESCRIPTION,
|
|
3
3
|
CLI_NAME,
|
|
4
4
|
createProgram
|
|
5
|
-
} from "./mesh.chunk-
|
|
5
|
+
} from "./mesh.chunk-XOCERV6F.js";
|
|
6
6
|
import "./mesh.chunk-QUKWWFZI.js";
|
|
7
|
-
import "./mesh.chunk-
|
|
7
|
+
import "./mesh.chunk-OQA2UBOD.js";
|
|
8
8
|
import "./mesh.chunk-QE5LUIHN.js";
|
|
9
9
|
import "./mesh.chunk-ZNM3DDAM.js";
|
|
10
10
|
import "./mesh.chunk-PANTMVC3.js";
|
package/dist/build-info.json
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
interface ExtractedWorkflow {
|
|
3
|
+
workflowType: string;
|
|
4
|
+
ir: {
|
|
5
|
+
name: string;
|
|
6
|
+
nodes: unknown[];
|
|
7
|
+
edges: unknown[];
|
|
8
|
+
};
|
|
9
|
+
sourceFile: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function workflowIrFiles(appName: string, workflows: ExtractedWorkflow[], root: string): {
|
|
12
|
+
name: string;
|
|
13
|
+
body: string;
|
|
14
|
+
}[];
|
|
2
15
|
export declare function registerWorkflowCommands(program: Command): void;
|
|
16
|
+
export {};
|
|
@@ -123,7 +123,7 @@ const target = ${JSON.stringify(targetPath)};
|
|
|
123
123
|
const explicitProcessArtifact = ${JSON.stringify(explicitProcessArtifact ?? null)};
|
|
124
124
|
const stat = statSync(target);
|
|
125
125
|
const files = stat.isDirectory()
|
|
126
|
-
? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts").map(f => join(target, f))
|
|
126
|
+
? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts" && !/\\.(test|spec|d)\\.ts$/.test(f)).map(f => join(target, f))
|
|
127
127
|
: [target];
|
|
128
128
|
|
|
129
129
|
const results = [];
|
|
@@ -168,7 +168,7 @@ ${DISCOVERY_HELPERS_SRC}
|
|
|
168
168
|
const target = ${JSON.stringify(targetPath)};
|
|
169
169
|
const stat = statSync(target);
|
|
170
170
|
const files = stat.isDirectory()
|
|
171
|
-
? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts").map(f => join(target, f))
|
|
171
|
+
? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts" && !/\\.(test|spec|d)\\.ts$/.test(f)).map(f => join(target, f))
|
|
172
172
|
: [target];
|
|
173
173
|
|
|
174
174
|
const results = [];
|
|
@@ -220,7 +220,7 @@ const target = ${JSON.stringify(targetPath)};
|
|
|
220
220
|
const explicitProcessArtifact = ${JSON.stringify(explicitProcessArtifact ?? null)};
|
|
221
221
|
const stat = statSync(target);
|
|
222
222
|
const files = stat.isDirectory()
|
|
223
|
-
? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts").map(f => join(target, f))
|
|
223
|
+
? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts" && !/\\.(test|spec|d)\\.ts$/.test(f)).map(f => join(target, f))
|
|
224
224
|
: [target];
|
|
225
225
|
|
|
226
226
|
const results = [];
|
|
@@ -253,40 +253,37 @@ process.stdout.write(JSON.stringify(results));
|
|
|
253
253
|
return null;
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
const { S3Client, PutObjectCommand } = await import("@aws-sdk/client-s3");
|
|
258
|
-
const s3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-2" });
|
|
259
|
-
for (const wf of workflows) {
|
|
260
|
-
const key = `workflow-ir/${appName}/${wf.workflowType}.json`;
|
|
261
|
-
const body = JSON.stringify(wf.ir, null, 2);
|
|
262
|
-
logInfo(` Uploading s3://${bucket}/${key} (${body.length} bytes)`);
|
|
263
|
-
await s3.send(new PutObjectCommand({
|
|
264
|
-
Bucket: bucket,
|
|
265
|
-
Key: key,
|
|
266
|
-
Body: body,
|
|
267
|
-
ContentType: "application/json",
|
|
268
|
-
}));
|
|
269
|
-
}
|
|
256
|
+
export function workflowIrFiles(appName, workflows, root) {
|
|
270
257
|
const manifest = {
|
|
271
258
|
extractedAt: new Date().toISOString(),
|
|
272
259
|
app: appName,
|
|
273
260
|
workflows: Object.fromEntries(workflows.map((wf) => [
|
|
274
261
|
wf.workflowType,
|
|
275
262
|
{
|
|
276
|
-
sourceFile: wf.sourceFile,
|
|
263
|
+
sourceFile: path.relative(root, wf.sourceFile) || path.basename(wf.sourceFile),
|
|
277
264
|
nodeCount: wf.ir.nodes.length,
|
|
278
265
|
edgeCount: wf.ir.edges.length,
|
|
279
266
|
},
|
|
280
267
|
])),
|
|
281
268
|
};
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
})
|
|
269
|
+
return [
|
|
270
|
+
...workflows.map((wf) => ({ name: `${wf.workflowType}.json`, body: JSON.stringify(wf.ir, null, 2) })),
|
|
271
|
+
{ name: "_manifest.json", body: JSON.stringify(manifest, null, 2) },
|
|
272
|
+
];
|
|
273
|
+
}
|
|
274
|
+
async function uploadToS3(bucket, appName, files) {
|
|
275
|
+
const { S3Client, PutObjectCommand } = await import("@aws-sdk/client-s3");
|
|
276
|
+
const s3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-2", followRegionRedirects: true });
|
|
277
|
+
for (const file of files) {
|
|
278
|
+
const key = `workflow-ir/${appName}/${file.name}`;
|
|
279
|
+
logInfo(` Uploading s3://${bucket}/${key} (${file.body.length} bytes)`);
|
|
280
|
+
await s3.send(new PutObjectCommand({
|
|
281
|
+
Bucket: bucket,
|
|
282
|
+
Key: key,
|
|
283
|
+
Body: file.body,
|
|
284
|
+
ContentType: "application/json",
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
290
287
|
}
|
|
291
288
|
function parseNameList(value) {
|
|
292
289
|
return value
|
|
@@ -307,6 +304,7 @@ export function registerWorkflowCommands(program) {
|
|
|
307
304
|
"Supports single files or directories.")
|
|
308
305
|
.option("--app <name>", "Application name (used as S3 key prefix)")
|
|
309
306
|
.option("--upload <bucket>", "S3 bucket to upload extracted IR (requires --app)")
|
|
307
|
+
.option("--out <dir>", "Write the files the upload would write (one JSON per workflow type, plus _manifest.json) to a directory (requires --app)")
|
|
310
308
|
.option("--process <path>", "Path to a process artifact JSON file (docs/plans/2026-07-05-process-artifact-design.md §1); " +
|
|
311
309
|
"renders substeps/actors/outcomes in place of a BUSINESS_STAGES map. Absent this flag, a sibling " +
|
|
312
310
|
"process/*.process.json is auto-discovered per workflow file.")
|
|
@@ -346,15 +344,29 @@ export function registerWorkflowCommands(program) {
|
|
|
346
344
|
for (const wf of results) {
|
|
347
345
|
logSuccess(` ${wf.workflowType} (${wf.ir.nodes.length} nodes, ${wf.ir.edges.length} edges)`);
|
|
348
346
|
}
|
|
349
|
-
if (opts.upload && opts.app) {
|
|
347
|
+
if ((opts.upload || opts.out) && !opts.app) {
|
|
348
|
+
logError("--upload and --out need --app (the IR's key prefix)");
|
|
349
|
+
process.exitCode = 1;
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const root = fs.statSync(resolvedPath).isDirectory() ? resolvedPath : path.dirname(resolvedPath);
|
|
353
|
+
const files = opts.app ? workflowIrFiles(opts.app, results, root) : [];
|
|
354
|
+
if (opts.out) {
|
|
355
|
+
const outDir = path.resolve(opts.out);
|
|
356
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
357
|
+
for (const file of files)
|
|
358
|
+
fs.writeFileSync(path.join(outDir, file.name), file.body);
|
|
359
|
+
logSuccess(`Wrote ${files.length} file(s) to ${outDir}`);
|
|
360
|
+
}
|
|
361
|
+
if (opts.upload) {
|
|
350
362
|
logInfo(`Uploading ${results.length} workflow IR(s) to s3://${opts.upload}/workflow-ir/${opts.app}/`);
|
|
351
|
-
await uploadToS3(opts.upload, opts.app,
|
|
363
|
+
await uploadToS3(opts.upload, opts.app, files);
|
|
352
364
|
logSuccess("Upload complete");
|
|
353
365
|
}
|
|
354
|
-
else if (opts.
|
|
355
|
-
logWarn("
|
|
366
|
+
else if (opts.app && !opts.out) {
|
|
367
|
+
logWarn("--app does nothing without --upload or --out");
|
|
356
368
|
}
|
|
357
|
-
|
|
369
|
+
if (!opts.upload && !opts.out) {
|
|
358
370
|
console.log(JSON.stringify(results.map((r) => r.ir), null, 2));
|
|
359
371
|
}
|
|
360
372
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mesh-tech/mesh-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "CLI for Mesh platform development utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@mesh-tech/agent-contracts": "0.7.0",
|
|
45
|
-
"@mesh-tech/tsconfig": "2.
|
|
45
|
+
"@mesh-tech/tsconfig": "2.62.0",
|
|
46
46
|
"@mesh-tech/workflow-viz": "0.3.4",
|
|
47
47
|
"@tanstack/intent": "^0.3.6",
|
|
48
48
|
"@types/node": "^20.0.0",
|
package/skills/mesh/SKILL.md
CHANGED
|
@@ -191,7 +191,7 @@ Top-level commands (each `register*` is wired in `src/program.ts`, which `bin/me
|
|
|
191
191
|
| `mesh artifacts` | `get <ref>` | Download workflow artifact files from an AI-agent conversation. Ref `<conversationId>:<artifactId>` (artifactId defaults to `workflow-artifact`). | `-o/--output <dir>`, `--target <name>`, `--api-url <url>`, `--context <ctx>` (default `mesh.dev`) |
|
|
192
192
|
| `mesh conversations` (alias `conv`) | `list`, `show <id>`, `artifacts <id>` | Read a deployed Mesh agent's conversations: list the caller's conversations, render a transcript, or list a conversation's artifacts. Resolves against the same `agent-targets` registry the MCP `agent_*` tools use. | all three: `--target <name>`, `--api-url <url>` (overrides `--target`), `--context <ctx>` (used with `--api-url`, default `mesh.dev`), `--json` (default when stdout isn't a TTY) |
|
|
193
193
|
| `mesh vpn` | `connect <context>`, `disconnect`, `status`, `tunnel <up\|down\|status>`, `api-key`, `pre-auth-key`, `users` | Headscale VPN mgmt via Tailscale + kubectl. **`connect` now defaults to the userspace `tailscaled`** (brew formula, NOT the GUI Tailscale.app) — the same daemon `mesh dev --transport tailscale` / `mesh vpn tunnel` use, so it **runs headless / under the sandbox** and exposes a local SOCKS5 proxy (route a tool via `ALL_PROXY=socks5://127.0.0.1:<port>`). It relays a one-time browser-register URL for Zitadel auth. `--system` opts into the whole-machine GUI Tailscale.app (system TUN) — needs the app installed and **cannot run headless/sandboxed** (Sparkle.framework abort). For auto-forwarded VPC services (Temporal/RDS) prefer **`mesh vpn tunnel up`** or `mesh dev`. `tunnel status` reports runner **ownership** (`Runner: owned (verified)` vs `NOT OWNED (<reason>)` — a port answering a dial is not proof it's mesh's); `--json` adds `owned` (bool) + `ownership` (reason string). Admin subcommands `exec` into the `headscale-0` pod. | root: `-t/--tenant` (default `mesh`), `-e/--env` (default `dev`), `-n/--namespace`; `connect`/`disconnect`: `--system`; `tunnel up`: `--context <ctx>`; `tunnel down`: `--stop` (stop daemon, keep login), `--logout`; `tunnel status`: `--json`; `pre-auth-key`: `-u/--user` (**required**), `--expiration <24h>`, `--reusable`, `--ephemeral` |
|
|
194
|
-
| `mesh workflow` | `extract-ir <path>`, `inventory <path>`, `lint-process <path>` | `extract-ir`: parse Temporal workflow TS source → WorkflowIR graph (nodes+edges); prints JSON or
|
|
194
|
+
| `mesh workflow` | `extract-ir <path>`, `inventory <path>`, `lint-process <path>` | `extract-ir`: parse Temporal workflow TS source → WorkflowIR graph (nodes+edges); prints JSON, uploads to S3, or writes the same files to a directory (so a package can ship IR it extracted at build time). A directory's `*.test.ts`/`*.spec.ts`/`*.d.ts` files are skipped. `inventory`: the as-built `{workflowType, commands, queries, activities}` the process lint diffs against. `lint-process`: parse + conformance-lint a process artifact against that inventory; exits 1 on any error-severity finding. | `extract-ir`: `--app <name>`, `--upload <bucket>`, `--out <dir>` (`--upload` and `--out` each need `--app`); `extract-ir`/`lint-process`: `--process <path>` (else a sibling `process/*.process.json` is discovered); `lint-process`: `--predicates <csv>`, `--selectors <csv>` — the CLI cannot execute the worker's registries, so without a flag those findings are skipped (a note is printed) while every other rule still runs |
|
|
195
195
|
| `mesh site` | `publish <name> <dir>`, `versions <name>`, `rollback <name> <version>` | Publish a built directory as an OAuth-protected static site served by Studio, content-addressed and incremental: `publish` walks and hashes the tree, uploads only the blobs the site does not already hold, then commits a version and points the site at it; `versions` lists what has been published, newest first; `rollback` points the site back at an earlier version. Three stateless calls against the agent-api, so a run that dies partway leaves nothing to clean up. | all: `--target <name>`, `--api-url <url>`, `--context <ctx>`; `publish`: `--version-id <id>`, `--no-activate` (publish without pointing the site at it) |
|
|
196
196
|
| `mesh vcs` | `clone <repo> [dest]`, `get <repo> <path>`, `propose`, `rm <repo> <paths...>`, `proposals`/`show`/`diff`/`approve`/`reject`/`comment`/`request-changes`, `drafts <list\|show\|create\|submit\|discard>` | Versioned content repos (`mesh.vcs`). Repos are real git repos over smart HTTP but **read-only** — every change goes through a proposal. `clone` wires the bearer auth header into the clone; `propose` submits the working tree (binary content is base64-encoded from the bytes, not the extension, so images survive intact); **`rm` proposes deletions of files or folders with no clone at all**, and `--dry-run` lists what would go without proposing anything. | all: `--url <base>`, `--token <t>`, `--context <ctx>`; `propose`: `-m/--message`, `--revise <id>`, `--merge-parent <sha>`; `rm`: `-m/--message`, `--dry-run` |
|
|
197
197
|
| `mesh temporal` | `describe <wfId> [runId]`, `history <wfId> [runId]`, `recover-conversation <wfId> [runId]`, `capture-history <wfId> [runId]` | Inspect Temporal workflows for the current app/stack; reconstruct an agent conversation transcript from durable history when the worker can't replay it; capture a full history to a local replay fixture. | shared: `--stack`, `--address`, `--namespace`; `history`: `-n/--limit <200>`, `-f/--follow`, `--no-compact`, `-p/--show-payloads` (decrypts via `TEMPORAL_ENCODING_KEY` from the K8s secret); `recover-conversation`: `--out <path>`, `--json`, `--snapshot` (structured `{conversationId,messages,artifacts,focus}` blob); `capture-history`: `--out <path>` (default `~/.mesh/replay-histories/<wfId>.json`, do not commit) | <!-- skill-lint-disable-next-line — row documents the mesh-owned kubectl wrappers; the backticked `aws eks get-token` describes what the CLI runs internally, not an operator step -->
|
|
@@ -483,7 +483,7 @@ the program (…); run `mesh deploy up --stack <s>` to refresh the dev env.").
|
|
|
483
483
|
| 401 installing a **public** package (`npm view lodash version` fails) | an unscoped `registry=<codeartifact>` line in `~/.npmrc` makes CodeArtifact the DEFAULT registry, so public packages resolve through it and 401 at the 12h token expiry | `mesh registry login` — it removes the line after backing `~/.npmrc` up; confirm with `npm config get registry` (expect `https://registry.npmjs.org/`) |
|
|
484
484
|
| `--export` prints nothing | no role resolved | pass `--role <arn>` or set `MESH_AWS_ROLE` |
|
|
485
485
|
| `--export` / `EPERM … ~/.aws` in a sandbox | `~/.aws` not writable | it now auto-falls back to a mesh-managed config (`~/.config/mesh/aws-config`) and also exports `AWS_CONFIG_FILE`; or prefer `mesh deploy <op>` (no shell profile needed) |
|
|
486
|
-
| `workflow extract-ir`
|
|
486
|
+
| `workflow extract-ir` exits 1: `--upload and --out need --app` | `--upload` or `--out` without `--app` | add `--app <name>`; `--app` alone only prints JSON |
|
|
487
487
|
|
|
488
488
|
## Programmatic API
|
|
489
489
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|