@loopstack/cli 0.15.1 → 0.17.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 (96) hide show
  1. package/README.md +62 -0
  2. package/dist/commands/create.d.ts +3 -0
  3. package/dist/commands/create.d.ts.map +1 -0
  4. package/dist/commands/create.js +80 -0
  5. package/dist/commands/create.js.map +1 -0
  6. package/dist/commands/env.d.ts +3 -0
  7. package/dist/commands/env.d.ts.map +1 -0
  8. package/dist/commands/env.js +42 -0
  9. package/dist/commands/env.js.map +1 -0
  10. package/dist/commands/list.d.ts +3 -0
  11. package/dist/commands/list.d.ts.map +1 -0
  12. package/dist/commands/list.js +119 -0
  13. package/dist/commands/list.js.map +1 -0
  14. package/dist/commands/login.d.ts +3 -0
  15. package/dist/commands/login.d.ts.map +1 -0
  16. package/dist/commands/login.js +62 -0
  17. package/dist/commands/login.js.map +1 -0
  18. package/dist/commands/run.d.ts +3 -0
  19. package/dist/commands/run.d.ts.map +1 -0
  20. package/dist/commands/run.js +94 -0
  21. package/dist/commands/run.js.map +1 -0
  22. package/dist/commands/runs.d.ts +3 -0
  23. package/dist/commands/runs.d.ts.map +1 -0
  24. package/dist/commands/runs.js +153 -0
  25. package/dist/commands/runs.js.map +1 -0
  26. package/dist/commands/watch.d.ts +3 -0
  27. package/dist/commands/watch.d.ts.map +1 -0
  28. package/dist/commands/watch.js +48 -0
  29. package/dist/commands/watch.js.map +1 -0
  30. package/dist/config/config.d.ts +14 -0
  31. package/dist/config/config.d.ts.map +1 -0
  32. package/dist/config/config.js +25 -0
  33. package/dist/config/config.js.map +1 -0
  34. package/dist/config/resolve.d.ts +18 -0
  35. package/dist/config/resolve.d.ts.map +1 -0
  36. package/dist/config/resolve.js +57 -0
  37. package/dist/config/resolve.js.map +1 -0
  38. package/dist/errors.d.ts +12 -0
  39. package/dist/errors.d.ts.map +1 -0
  40. package/dist/errors.js +36 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/hitl/discovery.d.ts +16 -0
  43. package/dist/hitl/discovery.d.ts.map +1 -0
  44. package/dist/hitl/discovery.js +67 -0
  45. package/dist/hitl/discovery.js.map +1 -0
  46. package/dist/hitl/editor.d.ts +4 -0
  47. package/dist/hitl/editor.d.ts.map +1 -0
  48. package/dist/hitl/editor.js +73 -0
  49. package/dist/hitl/editor.js.map +1 -0
  50. package/dist/hitl/idle-handler.d.ts +8 -0
  51. package/dist/hitl/idle-handler.d.ts.map +1 -0
  52. package/dist/hitl/idle-handler.js +71 -0
  53. package/dist/hitl/idle-handler.js.map +1 -0
  54. package/dist/hitl/prompt.d.ts +14 -0
  55. package/dist/hitl/prompt.d.ts.map +1 -0
  56. package/dist/hitl/prompt.js +127 -0
  57. package/dist/hitl/prompt.js.map +1 -0
  58. package/dist/main.d.ts +3 -0
  59. package/dist/main.d.ts.map +1 -0
  60. package/dist/main.js +33 -0
  61. package/dist/main.js.map +1 -0
  62. package/dist/output/format.d.ts +7 -0
  63. package/dist/output/format.d.ts.map +1 -0
  64. package/dist/output/format.js +47 -0
  65. package/dist/output/format.js.map +1 -0
  66. package/dist/output/studio-link.d.ts +4 -0
  67. package/dist/output/studio-link.d.ts.map +1 -0
  68. package/dist/output/studio-link.js +17 -0
  69. package/dist/output/studio-link.js.map +1 -0
  70. package/dist/run/args.d.ts +2 -0
  71. package/dist/run/args.d.ts.map +1 -0
  72. package/dist/run/args.js +41 -0
  73. package/dist/run/args.js.map +1 -0
  74. package/dist/run/documents.d.ts +3 -0
  75. package/dist/run/documents.d.ts.map +1 -0
  76. package/dist/run/documents.js +40 -0
  77. package/dist/run/documents.js.map +1 -0
  78. package/dist/run/follow.d.ts +14 -0
  79. package/dist/run/follow.d.ts.map +1 -0
  80. package/dist/run/follow.js +148 -0
  81. package/dist/run/follow.js.map +1 -0
  82. package/dist/run/workspace.d.ts +3 -0
  83. package/dist/run/workspace.d.ts.map +1 -0
  84. package/dist/run/workspace.js +26 -0
  85. package/dist/run/workspace.js.map +1 -0
  86. package/fixtures/app/CLAUDE.md +40 -0
  87. package/fixtures/app/README.md +21 -0
  88. package/fixtures/app/docker-compose.yml +33 -0
  89. package/fixtures/app/env.example +16 -0
  90. package/fixtures/app/nest-cli.json +10 -0
  91. package/fixtures/app/src/app.module.ts +8 -0
  92. package/fixtures/app/src/hello/hello.module.ts +12 -0
  93. package/fixtures/app/src/hello/hello.workflow.ts +28 -0
  94. package/fixtures/app/src/main.ts +8 -0
  95. package/package.json +36 -10
  96. package/bin/loopstack.js +0 -33
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @loopstack/cli
2
+
3
+ Scaffold, run, inspect, and watch [Loopstack](https://loopstack.ai) workflows from the terminal — live transition and LLM token streaming, human-in-the-loop prompts answered inline, and CI-ready JSON output with meaningful exit codes.
4
+
5
+ ```bash
6
+ npm install -g @loopstack/cli
7
+ ```
8
+
9
+ Start a new app with a zero-config hello workflow:
10
+
11
+ ```bash
12
+ loopstack create my-app
13
+ cd my-app && docker compose up -d && npm run start:dev
14
+ ```
15
+
16
+ ```bash
17
+ $ loopstack run hello --arg name=Maya
18
+
19
+ ▸ run 088cd19c… started
20
+ ▸ start
21
+ ✓ start (9ms)
22
+ Hello, Maya! 👋
23
+ result: {"greeting":"Hello, Maya! 👋"}
24
+ ■ run completed in 96ms
25
+ ```
26
+
27
+ When a run asks a question, answer it right there — or in Studio; whichever answers first wins, and the CLI keeps following either way. Field forms hand off to Studio via deep link (or open in `$EDITOR` with `--editor`):
28
+
29
+ ```
30
+ ⏸ waiting_for_answer
31
+
32
+ Which environment should we deploy to?
33
+ 1. staging
34
+ 2. production
35
+ answer: 2
36
+ ■ run completed
37
+ ```
38
+
39
+ ## Commands
40
+
41
+ | Command | What it does |
42
+ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
43
+ | `loopstack create <dir>` | Scaffold a new Loopstack app (NestJS + LoopstackModule + hello workflow + docker-compose) |
44
+ | `loopstack list [workflow]` | Workflows you can run; with a name: its arguments and a ready-to-run example |
45
+ | `loopstack run <workflow>` | Start a run and follow it live; `--arg k=v`, `--arg k=@file.json`, `--arg k=@-` (stdin), `--detach`, `--quiet`, `--open`, `--json` |
46
+ | `loopstack runs [run-id]` | Recent runs (waiting-for-input first) or one run’s audit trail; `--follow` reattaches and answers prompts |
47
+ | `loopstack watch` | Live event stream; `--workflow`, `--type`, NDJSON with `--json` |
48
+ | `loopstack login` | Save a backend environment to `~/.loopstack/config.json` |
49
+ | `loopstack env list\|use` | Manage saved environments |
50
+
51
+ ## CI
52
+
53
+ ```yaml
54
+ - run: npx --yes @loopstack/cli run triage-ticket --arg ticket=@samples/ticket-042.json --json
55
+ env:
56
+ LOOPSTACK_URL: ${{ vars.LOOPSTACK_URL }}
57
+ LOOPSTACK_TOKEN: ${{ secrets.LOOPSTACK_TOKEN }}
58
+ ```
59
+
60
+ Exit codes: `0` completed · `1` failed · `2` connection/config error · `3` waiting for input (non-interactive). `--json` prints one final object — `{ workflowId, status, result, errorMessage, durationMs }` — on a clean stdout.
61
+
62
+ Local backends with auth disabled need no login or token at all. When an environment has a Studio URL (saved via `login`, `LOOPSTACK_STUDIO_URL`, or the local default), run output includes deep links into Studio — and `--open` jumps straight there. Full documentation: [CLI Reference](https://loopstack.ai/docs/reference/cli).
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerCreateCommand(program: Command): void;
3
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4D5D"}
@@ -0,0 +1,80 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import pc from 'picocolors';
6
+ import { CliError } from '../errors.js';
7
+ import { printData, printStatus } from '../output/format.js';
8
+ const FIXTURES_DIR = fileURLToPath(new URL('../../fixtures/app', import.meta.url));
9
+ const LOOPSTACK_DEPENDENCIES = ['@loopstack/loopstack-module', '@loopstack/common', 'zod'];
10
+ function run(label, command, args, cwd) {
11
+ printStatus(pc.dim(`▸ ${label}`));
12
+ const result = spawnSync(command, args, { cwd, stdio: ['ignore', 2, 2] });
13
+ if (result.error)
14
+ throw new CliError(`${label} failed: ${result.error.message}`);
15
+ if (result.status !== 0)
16
+ throw new CliError(`${label} failed (exit ${result.status ?? 'unknown'})`);
17
+ }
18
+ function overlayFixtures(targetDir) {
19
+ fs.cpSync(FIXTURES_DIR, targetDir, { recursive: true });
20
+ const example = path.join(targetDir, 'env.example');
21
+ fs.copyFileSync(example, path.join(targetDir, '.env'));
22
+ fs.renameSync(example, path.join(targetDir, '.env.example'));
23
+ }
24
+ function addDependencies(targetDir) {
25
+ const pkgPath = path.join(targetDir, 'package.json');
26
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
27
+ pkg.dependencies ??= {};
28
+ for (const name of LOOPSTACK_DEPENDENCIES) {
29
+ pkg.dependencies[name] = 'latest';
30
+ }
31
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
32
+ }
33
+ export function registerCreateCommand(program) {
34
+ program
35
+ .command('create')
36
+ .description('Scaffold a new Loopstack app (NestJS + LoopstackModule + a hello workflow)')
37
+ .argument('<dir>', 'target directory — its basename becomes the project name')
38
+ .option('--skip-install', 'skip npm install (dependencies are added to package.json)')
39
+ .option('--no-git', 'skip git init')
40
+ .action((dir, options) => {
41
+ const targetDir = path.resolve(dir);
42
+ const name = path.basename(targetDir);
43
+ const parentDir = path.dirname(targetDir);
44
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(name)) {
45
+ throw new CliError(`Invalid project name "${name}" — use lowercase letters, digits, and hyphens.`);
46
+ }
47
+ if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
48
+ throw new CliError(`Directory ${targetDir} already exists and is not empty.`);
49
+ }
50
+ fs.mkdirSync(parentDir, { recursive: true });
51
+ run('Scaffolding NestJS app', 'npx', ['--yes', '@nestjs/cli@latest', 'new', name, '--skip-git', '--skip-install', '--package-manager', 'npm'], parentDir);
52
+ printStatus(pc.dim('▸ Applying Loopstack fixtures'));
53
+ overlayFixtures(targetDir);
54
+ addDependencies(targetDir);
55
+ if (!options.skipInstall) {
56
+ run('Installing dependencies', 'npm', ['install'], targetDir);
57
+ }
58
+ if (options.git !== false) {
59
+ run('Initializing git repository', 'git', ['init', '-b', 'main'], targetDir);
60
+ spawnSync('git', ['add', '-A'], { cwd: targetDir, stdio: 'ignore' });
61
+ spawnSync('git', ['commit', '-m', 'Initial commit'], { cwd: targetDir, stdio: 'ignore' });
62
+ }
63
+ printStatus(pc.green(`■ Created ${name}`));
64
+ printData([
65
+ '',
66
+ 'Next steps:',
67
+ ` cd ${path.relative(process.cwd(), targetDir) || '.'}`,
68
+ ...(options.skipInstall ? [' npm install'] : []),
69
+ ' docker compose up -d # Postgres, Redis, and Studio',
70
+ ' npm run start:dev # backend on http://localhost:3000',
71
+ '',
72
+ ' Studio: http://localhost:5173',
73
+ ' Terminal: npx @loopstack/cli run hello --arg name=You',
74
+ '',
75
+ ' CLAUDE.md primes coding agents with the conventions and the CLI feedback loop.',
76
+ '',
77
+ ].join('\n'));
78
+ });
79
+ }
80
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerEnvCommand(program: Command): void;
3
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuCzD"}
@@ -0,0 +1,42 @@
1
+ import pc from 'picocolors';
2
+ import { loadConfig, saveConfig } from '../config/config.js';
3
+ import { CliError } from '../errors.js';
4
+ import { printData, printStatus, renderTable } from '../output/format.js';
5
+ export function registerEnvCommand(program) {
6
+ const env = program.command('env').description('Manage saved backend environments');
7
+ env
8
+ .command('list')
9
+ .description('List saved environments')
10
+ .action((_options, cmd) => {
11
+ const config = loadConfig();
12
+ const names = Object.keys(config.environments);
13
+ const globals = cmd.optsWithGlobals();
14
+ if (globals.json) {
15
+ printData(JSON.stringify(config, null, 2));
16
+ return;
17
+ }
18
+ if (names.length === 0) {
19
+ printStatus('No environments saved — run `loopstack login`.');
20
+ return;
21
+ }
22
+ const rows = names.map((name) => [
23
+ config.defaultEnvironment === name ? `${name} ${pc.dim('(default)')}` : name,
24
+ config.environments[name].url,
25
+ config.environments[name].token ? 'yes' : 'no',
26
+ ]);
27
+ printData(renderTable(['NAME', 'URL', 'TOKEN'], rows));
28
+ });
29
+ env
30
+ .command('use <name>')
31
+ .description('Set the default environment')
32
+ .action((name) => {
33
+ const config = loadConfig();
34
+ if (!config.environments[name]) {
35
+ throw new CliError(`Unknown environment "${name}" — run \`loopstack env list\`.`);
36
+ }
37
+ config.defaultEnvironment = name;
38
+ saveConfig(config);
39
+ printStatus(pc.green(`✔ Default environment is now "${name}".`));
40
+ });
41
+ }
42
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE1E,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC;IAEpF,GAAG;SACA,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,EAAwB,CAAC;QAE5D,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,WAAW,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;YAC5E,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG;YAC7B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;SAC/C,CAAC,CAAC;QACH,SAAS,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,YAAY,CAAC;SACrB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,QAAQ,CAAC,wBAAwB,IAAI,iCAAiC,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,CAAC,kBAAkB,GAAG,IAAI,CAAC;QACjC,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,iCAAiC,IAAI,IAAI,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerListCommand(program: Command): void;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAe1D"}
@@ -0,0 +1,119 @@
1
+ import pc from 'picocolors';
2
+ import { createClientFor, resolveConnection } from '../config/resolve.js';
3
+ import { CliError } from '../errors.js';
4
+ import { printData, printStatus, renderTable } from '../output/format.js';
5
+ export function registerListCommand(program) {
6
+ program
7
+ .command('list [workflow]')
8
+ .description('List the workflows you can run, or show one workflow’s arguments')
9
+ .action(async (workflowName, _options, cmd) => {
10
+ const globals = cmd.optsWithGlobals();
11
+ const connection = resolveConnection(globals);
12
+ const client = createClientFor(connection);
13
+ if (workflowName) {
14
+ await describeWorkflow(client, workflowName, !!globals.json);
15
+ return;
16
+ }
17
+ await listWorkflows(client, connection, !!globals.json);
18
+ });
19
+ }
20
+ async function listWorkflows(client, connection, json) {
21
+ const apps = await client.config.apps();
22
+ const workflows = apps.flatMap((app) => app.workflows.map((workflow) => ({
23
+ workflowName: workflow.workflowName,
24
+ title: workflow.title ?? '',
25
+ description: workflow.description ?? '',
26
+ appName: app.appName,
27
+ appTitle: app.title,
28
+ })));
29
+ if (json) {
30
+ printData(JSON.stringify(workflows, null, 2));
31
+ return;
32
+ }
33
+ if (workflows.length === 0) {
34
+ printStatus(`No workflows on ${connection.url} — is a Loopstack app with @StudioApp modules running?`);
35
+ return;
36
+ }
37
+ const rows = workflows.map((workflow) => [workflow.workflowName, workflow.title, workflow.appTitle]);
38
+ printData(renderTable(['WORKFLOW', 'TITLE', 'APP'], rows, [32, 42, 20]));
39
+ printStatus('');
40
+ printStatus(`${workflows.length} workflows in ${apps.length} apps (${connection.name}) — \`loopstack list <workflow>\` shows its arguments`);
41
+ }
42
+ async function describeWorkflow(client, workflowName, json) {
43
+ const apps = await client.config.apps();
44
+ let app;
45
+ let workflow;
46
+ for (const candidate of apps) {
47
+ workflow = candidate.workflows.find((entry) => entry.workflowName === workflowName);
48
+ if (workflow) {
49
+ app = candidate;
50
+ break;
51
+ }
52
+ }
53
+ if (!workflow || !app) {
54
+ const available = apps.flatMap((entry) => entry.workflows.map((item) => item.workflowName)).sort();
55
+ throw new CliError(`Unknown workflow "${workflowName}". Available workflows: ${available.join(', ')}`);
56
+ }
57
+ const schema = (workflow.schema ?? {});
58
+ const properties = schema.type === 'object' ? (schema.properties ?? {}) : {};
59
+ const required = new Set(schema.required ?? []);
60
+ if (json) {
61
+ printData(JSON.stringify({
62
+ workflowName: workflow.workflowName,
63
+ title: workflow.title,
64
+ description: workflow.description,
65
+ appName: app.appName,
66
+ appTitle: app.title,
67
+ schema: workflow.schema ?? null,
68
+ }, null, 2));
69
+ return;
70
+ }
71
+ const title = workflow.title ? ` — ${workflow.title}` : '';
72
+ printData(`${pc.bold(workflow.workflowName)}${title}`);
73
+ if (workflow.description)
74
+ printData(workflow.description);
75
+ printData(pc.dim(`app: ${app.title} (${app.appName})`));
76
+ printData('');
77
+ const argNames = Object.keys(properties);
78
+ if (argNames.length === 0) {
79
+ printData(pc.dim('No arguments.'));
80
+ }
81
+ else {
82
+ const rows = argNames.map((name) => {
83
+ const property = properties[name];
84
+ return [
85
+ name,
86
+ property.type ?? 'any',
87
+ required.has(name) && property.default === undefined ? 'yes' : 'no',
88
+ property.default !== undefined ? JSON.stringify(property.default) : '',
89
+ property.description ?? '',
90
+ ];
91
+ });
92
+ printData(renderTable(['ARGUMENT', 'TYPE', 'REQUIRED', 'DEFAULT', 'DESCRIPTION'], rows));
93
+ }
94
+ printData('');
95
+ printData(`Run it: ${pc.bold(exampleInvocation(workflow.workflowName, properties, required))}`);
96
+ }
97
+ function exampleInvocation(workflowName, properties, required) {
98
+ const sample = (property) => {
99
+ if (property.default !== undefined)
100
+ return JSON.stringify(property.default);
101
+ switch (property.type) {
102
+ case 'number':
103
+ case 'integer':
104
+ return '42';
105
+ case 'boolean':
106
+ return 'true';
107
+ default:
108
+ return `<${property.type ?? 'value'}>`;
109
+ }
110
+ };
111
+ const names = Object.keys(properties);
112
+ const shown = names.filter((name) => required.has(name));
113
+ const optional = names.filter((name) => !required.has(name));
114
+ if (shown.length === 0 || names.length <= 3)
115
+ shown.push(...optional.slice(0, 3 - shown.length));
116
+ const args = shown.map((name) => `--arg ${name}=${sample(properties[name])}`).join(' ');
117
+ return `loopstack run ${workflowName}${args ? ` ${args}` : ''}`;
118
+ }
119
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerLoginCommand(program: Command): void;
3
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsD3D"}
@@ -0,0 +1,62 @@
1
+ import { stdin, stdout } from 'node:process';
2
+ import { createInterface } from 'node:readline/promises';
3
+ import pc from 'picocolors';
4
+ import { createClient } from '@loopstack/client';
5
+ import { configPath, loadConfig, saveConfig } from '../config/config.js';
6
+ import { CliError } from '../errors.js';
7
+ import { printStatus } from '../output/format.js';
8
+ function suggestName(url) {
9
+ const hostname = new URL(url).hostname;
10
+ return hostname === 'localhost' || hostname === '127.0.0.1' ? 'local' : hostname;
11
+ }
12
+ export function registerLoginCommand(program) {
13
+ program
14
+ .command('login')
15
+ .description('Save a backend environment to ~/.loopstack/config.json (pass --url/--token or answer the prompts)')
16
+ .option('--name <name>', 'environment name')
17
+ .option('--studio-url <url>', 'Studio frontend URL — enables deep links in run output')
18
+ .action(async (_options, cmd) => {
19
+ const merged = cmd.optsWithGlobals();
20
+ let { url, token, name, studioUrl } = merged;
21
+ token = token || undefined;
22
+ studioUrl = studioUrl || undefined;
23
+ if (!url && !stdin.isTTY) {
24
+ throw new CliError('Non-interactive shell — pass --url (and --token for authenticated backends).');
25
+ }
26
+ if (!url || (token === undefined && stdin.isTTY)) {
27
+ const rl = createInterface({ input: stdin, output: stdout });
28
+ try {
29
+ if (!url) {
30
+ url = (await rl.question('Backend URL [http://localhost:3000]: ')).trim() || 'http://localhost:3000';
31
+ }
32
+ if (token === undefined) {
33
+ token = (await rl.question('API token (lsk_…, empty for local no-auth): ')).trim() || undefined;
34
+ }
35
+ if (studioUrl === undefined) {
36
+ const isLocal = ['localhost', '127.0.0.1'].includes(new URL(url).hostname);
37
+ const suggestion = isLocal ? 'http://localhost:5173' : '';
38
+ const hint = suggestion ? ` [${suggestion}]` : ' (empty for none)';
39
+ studioUrl = (await rl.question(`Studio URL${hint}: `)).trim() || suggestion || undefined;
40
+ }
41
+ if (!name) {
42
+ const suggested = suggestName(url);
43
+ name = (await rl.question(`Environment name [${suggested}]: `)).trim() || suggested;
44
+ }
45
+ }
46
+ finally {
47
+ rl.close();
48
+ }
49
+ }
50
+ name ??= suggestName(url);
51
+ printStatus(pc.dim(`Probing ${url} …`));
52
+ const client = createClient({ url, token, envKey: name });
53
+ await client.workflows.list({ limit: 1 });
54
+ const config = loadConfig();
55
+ config.environments[name] = { ...config.environments[name], url, token, ...(studioUrl && { studioUrl }) };
56
+ config.defaultEnvironment ??= name;
57
+ saveConfig(config);
58
+ const isDefault = config.defaultEnvironment === name;
59
+ printStatus(pc.green(`✔ Environment "${name}" saved to ${configPath()}${isDefault ? ' (default)' : ''}.`));
60
+ });
61
+ }
62
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerRunCommand(program: Command): void;
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgGzD"}
@@ -0,0 +1,94 @@
1
+ import { Writable } from 'node:stream';
2
+ import pc from 'picocolors';
3
+ import { WorkflowState } from '@loopstack/contracts/enums';
4
+ import { createClientFor, resolveConnection } from '../config/resolve.js';
5
+ import { ExitCode } from '../errors.js';
6
+ import { createIdleHandler } from '../hitl/idle-handler.js';
7
+ import { formatDuration, printData, printStatus, renderResult } from '../output/format.js';
8
+ import { openInBrowser, studioRunUrl } from '../output/studio-link.js';
9
+ import { parseRunArgs } from '../run/args.js';
10
+ import { createDocumentRenderer } from '../run/documents.js';
11
+ import { followRun } from '../run/follow.js';
12
+ import { resolveWorkspaceId } from '../run/workspace.js';
13
+ const collect = (value, previous) => [...previous, value];
14
+ const discard = () => new Writable({ write: (_chunk, _encoding, callback) => callback() });
15
+ export function registerRunCommand(program) {
16
+ program
17
+ .command('run <workflow>')
18
+ .description('Start a workflow run and follow it live (exit 0 completed / 1 failed / 3 waiting for input)')
19
+ .option('--arg <key=value>', 'workflow argument, repeatable; key=@file.json reads a file, key=@- reads stdin', collect, [])
20
+ .option('--workspace <id>', 'workspace to run in (default: newest workspace of the workflow’s app)')
21
+ .option('--detach', 'start the run, print its id, exit immediately')
22
+ .option('--quiet', 'no progress — print only the final result')
23
+ .option('--open', 'open the run in Studio')
24
+ .option('--editor', 'answer field forms in $EDITOR instead of handing off to Studio')
25
+ .action(async (workflowName, options, cmd) => {
26
+ const globals = cmd.optsWithGlobals();
27
+ const connection = resolveConnection(globals);
28
+ const client = createClientFor(connection);
29
+ const json = !!globals.json;
30
+ const quiet = !!options.quiet;
31
+ const out = json ? process.stderr : quiet ? discard() : process.stdout;
32
+ const statusOut = json || quiet ? process.stderr : process.stdout;
33
+ const args = parseRunArgs(options.arg);
34
+ const workspaceId = await resolveWorkspaceId(client, workflowName, options.workspace, connection.workspaceId);
35
+ const events = options.detach ? undefined : client.stream.events();
36
+ const startedAt = Date.now();
37
+ const run = await client.processor.start({ workflowName, workspaceId, args });
38
+ out.write(pc.dim(`▸ run ${run.workflowId} started\n`));
39
+ const link = studioRunUrl(connection, run.workflowId);
40
+ if (link && events)
41
+ out.write(pc.dim(`⧉ ${link}\n`));
42
+ if (options.open) {
43
+ if (link)
44
+ openInBrowser(link);
45
+ else
46
+ printStatus('No Studio URL configured for this environment — set one with `loopstack login`.');
47
+ }
48
+ if (!events) {
49
+ if (link)
50
+ printStatus(pc.dim(`⧉ ${link}`));
51
+ printStatus(pc.dim(`resume with: loopstack runs ${run.workflowId} --follow`));
52
+ printData(json ? JSON.stringify({ workflowId: run.workflowId, ...(link && { studioUrl: link }) }) : run.workflowId);
53
+ process.exit(ExitCode.Success);
54
+ }
55
+ const outcome = await followRun(events, run.workflowId, out, {
56
+ onIdle: createIdleHandler(client, run.workflowId, statusOut, { studioUrl: link, editor: options.editor }),
57
+ onDocument: createDocumentRenderer(client, out),
58
+ });
59
+ client.stream.close();
60
+ const durationMs = Date.now() - startedAt;
61
+ const full = await client.workflows.get(run.workflowId);
62
+ if (json) {
63
+ printData(JSON.stringify({
64
+ workflowId: run.workflowId,
65
+ status: outcome.status,
66
+ result: full.result,
67
+ errorMessage: full.errorMessage,
68
+ durationMs,
69
+ ...(link && { studioUrl: link }),
70
+ }, null, 2));
71
+ }
72
+ if (outcome.status === WorkflowState.Completed) {
73
+ if (!json && quiet) {
74
+ const result = full.result;
75
+ printData(typeof result === 'string' ? result : JSON.stringify(result ?? null, null, 2));
76
+ }
77
+ if (!json && !quiet)
78
+ renderResult(out, full.result);
79
+ statusOut.write(`${pc.green('■')} run completed in ${formatDuration(durationMs)}\n`);
80
+ process.exit(ExitCode.Success);
81
+ }
82
+ if (outcome.status === WorkflowState.Waiting || outcome.status === WorkflowState.Paused) {
83
+ statusOut.write(`${pc.yellow('⏸')} run is waiting for input — resume with \`loopstack runs ${run.workflowId} --follow\`\n`);
84
+ if (link)
85
+ statusOut.write(pc.dim(`⧉ answer in Studio: ${link}\n`));
86
+ process.exit(ExitCode.NeedsInput);
87
+ }
88
+ statusOut.write(`${pc.red('■')} run ${outcome.status}${full.errorMessage ? `: ${full.errorMessage}` : ''}\n`);
89
+ if (link)
90
+ statusOut.write(pc.dim(`⧉ inspect in Studio: ${link}\n`));
91
+ process.exit(ExitCode.RunFailed);
92
+ });
93
+ }
94
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerRunsCommand(program: Command): void;
3
+ //# sourceMappingURL=runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwB1D"}