@loopstack/cli 0.15.1 → 0.18.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/README.md +66 -0
- package/dist/commands/answer.d.ts +3 -0
- package/dist/commands/answer.d.ts.map +1 -0
- package/dist/commands/answer.js +82 -0
- package/dist/commands/answer.js.map +1 -0
- package/dist/commands/attach.d.ts +3 -0
- package/dist/commands/attach.d.ts.map +1 -0
- package/dist/commands/attach.js +103 -0
- package/dist/commands/attach.js.map +1 -0
- package/dist/commands/create.d.ts +3 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +80 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/env.d.ts +3 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +42 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +119 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +62 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +119 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/runs.d.ts +3 -0
- package/dist/commands/runs.d.ts.map +1 -0
- package/dist/commands/runs.js +151 -0
- package/dist/commands/runs.js.map +1 -0
- package/dist/commands/watch.d.ts +3 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +50 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/config/config.d.ts +14 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +25 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/resolve.d.ts +18 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +57 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +36 -0
- package/dist/errors.js.map +1 -0
- package/dist/hitl/discovery.d.ts +24 -0
- package/dist/hitl/discovery.d.ts.map +1 -0
- package/dist/hitl/discovery.js +124 -0
- package/dist/hitl/discovery.js.map +1 -0
- package/dist/hitl/idle-handler.d.ts +7 -0
- package/dist/hitl/idle-handler.d.ts.map +1 -0
- package/dist/hitl/idle-handler.js +103 -0
- package/dist/hitl/idle-handler.js.map +1 -0
- package/dist/hitl/pending.d.ts +16 -0
- package/dist/hitl/pending.d.ts.map +1 -0
- package/dist/hitl/pending.js +45 -0
- package/dist/hitl/pending.js.map +1 -0
- package/dist/hitl/prompt.d.ts +11 -0
- package/dist/hitl/prompt.d.ts.map +1 -0
- package/dist/hitl/prompt.js +69 -0
- package/dist/hitl/prompt.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +37 -0
- package/dist/main.js.map +1 -0
- package/dist/output/format.d.ts +7 -0
- package/dist/output/format.d.ts.map +1 -0
- package/dist/output/format.js +58 -0
- package/dist/output/format.js.map +1 -0
- package/dist/output/studio-link.d.ts +4 -0
- package/dist/output/studio-link.d.ts.map +1 -0
- package/dist/output/studio-link.js +17 -0
- package/dist/output/studio-link.js.map +1 -0
- package/dist/run/args.d.ts +2 -0
- package/dist/run/args.d.ts.map +1 -0
- package/dist/run/args.js +41 -0
- package/dist/run/args.js.map +1 -0
- package/dist/run/documents.d.ts +15 -0
- package/dist/run/documents.d.ts.map +1 -0
- package/dist/run/documents.js +100 -0
- package/dist/run/documents.js.map +1 -0
- package/dist/run/follow.d.ts +18 -0
- package/dist/run/follow.d.ts.map +1 -0
- package/dist/run/follow.js +200 -0
- package/dist/run/follow.js.map +1 -0
- package/dist/run/retry.d.ts +5 -0
- package/dist/run/retry.d.ts.map +1 -0
- package/dist/run/retry.js +59 -0
- package/dist/run/retry.js.map +1 -0
- package/dist/run/trail.d.ts +17 -0
- package/dist/run/trail.d.ts.map +1 -0
- package/dist/run/trail.js +42 -0
- package/dist/run/trail.js.map +1 -0
- package/dist/run/workspace.d.ts +3 -0
- package/dist/run/workspace.d.ts.map +1 -0
- package/dist/run/workspace.js +26 -0
- package/dist/run/workspace.js.map +1 -0
- package/dist/widgets/collect/form.collect.d.ts +7 -0
- package/dist/widgets/collect/form.collect.d.ts.map +1 -0
- package/dist/widgets/collect/form.collect.js +71 -0
- package/dist/widgets/collect/form.collect.js.map +1 -0
- package/dist/widgets/collect/prompts.collect.d.ts +5 -0
- package/dist/widgets/collect/prompts.collect.d.ts.map +1 -0
- package/dist/widgets/collect/prompts.collect.js +38 -0
- package/dist/widgets/collect/prompts.collect.js.map +1 -0
- package/dist/widgets/collect/secret-input.collect.d.ts +3 -0
- package/dist/widgets/collect/secret-input.collect.d.ts.map +1 -0
- package/dist/widgets/collect/secret-input.collect.js +47 -0
- package/dist/widgets/collect/secret-input.collect.js.map +1 -0
- package/dist/widgets/collect/transition.d.ts +3 -0
- package/dist/widgets/collect/transition.d.ts.map +1 -0
- package/dist/widgets/collect/transition.js +5 -0
- package/dist/widgets/collect/transition.js.map +1 -0
- package/dist/widgets/collect/workflow.collect.d.ts +4 -0
- package/dist/widgets/collect/workflow.collect.d.ts.map +1 -0
- package/dist/widgets/collect/workflow.collect.js +24 -0
- package/dist/widgets/collect/workflow.collect.js.map +1 -0
- package/dist/widgets/document/form.widget.d.ts +3 -0
- package/dist/widgets/document/form.widget.d.ts.map +1 -0
- package/dist/widgets/document/form.widget.js +34 -0
- package/dist/widgets/document/form.widget.js.map +1 -0
- package/dist/widgets/document/json.widget.d.ts +3 -0
- package/dist/widgets/document/json.widget.d.ts.map +1 -0
- package/dist/widgets/document/json.widget.js +17 -0
- package/dist/widgets/document/json.widget.js.map +1 -0
- package/dist/widgets/document/link.widget.d.ts +3 -0
- package/dist/widgets/document/link.widget.d.ts.map +1 -0
- package/dist/widgets/document/link.widget.js +9 -0
- package/dist/widgets/document/link.widget.js.map +1 -0
- package/dist/widgets/document/llm-message.widget.d.ts +3 -0
- package/dist/widgets/document/llm-message.widget.d.ts.map +1 -0
- package/dist/widgets/document/llm-message.widget.js +67 -0
- package/dist/widgets/document/llm-message.widget.js.map +1 -0
- package/dist/widgets/document/message.widget.d.ts +5 -0
- package/dist/widgets/document/message.widget.d.ts.map +1 -0
- package/dist/widgets/document/message.widget.js +35 -0
- package/dist/widgets/document/message.widget.js.map +1 -0
- package/dist/widgets/document/oauth-prompt.widget.d.ts +4 -0
- package/dist/widgets/document/oauth-prompt.widget.d.ts.map +1 -0
- package/dist/widgets/document/oauth-prompt.widget.js +22 -0
- package/dist/widgets/document/oauth-prompt.widget.js.map +1 -0
- package/dist/widgets/document/secret-request.widget.d.ts +3 -0
- package/dist/widgets/document/secret-request.widget.d.ts.map +1 -0
- package/dist/widgets/document/secret-request.widget.js +9 -0
- package/dist/widgets/document/secret-request.widget.js.map +1 -0
- package/dist/widgets/editor.d.ts +3 -0
- package/dist/widgets/editor.d.ts.map +1 -0
- package/dist/widgets/editor.js +60 -0
- package/dist/widgets/editor.js.map +1 -0
- package/dist/widgets/field/field-widgets.d.ts +6 -0
- package/dist/widgets/field/field-widgets.d.ts.map +1 -0
- package/dist/widgets/field/field-widgets.js +64 -0
- package/dist/widgets/field/field-widgets.js.map +1 -0
- package/dist/widgets/registry.d.ts +6 -0
- package/dist/widgets/registry.d.ts.map +1 -0
- package/dist/widgets/registry.js +45 -0
- package/dist/widgets/registry.js.map +1 -0
- package/dist/widgets/types.d.ts +44 -0
- package/dist/widgets/types.d.ts.map +1 -0
- package/dist/widgets/types.js +2 -0
- package/dist/widgets/types.js.map +1 -0
- package/fixtures/app/CLAUDE.md +54 -0
- package/fixtures/app/README.md +21 -0
- package/fixtures/app/docker-compose.yml +33 -0
- package/fixtures/app/env.example +16 -0
- package/fixtures/app/nest-cli.json +10 -0
- package/fixtures/app/src/app.module.ts +8 -0
- package/fixtures/app/src/hello/hello.module.ts +12 -0
- package/fixtures/app/src/hello/hello.workflow.ts +28 -0
- package/fixtures/app/src/main.ts +11 -0
- package/package.json +36 -10
- package/bin/loopstack.js +0 -33
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
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. Choices, confirms, chat inputs, and secret entry render as native prompts; forms submit as-is or open the complete content in `$EDITOR` first:
|
|
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
|
+
Input only Studio can collect is named explicitly (with a deep link) instead of hanging, and browser-based waits — like an OAuth sign-in link — resume the attached session automatically once completed.
|
|
40
|
+
|
|
41
|
+
## Commands
|
|
42
|
+
|
|
43
|
+
| Command | What it does |
|
|
44
|
+
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| `loopstack create <dir>` | Scaffold a new Loopstack app (NestJS + LoopstackModule + hello workflow + docker-compose) |
|
|
46
|
+
| `loopstack list [workflow]` | Workflows you can run; with a name: its arguments and a ready-to-run example |
|
|
47
|
+
| `loopstack run <workflow>` | Start a run and follow it live; `--arg k=v`, `--arg k=@file.json`, `--arg k=@-` (stdin), `--detach`, `--quiet`, `--open`, `--json` |
|
|
48
|
+
| `loopstack runs [run-id]` | Recent runs (waiting-for-input first) or one run’s full transcript; `--json` includes the pending prompt (`pendingPrompt`), `--record <file>` derives a replay fixture from the run’s recorded tool calls |
|
|
49
|
+
| `loopstack answer <run-id>` | Answer a waiting run’s prompt non-interactively — `--arg k=v` fields or `--payload <json>`; for agents and scripts |
|
|
50
|
+
| `loopstack attach <run-id>` | Rejoin a run live — transcript so far, then streaming output and interactive prompts (docker/tmux semantics) |
|
|
51
|
+
| `loopstack watch` | Live event stream; `--workflow`, `--type`, NDJSON with `--json` |
|
|
52
|
+
| `loopstack login` | Save a backend environment to `~/.loopstack/config.json` |
|
|
53
|
+
| `loopstack env list\|use` | Manage saved environments |
|
|
54
|
+
|
|
55
|
+
## CI
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
- run: npx --yes @loopstack/cli run triage-ticket --arg ticket=@samples/ticket-042.json --json
|
|
59
|
+
env:
|
|
60
|
+
LOOPSTACK_URL: ${{ vars.LOOPSTACK_URL }}
|
|
61
|
+
LOOPSTACK_TOKEN: ${{ secrets.LOOPSTACK_TOKEN }}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
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.
|
|
65
|
+
|
|
66
|
+
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 @@
|
|
|
1
|
+
{"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/commands/answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyD5D"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { createClientFor, resolveConnection } from '../config/resolve.js';
|
|
4
|
+
import { CliError, ExitCode } from '../errors.js';
|
|
5
|
+
import { inspectPendingPrompt } from '../hitl/pending.js';
|
|
6
|
+
import { printData, printStatus } from '../output/format.js';
|
|
7
|
+
import { parseRunArgs } from '../run/args.js';
|
|
8
|
+
const collect = (value, previous) => [...previous, value];
|
|
9
|
+
export function registerAnswerCommand(program) {
|
|
10
|
+
program
|
|
11
|
+
.command('answer <runId>')
|
|
12
|
+
.description('Answer the prompt a waiting run is parked on — non-interactive (for agents and scripts)')
|
|
13
|
+
.option('--arg <key=value>', 'answer field (repeatable); key=@file reads a file, key=@- reads stdin', collect, [])
|
|
14
|
+
.option('--payload <json>', 'full answer payload as JSON; @file reads a file, @- reads stdin')
|
|
15
|
+
.option('--transition <id>', 'wait transition to answer (required when several are available)')
|
|
16
|
+
.action(async (runId, options, cmd) => {
|
|
17
|
+
const globals = cmd.optsWithGlobals();
|
|
18
|
+
const connection = resolveConnection(globals);
|
|
19
|
+
const client = createClientFor(connection);
|
|
20
|
+
const json = !!globals.json;
|
|
21
|
+
const pending = await inspectPendingPrompt(client, runId);
|
|
22
|
+
if (!pending) {
|
|
23
|
+
throw new CliError(`Run ${runId} has no pending prompt — nothing to answer.`);
|
|
24
|
+
}
|
|
25
|
+
if (pending.studioOnly) {
|
|
26
|
+
throw new CliError(`The pending input (${pending.widget}) can only be collected in Studio — the CLI cannot answer it.`);
|
|
27
|
+
}
|
|
28
|
+
const transition = options.transition ?? pending.transition;
|
|
29
|
+
if (!transition) {
|
|
30
|
+
throw new CliError(`Several transitions are available (${pending.transitions.join(', ')}) — pick one with --transition <id>.`);
|
|
31
|
+
}
|
|
32
|
+
if (!pending.transitions.includes(transition)) {
|
|
33
|
+
throw new CliError(`Transition '${transition}' is not available — currently available: ${pending.transitions.join(', ')}.`);
|
|
34
|
+
}
|
|
35
|
+
const payload = buildPayload(options);
|
|
36
|
+
await client.processor.run(pending.workflowId, {
|
|
37
|
+
transition: { id: transition, workflowId: pending.workflowId, payload },
|
|
38
|
+
});
|
|
39
|
+
if (json) {
|
|
40
|
+
printData(JSON.stringify({ runId, promptWorkflowId: pending.workflowId, transition, payload, submitted: true }, null, 2));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
printStatus(`${pc.green('✓')} answered '${transition}' on ${pending.workflowName}`);
|
|
44
|
+
printStatus(pc.dim(` follow with: loopstack attach ${runId}`));
|
|
45
|
+
}
|
|
46
|
+
process.exit(ExitCode.Success);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function buildPayload(options) {
|
|
50
|
+
if (options.payload !== undefined && options.arg.length > 0) {
|
|
51
|
+
throw new CliError('Use either --payload or --arg, not both.');
|
|
52
|
+
}
|
|
53
|
+
if (options.payload !== undefined) {
|
|
54
|
+
const raw = options.payload === '@-'
|
|
55
|
+
? readFileSync(0, 'utf8')
|
|
56
|
+
: options.payload.startsWith('@')
|
|
57
|
+
? readPayloadFile(options.payload.slice(1))
|
|
58
|
+
: options.payload;
|
|
59
|
+
try {
|
|
60
|
+
const parsed = JSON.parse(raw);
|
|
61
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
62
|
+
throw new CliError('--payload must be a JSON object.');
|
|
63
|
+
}
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof CliError)
|
|
68
|
+
throw error;
|
|
69
|
+
throw new CliError(`--payload is not valid JSON: ${raw.slice(0, 120)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return parseRunArgs(options.arg);
|
|
73
|
+
}
|
|
74
|
+
function readPayloadFile(path) {
|
|
75
|
+
try {
|
|
76
|
+
return readFileSync(path, 'utf8');
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new CliError(`Cannot read --payload file "${path}".`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=answer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer.js","sourceRoot":"","sources":["../../src/commands/answer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../../src/commands/attach.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+BzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyG5D"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { WorkflowState } from '@loopstack/contracts/enums';
|
|
3
|
+
import { createClientFor, resolveConnection } from '../config/resolve.js';
|
|
4
|
+
import { ExitCode } from '../errors.js';
|
|
5
|
+
import { createIdleHandler } from '../hitl/idle-handler.js';
|
|
6
|
+
import { printData, printStatus, renderResult } from '../output/format.js';
|
|
7
|
+
import { openInBrowser, studioRunUrl } from '../output/studio-link.js';
|
|
8
|
+
import { followRun } from '../run/follow.js';
|
|
9
|
+
import { offerRetry } from '../run/retry.js';
|
|
10
|
+
import { renderRunTrail } from '../run/trail.js';
|
|
11
|
+
const TERMINAL_STATES = [
|
|
12
|
+
WorkflowState.Completed,
|
|
13
|
+
WorkflowState.Failed,
|
|
14
|
+
WorkflowState.Canceled,
|
|
15
|
+
];
|
|
16
|
+
const IDLE_STATES = [WorkflowState.Waiting, WorkflowState.Paused];
|
|
17
|
+
function exitCodeForStatus(status) {
|
|
18
|
+
if (status === WorkflowState.Completed)
|
|
19
|
+
return ExitCode.Success;
|
|
20
|
+
if (IDLE_STATES.includes(status))
|
|
21
|
+
return ExitCode.NeedsInput;
|
|
22
|
+
return ExitCode.RunFailed;
|
|
23
|
+
}
|
|
24
|
+
export function registerAttachCommand(program) {
|
|
25
|
+
program
|
|
26
|
+
.command('attach <runId>')
|
|
27
|
+
.description('Attach to a run: transcript so far, then live progress and prompts (exit 0 completed / 1 failed / 3 waiting)')
|
|
28
|
+
.option('--open', 'open the run in Studio')
|
|
29
|
+
.action(async (runId, options, cmd) => {
|
|
30
|
+
const globals = cmd.optsWithGlobals();
|
|
31
|
+
const connection = resolveConnection(globals);
|
|
32
|
+
const client = createClientFor(connection);
|
|
33
|
+
const json = !!globals.json;
|
|
34
|
+
const out = json ? process.stderr : process.stdout;
|
|
35
|
+
const link = studioRunUrl(connection, runId);
|
|
36
|
+
if (options.open) {
|
|
37
|
+
if (link)
|
|
38
|
+
openInBrowser(link);
|
|
39
|
+
else
|
|
40
|
+
printStatus('No Studio URL configured for this environment — set one with `loopstack login`.');
|
|
41
|
+
}
|
|
42
|
+
const events = client.stream.events();
|
|
43
|
+
await client.stream.waitForOpen();
|
|
44
|
+
const workflow = await client.workflows.get(runId);
|
|
45
|
+
const checkpoints = await client.workflows.checkpoints(runId);
|
|
46
|
+
const { renderer, streamedMessageIds, streamedToolCallIds, visibleWorkflowIds } = await renderRunTrail(client, connection, out, workflow, checkpoints);
|
|
47
|
+
if (TERMINAL_STATES.includes(workflow.status)) {
|
|
48
|
+
if (json) {
|
|
49
|
+
printData(JSON.stringify({
|
|
50
|
+
workflowId: runId,
|
|
51
|
+
status: workflow.status,
|
|
52
|
+
result: workflow.result,
|
|
53
|
+
errorMessage: workflow.errorMessage,
|
|
54
|
+
}, null, 2));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
out.write('\n');
|
|
58
|
+
if (renderResult(out, workflow.result))
|
|
59
|
+
out.write('\n');
|
|
60
|
+
}
|
|
61
|
+
out.write(pc.dim(`run already ${workflow.status} — nothing to attach to\n`));
|
|
62
|
+
if (workflow.status !== WorkflowState.Completed && workflow.errorMessage) {
|
|
63
|
+
out.write(`${pc.red('■')} ${workflow.errorMessage}\n`);
|
|
64
|
+
}
|
|
65
|
+
client.stream.close();
|
|
66
|
+
process.exit(exitCodeForStatus(workflow.status));
|
|
67
|
+
}
|
|
68
|
+
out.write(pc.dim('\n— attached, following live —\n'));
|
|
69
|
+
const followOptions = {
|
|
70
|
+
onIdle: createIdleHandler(client, runId, out, { studioUrl: link }),
|
|
71
|
+
initiallyIdle: IDLE_STATES.includes(workflow.status),
|
|
72
|
+
onDocument: renderer.onDocument,
|
|
73
|
+
streamedMessageIds,
|
|
74
|
+
streamedToolCallIds,
|
|
75
|
+
visibleWorkflowIds,
|
|
76
|
+
onStreamReset: async () => (await client.workflows.get(runId)).status,
|
|
77
|
+
};
|
|
78
|
+
let outcome = await followRun(events, runId, out, followOptions);
|
|
79
|
+
if (!json)
|
|
80
|
+
outcome = await offerRetry(client, runId, events, out, out, followOptions, outcome);
|
|
81
|
+
client.stream.close();
|
|
82
|
+
const full = await client.workflows.get(runId);
|
|
83
|
+
if (json) {
|
|
84
|
+
printData(JSON.stringify({ workflowId: runId, status: outcome.status, result: full.result, errorMessage: full.errorMessage }, null, 2));
|
|
85
|
+
}
|
|
86
|
+
if (outcome.status === WorkflowState.Completed) {
|
|
87
|
+
if (!json) {
|
|
88
|
+
out.write('\n');
|
|
89
|
+
if (renderResult(out, full.result))
|
|
90
|
+
out.write('\n');
|
|
91
|
+
}
|
|
92
|
+
out.write(`${pc.green('■')} run completed\n`);
|
|
93
|
+
}
|
|
94
|
+
else if (IDLE_STATES.includes(outcome.status)) {
|
|
95
|
+
out.write(`${pc.yellow('⏸')} run is still waiting for input\n`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
out.write(`${pc.red('■')} run ${outcome.status}${full.errorMessage ? `: ${full.errorMessage}` : ''}\n`);
|
|
99
|
+
}
|
|
100
|
+
process.exit(exitCodeForStatus(outcome.status));
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.js","sourceRoot":"","sources":["../../src/commands/attach.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|