@storystick/cli 0.0.0-stage → 0.2.0-rc.1

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 (123) hide show
  1. package/CONTENT-IMPORT.md +349 -0
  2. package/LICENSE +112 -0
  3. package/PUBLIC-API.md +30 -0
  4. package/README.md +263 -2
  5. package/assets/next-v1/app/[[...pathname]]/error.tsx +10 -0
  6. package/assets/next-v1/app/[[...pathname]]/not-found.tsx +8 -0
  7. package/assets/next-v1/app/[[...pathname]]/page.tsx +38 -0
  8. package/assets/next-v1/app/api/storystick/[...action]/route.ts +4 -0
  9. package/assets/next-v1/app/layout.tsx +28 -0
  10. package/assets/next-v1/app/sitemap.ts +3 -0
  11. package/assets/next-v1/env.local.example +13 -0
  12. package/assets/next-v1/globals.css +17 -0
  13. package/assets/next-v1/lib/site.ts +10 -0
  14. package/assets/next-v1/next.config.ts +4 -0
  15. package/assets/skills/storystick-development/SKILL.md +79 -0
  16. package/assets/skills/storystick-development/references/setup.md +152 -0
  17. package/assets/skills/storystick-development/references/story-and-next.md +49 -0
  18. package/dist/_backfill-recommendation.d.ts +12 -0
  19. package/dist/_backfill-recommendation.js +18 -0
  20. package/dist/asset-import.d.ts +50 -0
  21. package/dist/asset-import.js +160 -0
  22. package/dist/assistant-read-client.d.ts +3 -0
  23. package/dist/assistant-read-client.js +8 -0
  24. package/dist/auth-device.d.ts +153 -0
  25. package/dist/auth-device.js +390 -0
  26. package/dist/bootstrap-client.d.ts +52 -0
  27. package/dist/bootstrap-client.js +19 -0
  28. package/dist/cli-error.d.ts +54 -0
  29. package/dist/cli-error.js +107 -0
  30. package/dist/cli.d.ts +68 -0
  31. package/dist/cli.js +1520 -0
  32. package/dist/commands/archive.d.ts +17 -0
  33. package/dist/commands/archive.js +86 -0
  34. package/dist/commands/backfill-refs.d.ts +54 -0
  35. package/dist/commands/backfill-refs.js +217 -0
  36. package/dist/commands/connect.d.ts +11 -0
  37. package/dist/commands/connect.js +124 -0
  38. package/dist/commands/connection.d.ts +57 -0
  39. package/dist/commands/connection.js +83 -0
  40. package/dist/commands/content.d.ts +11 -0
  41. package/dist/commands/content.js +107 -0
  42. package/dist/commands/delivery.d.ts +22 -0
  43. package/dist/commands/delivery.js +99 -0
  44. package/dist/commands/info.d.ts +35 -0
  45. package/dist/commands/info.js +62 -0
  46. package/dist/commands/list.d.ts +28 -0
  47. package/dist/commands/list.js +116 -0
  48. package/dist/commands/migrate.d.ts +80 -0
  49. package/dist/commands/migrate.js +550 -0
  50. package/dist/commands/release.d.ts +8 -0
  51. package/dist/commands/release.js +60 -0
  52. package/dist/commands/setup.d.ts +6 -0
  53. package/dist/commands/setup.js +58 -0
  54. package/dist/commands/slice-previews.d.ts +17 -0
  55. package/dist/commands/slice-previews.js +233 -0
  56. package/dist/commands/source.d.ts +82 -0
  57. package/dist/commands/source.js +192 -0
  58. package/dist/content-import.d.ts +78 -0
  59. package/dist/content-import.js +210 -0
  60. package/dist/generated-transaction.d.ts +22 -0
  61. package/dist/generated-transaction.js +330 -0
  62. package/dist/hub-client.d.ts +72 -0
  63. package/dist/hub-client.js +178 -0
  64. package/dist/init-operation.d.ts +98 -0
  65. package/dist/init-operation.js +427 -0
  66. package/dist/init-readiness.d.ts +10 -0
  67. package/dist/init-readiness.js +50 -0
  68. package/dist/init-scaffold.d.ts +54 -0
  69. package/dist/init-scaffold.js +439 -0
  70. package/dist/init.d.ts +51 -0
  71. package/dist/init.js +789 -0
  72. package/dist/mcp-execution.d.ts +15 -0
  73. package/dist/mcp-execution.js +90 -0
  74. package/dist/mcp.d.ts +7 -0
  75. package/dist/mcp.js +41 -0
  76. package/dist/migration-artifact.d.ts +13 -0
  77. package/dist/migration-artifact.js +154 -0
  78. package/dist/operations-client.d.ts +137 -0
  79. package/dist/operations-client.js +130 -0
  80. package/dist/output.d.ts +347 -0
  81. package/dist/output.js +771 -0
  82. package/dist/project-access.d.ts +18 -0
  83. package/dist/project-access.js +1 -0
  84. package/dist/project-connection.d.ts +62 -0
  85. package/dist/project-connection.js +347 -0
  86. package/dist/project-execution-client.d.ts +2 -0
  87. package/dist/project-execution-client.js +33 -0
  88. package/dist/push-client.d.ts +100 -0
  89. package/dist/push-client.js +160 -0
  90. package/dist/release-context.d.ts +13 -0
  91. package/dist/release-context.js +39 -0
  92. package/dist/release-schema-client.d.ts +16 -0
  93. package/dist/release-schema-client.js +33 -0
  94. package/dist/release-sync.d.ts +36 -0
  95. package/dist/release-sync.js +31 -0
  96. package/dist/resolve.d.ts +15 -0
  97. package/dist/resolve.js +80 -0
  98. package/dist/runtime-config.d.ts +18 -0
  99. package/dist/runtime-config.js +86 -0
  100. package/dist/schema-export.d.ts +10 -0
  101. package/dist/schema-export.js +28 -0
  102. package/dist/setup.d.ts +65 -0
  103. package/dist/setup.js +135 -0
  104. package/dist/source-git.d.ts +36 -0
  105. package/dist/source-git.js +197 -0
  106. package/dist/starter-resolver.d.ts +82 -0
  107. package/dist/starter-resolver.js +495 -0
  108. package/dist/sync-transaction.d.ts +29 -0
  109. package/dist/sync-transaction.js +159 -0
  110. package/dist/transport.d.ts +8 -0
  111. package/dist/transport.js +73 -0
  112. package/examples/sanity/README.md +79 -0
  113. package/examples/sanity/convert.mjs +228 -0
  114. package/examples/sanity/fixture/data.ndjson +7 -0
  115. package/examples/sanity/fixture/mapping.json +44 -0
  116. package/examples/sanity/fixture/originals/mark.svg +1 -0
  117. package/examples/sanity/stories/articleBody.story +23 -0
  118. package/examples/sanity/stories/copy.story +7 -0
  119. package/examples/sanity/stories/page.story +19 -0
  120. package/examples/sanity/stories/picture.story +7 -0
  121. package/examples/sanity/stories/settings.story +9 -0
  122. package/examples/sanity/stories/stack.story +10 -0
  123. package/package.json +75 -3
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Storystick CLI — output primitives (ADR-061).
3
+ *
4
+ * Every user-visible byte the CLI emits flows through this module. The
5
+ * boundary is enforced mechanically by `scripts/lint-output.mjs`, which
6
+ * forbids raw `console.*`, `process.(stdout|stderr).write`, and direct
7
+ * imports of `ora` / `@inquirer/prompts` anywhere outside this file.
8
+ *
9
+ * The five locked style rules (ADR-061 §Decision):
10
+ * 1. One active line at a time — spinner text mutates in place.
11
+ * 2. Two icons (✔ green, ✖ red), four colors (green / red / cyan-spinner
12
+ * / rare yellow+gray).
13
+ * 3. Zero chrome — no boxes, no gutters, no banners.
14
+ * 4. URLs emitted bare (terminal auto-linkifies).
15
+ * 5. stderr for status, stdout for data payloads.
16
+ *
17
+ * Mode state is module-global: a CLI is a single short-lived process, not
18
+ * a library. `resetOutput()` is the only test-isolation mechanism.
19
+ *
20
+ * `ora` and `@inquirer/prompts` are lazy-imported inside the primitives
21
+ * that need them — fast commands (`generate`, `push`, `sync`) never pay
22
+ * the startup cost.
23
+ */
24
+ import type { Diagnostic } from '@storystick/core';
25
+ export type OutputMode = 'human' | 'json';
26
+ export type OutputEvent = {
27
+ type: 'spinner-start';
28
+ text: string;
29
+ } | {
30
+ type: 'spinner-change';
31
+ text: string;
32
+ } | {
33
+ type: 'spinner-success';
34
+ text: string;
35
+ } | {
36
+ type: 'spinner-failure';
37
+ text: string;
38
+ } | {
39
+ type: 'spinner-stop';
40
+ } | {
41
+ type: 'finished-step';
42
+ text: string;
43
+ } | {
44
+ type: 'failure';
45
+ text: string;
46
+ } | {
47
+ type: 'warning';
48
+ text: string;
49
+ } | {
50
+ type: 'message';
51
+ text: string;
52
+ } | {
53
+ type: 'data';
54
+ } | {
55
+ type: 'data-jsonl';
56
+ event: string;
57
+ } | {
58
+ type: 'prompt-device-auth';
59
+ } | {
60
+ type: 'prompt-input';
61
+ } | {
62
+ type: 'prompt-select';
63
+ } | {
64
+ type: 'prompt-confirm';
65
+ };
66
+ export interface Capture {
67
+ stdout: string[];
68
+ stderr: string[];
69
+ events: OutputEvent[];
70
+ }
71
+ export interface DeviceAuthPromptData {
72
+ /** Canonical recipient of the device credential, independent of the Hub UI. */
73
+ issuer?: string;
74
+ verificationUrl: string;
75
+ userCode: string;
76
+ expiresIn: number;
77
+ /** Text shown on the post-prompt spinner. Defaults to "Waiting for
78
+ * authorization…". Per ADR-061, all six call sites collapse to this
79
+ * single function. */
80
+ waitingText?: string;
81
+ }
82
+ export interface ConfigureOutputOptions {
83
+ json?: boolean;
84
+ verbose?: boolean;
85
+ quiet?: boolean;
86
+ }
87
+ /**
88
+ * Configure the per-invocation output mode (ADR-072 §D12).
89
+ *
90
+ * Mutual exclusivity:
91
+ * - `verbose + quiet` → fatal (exit 1 with hint) — they're directly
92
+ * contradictory.
93
+ * - `verbose + json` → JSON wins. `verbose` still affects what makes
94
+ * it INTO the envelope (info diagnostics rendered) but the human
95
+ * rendering layer is muted under JSON regardless.
96
+ * - `quiet + json` → both apply. stdout still emits the envelope
97
+ * (data is data); stderr is silent except for failures.
98
+ */
99
+ export declare function configureOutput(opts?: ConfigureOutputOptions): void;
100
+ export declare function getOutputMode(): OutputMode;
101
+ /**
102
+ * `--verbose` is set. Action handlers consult this to decide whether to
103
+ * render info-level diagnostics + list warning details post-success,
104
+ * instead of just counting them.
105
+ */
106
+ export declare function isVerbose(): boolean;
107
+ /**
108
+ * `--quiet` is set. Status / warning lines are muted under quiet — but
109
+ * failures (`logFailure`) and data (`logOutput`) always pass through
110
+ * per ADR-061 rule 5.
111
+ */
112
+ export declare function isQuiet(): boolean;
113
+ /**
114
+ * Fully reset module state. Call from `beforeEach` in tests — the in-process
115
+ * test suite shares this module across cases.
116
+ */
117
+ export declare function resetOutput(): void;
118
+ /**
119
+ * Start capturing output. Writes go to in-memory buffers instead of the
120
+ * real streams; events are appended to `events`. Inversion of control,
121
+ * no `process.std*` spying.
122
+ */
123
+ export declare function __testing_enableCapture(): Capture;
124
+ export declare function onEvent(fn: (event: OutputEvent) => void): () => void;
125
+ /** Dimmed status line — muted under --json or --quiet. */
126
+ export declare function logMessage(text: string): void;
127
+ export declare function logFinishedStep(text: string): void;
128
+ export declare function logFailure(text: string): void;
129
+ export declare function logWarning(text: string): void;
130
+ /**
131
+ * THE ONLY function writing to stdout. Payload must already carry its own
132
+ * trailing newline when the caller wants one (matches the Pattern D JSON
133
+ * convention at `list.ts` / `info.ts` today).
134
+ */
135
+ export declare function logOutput(payload: string): void;
136
+ import type { Envelope } from '@storystick/types/errors';
137
+ export type JsonDiagnostic = Diagnostic;
138
+ export type JsonError = Envelope;
139
+ export type CliJsonEnvelope = {
140
+ ok: true;
141
+ command: string;
142
+ version: '1';
143
+ data: unknown;
144
+ diagnostics: JsonDiagnostic[];
145
+ } | {
146
+ ok: false;
147
+ command: string;
148
+ version: '1';
149
+ error: JsonError;
150
+ diagnostics: JsonDiagnostic[];
151
+ };
152
+ /**
153
+ * Identity helper retained for source stability — `Diagnostic` IS
154
+ * `JsonDiagnostic` post-batch-6, so the conversion is a no-op. Kept
155
+ * exported (vs deleted) so existing call sites don't churn ; can be
156
+ * inlined in a future cleanup batch.
157
+ */
158
+ export declare function diagnosticToJson(d: Diagnostic): JsonDiagnostic;
159
+ /**
160
+ * Emit the single-result envelope on stdout. One call per command — the
161
+ * stream-discipline lint asserts a single `data` event per invocation.
162
+ *
163
+ * `version: "1"` is documented as a "format placeholder for future schema
164
+ * evolution" (ADR-072 §L8 / D15) — there's no migration negotiation
165
+ * promised, just a stable marker.
166
+ */
167
+ export declare function emitJsonResult<T>(args: {
168
+ command: string;
169
+ ok: true;
170
+ data: T;
171
+ diagnostics?: JsonDiagnostic[];
172
+ }): void;
173
+ export declare function emitJsonResult(args: {
174
+ command: string;
175
+ ok: false;
176
+ error: JsonError;
177
+ diagnostics?: JsonDiagnostic[];
178
+ }): void;
179
+ /**
180
+ * Emit a single line of the JSONL stream. Used by `backfill-refs --json`
181
+ * (ADR-072 §A3 / L5) — multiple `progress` events followed by exactly
182
+ * one `final` event.
183
+ */
184
+ export declare function emitJsonlEvent<T>(args: {
185
+ command: string;
186
+ event: 'progress' | 'final';
187
+ data: T;
188
+ ok?: boolean;
189
+ }): void;
190
+ /** Emit the terminal canonical failure event for a JSONL command. */
191
+ export declare function emitJsonlFailure(args: {
192
+ command: string;
193
+ err: unknown;
194
+ hint?: string;
195
+ }): void;
196
+ export declare function formatDiagnostic(d: Diagnostic, rootDir: string): string;
197
+ /**
198
+ * Start a spinner. Under `--json` or capture, no TTY updates happen — the
199
+ * event is still emitted so tests can assert the orchestration shape.
200
+ */
201
+ export declare function showSpinner(text: string): Promise<void>;
202
+ /** Mutate the active spinner's text in place. No-op if no spinner is live. */
203
+ export declare function changeSpinner(text: string): void;
204
+ /** Land the spinner with `✔ <text>` (or the current spinner text). */
205
+ export declare function succeedSpinner(text?: string): void;
206
+ /** Land the spinner with `✖ <text>`. */
207
+ export declare function failSpinner(text?: string): void;
208
+ /** Stop the spinner without landing a symbol. UI cleanup — no event. */
209
+ export declare function stopSpinner(): void;
210
+ /**
211
+ * Show a spinner ONLY if `fn` takes longer than `delayMs`. Used for init's
212
+ * six orchestration phases — fast ops (<delayMs) finish silently; slow ops
213
+ * land a `✔`; throws land a `✖` and rethrow.
214
+ *
215
+ * NOT for device-auth: that path goes through `promptDeviceAuth` directly.
216
+ *
217
+ * For multi-phase work that needs an external success line (push/sync),
218
+ * use `withSlowSpinner` instead — it suppresses the auto-✔ so the caller
219
+ * can print its own `logFinishedStep` line after.
220
+ */
221
+ export declare function showSpinnerIfSlow<T>(text: string, delayMs: number, fn: () => Promise<T>): Promise<T>;
222
+ /**
223
+ * Thin slow-gate around the bare spinner primitives, for ADR-072 §D11
224
+ * (push/sync/generate spinners). Like `showSpinnerIfSlow` but:
225
+ *
226
+ * - Does NOT auto-succeed at the end — caller is expected to print its
227
+ * own success line via `logFinishedStep` after the work returns. This
228
+ * avoids the double-✔ that `showSpinnerIfSlow` produces when callers
229
+ * also want a structured success line.
230
+ * - Stops the spinner cleanly on success (no ✔ symbol) and on throw
231
+ * (no ✖ symbol either — failures are surfaced by the caller's
232
+ * diagnostic rendering + `logFailure` / `exitWithError`).
233
+ * - Inside `fn`, callers may call `changeSpinner('…')` to mutate the
234
+ * visible text across phases. The "single spinner that mutates"
235
+ * pattern in ADR-072 §D11.
236
+ *
237
+ * On fast paths (<delayMs), no spinner is ever shown — UX is silent
238
+ * during the work; the caller's success line is the only visible output.
239
+ */
240
+ export declare function withSlowSpinner<T>(text: string, delayMs: number, fn: () => Promise<T>): Promise<T>;
241
+ /**
242
+ * Render the "visit URL + type code" block and resume with a spinner. If
243
+ * a spinner is active when the prompt fires (typical during `link`'s
244
+ * resolve-project phase), it is stopped before the block lands so the
245
+ * prompt doesn't race with the spinner frame.
246
+ *
247
+ * URL is emitted bare per rule 4 — no underline, no brackets, no color.
248
+ */
249
+ export declare function promptDeviceAuth(data: DeviceAuthPromptData): void;
250
+ /**
251
+ * Type guard for the "user cancelled a prompt" case. `@inquirer/prompts`
252
+ * throws a specific error class on Ctrl-C; every prompt call site catches
253
+ * this and treats it as an exit-0 cancel (per-command semantic, ADR-061
254
+ * §SIGINT scope).
255
+ *
256
+ * Lives here so the boundary-lint can keep @inquirer/core out of command
257
+ * files — matching by `name` is sufficient since the error surfaces from
258
+ * our own wrappers.
259
+ */
260
+ export declare function isExitPromptCancel(err: unknown): boolean;
261
+ export declare function promptText(message: string, opts?: {
262
+ placeholder?: string;
263
+ validate?: (v: string) => string | undefined;
264
+ }): Promise<string>;
265
+ export declare function promptSelect<T extends string>(message: string, choices: Array<{
266
+ value: T;
267
+ name: string;
268
+ description?: string;
269
+ }>): Promise<T>;
270
+ export declare function promptConfirm(message: string, opts?: {
271
+ default?: boolean;
272
+ }): Promise<boolean>;
273
+ /**
274
+ * Map an error onto its semantic exit code (ADR-072 §D13 / A4):
275
+ * 130 — user cancel (Ctrl-C / ExitPromptError)
276
+ * 2 — system failure (5xx / connection refused / DNS / timeout)
277
+ * 1 — user error (parse, validation, 4xx, missing env, …)
278
+ *
279
+ * 0 is reserved for success (no error → caller never reaches this path).
280
+ *
281
+ * The predicate handles errors at any wrapping depth: post-Batch 3,
282
+ * `StorystickError(cause: TypeError(cause: { code: 'ECONNREFUSED' }))` is
283
+ * the canonical shape for fetch failures. We descend up to two `cause`
284
+ * levels so the predicate stays robust against future shapes.
285
+ */
286
+ export declare function routeExitCode(err: unknown): 130 | 2 | 1;
287
+ export interface ExitWithErrorOptions {
288
+ /** Override the routed exit code. Pass `1` or `2`. */
289
+ exitCode?: 1 | 2;
290
+ }
291
+ /**
292
+ * Print an error and exit. Accepts our `StorystickError` (for which we
293
+ * dim-append the Pattern D code) or any other `Error | unknown`.
294
+ *
295
+ * The caller passes `hint` for structured follow-up text (rendered as a
296
+ * dim line). Exit code defaults to `routeExitCode(err)` (ADR-072 §D13);
297
+ * pass `{ exitCode }` to force a specific value.
298
+ *
299
+ * Under JSON mode, the human-readable failure line is suppressed — the
300
+ * caller is expected to have already emitted (or to emit immediately
301
+ * after) a `{ ok: false, ... }` envelope on stdout.
302
+ *
303
+ * Mock via `vi.spyOn(process, 'exit')` in tests.
304
+ */
305
+ export declare function exitWithError(err: unknown, hint?: string, opts?: ExitWithErrorOptions): never;
306
+ /**
307
+ * Centralized Ctrl-C → exit 130 routing (ADR-072 §A5 / D16). Replaces
308
+ * the per-call `if (isExitPromptCancel(err)) process.exit(0)` pattern at
309
+ * 4 sites pre-ADR-072. Only exits if the error IS a prompt cancel; no-op
310
+ * otherwise so callers can continue with their normal catch path.
311
+ */
312
+ export declare function maybeExitOnCancel(err: unknown): void;
313
+ /**
314
+ * Combined "emit JSON failure envelope + exit" for action handlers under
315
+ * --json mode. Calling exitWithError directly from the canonical-shell
316
+ * catch block under JSON mode emits a failure event but no envelope —
317
+ * this helper closes that gap. Caller is responsible for choosing a
318
+ * meaningful `error.code`; falls back to the StorystickError's code or
319
+ * a generic 'INTERNAL' marker.
320
+ */
321
+ export declare function exitJsonFailure(args: {
322
+ command: string;
323
+ err: unknown;
324
+ diagnostics?: JsonDiagnostic[];
325
+ hint?: string;
326
+ }): never;
327
+ /** Convert an arbitrary command error into the canonical JSON wire shape. */
328
+ export declare function jsonErrorFromUnknown(err: unknown, hint?: string): JsonError;
329
+ /**
330
+ * Bind an `AbortController` to SIGINT for the duration of a piece of work.
331
+ * Complements the output.ts SIGINT handler (which only cleans UI): this is
332
+ * how a command translates Ctrl-C into "throw out of the in-flight poll /
333
+ * fetch". Call `dispose()` in a `finally` so the listener doesn't leak.
334
+ *
335
+ * ```ts
336
+ * const { signal, dispose } = withInterrupt()
337
+ * try {
338
+ * await callHubApi(path, { signal, onAuthPrompt: promptDeviceAuth })
339
+ * } finally {
340
+ * dispose()
341
+ * }
342
+ * ```
343
+ */
344
+ export declare function withInterrupt(): {
345
+ signal: AbortSignal;
346
+ dispose: () => void;
347
+ };