@a-company/atelier 0.36.0 → 0.38.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 (99) hide show
  1. package/dist/{chunk-JPZ4F4PW.js → chunk-3ARBOSWY.js} +64 -5
  2. package/dist/chunk-3ARBOSWY.js.map +1 -0
  3. package/dist/cli.js +11469 -413
  4. package/dist/cli.js.map +1 -1
  5. package/dist/{dist-M67UZGFQ.js → dist-3YQK6PI6.js} +2 -2
  6. package/dist/index.cjs +3193 -227
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +701 -8
  9. package/dist/index.d.ts +701 -8
  10. package/dist/index.js +7237 -72
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp.js +2898 -507
  13. package/dist/mcp.js.map +1 -1
  14. package/package.json +14 -9
  15. package/src/web/inline-app.ts +55 -4
  16. package/src/web/timeline-state-types.ts +28 -0
  17. package/src/web/timeline-view.test.ts +99 -0
  18. package/src/web/timeline-view.ts +339 -0
  19. package/src/web/workspace-app.ts +3146 -0
  20. package/templates/workspace/.claude/agents/atelier-iris.md +75 -0
  21. package/templates/workspace/.claude/agents/atelier-lux.md +67 -0
  22. package/templates/workspace/.claude/agents/atelier-quill.md +61 -0
  23. package/templates/workspace/.gitignore +30 -0
  24. package/templates/workspace/.paradigm/personas/_shared/cascade-merge.md +172 -0
  25. package/templates/workspace/CLAUDE.md +93 -0
  26. package/templates/workspace/README.md +75 -0
  27. package/templates/workspace/SETUP.md +127 -0
  28. package/templates/workspace/_brand/.atelier-brand.yaml +34 -0
  29. package/templates/workspace/_brand/DESIGN.md +56 -0
  30. package/templates/workspace/_brand/SCRIPT.md +41 -0
  31. package/templates/workspace/_brand/STORYBOARD.md +33 -0
  32. package/templates/workspace/_packs/README.md +54 -0
  33. package/templates/workspace/projects/README.md +49 -0
  34. package/templates/workspace/workspace.atelier +22 -0
  35. package/university/content/notes/N-atel-001-first-render.md +114 -0
  36. package/university/content/notes/N-atel-001-install-and-launch.md +84 -0
  37. package/university/content/notes/N-atel-001-what-is-atelier.md +51 -0
  38. package/university/content/notes/N-atel-101-easings.md +97 -0
  39. package/university/content/notes/N-atel-101-layers.md +106 -0
  40. package/university/content/notes/N-atel-101-states-and-deltas.md +94 -0
  41. package/university/content/notes/N-atel-101-the-atelier-format.md +72 -0
  42. package/university/content/notes/N-atel-201-authoring-tools.md +141 -0
  43. package/university/content/notes/N-atel-201-mcp-overview.md +86 -0
  44. package/university/content/notes/N-atel-201-patterns.md +108 -0
  45. package/university/content/notes/N-atel-201-visual-and-effects.md +125 -0
  46. package/university/content/notes/N-atel-301-composition-and-overlays.md +141 -0
  47. package/university/content/notes/N-atel-301-effects.md +136 -0
  48. package/university/content/notes/N-atel-301-images-and-video.md +126 -0
  49. package/university/content/notes/N-atel-301-shapes-and-text.md +118 -0
  50. package/university/content/notes/N-atel-401-hierarchical-states.md +71 -0
  51. package/university/content/notes/N-atel-401-motion-deep-dive.md +106 -0
  52. package/university/content/notes/N-atel-401-presets-and-templates.md +98 -0
  53. package/university/content/notes/N-atel-401-transitions.md +94 -0
  54. package/university/content/notes/N-atel-501-detected-vs-user-edited.md +76 -0
  55. package/university/content/notes/N-atel-501-layer-tag-isolation.md +62 -0
  56. package/university/content/notes/N-atel-501-silence-trim.md +98 -0
  57. package/university/content/notes/N-atel-501-transcribe-and-captions.md +98 -0
  58. package/university/content/notes/N-atel-601-carousel.md +71 -0
  59. package/university/content/notes/N-atel-601-overlay-rules.md +96 -0
  60. package/university/content/notes/N-atel-601-recipe-tools-and-apply.md +84 -0
  61. package/university/content/notes/N-atel-601-studio-recipe.md +103 -0
  62. package/university/content/notes/N-atel-701-choosing-output.md +68 -0
  63. package/university/content/notes/N-atel-701-png-and-frames.md +84 -0
  64. package/university/content/notes/N-atel-701-vector.md +85 -0
  65. package/university/content/notes/N-atel-701-video.md +88 -0
  66. package/university/content/notes/N-atel-801-editing-surface.md +69 -0
  67. package/university/content/notes/N-atel-801-live-bridge.md +84 -0
  68. package/university/content/notes/N-atel-801-studio-app.md +72 -0
  69. package/university/content/notes/N-atel-801-symbiotic-loop.md +56 -0
  70. package/university/content/paths/LP-atel-001.yaml +21 -0
  71. package/university/content/paths/LP-atel-101.yaml +22 -0
  72. package/university/content/paths/LP-atel-201.yaml +23 -0
  73. package/university/content/paths/LP-atel-301.yaml +22 -0
  74. package/university/content/paths/LP-atel-401.yaml +22 -0
  75. package/university/content/paths/LP-atel-501.yaml +22 -0
  76. package/university/content/paths/LP-atel-601.yaml +22 -0
  77. package/university/content/paths/LP-atel-701.yaml +22 -0
  78. package/university/content/paths/LP-atel-801.yaml +22 -0
  79. package/university/content/quizzes/Q-atel-001-orientation.yaml +66 -0
  80. package/university/content/quizzes/Q-atel-101-document-model.yaml +66 -0
  81. package/university/content/quizzes/Q-atel-201-mcp-authoring.yaml +66 -0
  82. package/university/content/quizzes/Q-atel-301-visual-system.yaml +66 -0
  83. package/university/content/quizzes/Q-atel-401-state-machines.yaml +66 -0
  84. package/university/content/quizzes/Q-atel-501-video-pipeline.yaml +66 -0
  85. package/university/content/quizzes/Q-atel-601-recipes.yaml +66 -0
  86. package/university/content/quizzes/Q-atel-701-export.yaml +66 -0
  87. package/university/content/quizzes/Q-atel-801-studio-loop.yaml +66 -0
  88. package/university/index.yaml +720 -0
  89. package/university/pack.yaml +21 -0
  90. package/dist/chunk-5QQESXI6.js +0 -4432
  91. package/dist/chunk-5QQESXI6.js.map +0 -1
  92. package/dist/chunk-JPZ4F4PW.js.map +0 -1
  93. package/dist/cli.cjs +0 -6313
  94. package/dist/cli.cjs.map +0 -1
  95. package/dist/cli.d.cts +0 -1
  96. package/dist/cli.d.ts +0 -1
  97. package/dist/mcp.cjs +0 -5462
  98. package/dist/mcp.cjs.map +0 -1
  99. /package/dist/{dist-M67UZGFQ.js.map → dist-3YQK6PI6.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Command } from 'commander';
2
- import { AtelierDocument, StudioRecipe, VideoProjectManifest, CutEntry, VideoCutList, VideoTranscript, Layer, Delta, TranscriptWord } from '@a-company/atelier-types';
2
+ import { AtelierDocument, StudioRecipe, VideoProjectManifest, CutEntry, VideoCutList, VideoTranscript, Layer, Delta, TranscriptWord, SlideTransition, ProjectKind } from '@a-company/atelier-types';
3
3
  import { ResolvedFrame } from '@a-company/atelier-core';
4
+ import { DesignArtifact, ScriptArtifact, StoryboardArtifact } from '@a-company/atelier-schema';
4
5
 
5
6
  /**
6
7
  * Validate an .atelier file: parse YAML, check schema, check delta overlaps.
@@ -261,17 +262,24 @@ declare function carouselFileName(index: number, total: number, imagePath: strin
261
262
  */
262
263
  declare function carouselCommand(program: Command): void;
263
264
 
264
- /** Asset summary entry */
265
+ /**
266
+ * Asset summary entry. v1.0: `usedByStates` removed — audio is no longer
267
+ * state-scoped (it's an AudioVisual layer), so layer-only tracking is now
268
+ * the complete picture.
269
+ */
265
270
  interface AssetInfo {
266
271
  assetId: string;
267
272
  type: string;
268
273
  src: string;
269
274
  description?: string;
270
275
  usedByLayers: string[];
271
- usedByStates: string[];
272
276
  }
273
277
  /**
274
278
  * Extract asset info from a parsed AtelierDocument.
279
+ *
280
+ * Walks all layers (image, video, audio) for assetId references. Pre-v1
281
+ * docs that still carry `state.audio` are silently migrated by the parser
282
+ * (audio field stripped); no per-state asset usage is tracked.
275
283
  */
276
284
  declare function getAssets(doc: AtelierDocument): AssetInfo[];
277
285
  /**
@@ -310,6 +318,19 @@ interface RenderOptions {
310
318
  format: RenderFormat;
311
319
  states?: string[];
312
320
  onProgress?: (info: ProgressInfo) => void;
321
+ /**
322
+ * Absolute path of the .atelier document being rendered. Used to resolve
323
+ * relative `media/...` src paths in VideoVisual layers. When set, the
324
+ * pipeline detects the first video layer, passes the source MOV/MP4 to
325
+ * ffmpeg as a SECOND input, and uses an overlay filter to composite the
326
+ * caption canvas ON TOP of the source video frames (instead of feeding
327
+ * the encoder a synthetic canvas-only stream). Source audio is also
328
+ * mapped through verbatim. This is what closes the
329
+ * RENDER-AUDIO-ISSUE.md gap reported by the agent team on 2026-05-28.
330
+ *
331
+ * Omitted → legacy behaviour (canvas-only frames, no audio).
332
+ */
333
+ docPath?: string;
313
334
  }
314
335
  interface ProgressInfo {
315
336
  frame: number;
@@ -326,8 +347,26 @@ interface RenderResult {
326
347
  }
327
348
  /** Check whether FFmpeg is available on the system PATH. */
328
349
  declare function checkFfmpeg(): Promise<boolean>;
329
- /** Build the FFmpeg argument array for the given format. Pure function. */
330
- declare function buildFfmpegArgs(width: number, height: number, fps: number, format: RenderFormat, output: string): string[];
350
+ /**
351
+ * Build the FFmpeg argument array for the given format. Pure function.
352
+ *
353
+ * When `sourceVideoPath` is provided, ffmpeg gets TWO inputs:
354
+ * - Input 0: the source video file (decoded photographic frames + audio)
355
+ * - Input 1: raw BGRA canvas frames on stdin (the caption overlay)
356
+ *
357
+ * A `[0:v][1:v]overlay` filter composites the canvas on top of the source
358
+ * video at matching timestamps. Source audio is copied through with
359
+ * `-map 0:a -c:a copy` (no re-encode). The MP4 output then has full source
360
+ * video bitrate + source audio + caption overlays — what the studio's
361
+ * MediaRecorder path produces by accident, but deterministically and
362
+ * scriptable for agent use.
363
+ *
364
+ * When `sourceVideoPath` is omitted, falls back to the legacy stdin-only
365
+ * mode (canvas frames only, no source pixels, no audio). Used by docs
366
+ * without any VideoVisual layers (e.g. text-only animations, image
367
+ * carousels).
368
+ */
369
+ declare function buildFfmpegArgs(width: number, height: number, fps: number, format: RenderFormat, output: string, sourceVideoPath?: string): string[];
331
370
  /**
332
371
  * Render an Atelier document to a video/GIF file via FFmpeg.
333
372
  * Dynamically imports `canvas` (node-canvas) — fails with a helpful
@@ -460,8 +499,20 @@ declare function trimProject(projectDir: string, options?: TrimOptions): Promise
460
499
  /** Register `atelier trim` on the Commander program */
461
500
  declare function trimCommand(program: Command): void;
462
501
 
463
- /** Whisper model selection (size/quality tradeoff) */
464
- type WhisperModel = "tiny" | "tiny.en" | "base" | "base.en" | "small" | "small.en" | "medium" | "medium.en" | "large-v3";
502
+ /**
503
+ * Whisper model selection (size/quality tradeoff).
504
+ *
505
+ * The set mirrors whisper.cpp's published model registry on HuggingFace
506
+ * (https://huggingface.co/ggerganov/whisper.cpp). Quantized variants and
507
+ * the v3-turbo line are first-class — creators get the best local-quality
508
+ * tradeoff without needing to know the model-zoo URL by heart.
509
+ *
510
+ * Note: the type is intentionally open to `string` via the fallback union so a
511
+ * creator can pass a future model name (e.g. a new quant variant) without us
512
+ * having to ship a code change. `resolveWhisperModelPath` will attempt to
513
+ * resolve any string against the cache + HuggingFace registry.
514
+ */
515
+ type WhisperModel = "tiny" | "tiny.en" | "base" | "base.en" | "small" | "small.en" | "medium" | "medium.en" | "large-v3" | "large-v3-turbo" | "large-v3-turbo-q5_0" | "large-v3-q5_0" | (string & {});
465
516
  interface WhisperOptions {
466
517
  /** Model size (default: "base.en") */
467
518
  model?: WhisperModel;
@@ -469,6 +520,11 @@ interface WhisperOptions {
469
520
  language?: string;
470
521
  /** Explicit path to the model file — overrides model lookup by name */
471
522
  modelPath?: string;
523
+ /**
524
+ * Optional progress callback for model download (bytes received, total bytes
525
+ * when known). Surfaced as a one-time download on first use of any model name.
526
+ */
527
+ onProgress?: (received: number, total: number | null) => void;
472
528
  }
473
529
  /** Backend that produced a transcript run */
474
530
  type WhisperBackend = "whisper-cpp" | "openai-api" | "none";
@@ -486,6 +542,11 @@ declare function probeWhisper(): Promise<WhisperBackend>;
486
542
  * Note: whisper-cli writes JSON to stdout when given --output-json and "-"
487
543
  * as the output destination. Some builds always write to a file with the
488
544
  * `.json` suffix appended to the input path; we handle both.
545
+ *
546
+ * Model resolution: if `options.modelPath` is set, it's passed through. Else
547
+ * `options.model` (default `base.en`) is resolved via `resolveWhisperModelPath`,
548
+ * downloading from the HuggingFace public registry on first use. Once the
549
+ * model is cached, no network call is made.
489
550
  */
490
551
  declare function runWhisperCpp(sourcePath: string, options?: WhisperOptions): Promise<string>;
491
552
  /**
@@ -564,6 +625,15 @@ declare function rewriteCaptionLayers(doc: AtelierDocument, transcript: VideoTra
564
625
  interface TranscribeOptions {
565
626
  /** Whisper model selection */
566
627
  model?: WhisperModel;
628
+ /** Explicit path to the model file — overrides model short-name lookup */
629
+ modelPath?: string;
630
+ /**
631
+ * Override the source video path. By default `transcribeProject` uses the
632
+ * legacy VideoProject scanner (`<projectDir>/source.<ext>`). Passing
633
+ * `sourcePath` lets the multi-media ingest target an arbitrary media file
634
+ * (e.g. `<projectDir>/media/<basename>`) without copying it to root.
635
+ */
636
+ sourcePath?: string;
567
637
  /** BCP-47 language hint (omit for autodetect) */
568
638
  language?: string;
569
639
  /** Discard existing user edits; full fresh transcript */
@@ -683,6 +753,255 @@ declare function recipeCommand(program: Command): void;
683
753
  */
684
754
  declare function applyRecipeCommand(program: Command): void;
685
755
 
756
+ /**
757
+ * Atelier creator learning-mode I/O.
758
+ *
759
+ * `learning-mode.yaml` lives at `<project-dir>/.atelier/learning-mode.yaml`
760
+ * and stores the creator's pre-declared autonomy posture (TD-2026-05-26-646):
761
+ *
762
+ * - `ambient` — the agent team captures corrections silently and surfaces
763
+ * patterns when confident.
764
+ * - `explicit` — nothing locks in without the creator's "yes"; high control,
765
+ * more friction.
766
+ *
767
+ * Set once by `atelier init`. The system never auto-prompts to switch — the
768
+ * creator changes mode by editing the file. Iris (and friends) read it at
769
+ * session start to calibrate their behavior.
770
+ *
771
+ * Format is hand-rolled YAML (a handful of scalars) so we don't pull in a YAML
772
+ * dep here; the schema is intentionally tiny and stable.
773
+ */
774
+ type LearningMode = "ambient" | "explicit";
775
+ declare const LEARNING_MODES: readonly LearningMode[];
776
+ declare const LEARNING_MODE_VERSION: "1.0";
777
+ /** Shape persisted to disk. */
778
+ interface LearningModeFile {
779
+ /** Schema version of this file. */
780
+ version: string;
781
+ /** Creator's chosen autonomy posture. */
782
+ mode: LearningMode;
783
+ /** ISO 8601 timestamp set by the writer. */
784
+ chosen_at: string;
785
+ }
786
+ /** Absolute path to the learning-mode file for a project. */
787
+ declare function learningModePath(projectDir: string): string;
788
+ /**
789
+ * Write `<projectDir>/.atelier/learning-mode.yaml` with the given mode and a
790
+ * fresh ISO timestamp. Creates `<projectDir>/.atelier/` if absent. Overwrites
791
+ * any existing file — re-running init is supported and refreshes the
792
+ * timestamp (mode is whatever the caller passes; the caller decides whether
793
+ * to re-prompt). Returns the absolute path written.
794
+ */
795
+ declare function writeLearningMode(projectDir: string, mode: LearningMode, opts?: {
796
+ chosenAt?: Date;
797
+ }): string;
798
+ /**
799
+ * Read `<projectDir>/.atelier/learning-mode.yaml` if present. Returns `undefined`
800
+ * when the file does not exist. Throws a clear Error when the file exists but
801
+ * is malformed (missing required fields, unknown mode). Hand-rolled scalar
802
+ * parser — no YAML dep — matched to whatever `writeLearningMode` emits.
803
+ */
804
+ declare function readLearningMode(projectDir: string): LearningModeFile | undefined;
805
+ /**
806
+ * Render the canonical YAML body — a fixed-shape doc with header comments
807
+ * pointing the creator at where to change the mode (TD-2026-05-26-646). Kept
808
+ * here so the writer and any future reader/round-tripper agree on the shape.
809
+ */
810
+ declare function renderLearningModeYaml(file: LearningModeFile): string;
811
+
812
+ /**
813
+ * `atelier init <project-dir>` — first-run setup for a creator Project.
814
+ *
815
+ * Sequence (Phase 3, delegation C; see
816
+ * docs/keynote/paradigm/phase-3-reconciliation-notes.md §3):
817
+ *
818
+ * 1. Create `<project-dir>` if absent (recursive). Refuse if the path
819
+ * exists as a file rather than a directory. Existing non-empty dir is
820
+ * a "complete the init" workflow — proceed with a note in output.
821
+ * 2. Determine learning mode. `--mode <ambient|explicit>` skips the
822
+ * prompt; otherwise readline-prompts the creator (single question, two
823
+ * options, max 3 attempts). Bad `--mode` value exits 1 before any fs
824
+ * writes (TD-2026-05-26-646: autonomy posture is pre-declared).
825
+ * 3. Write `<project-dir>/.atelier/learning-mode.yaml` with the choice
826
+ * and an ISO timestamp (delegated to #learning-mode-io).
827
+ * 4. Create `<project-dir>/.atelier/mind-map/` with a README explaining
828
+ * what to put there. README is preserved on re-init (TD-2026-05-26-271:
829
+ * nothing in the mind-map leaves the machine).
830
+ * 5. Unless `--no-scaffold`, drop DESIGN/SCRIPT/STORYBOARD via the
831
+ * existing #cli-artifacts `scaffoldArtifacts` helper. Re-init swallows
832
+ * the refuse-to-overwrite throw as a soft skip (the operation is
833
+ * explicitly idempotent — see init-idempotent-re-run-safe aspect).
834
+ * 6. Unless `--no-git`, run `git init` in `<project-dir>` if it isn't
835
+ * already inside a git repo. Writes a minimal `.gitignore` only when
836
+ * one doesn't exist.
837
+ *
838
+ * Output: human-formatted step-by-step summary by default; `--json` emits
839
+ * the documented machine-readable shape. Exit 0 on success, 1 on any
840
+ * irrecoverable error (file-not-dir, can't determine mode, fs failure).
841
+ *
842
+ * The Commander wiring is a thin shell around the pure `runInit(opts)`
843
+ * helper so test code drives the same code path without process.exit
844
+ * shenanigans (matches the artifacts.ts split).
845
+ */
846
+ declare function initCommand(program: Command): void;
847
+ /** Input to `runInit`. Booleans are positive-form (caller pre-resolves --no-X). */
848
+ interface RunInitOptions {
849
+ projectDir: string;
850
+ /** Pre-supplied mode (skips the prompt). */
851
+ mode?: string;
852
+ /**
853
+ * When the mode was inherited from a workspace (not explicitly chosen
854
+ * by the creator for this project), the per-project learning-mode.yaml
855
+ * gets a comment noting the inheritance. The wrapper sets this when
856
+ * `--mode` was absent and a workspace's `default_mode` was used.
857
+ */
858
+ modeInheritedFromWorkspace?: boolean;
859
+ /** Run `git init` when not already in a repo. Default true. */
860
+ git: boolean;
861
+ /** Drop DESIGN/SCRIPT/STORYBOARD via `scaffoldArtifacts`. Default true. */
862
+ scaffold: boolean;
863
+ /** Forward to `scaffoldArtifacts({ force })`. Default false. */
864
+ force: boolean;
865
+ /** Suppress interactive prompt fallback (used by --json path). Default false. */
866
+ json: boolean;
867
+ /**
868
+ * Drop a minimal `project.atelier` manifest at the project root so this
869
+ * directory is recognized as a Project by legacy discovery callers. The
870
+ * CLI surface (`atelier init`) leaves this true so existing tooling that
871
+ * keys on the manifest's presence keeps working; the workspace `+ new`
872
+ * surface (via `createProjectInWorkspace`) passes `false` so the project
873
+ * stays "lazy" until its first composed `.atelier` doc lands. Default
874
+ * true (preserves pre-pivot behavior on the CLI path).
875
+ */
876
+ writeManifest?: boolean;
877
+ /**
878
+ * Test/programmatic override: a function that resolves to the chosen mode
879
+ * when no `--mode` was passed. Production wiring uses the readline prompt.
880
+ * Returning `undefined` or throwing aborts with the standard "couldn't
881
+ * determine learning mode" error.
882
+ */
883
+ promptForMode?: () => Promise<LearningMode>;
884
+ }
885
+ /** Result returned by `runInit` and serialized for `--json`. */
886
+ interface InitResult {
887
+ /** True on the success path. */
888
+ ok: true;
889
+ projectDir: string;
890
+ mode: LearningMode;
891
+ learningModeFile: string;
892
+ /** Absolute paths of artifacts written by the scaffold step (may be empty). */
893
+ scaffolded: string[];
894
+ /** Absolute paths of artifacts skipped (already existed, no --force). */
895
+ scaffoldSkipped: string[];
896
+ mindMapDir: string;
897
+ /** True when `git init` ran in this invocation. */
898
+ gitInitialized: boolean;
899
+ /** True when the dir was already inside an existing git repo. */
900
+ alreadyInRepo: boolean;
901
+ /** Notes accumulated during the run (re-init warnings, etc.). */
902
+ notes: string[];
903
+ }
904
+ /**
905
+ * Pure helper for `atelier init`. Throws on any irrecoverable error; the
906
+ * Commander wrapper catches and maps to `process.exit(1)`. Re-runnable on an
907
+ * already-initialized dir (scaffold's refuse-to-overwrite is downgraded to a
908
+ * soft skip in this surface — see init-idempotent-re-run-safe aspect).
909
+ */
910
+ declare function runInit(opts: RunInitOptions): Promise<InitResult>;
911
+ /**
912
+ * Returns true when `dir` (or any ancestor) sits inside an existing git work
913
+ * tree. Implemented via `git rev-parse --show-toplevel`; non-zero exit and
914
+ * any spawn failure (missing git, etc.) are treated as "not in a repo" so the
915
+ * caller falls through to `git init`.
916
+ */
917
+ declare function isInsideGitRepo(dir: string): boolean;
918
+ /** Parse a single answer to the mode prompt. Returns undefined on no match. */
919
+ declare function parseModeAnswer(answer: string): LearningMode | undefined;
920
+
921
+ /**
922
+ * `atelier artifacts <verb>` — first user-facing surface over the
923
+ * Phase 2 front-of-pipeline artifact schemas (DESIGN/SCRIPT/STORYBOARD).
924
+ *
925
+ * Phase 2 lands the schemas + the `^valid-artifact-set` gate; this CLI
926
+ * verb is the on-disk runner. `atelier artifacts validate <project-dir>`
927
+ * walks a Project directory for the three artifact files, parses each
928
+ * one that's present, runs the cross-artifact validator on whatever
929
+ * parsed, and prints a human or JSON report.
930
+ *
931
+ * Exit-code matrix:
932
+ * - parse error on any file → 1
933
+ * - validator returns ok: false → 1
934
+ * - warnings only, no errors → 0 (per spec §9: pre-VO duration overrun
935
+ * is warn-only and must NOT fail the gate)
936
+ * - missing artifacts → 0 (per validator: only what's present is checked)
937
+ *
938
+ * Output style mirrors `recipe.ts` — `console.log` for results, status
939
+ * lines prefixed with PASS/FAIL/WARN, `--json` toggles a machine
940
+ * readable payload. (CLI stdout IS the deliverable here; the generic
941
+ * Paradigm-logger rule does not apply to CLI verbs — see `recipe.ts`,
942
+ * `validate.ts`, etc., which all follow this same convention.)
943
+ */
944
+ declare function artifactsCommand(program: Command): void;
945
+
946
+ /**
947
+ * Pure filesystem walker for the front-of-pipeline artifact triplet
948
+ * (DESIGN.md, SCRIPT.md, STORYBOARD.md). Sibling-of-`project.atelier`
949
+ * convention per `docs/keynote/paradigm/atelier-front-of-pipeline-artifacts.md`
950
+ * §2 — the three files sit at the root of a Project directory.
951
+ *
952
+ * This module is intentionally pure: no stdout/exit-code coupling. The
953
+ * `atelier artifacts validate` CLI command (and any future agent / MCP
954
+ * caller) consumes the structured result and decides what to print.
955
+ *
956
+ * Any subset of the three files may exist — the absent ones are
957
+ * surfaced via `missing` (informational, NOT an error). The validator
958
+ * (`validateArtifactSet`) runs on whatever was successfully parsed.
959
+ */
960
+ /** Filenames the walker looks for at the project-dir root. */
961
+ declare const ARTIFACT_FILENAMES: {
962
+ readonly design: "DESIGN.md";
963
+ readonly script: "SCRIPT.md";
964
+ readonly storyboard: "STORYBOARD.md";
965
+ };
966
+ /** Per-file parse failure surface. */
967
+ interface ArtifactParseError {
968
+ /** Which artifact triplet slot failed. */
969
+ artifact: "design" | "script" | "storyboard";
970
+ /** Absolute path to the file that failed. */
971
+ file: string;
972
+ /** Human-readable failure message. */
973
+ message: string;
974
+ }
975
+ /** Structured result of loading the three artifacts from a project dir. */
976
+ interface LoadedArtifactProject {
977
+ /** Absolute project-dir path that was inspected. */
978
+ projectDir: string;
979
+ /** Successfully-parsed DESIGN.md, if present and valid. */
980
+ design?: DesignArtifact;
981
+ /** Successfully-parsed SCRIPT.md, if present and valid. */
982
+ script?: ScriptArtifact;
983
+ /** Successfully-parsed STORYBOARD.md, if present and valid. */
984
+ storyboard?: StoryboardArtifact;
985
+ /**
986
+ * Names of artifact files that were not found on disk.
987
+ * NOT an error — absent artifacts are valid per the spec
988
+ * (only what is present is validated).
989
+ */
990
+ missing: string[];
991
+ /** Per-file parse errors. Empty when all present artifacts parsed cleanly. */
992
+ parseErrors: ArtifactParseError[];
993
+ }
994
+ /**
995
+ * Walk a project directory for DESIGN.md / SCRIPT.md / STORYBOARD.md and
996
+ * parse whichever are present.
997
+ *
998
+ * Throws (synchronously) only when `projectDir` itself does not exist or
999
+ * is not a directory — per-file parse failures are captured into the
1000
+ * returned `parseErrors` array so callers can show every problem at
1001
+ * once instead of one at a time.
1002
+ */
1003
+ declare function loadArtifactsFromProject(projectDir: string): LoadedArtifactProject;
1004
+
686
1005
  declare const RECIPE_VERSION = "1.0";
687
1006
  interface LoadedRecipe {
688
1007
  recipe: StudioRecipe;
@@ -741,4 +1060,378 @@ declare function renderRecipeWithDefaults(recipe: StudioRecipe): StudioRecipe;
741
1060
  /** Serialize a recipe back to YAML for `recipe show` output */
742
1061
  declare function recipeToYaml(recipe: StudioRecipe): string;
743
1062
 
744
- export { type AssetInfo, type BuildCaptionsOptions, CanvasUnavailableError, type CaptionStyle, type DocumentInfo, type LoadedRecipe, type ProgressInfo, RECIPE_VERSION, type RenderFormat, type RenderOptions, type RenderResult, type TranscribeOptions, type TranscribeResult, type TrimOptions, type TrimResult, VIDEO_CUTLIST_VERSION, VIDEO_PROJECT_VERSION, VIDEO_TRANSCRIPT_VERSION, type VariableInfo, type VideoProject, type WhisperBackend, type WhisperModel, type WhisperOptions, applyAdd, applyBatchReplace, applyHide, applyMerge, applyRecipeCommand, applyRecipeToCaptionOptions, applyRecipeToTranscribeOptions, applyRecipeToTrimOptions, applySplit, applyTextEdit, assetsCommand, buildCaptionLayers, buildFfmpegArgs, captionsCommand, carouselCommand, carouselFileName, checkFfmpeg, composeCarouselFrameDoc, createVideoProject, effectiveSpan, expandInputs, exportImageCommand, exportLottieCommand, exportSvgCommand, fitImageToCanvas, flattenWords, getAssets, getInfo, getVariables, groupIntoPhrases, infoCommand, loadCanvasModule, loadRecipe, loadVideoProject, mergeTranscriptWithExisting, parseWhisperCppJson, probeWhisper, readComposition, readCutList, readTranscript, recipeCommand, recipeToYaml, renderCommand, renderDocument, renderDocumentToPng, renderRecipeWithDefaults, resolveExportDimensions, resolveRecipePath, resolveStill, rewriteCaptionLayers, rewriteCutLayers, runWhisperCpp, scaffoldRecipeYaml, stillCommand, transcribeCommand, transcribeProject, transcriptCommand, trimCommand, trimProject, validateCommand, validateFile, variablesCommand, writeComposition, writeCutList, writeTranscript };
1063
+ interface ComposeVideoProjectOptions {
1064
+ /** Absolute path to the project root (contains the doc at docPath). */
1065
+ projectDir: string;
1066
+ /**
1067
+ * Project-relative path to the .atelier composition document this helper
1068
+ * reads/writes. Required — no default. Caller computes this from the
1069
+ * ingest slug (e.g. `"img-7346.atelier"`, `"slides/slide-1.atelier"`).
1070
+ * The parent directory is created on demand. The helper NEVER touches
1071
+ * `project.atelier` specifically; only this caller-supplied path.
1072
+ */
1073
+ docPath: string;
1074
+ /**
1075
+ * Absolute path to the source media file. Used to (a) compute a canonical
1076
+ * assetId/layer src reference, and (b) probe duration via ffprobe.
1077
+ */
1078
+ sourceFile: string;
1079
+ /**
1080
+ * Whether to run whisper transcription. Default true. When false, only the
1081
+ * state-duration + video-layer wiring runs (useful when re-composing a
1082
+ * project that already has transcript.json).
1083
+ */
1084
+ transcribe?: boolean;
1085
+ /** Forwarded to `transcribeProject` — model selection, language, etc. */
1086
+ transcribeOptions?: TranscribeOptions;
1087
+ /**
1088
+ * When set, after `transcribeProject` writes the root `transcript.json`
1089
+ * the result is mirrored to `<projectDir>/transcripts/<stem>.json` (per
1090
+ * #transcribe-orchestrator). Pass the basename of the file the creator
1091
+ * just ingested — e.g. `IMG_7347.MOV` for a drag-drop video, or
1092
+ * `source.mp4` for the legacy single-source layout. Omit for
1093
+ * single-source projects that only need the root `transcript.json`
1094
+ * (preserves the legacy `atelier transcribe` contract).
1095
+ */
1096
+ mediaBasename?: string;
1097
+ /**
1098
+ * Test injection point — production wiring uses the real `transcribeProject`.
1099
+ * Mirrors the same hook on `runMediaIngest`. Used by both the single-source
1100
+ * `transcribeProject` path and the per-file `transcribeMediaFile` path
1101
+ * (the orchestrator forwards this fn through unchanged).
1102
+ */
1103
+ transcribeFn?: (dir: string, opts: TranscribeOptions) => Promise<TranscribeResult>;
1104
+ /**
1105
+ * Test injection point — production wiring uses `probeDuration` (ffprobe).
1106
+ * When omitted and ffprobe fails (or isn't installed), we fall back to the
1107
+ * transcript's last word end time.
1108
+ */
1109
+ probeDurationFn?: (sourcePath: string) => Promise<number>;
1110
+ /** Optional caption style overrides passed through to `buildCaptionLayers`. */
1111
+ captionOptions?: BuildCaptionsOptions;
1112
+ }
1113
+ interface ComposeVideoProjectResult {
1114
+ /** The project.atelier as written to disk. */
1115
+ doc: AtelierDocument;
1116
+ /** True iff a NEW clip layer was added (false on re-ingest of the same src). */
1117
+ addedVideoLayer: boolean;
1118
+ /** Slug derived from the source basename — `clip-<slug>` is the clip layer id. */
1119
+ clipSlug: string;
1120
+ /** Id of the clip layer just (re-)ingested. */
1121
+ clipLayerId: string;
1122
+ /** Name of the state whose duration was set/updated. */
1123
+ targetStateName: string;
1124
+ /** Total duration in seconds written into the target state. */
1125
+ targetDurationSeconds: number;
1126
+ /** Transcription result, when transcription ran. */
1127
+ transcribe?: TranscribeResult;
1128
+ /**
1129
+ * Absolute path to the per-file transcript mirror at
1130
+ * `<projectDir>/transcripts/<stem>.json`. Present only when caller passed
1131
+ * `mediaBasename` and transcription actually ran (and wasn't a dry-run).
1132
+ */
1133
+ mirroredTranscriptPath?: string;
1134
+ }
1135
+ /**
1136
+ * Compose a playable VideoProject from an ingested source + transcript.
1137
+ *
1138
+ * - Transcribes (unless `transcribe: false`) — writes the transcript file(s).
1139
+ * The legacy caption-rewrite side effect is neutralized below.
1140
+ * - Lazy-creates the `track-video-1` Group layer if absent.
1141
+ * - Appends a `clip-<slug>` VideoVisual layer parented to the track at the
1142
+ * end-of-track startFrame (or preserves placement on re-ingest of the same).
1143
+ * - Rebuilds per-clip captions as `cap-<slug>-N` parented to `clip-<slug>`,
1144
+ * leaving other clips' captions untouched.
1145
+ * - Regenerates the derived `timeline` summary block.
1146
+ * - Sets the target state's duration to cover all clips on all tracks.
1147
+ */
1148
+ declare function composeVideoProject(opts: ComposeVideoProjectOptions): Promise<ComposeVideoProjectResult>;
1149
+
1150
+ interface ComposeImageProjectOptions {
1151
+ /** Absolute path to project root (contains or will contain the doc at docPath). */
1152
+ projectDir: string;
1153
+ /**
1154
+ * Project-relative path to the .atelier composition document this helper
1155
+ * reads/writes. Required — no default. Caller computes this from the
1156
+ * ingest slug (e.g. `"hero-image.atelier"`, `"slides/slide-1.atelier"`).
1157
+ * The parent directory is created on demand. The helper NEVER touches
1158
+ * `project.atelier` specifically; only this caller-supplied path.
1159
+ */
1160
+ docPath: string;
1161
+ /** Absolute path to the source image file. */
1162
+ sourceFile: string;
1163
+ /** Override target basename inside media/. Defaults to basename(sourceFile). */
1164
+ mediaBasename?: string;
1165
+ }
1166
+ interface ComposeImageProjectResult {
1167
+ doc: AtelierDocument;
1168
+ /** True iff a new ImageVisual layer was added (vs. doc already had one). */
1169
+ addedImageLayer: boolean;
1170
+ /** Slug-based layer id, e.g. "img-photo-1". One-to-one with assetId. */
1171
+ layerId: string;
1172
+ /** Same as layerId — the asset key. */
1173
+ assetId: string;
1174
+ }
1175
+ /**
1176
+ * Compose (or re-compose) an Atelier image project from a single source image.
1177
+ *
1178
+ * - Single-image invariant: a second, differently-named image throws.
1179
+ * - Idempotent on re-ingest of the same basename.
1180
+ * - No timeline, no transcript — image projects render as a single frame.
1181
+ */
1182
+ declare function composeImageProject(opts: ComposeImageProjectOptions): Promise<ComposeImageProjectResult>;
1183
+
1184
+ interface ComposeCarouselProjectOptions {
1185
+ /** Absolute path to project root (contains or will contain the doc at docPath). */
1186
+ projectDir: string;
1187
+ /**
1188
+ * Project-relative path to the CAROUSEL .atelier composition document this
1189
+ * helper reads/writes. Required — no default. Distinct from `slidePath`,
1190
+ * which is the slide being added. Caller computes this from the ingest
1191
+ * slug (e.g. `"gallery.atelier"`). The parent directory is created on
1192
+ * demand. The helper NEVER touches `project.atelier` specifically; only
1193
+ * this caller-supplied path.
1194
+ */
1195
+ docPath: string;
1196
+ /** Absolute path to any .atelier file in the workspace — the slide to add. */
1197
+ slidePath: string;
1198
+ /** Workspace root used for cycle detection. Defaults to dirname(projectDir). */
1199
+ workspaceRoot?: string;
1200
+ /** Index to insert at; default = append. */
1201
+ insertAt?: number;
1202
+ transition?: SlideTransition;
1203
+ /** For image slides — frames to hold; ignored for video slides. */
1204
+ duration?: number;
1205
+ label?: string;
1206
+ }
1207
+ interface ComposeCarouselProjectResult {
1208
+ doc: AtelierDocument;
1209
+ slideIndex: number;
1210
+ addedSlide: boolean;
1211
+ }
1212
+ /**
1213
+ * Add a slide reference to a carousel project, cycle-safe.
1214
+ *
1215
+ * - Scaffolds a fresh kind:"carousel" doc if project.atelier is absent.
1216
+ * - Refuses to convert a non-carousel project.
1217
+ * - Refuses to introduce a cycle.
1218
+ * - Idempotent on duplicate slide src.
1219
+ */
1220
+ declare function composeCarouselProject(opts: ComposeCarouselProjectOptions): Promise<ComposeCarouselProjectResult>;
1221
+
1222
+ /** Classification result for a media filename. */
1223
+ type IngestKind = "video" | "image" | "audio" | "unsupported";
1224
+ /**
1225
+ * Routing decision for a no-target ingest (file lands in the media bin).
1226
+ *
1227
+ * Post-pivot (TD-2026-05-28): either the file is a supported media kind and
1228
+ * goes to `add-to-bin`, or it's unsupported and we reject. Project kind no
1229
+ * longer factors in — composition is a separate, explicit step.
1230
+ */
1231
+ interface BinIngestRoute {
1232
+ kind: IngestKind;
1233
+ target: "add-to-bin" | "reject";
1234
+ /** When target === "reject", the human-readable reason. */
1235
+ error?: string;
1236
+ }
1237
+ /**
1238
+ * Routing decision for an explicit-target ingest (canvas-area drop).
1239
+ *
1240
+ * The target-set path still uses the legacy four-way target enum since it
1241
+ * really does dispatch to compose-video / add-audio-clip / etc.
1242
+ */
1243
+ interface IngestRoute {
1244
+ kind: IngestKind;
1245
+ target: "compose-video" | "compose-image" | "add-audio-clip" | "reject";
1246
+ /** When target === "reject", the human-readable reason. */
1247
+ error?: string;
1248
+ /**
1249
+ * When set, the project-relative `.atelier` doc path the route resolved
1250
+ * to. Populated by `routeIngestWithTarget` for explicit canvas drops so the
1251
+ * server-side handler can pass it straight to the composer / audio-add path
1252
+ * without re-deriving.
1253
+ */
1254
+ docPath?: string;
1255
+ }
1256
+ /**
1257
+ * Classify a media filename by its extension. Case-insensitive — `.MOV` and
1258
+ * `.mov` both yield `"video"`. Returns `"unsupported"` for anything outside
1259
+ * the known video/image/audio extension lists, including files with no
1260
+ * extension at all.
1261
+ */
1262
+ declare function classifyMediaFile(filename: string): IngestKind;
1263
+ /**
1264
+ * Route a no-target ingest into the project's media bin.
1265
+ *
1266
+ * Post-pivot (TD-2026-05-28) the no-target path doesn't care about project
1267
+ * kind — supported media always goes to `add-to-bin`, unsupported types are
1268
+ * rejected. Composition is a separate explicit step downstream.
1269
+ *
1270
+ * Mirrors `classifyMediaFile` for the kind detection; the routing decision is
1271
+ * a pure function of the filename.
1272
+ */
1273
+ declare function routeIngest(filename: string): BinIngestRoute;
1274
+ /**
1275
+ * Routing matrix for explicit "add to this specific doc" drops (canvas-area
1276
+ * drag-drop, post-pivot). When the browser knows which doc is loaded in the
1277
+ * canvas, it sends `targetDocPath` + the target doc's `kind`; the routing
1278
+ * decision is then governed by the TARGET doc's kind — not the project's
1279
+ * inferred kind — because the user picked a specific doc.
1280
+ *
1281
+ * file kind target doc kind → target
1282
+ * ─────────────────────────────────────
1283
+ * video video → compose-video (docPath = targetDocPath)
1284
+ * audio video → add-audio-clip (docPath = targetDocPath)
1285
+ * image * → reject (v1)
1286
+ * video image / carousel → reject
1287
+ * audio image / carousel → reject
1288
+ * unsupported * → reject
1289
+ *
1290
+ * Pure / synchronous. The caller is responsible for verifying the target doc
1291
+ * exists on disk and reading its kind — this function only encodes the
1292
+ * compatibility matrix and produces the route decision.
1293
+ */
1294
+ declare function routeIngestWithTarget(filename: string, targetDocPath: string, targetDocKind: ProjectKind | undefined): IngestRoute;
1295
+
1296
+ /**
1297
+ * Project kind that a NEW doc can be created as.
1298
+ *
1299
+ * Owner explicitly excluded "blank" from v1 — only the three named kinds.
1300
+ * Future v1.1 may add `undefined` for blank docs.
1301
+ */
1302
+ type DocKind = "video" | "image" | "carousel";
1303
+ interface CreateDocOptions {
1304
+ projectDir: string;
1305
+ name: string;
1306
+ kind: DocKind;
1307
+ /** For carousel slides: place file under slides/ and append SlideRef to target carousel. */
1308
+ asCarouselSlide?: boolean;
1309
+ /** Required when asCarouselSlide:true — the carousel doc whose slides[] should receive the ref. Usually <projectDir>/project.atelier. */
1310
+ carouselDocPath?: string;
1311
+ /** Insertion index for SlideRef (default = append). */
1312
+ insertAt?: number;
1313
+ }
1314
+ interface DuplicateDocOptions {
1315
+ projectDir: string;
1316
+ /** Project-relative path of the doc to duplicate (e.g. "slides/slide-1.atelier" or "scenes/intro.atelier"). */
1317
+ sourceDocPath: string;
1318
+ /** When source is a slide, also append a new SlideRef pointing at the duplicate. */
1319
+ appendSlideRef?: boolean;
1320
+ }
1321
+ interface DeleteDocOptions {
1322
+ workspaceDir: string;
1323
+ projectName: string;
1324
+ /** Project-relative path of the doc to delete. */
1325
+ docPath: string;
1326
+ }
1327
+ interface DocListEntry {
1328
+ /** Project-relative path. */
1329
+ path: string;
1330
+ /** When determinable from the doc's `kind` field; undefined if doc kind is absent or unrecognized. */
1331
+ kind?: "video" | "image" | "carousel";
1332
+ }
1333
+ interface DocDeleteCascadeReport {
1334
+ /** Project-relative path of the doc that was deleted. */
1335
+ docPath: string;
1336
+ /** SlideRefs removed across the workspace. Each entry identifies the carousel project name + the index of the removed ref (PRE-removal index, in case multiple were removed). */
1337
+ slideRefsRemoved: Array<{
1338
+ project: string;
1339
+ slideIndex: number;
1340
+ }>;
1341
+ /** RefVisual layers in any .atelier across the workspace that still point at the deleted doc. These are NOT auto-removed; reported for surfacing as warnings. */
1342
+ refLayersDangling: Array<{
1343
+ project: string;
1344
+ docPath: string;
1345
+ layerId: string;
1346
+ }>;
1347
+ }
1348
+ interface DocDuplicateReport {
1349
+ /** Source doc path (project-relative). */
1350
+ sourceDocPath: string;
1351
+ /** New doc path (project-relative). */
1352
+ newDocPath: string;
1353
+ /** When appendSlideRef was set and the source is a carousel slide: the index of the appended SlideRef. */
1354
+ appendedSlideIndex?: number;
1355
+ }
1356
+ /**
1357
+ * Aegis surface — same posture as `isValidMediaBasenameForRename` in rename-media.ts.
1358
+ * Validates a user-typed doc display name.
1359
+ *
1360
+ * Rejects:
1361
+ * - empty / whitespace-only
1362
+ * - leading dot (hidden files)
1363
+ * - any `/`, `\`, or `..` substring
1364
+ * - control bytes (NUL through 0x1f)
1365
+ * - longer than 200 characters
1366
+ *
1367
+ * The slug (kebab-case derivative) is computed elsewhere via `slugifyBasename`;
1368
+ * this validator only checks the raw human input.
1369
+ */
1370
+ declare function isValidDocName(name: unknown): name is string;
1371
+
1372
+ interface CreateDocResult {
1373
+ doc: AtelierDocument;
1374
+ /** Project-relative. */
1375
+ docPath: string;
1376
+ /** Present when the new doc was appended as a SlideRef into a carousel. */
1377
+ appendedSlideIndex?: number;
1378
+ }
1379
+ /**
1380
+ * Scaffold a new .atelier doc inside a project.
1381
+ *
1382
+ * - Validates `opts.name` via `isValidDocName` (rejects path separators,
1383
+ * `..`, control bytes, etc.).
1384
+ * - Slugs the name via `slugifyBasename` for the filesystem path.
1385
+ * - Collision-suffixes with `-1`, `-2`, ... up to 999.
1386
+ * - For `asCarouselSlide: true`, writes under `slides/<slug>.atelier` AND
1387
+ * calls `composeCarouselProject` so the cycle check + SlideRef append
1388
+ * run as one indivisible step.
1389
+ */
1390
+ declare function createDoc(opts: CreateDocOptions): Promise<CreateDocResult>;
1391
+ /**
1392
+ * Duplicate an existing doc next to itself with a `-copy` (then `-copy-2`,
1393
+ * `-copy-3`, ...) suffix. Layer ids are preserved verbatim (they're
1394
+ * doc-local — no cross-doc id collision concern).
1395
+ *
1396
+ * `appendSlideRef: true` requires the source to live under `slides/`; we
1397
+ * also call `composeCarouselProject` for the append so the cycle detector
1398
+ * runs defensively even though duplicating a clean slide can't introduce a
1399
+ * new cycle.
1400
+ */
1401
+ declare function duplicateDoc(opts: DuplicateDocOptions): Promise<DocDuplicateReport>;
1402
+ /**
1403
+ * Delete a doc inside a project AND scrub any workspace-wide references:
1404
+ *
1405
+ * 1. Walk every project subdir of the workspace. For each project, walk
1406
+ * its root + `slides/` for *.atelier files (mirroring listDocs' scope).
1407
+ * 2. For each `.atelier` doc found: scan `slides[]` (if kind:carousel) for
1408
+ * refs that resolve to the absolute path of the doc being deleted;
1409
+ * splice those refs out, persist the updated doc.
1410
+ * 3. Same walk, but scan `layers[]` for RefVisual layers (`visual.type ==
1411
+ * "ref"`) whose `src` resolves to the same absolute path. Collect
1412
+ * these as `refLayersDangling` — do NOT remove them; the renderer
1413
+ * tolerates missing refs and we want the studio to surface dangling
1414
+ * refs as warnings rather than silently nuke them.
1415
+ * 4. Unlink the doc.
1416
+ *
1417
+ * Every .atelier is equal — there is no "project manifest" carve-out.
1418
+ */
1419
+ declare function deleteDoc(opts: DeleteDocOptions): DocDeleteCascadeReport;
1420
+ /**
1421
+ * Enumerate the .atelier docs belonging to a project for the studio sidebar.
1422
+ *
1423
+ * Post-pivot: every .atelier is equal. Returns a flat alphabetical list of
1424
+ * docs in the project's root + `slides/` subdir. The optional `kind` field
1425
+ * is filled in when the doc parses and has a top-level `kind`; otherwise
1426
+ * omitted.
1427
+ *
1428
+ * Scope is intentionally non-recursive (root + slides/ only) — per Arky's
1429
+ * v1 plan, deeper trees are out of scope for the sidebar.
1430
+ *
1431
+ * Hardening: the `.atelier/` directory at project root (paradigm artifact
1432
+ * sibling) matches `*.atelier` by name but is NOT a doc. We filter by
1433
+ * `statSync().isFile()` AND skip basename `.atelier` defensively.
1434
+ */
1435
+ declare function listDocs(projectDir: string): DocListEntry[];
1436
+
1437
+ export { ARTIFACT_FILENAMES, type ArtifactParseError, type AssetInfo, type BinIngestRoute, type BuildCaptionsOptions, CanvasUnavailableError, type CaptionStyle, type ComposeCarouselProjectOptions, type ComposeCarouselProjectResult, type ComposeImageProjectOptions, type ComposeImageProjectResult, type ComposeVideoProjectOptions, type ComposeVideoProjectResult, type CreateDocOptions, type CreateDocResult, type DeleteDocOptions, type DocDeleteCascadeReport, type DocDuplicateReport, type DocKind, type DocListEntry, type DocumentInfo, type DuplicateDocOptions, type IngestKind, type IngestRoute, type InitResult, LEARNING_MODES, LEARNING_MODE_VERSION, type LearningMode, type LearningModeFile, type LoadedArtifactProject, type LoadedRecipe, type ProgressInfo, RECIPE_VERSION, type RenderFormat, type RenderOptions, type RenderResult, type RunInitOptions, type TranscribeOptions, type TranscribeResult, type TrimOptions, type TrimResult, VIDEO_CUTLIST_VERSION, VIDEO_PROJECT_VERSION, VIDEO_TRANSCRIPT_VERSION, type VariableInfo, type VideoProject, type WhisperBackend, type WhisperModel, type WhisperOptions, applyAdd, applyBatchReplace, applyHide, applyMerge, applyRecipeCommand, applyRecipeToCaptionOptions, applyRecipeToTranscribeOptions, applyRecipeToTrimOptions, applySplit, applyTextEdit, artifactsCommand, assetsCommand, buildCaptionLayers, buildFfmpegArgs, captionsCommand, carouselCommand, carouselFileName, checkFfmpeg, classifyMediaFile, composeCarouselFrameDoc, composeCarouselProject, composeImageProject, composeVideoProject, createDoc, createVideoProject, deleteDoc, duplicateDoc, effectiveSpan, expandInputs, exportImageCommand, exportLottieCommand, exportSvgCommand, fitImageToCanvas, flattenWords, getAssets, getInfo, getVariables, groupIntoPhrases, infoCommand, initCommand, isInsideGitRepo, isValidDocName, learningModePath, listDocs, loadArtifactsFromProject, loadCanvasModule, loadRecipe, loadVideoProject, mergeTranscriptWithExisting, parseModeAnswer, parseWhisperCppJson, probeWhisper, readComposition, readCutList, readLearningMode, readTranscript, recipeCommand, recipeToYaml, renderCommand, renderDocument, renderDocumentToPng, renderLearningModeYaml, renderRecipeWithDefaults, resolveExportDimensions, resolveRecipePath, resolveStill, rewriteCaptionLayers, rewriteCutLayers, routeIngest, routeIngestWithTarget, runInit, runWhisperCpp, scaffoldRecipeYaml, stillCommand, transcribeCommand, transcribeProject, transcriptCommand, trimCommand, trimProject, validateCommand, validateFile, variablesCommand, writeComposition, writeCutList, writeLearningMode, writeTranscript };