mimetic-cli 0.1.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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/dist/argv.d.ts +1 -0
  4. package/dist/argv.js +8 -0
  5. package/dist/argv.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +5 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/feedback.d.ts +48 -0
  10. package/dist/feedback.js +243 -0
  11. package/dist/feedback.js.map +1 -0
  12. package/dist/index.d.ts +15 -0
  13. package/dist/index.js +9 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/init-templates.d.ts +12 -0
  16. package/dist/init-templates.js +251 -0
  17. package/dist/init-templates.js.map +1 -0
  18. package/dist/init.d.ts +26 -0
  19. package/dist/init.js +343 -0
  20. package/dist/init.js.map +1 -0
  21. package/dist/observer-assets.d.ts +2 -0
  22. package/dist/observer-assets.js +2322 -0
  23. package/dist/observer-assets.js.map +1 -0
  24. package/dist/observer-data.d.ts +53 -0
  25. package/dist/observer-data.js +123 -0
  26. package/dist/observer-data.js.map +1 -0
  27. package/dist/observer.d.ts +36 -0
  28. package/dist/observer.js +360 -0
  29. package/dist/observer.js.map +1 -0
  30. package/dist/oss-lab.d.ts +50 -0
  31. package/dist/oss-lab.js +298 -0
  32. package/dist/oss-lab.js.map +1 -0
  33. package/dist/oss-meta-lab.d.ts +43 -0
  34. package/dist/oss-meta-lab.js +901 -0
  35. package/dist/oss-meta-lab.js.map +1 -0
  36. package/dist/program.d.ts +36 -0
  37. package/dist/program.js +825 -0
  38. package/dist/program.js.map +1 -0
  39. package/dist/run.d.ts +206 -0
  40. package/dist/run.js +688 -0
  41. package/dist/run.js.map +1 -0
  42. package/package.json +78 -0
  43. package/skills/mimetic-cli/SKILL.md +92 -0
  44. package/skills/mimetic-cli/agents/openai.yaml +7 -0
@@ -0,0 +1,825 @@
1
+ import { Command, Option } from "commander";
2
+ import { draftFeedback, listFeedback, renderIssueMarkdown, renderIssueUrl, verifyFeedback } from "./feedback.js";
3
+ import { runInit } from "./init.js";
4
+ import { renderObserver, serveObserver } from "./observer.js";
5
+ import { DEFAULT_OSS_REPOS, runOssLab } from "./oss-lab.js";
6
+ import { runOssMetaLab } from "./oss-meta-lab.js";
7
+ import { doctor, listRuns, readReview, runDryRun, verifyRun } from "./run.js";
8
+ export const CLI_RESPONSE_SCHEMA = "mimetic.cli-response.v1";
9
+ const defaultIo = {
10
+ writeOut: (text) => process.stdout.write(text),
11
+ writeErr: (text) => process.stderr.write(text),
12
+ setExitCode: (code) => {
13
+ process.exitCode = code;
14
+ }
15
+ };
16
+ const commonDocs = [
17
+ "docs/product/open-source-install-experience.md",
18
+ "docs/roadmap/world-class-open-source-v0.md",
19
+ "docs/release/open-source-readiness.md"
20
+ ];
21
+ export const plannedCommands = [
22
+ {
23
+ name: "init",
24
+ description: "Set up committed mimetic/ source files and ignored .mimetic/ runtime state.",
25
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/14",
26
+ docs: ["docs/architecture/project-layout.md", ...commonDocs],
27
+ options: [
28
+ { flags: "--dry-run", description: "Print planned changes without writing files." },
29
+ { flags: "--yes", description: "Apply safe generated changes without prompting." },
30
+ { flags: "--cwd <path>", description: "Target project directory.", defaultValue: "." }
31
+ ]
32
+ },
33
+ {
34
+ name: "doctor",
35
+ description: "Explain project readiness and missing Mimetic setup.",
36
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/7",
37
+ docs: commonDocs
38
+ },
39
+ {
40
+ name: "run",
41
+ description: "Run a persona/scenario simulation or synthetic dry-run bundle.",
42
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/7",
43
+ docs: commonDocs,
44
+ options: [
45
+ { flags: "--dry-run", description: "Generate contract proof without browser, keys, or provider spend." },
46
+ { flags: "--cwd <path>", description: "Target project directory.", defaultValue: "." }
47
+ ]
48
+ },
49
+ {
50
+ name: "verify",
51
+ description: "Validate a run bundle and public-safety gates.",
52
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/7",
53
+ docs: commonDocs,
54
+ options: [
55
+ { flags: "--run <id>", description: "Run id or latest pointer.", defaultValue: "latest" }
56
+ ]
57
+ },
58
+ {
59
+ name: "review",
60
+ description: "Build a review packet from verified run evidence.",
61
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/7",
62
+ docs: commonDocs,
63
+ options: [
64
+ { flags: "--run <id>", description: "Run id or latest pointer.", defaultValue: "latest" }
65
+ ]
66
+ },
67
+ {
68
+ name: "watch",
69
+ description: "Run sims, open the observer, and keep the shell attached.",
70
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/10",
71
+ docs: commonDocs,
72
+ options: [
73
+ { flags: "--run <id>", description: "Watch an existing run id or latest pointer." },
74
+ { flags: "--sims <count>", description: "Start a fresh synthetic run with this many sims before rendering.", defaultValue: "4 when --run is omitted" },
75
+ { flags: "--open", description: "Open the observer in the default browser.", defaultValue: "true for human output" },
76
+ { flags: "--detach", description: "Render/open once and exit without attached watch server." },
77
+ { flags: "--port <port>", description: "Local observer server port when following.", defaultValue: "0" },
78
+ { flags: "--no-open", description: "Render without opening a browser." }
79
+ ]
80
+ },
81
+ {
82
+ name: "runs",
83
+ description: "List local Mimetic runs and latest pointers.",
84
+ issue: "https://github.com/danielgwilson/mimetic-cli/issues/7",
85
+ docs: commonDocs
86
+ }
87
+ ];
88
+ export function createProgram(io = {}) {
89
+ const cliIo = { ...defaultIo, ...io };
90
+ const program = new Command();
91
+ program
92
+ .name("mimetic")
93
+ .description("Open-source-safe persona simulation CLI and proof harness.")
94
+ .version("0.1.0")
95
+ .showHelpAfterError()
96
+ .option("--json", "Print machine-readable JSON responses where supported.")
97
+ .configureOutput({
98
+ writeOut: (text) => cliIo.writeOut(text),
99
+ writeErr: (text) => cliIo.writeErr(text)
100
+ })
101
+ .addHelpText("after", [
102
+ "",
103
+ "Examples:",
104
+ " mimetic watch",
105
+ " mimetic watch --run latest --detach",
106
+ " mimetic watch --json --no-open",
107
+ " mimetic lab oss --repos developit/mitt,lukeed/clsx",
108
+ " mimetic lab oss-smoke --limit 1 --keep",
109
+ " mimetic verify --run latest --json",
110
+ "",
111
+ "Public-safety boundary:",
112
+ " Mimetic must not commit or emit PII, PHI, secrets, keys, raw private transcripts,",
113
+ " private screenshots, or private source-system artifacts."
114
+ ].join("\n"));
115
+ registerInitCommand(program, cliIo);
116
+ registerDoctorCommand(program, cliIo);
117
+ registerRunCommand(program, cliIo);
118
+ registerVerifyCommand(program, cliIo);
119
+ registerReviewCommand(program, cliIo);
120
+ registerRunsCommand(program, cliIo);
121
+ registerWatchCommand(program, cliIo);
122
+ registerLabCommands(program, cliIo);
123
+ const implementedCommands = new Set(["init", "doctor", "run", "verify", "review", "runs", "watch", "lab"]);
124
+ for (const plannedCommand of plannedCommands.filter((command) => !implementedCommands.has(command.name))) {
125
+ registerUnsupportedCommand(program, plannedCommand, cliIo);
126
+ }
127
+ registerFeedbackCommands(program, cliIo);
128
+ return program;
129
+ }
130
+ function registerInitCommand(parent, io) {
131
+ parent
132
+ .command("init")
133
+ .description("Set up committed mimetic/ source files and ignored .mimetic/ runtime state.")
134
+ .option("--dry-run", "Print planned changes without writing files.")
135
+ .option("--yes", "Apply safe generated changes without prompting.")
136
+ .option("--cwd <path>", "Target project directory.", ".")
137
+ .option("--json", "Print a machine-readable JSON response.")
138
+ .action(async (options, command) => {
139
+ const initOptions = {
140
+ cwd: options.cwd,
141
+ ...(options.dryRun === undefined ? {} : { dryRun: options.dryRun }),
142
+ ...(options.yes === undefined ? {} : { yes: options.yes })
143
+ };
144
+ const result = await runInit(initOptions);
145
+ if (wantsJson(command)) {
146
+ io.writeOut(`${JSON.stringify(result, null, 2)}\n`);
147
+ }
148
+ else if (result.ok) {
149
+ io.writeOut(formatInitHuman(result));
150
+ }
151
+ else {
152
+ io.writeErr(formatInitHuman(result));
153
+ }
154
+ io.setExitCode(result.ok ? 0 : 2);
155
+ });
156
+ }
157
+ function registerDoctorCommand(parent, io) {
158
+ parent
159
+ .command("doctor")
160
+ .description("Explain project readiness and missing Mimetic setup.")
161
+ .option("--cwd <path>", "Target project directory.", ".")
162
+ .option("--json", "Print a machine-readable JSON response.")
163
+ .action(async (options, command) => {
164
+ const result = await doctor(options.cwd);
165
+ writeResult(command, io, result, formatDoctorHuman);
166
+ io.setExitCode(result.ok ? 0 : 1);
167
+ });
168
+ }
169
+ function registerRunCommand(parent, io) {
170
+ parent
171
+ .command("run")
172
+ .description("Run a persona/scenario simulation or synthetic dry-run bundle.")
173
+ .option("--dry-run", "Generate contract proof without browser, keys, or provider spend.")
174
+ .option("--cwd <path>", "Target project directory.", ".")
175
+ .option("--run-id <id>", "Explicit run id for deterministic fixture tests.")
176
+ .option("--json", "Print a machine-readable JSON response.")
177
+ .action(async (options, command) => {
178
+ const result = await runDryRun({
179
+ cwd: options.cwd,
180
+ ...(options.dryRun === undefined ? {} : { dryRun: options.dryRun }),
181
+ ...(options.runId === undefined ? {} : { runId: options.runId })
182
+ });
183
+ writeResult(command, io, result, formatRunHuman);
184
+ io.setExitCode(result.ok ? 0 : 2);
185
+ });
186
+ }
187
+ function registerVerifyCommand(parent, io) {
188
+ parent
189
+ .command("verify")
190
+ .description("Validate a run bundle and public-safety gates.")
191
+ .option("--run <id>", "Run id or latest pointer.", "latest")
192
+ .option("--cwd <path>", "Target project directory.", ".")
193
+ .option("--json", "Print a machine-readable JSON response.")
194
+ .action(async (options, command) => {
195
+ const result = await verifyRun(options.cwd, options.run);
196
+ writeResult(command, io, result, formatVerifyHuman);
197
+ io.setExitCode(result.ok ? 0 : 2);
198
+ });
199
+ }
200
+ function registerReviewCommand(parent, io) {
201
+ parent
202
+ .command("review")
203
+ .description("Build a review packet from verified run evidence.")
204
+ .option("--run <id>", "Run id or latest pointer.", "latest")
205
+ .option("--cwd <path>", "Target project directory.", ".")
206
+ .option("--json", "Print a machine-readable JSON response.")
207
+ .action(async (options, command) => {
208
+ const result = await readReview(options.cwd, options.run);
209
+ writeResult(command, io, result, (value) => `${JSON.stringify(value, null, 2)}\n`);
210
+ io.setExitCode("ok" in result && result.ok === false ? 2 : 0);
211
+ });
212
+ }
213
+ function registerRunsCommand(parent, io) {
214
+ parent
215
+ .command("runs")
216
+ .description("List local Mimetic runs and latest pointers.")
217
+ .option("--cwd <path>", "Target project directory.", ".")
218
+ .option("--json", "Print a machine-readable JSON response.")
219
+ .action(async (options, command) => {
220
+ const result = await listRuns(options.cwd);
221
+ writeResult(command, io, result, formatRunsHuman);
222
+ io.setExitCode(0);
223
+ });
224
+ }
225
+ function registerWatchCommand(parent, io) {
226
+ parent
227
+ .command("watch")
228
+ .description("Run sims, open the observer, and keep the shell attached.")
229
+ .option("--run <id>", "Watch an existing run id or latest pointer.")
230
+ .option("--sims <count>", "Start a fresh synthetic run with this many sims before rendering. Defaults to 4 when --run is omitted.")
231
+ .option("--run-id <id>", "Explicit run id for deterministic fixture tests.")
232
+ .option("--cwd <path>", "Target project directory.", ".")
233
+ .option("--open", "Open the observer in the default browser.")
234
+ .option("--no-open", "Render without opening a browser.")
235
+ .addOption(new Option("--follow", "Deprecated; human output follows by default.").hideHelp())
236
+ .option("--detach", "Render/open once and exit without attached watch server.")
237
+ .option("--port <port>", "Local observer server port when following.", "0")
238
+ .option("--json", "Print a machine-readable JSON response.")
239
+ .addHelpText("after", [
240
+ "",
241
+ "Happy path:",
242
+ " mimetic watch",
243
+ "",
244
+ "Agent/CI path:",
245
+ " mimetic watch --json --no-open",
246
+ "",
247
+ "Existing evidence:",
248
+ " mimetic watch --run latest --detach"
249
+ ].join("\n"))
250
+ .action(async (options, command) => {
251
+ const runOptionSource = typeof command.getOptionValueSource === "function"
252
+ ? command.getOptionValueSource("run")
253
+ : undefined;
254
+ const runWasOmitted = runOptionSource === undefined || runOptionSource === "default";
255
+ const simCount = options.sims === undefined ? undefined : parsePositiveInteger(options.sims);
256
+ const port = parseObserverPort(options.port);
257
+ if (options.sims !== undefined && simCount === null) {
258
+ const result = {
259
+ schema: "mimetic.run-result.v1",
260
+ ok: false,
261
+ cwd: options.cwd,
262
+ warnings: [],
263
+ error: {
264
+ code: "MIMETIC_INVALID_SIM_COUNT",
265
+ message: "--sims must be an integer between 1 and 64."
266
+ }
267
+ };
268
+ writeResult(command, io, result, formatRunHuman);
269
+ io.setExitCode(2);
270
+ return;
271
+ }
272
+ if (!runWasOmitted && options.sims !== undefined) {
273
+ const result = {
274
+ schema: "mimetic.run-result.v1",
275
+ ok: false,
276
+ cwd: options.cwd,
277
+ warnings: [],
278
+ error: {
279
+ code: "MIMETIC_WATCH_OPTION_CONFLICT",
280
+ message: "Use either --run to watch existing evidence or --sims to start a fresh run, not both."
281
+ }
282
+ };
283
+ writeResult(command, io, result, formatRunHuman);
284
+ io.setExitCode(2);
285
+ return;
286
+ }
287
+ if (!runWasOmitted && options.runId !== undefined) {
288
+ const result = {
289
+ schema: "mimetic.run-result.v1",
290
+ ok: false,
291
+ cwd: options.cwd,
292
+ warnings: [],
293
+ error: {
294
+ code: "MIMETIC_WATCH_OPTION_CONFLICT",
295
+ message: "--run-id only applies to fresh watch runs; remove --run or remove --run-id."
296
+ }
297
+ };
298
+ writeResult(command, io, result, formatRunHuman);
299
+ io.setExitCode(2);
300
+ return;
301
+ }
302
+ if (port === null) {
303
+ const result = {
304
+ schema: "mimetic.run-result.v1",
305
+ ok: false,
306
+ cwd: options.cwd,
307
+ warnings: [],
308
+ error: {
309
+ code: "MIMETIC_INVALID_PORT",
310
+ message: "--port must be an integer between 0 and 65535."
311
+ }
312
+ };
313
+ writeResult(command, io, result, formatRunHuman);
314
+ io.setExitCode(2);
315
+ return;
316
+ }
317
+ const requestedSimCount = simCount ?? (runWasOmitted ? 4 : undefined);
318
+ let runInput = options.run ?? "latest";
319
+ if (requestedSimCount !== undefined && requestedSimCount !== null) {
320
+ const runResult = await runDryRun({
321
+ cwd: options.cwd,
322
+ dryRun: true,
323
+ simCount: requestedSimCount,
324
+ ...(options.runId === undefined ? {} : { runId: options.runId })
325
+ });
326
+ if (!runResult.ok || !runResult.runId) {
327
+ writeResult(command, io, runResult, formatRunHuman);
328
+ io.setExitCode(2);
329
+ return;
330
+ }
331
+ runInput = runResult.runId;
332
+ }
333
+ const wantsMachine = wantsJson(command);
334
+ const shouldOpen = options.open === false ? false : wantsMachine ? options.open === true : true;
335
+ const wantsFollow = !wantsMachine && options.detach !== true && (options.follow !== false);
336
+ const rendered = await renderObserver(options.cwd, runInput, { open: wantsFollow ? false : shouldOpen });
337
+ let server = null;
338
+ let result = rendered;
339
+ if (rendered.ok && wantsFollow) {
340
+ server = await serveObserver(rendered, { open: shouldOpen, port });
341
+ result = {
342
+ ...rendered,
343
+ observerUrl: server.url,
344
+ serverUrl: server.url,
345
+ opened: server.opened,
346
+ ...(server.openCommand ? { openCommand: server.openCommand } : {}),
347
+ warnings: [
348
+ ...rendered.warnings,
349
+ "Live observer server is polling observer-data.json with no-store caching.",
350
+ ...(server.warning ? [server.warning] : [])
351
+ ]
352
+ };
353
+ }
354
+ writeResult(command, io, result, formatObserverHuman);
355
+ io.setExitCode(result.ok ? 0 : 2);
356
+ if (result.ok && server) {
357
+ await followObserver(io, result, server);
358
+ }
359
+ });
360
+ }
361
+ function registerFeedbackCommands(parent, io) {
362
+ const feedback = parent
363
+ .command("feedback")
364
+ .description("Create public-safe feedback drafts without GitHub API mutation.");
365
+ feedback
366
+ .command("list")
367
+ .description("List feedback draft state for a run.")
368
+ .option("--run <id>", "Run id or latest pointer.", "latest")
369
+ .option("--cwd <path>", "Target project directory.", ".")
370
+ .option("--json", "Print a machine-readable JSON response.")
371
+ .action(async (options, command) => {
372
+ const result = await listFeedback(options.cwd, options.run);
373
+ writeResult(command, io, result, formatFeedbackHuman);
374
+ io.setExitCode(result.ok ? 0 : 2);
375
+ });
376
+ feedback
377
+ .command("draft")
378
+ .description("Generate a public-safe feedback draft from verified evidence.")
379
+ .option("--run <id>", "Run id or latest pointer.", "latest")
380
+ .option("--cwd <path>", "Target project directory.", ".")
381
+ .option("--json", "Print a machine-readable JSON response.")
382
+ .action(async (options, command) => {
383
+ const result = await draftFeedback(options.cwd, options.run);
384
+ writeResult(command, io, result, formatFeedbackHuman);
385
+ io.setExitCode(result.ok ? 0 : 2);
386
+ });
387
+ feedback
388
+ .command("verify")
389
+ .description("Verify the feedback draft for public issue eligibility.")
390
+ .option("--run <id>", "Run id or latest pointer.", "latest")
391
+ .option("--cwd <path>", "Target project directory.", ".")
392
+ .option("--json", "Print a machine-readable JSON response.")
393
+ .action(async (options, command) => {
394
+ const result = await verifyFeedback(options.cwd, options.run);
395
+ writeResult(command, io, result, formatFeedbackHuman);
396
+ io.setExitCode(result.ok ? 0 : 2);
397
+ });
398
+ feedback
399
+ .command("issue")
400
+ .description("Print Markdown for a public GitHub issue. Does not mutate GitHub.")
401
+ .option("--run <id>", "Run id or latest pointer.", "latest")
402
+ .option("--cwd <path>", "Target project directory.", ".")
403
+ .requiredOption("--repo <owner/repo>", "Repository slug used in rendered filing instructions.")
404
+ .option("--format <format>", "Output format.", "markdown")
405
+ .option("--json", "Print a machine-readable JSON response.")
406
+ .action(async (options, command) => {
407
+ const result = await renderIssueMarkdown(options.cwd, options.run, options.repo);
408
+ if (wantsJson(command)) {
409
+ io.writeOut(`${JSON.stringify(result, null, 2)}\n`);
410
+ }
411
+ else if (options.format !== "markdown") {
412
+ io.writeErr("Only --format markdown is supported.\n");
413
+ io.setExitCode(2);
414
+ return;
415
+ }
416
+ else if (result.ok && result.issueMarkdown) {
417
+ io.writeOut(result.issueMarkdown);
418
+ }
419
+ else {
420
+ io.writeErr(formatFeedbackHuman(result));
421
+ }
422
+ io.setExitCode(result.ok ? 0 : 2);
423
+ });
424
+ feedback
425
+ .command("issue-url")
426
+ .description("Print a prefilled public issue URL. Does not mutate GitHub.")
427
+ .option("--run <id>", "Run id or latest pointer.", "latest")
428
+ .option("--cwd <path>", "Target project directory.", ".")
429
+ .requiredOption("--repo <owner/repo>", "Repository slug used in the generated URL.")
430
+ .option("--json", "Print a machine-readable JSON response.")
431
+ .action(async (options, command) => {
432
+ const result = await renderIssueUrl(options.cwd, options.run, options.repo);
433
+ if (wantsJson(command)) {
434
+ io.writeOut(`${JSON.stringify(result, null, 2)}\n`);
435
+ }
436
+ else if (result.ok && result.issueUrl) {
437
+ io.writeOut(`${result.issueUrl}\n`);
438
+ }
439
+ else {
440
+ io.writeErr(formatFeedbackHuman(result));
441
+ }
442
+ io.setExitCode(result.ok ? 0 : 2);
443
+ });
444
+ }
445
+ function registerLabCommands(parent, io) {
446
+ const lab = parent
447
+ .command("lab")
448
+ .description("Run experimental Mimetic proof loops against disposable public targets.");
449
+ lab
450
+ .command("oss")
451
+ .description("Watch headed Codex/E2B OSS meta-sims setting up Mimetic inside public repos.")
452
+ .option("--repos <owner/repo,...>", "Comma-separated public GitHub repo slugs.")
453
+ .option("--repo <owner/repo>", "Public GitHub repo slug. Repeatable.", collectRepeated, [])
454
+ .option("--count <count>", "Number of headed desktop sims to assign.", String(DEFAULT_OSS_REPOS.length))
455
+ .option("--sims <count>", "Alias for --count.")
456
+ .option("--run-id <id>", "Explicit lab run id.")
457
+ .option("--cwd <path>", "Host directory for ignored .mimetic lab report.", ".")
458
+ .option("--dry-run", "Render the Observer-of-Observers contract without provider spend or live E2B launch.")
459
+ .option("--open", "Open the observer in the default browser.")
460
+ .option("--no-open", "Render without opening a browser.")
461
+ .option("--detach", "Render/open once and exit without attached watch server.")
462
+ .option("--port <port>", "Local observer server port when following.", "0")
463
+ .option("--smoke", "Run the disposable local clone smoke harness instead of headed meta-sims.")
464
+ .option("--limit <count>", "Smoke mode only: number of selected repos to trial.", String(DEFAULT_OSS_REPOS.length))
465
+ .option("--keep", "Smoke mode only: keep disposable clone sandbox for debugging.")
466
+ .option("--json", "Print a machine-readable JSON response.")
467
+ .addHelpText("after", [
468
+ "",
469
+ "Happy path:",
470
+ " mimetic lab oss",
471
+ "",
472
+ "Repo selection:",
473
+ " mimetic lab oss --repos developit/mitt,lukeed/clsx,sindresorhus/is-plain-obj,ai/nanoid",
474
+ " mimetic lab oss --repo developit/mitt --repo lukeed/clsx --count 4",
475
+ "",
476
+ "Agent/CI path:",
477
+ " mimetic lab oss --dry-run --json --no-open",
478
+ "",
479
+ "Disposable clone smoke:",
480
+ " mimetic lab oss-smoke --limit 1 --keep",
481
+ " mimetic lab oss --smoke --limit 1 --keep",
482
+ "",
483
+ "Shape:",
484
+ " The top-level Observer shows headed E2B desktop lanes. Each desktop is intended",
485
+ " to run Codex TUI, clone its assigned public OSS repo, set up Mimetic, and keep",
486
+ " that repo's nested Mimetic Observer visible in the E2B browser.",
487
+ "",
488
+ "Safety:",
489
+ " Only public GitHub owner/repo slugs are accepted. No keys or private artifacts",
490
+ " are written into committed Mimetic source."
491
+ ].join("\n"))
492
+ .action(async (options, command) => {
493
+ if (options.smoke) {
494
+ await runOssSmokeAction({ command, io, options });
495
+ return;
496
+ }
497
+ const countInput = options.sims ?? options.count;
498
+ const count = parsePositiveInteger(countInput);
499
+ const port = parseObserverPort(options.port);
500
+ if (port === null) {
501
+ const result = {
502
+ schema: "mimetic.oss-meta-lab-result.v1",
503
+ ok: false,
504
+ assignments: [],
505
+ cwd: options.cwd,
506
+ dryRun: options.dryRun === true,
507
+ error: {
508
+ code: "MIMETIC_META_RUN_FAILED",
509
+ message: "--port must be an integer between 0 and 65535."
510
+ },
511
+ liveRequested: options.dryRun !== true,
512
+ repos: [...options.repo, ...(options.repos ? [options.repos] : [])],
513
+ sandboxes: [],
514
+ warnings: []
515
+ };
516
+ writeResult(command, io, result, formatOssMetaLabHuman);
517
+ io.setExitCode(2);
518
+ return;
519
+ }
520
+ const wantsMachine = wantsJson(command);
521
+ const shouldOpen = options.open === false ? false : wantsMachine ? options.open === true : true;
522
+ const wantsFollow = !wantsMachine && options.detach !== true && options.dryRun !== true;
523
+ const result = await runOssMetaLab({
524
+ cwd: options.cwd,
525
+ open: wantsFollow ? false : shouldOpen,
526
+ repos: [...options.repo, ...(options.repos ? [options.repos] : [])],
527
+ ...(count === null ? { count: Number.NaN } : { count }),
528
+ ...(options.dryRun === undefined ? {} : { dryRun: options.dryRun }),
529
+ ...(options.runId === undefined ? {} : { runId: options.runId })
530
+ });
531
+ let server = null;
532
+ let output = result;
533
+ if (result.ok && wantsFollow && result.observer?.ok) {
534
+ server = await serveObserver(result.observer, { open: shouldOpen, port });
535
+ output = {
536
+ ...result,
537
+ observer: {
538
+ ...result.observer,
539
+ observerUrl: server.url,
540
+ serverUrl: server.url,
541
+ opened: server.opened,
542
+ ...(server.openCommand ? { openCommand: server.openCommand } : {}),
543
+ warnings: [
544
+ ...result.observer.warnings,
545
+ "Live OSS meta-lab server is polling observer-data.json with no-store caching.",
546
+ ...(server.warning ? [server.warning] : [])
547
+ ]
548
+ },
549
+ warnings: [
550
+ ...result.warnings,
551
+ "Live OSS meta-lab server is polling observer-data.json with no-store caching.",
552
+ ...(server.warning ? [server.warning] : [])
553
+ ]
554
+ };
555
+ }
556
+ writeResult(command, io, output, formatOssMetaLabHuman);
557
+ io.setExitCode(output.ok ? 0 : 2);
558
+ if (output.ok && options.detach === true && output.sandboxes.some((sandbox) => sandbox.urlPresent)) {
559
+ // The E2B SDK keeps local handles open after stream URL creation. Detach should
560
+ // return the user's shell while the remote desktops continue on E2B.
561
+ setTimeout(() => process.exit(0), 50);
562
+ }
563
+ if (output.ok && server && output.observer?.ok) {
564
+ await followObserver(io, output.observer, server);
565
+ }
566
+ });
567
+ lab
568
+ .command("oss-smoke")
569
+ .description("Clone lightweight public OSS repos, try Mimetic setup/proof, then discard clones.")
570
+ .option("--repos <owner/repo,...>", "Comma-separated public GitHub repo slugs.")
571
+ .option("--repo <owner/repo>", "Public GitHub repo slug. Repeatable.", collectRepeated, [])
572
+ .option("--limit <count>", "Number of selected repos to trial.", String(DEFAULT_OSS_REPOS.length))
573
+ .option("--run-id <id>", "Explicit lab run id.")
574
+ .option("--cwd <path>", "Host directory for ignored .mimetic lab report.", ".")
575
+ .option("--keep", "Keep disposable clone sandbox for debugging.")
576
+ .option("--json", "Print a machine-readable JSON response.")
577
+ .addHelpText("after", [
578
+ "",
579
+ "Examples:",
580
+ " mimetic lab oss-smoke",
581
+ " mimetic lab oss-smoke --repos developit/mitt,lukeed/clsx",
582
+ " mimetic lab oss-smoke --limit 1 --keep --json",
583
+ "",
584
+ "Safety:",
585
+ " Only public GitHub owner/repo slugs are accepted. Clones live under ignored .mimetic/",
586
+ " runtime state and are removed by default."
587
+ ].join("\n"))
588
+ .action(async (options, command) => {
589
+ await runOssSmokeAction({ command, io, options });
590
+ });
591
+ }
592
+ async function runOssSmokeAction(args) {
593
+ const limit = parsePositiveInteger(args.options.limit);
594
+ const labOptions = {
595
+ cwd: args.options.cwd,
596
+ limit: limit ?? Number.NaN,
597
+ repos: [...args.options.repo, ...(args.options.repos ? [args.options.repos] : [])],
598
+ ...(args.options.keep === undefined ? {} : { keep: args.options.keep }),
599
+ ...(args.options.runId === undefined ? {} : { runId: args.options.runId })
600
+ };
601
+ const result = await runOssLab(labOptions);
602
+ writeResult(args.command, args.io, result, formatOssLabHuman);
603
+ args.io.setExitCode(result.ok ? 0 : 2);
604
+ }
605
+ function writeResult(command, io, result, formatHuman) {
606
+ if (wantsJson(command)) {
607
+ io.writeOut(`${JSON.stringify(result, null, 2)}\n`);
608
+ }
609
+ else {
610
+ io.writeOut(formatHuman(result));
611
+ }
612
+ }
613
+ function formatDoctorHuman(result) {
614
+ return [
615
+ `mimetic doctor ${result.ok ? "ok" : "needs setup"}`,
616
+ `cwd: ${result.cwd}`,
617
+ ...result.checks.map((check) => `- ${check.ok ? "ok" : "missing"} ${check.name}: ${check.message}`)
618
+ ].join("\n") + "\n";
619
+ }
620
+ function formatRunHuman(result) {
621
+ if (!result.ok) {
622
+ return `${result.error?.code}: ${result.error?.message}\n`;
623
+ }
624
+ return [
625
+ `mimetic run ${result.mode}`,
626
+ `run: ${result.runId}`,
627
+ ...(result.simCount === undefined ? [] : [`sims: ${result.simCount}`]),
628
+ `bundle: ${result.bundlePath}`,
629
+ `review: ${result.reviewPath}`,
630
+ ...result.warnings.map((warning) => `warning: ${warning}`)
631
+ ].join("\n") + "\n";
632
+ }
633
+ function formatVerifyHuman(result) {
634
+ return [
635
+ `mimetic verify ${result.ok ? "passed" : "failed"}`,
636
+ `run: ${result.run}`,
637
+ ...result.checks.map((check) => `- ${check.ok ? "ok" : "fail"} ${check.name}: ${check.message}`)
638
+ ].join("\n") + "\n";
639
+ }
640
+ function formatRunsHuman(result) {
641
+ if (result.runs.length === 0) {
642
+ return `No Mimetic runs found in ${result.cwd}\n`;
643
+ }
644
+ return [
645
+ `latest: ${result.latest ?? "none"}`,
646
+ ...result.runs.map((run) => `- ${run.runId} ${run.mode ?? "unknown"} ${run.createdAt ?? "unknown"} ${run.path}`)
647
+ ].join("\n") + "\n";
648
+ }
649
+ function formatObserverHuman(result) {
650
+ if (!result.ok) {
651
+ return `${result.error?.code}: ${result.error?.message}\n`;
652
+ }
653
+ return [
654
+ "mimetic observer rendered",
655
+ `run: ${result.run}`,
656
+ `observer: ${result.observerPath}`,
657
+ ...(result.observerUrl ? [`url: ${result.observerUrl}`] : []),
658
+ ...(result.opened === undefined ? [] : [`opened: ${result.opened ? "yes" : "no"}`]),
659
+ `bundle: ${result.bundlePath}`,
660
+ ...result.warnings.map((warning) => `warning: ${warning}`)
661
+ ].join("\n") + "\n";
662
+ }
663
+ function parsePositiveInteger(value) {
664
+ if (!/^\d+$/.test(value)) {
665
+ return null;
666
+ }
667
+ const parsed = Number.parseInt(value, 10);
668
+ return parsed >= 1 && parsed <= 64 ? parsed : null;
669
+ }
670
+ function parseObserverPort(value) {
671
+ if (!/^\d+$/.test(value)) {
672
+ return null;
673
+ }
674
+ const parsed = Number.parseInt(value, 10);
675
+ return parsed >= 0 && parsed <= 65535 ? parsed : null;
676
+ }
677
+ async function followObserver(io, result, server) {
678
+ io.writeOut(`watching: ${result.serverUrl ?? result.observerUrl ?? result.observerPath}\n`);
679
+ io.writeOut("watching: press Ctrl-C to stop\n");
680
+ await new Promise((resolve) => {
681
+ process.once("SIGINT", () => {
682
+ server.close()
683
+ .catch((error) => {
684
+ io.writeErr(`watch cleanup failed: ${error instanceof Error ? error.message : String(error)}\n`);
685
+ })
686
+ .finally(() => {
687
+ io.writeOut("watch stopped\n");
688
+ resolve();
689
+ });
690
+ });
691
+ });
692
+ }
693
+ function formatFeedbackHuman(result) {
694
+ if (!result.ok) {
695
+ return `${result.error?.code}: ${result.error?.message}\n`;
696
+ }
697
+ return [
698
+ "mimetic feedback ready",
699
+ `run: ${result.run}`,
700
+ ...(result.draftPath ? [`draft: ${result.draftPath}`] : []),
701
+ ...(result.issuePath ? [`issue: ${result.issuePath}`] : [])
702
+ ].join("\n") + "\n";
703
+ }
704
+ function formatOssLabHuman(result) {
705
+ if (!result.ok && result.error) {
706
+ return `${result.error.code}: ${result.error.message}\n`;
707
+ }
708
+ return [
709
+ `mimetic lab oss-smoke ${result.ok ? "passed" : "failed"}`,
710
+ `run: ${result.runId}`,
711
+ ...(result.reportMarkdownPath ? [`report: ${result.reportMarkdownPath}`] : []),
712
+ `sandbox: ${result.cleanup.kept ? result.sandboxPath : "removed"}`,
713
+ ...result.repos.map((repo) => {
714
+ const passed = repo.steps.filter((step) => step.ok).length;
715
+ return `- ${repo.ok ? "ok" : "fail"} ${repo.repo}: ${passed}/${repo.steps.length} steps, ${repo.changedFiles.length} changed files in disposable clone`;
716
+ }),
717
+ ...result.warnings.map((warning) => `warning: ${warning}`)
718
+ ].join("\n") + "\n";
719
+ }
720
+ function formatOssMetaLabHuman(result) {
721
+ if (!result.ok && result.error) {
722
+ return `${result.error.code}: ${result.error.message}\n`;
723
+ }
724
+ return [
725
+ `mimetic lab oss ${result.dryRun ? "dry-run" : "watch"}`,
726
+ `run: ${result.runId ?? "not-created"}`,
727
+ `repos: ${result.repos.join(", ")}`,
728
+ ...(result.count === undefined ? [] : [`desktops: ${result.count}`]),
729
+ ...(result.observer?.observerPath ? [`observer: ${result.observer.observerPath}`] : []),
730
+ ...(result.observer?.observerUrl ? [`url: ${result.observer.observerUrl}`] : []),
731
+ ...(result.observer?.opened === undefined ? [] : [`opened: ${result.observer.opened ? "yes" : "no"}`]),
732
+ ...(result.observer?.bundlePath ? [`bundle: ${result.observer.bundlePath}`] : []),
733
+ ...result.assignments.map((assignment) => `- ${String(assignment.index).padStart(2, "0")} ${assignment.repo}: top-level desktop lane -> nested Mimetic Observer`),
734
+ ...result.sandboxes.map((sandbox) => {
735
+ const sandboxLabel = sandbox.sandboxId ? ` sandbox=${sandbox.sandboxId}` : "";
736
+ const bootstrapLabel = sandbox.bootstrapStatus ? ` bootstrap=${sandbox.bootstrapStatus}` : "";
737
+ return `sandbox ${sandbox.streamId}: ${sandbox.repo} stream=${sandbox.urlPresent ? "connected" : "missing"}${bootstrapLabel}${sandboxLabel}`;
738
+ }),
739
+ ...result.warnings.map((warning) => `warning: ${warning}`)
740
+ ].join("\n") + "\n";
741
+ }
742
+ function collectRepeated(value, previous) {
743
+ return [...previous, value];
744
+ }
745
+ function formatInitHuman(result) {
746
+ const title = result.ok
747
+ ? `mimetic init ${result.mode}`
748
+ : `mimetic init ${result.mode} blocked`;
749
+ const lines = [
750
+ title,
751
+ `cwd: ${result.cwd}`,
752
+ "",
753
+ "changes:",
754
+ ...result.changes.map(formatInitChange)
755
+ ];
756
+ if (result.warnings.length > 0) {
757
+ lines.push("", "warnings:", ...result.warnings.map((warning) => `- ${warning}`));
758
+ }
759
+ if (result.error) {
760
+ lines.push("", `${result.error.code}: ${result.error.message}`);
761
+ }
762
+ if (result.mode === "needs-confirmation") {
763
+ lines.push("", "Run with --dry-run --json to inspect or --yes to apply.");
764
+ }
765
+ return `${lines.join("\n")}\n`;
766
+ }
767
+ function formatInitChange(change) {
768
+ return `- ${change.action.padEnd(6)} ${change.path} (${change.target}: ${change.reason})`;
769
+ }
770
+ function registerUnsupportedCommand(parent, plannedCommand, io, commandName = plannedCommand.name) {
771
+ const command = parent.command(commandName).description(plannedCommand.description);
772
+ command.option("--json", "Print a machine-readable JSON response.");
773
+ for (const option of plannedCommand.options ?? []) {
774
+ if (option.defaultValue === undefined) {
775
+ command.option(option.flags, option.description);
776
+ }
777
+ else {
778
+ command.option(option.flags, option.description, option.defaultValue);
779
+ }
780
+ }
781
+ command.action((_options, actionCommand) => {
782
+ emitUnsupported(plannedCommand, actionCommand, io);
783
+ });
784
+ }
785
+ function emitUnsupported(plannedCommand, command, io) {
786
+ const envelope = {
787
+ schema: CLI_RESPONSE_SCHEMA,
788
+ ok: false,
789
+ command: plannedCommand.name,
790
+ error: {
791
+ code: "MIMETIC_UNIMPLEMENTED",
792
+ message: `${plannedCommand.name} is planned but not implemented in this scaffold slice.`
793
+ },
794
+ docs: plannedCommand.docs,
795
+ issue: plannedCommand.issue,
796
+ capabilities: {
797
+ githubMutation: false,
798
+ providerSpend: false,
799
+ productionData: false
800
+ }
801
+ };
802
+ if (wantsJson(command)) {
803
+ io.writeOut(`${JSON.stringify(envelope, null, 2)}\n`);
804
+ }
805
+ else {
806
+ io.writeErr([
807
+ `mimetic ${plannedCommand.name} is planned but not implemented yet.`,
808
+ `Track: ${plannedCommand.issue}`,
809
+ `Docs: ${plannedCommand.docs.join(", ")}`,
810
+ "This scaffold does not mutate GitHub, spend provider credits, or use production data."
811
+ ].join("\n") + "\n");
812
+ }
813
+ io.setExitCode(2);
814
+ }
815
+ function wantsJson(command) {
816
+ let current = command;
817
+ while (current) {
818
+ if (current.opts().json === true) {
819
+ return true;
820
+ }
821
+ current = current.parent ?? null;
822
+ }
823
+ return false;
824
+ }
825
+ //# sourceMappingURL=program.js.map