takt-marp 0.2.1 → 0.4.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 (60) hide show
  1. package/README.ja.md +18 -18
  2. package/README.md +18 -18
  3. package/fixtures/marp-slide-workflow/_workflow-smoke/brief.md +100 -14
  4. package/fixtures/marp-slide-workflow/_workflow-smoke/research/research-brief.md +12 -0
  5. package/package.json +9 -6
  6. package/scripts/lib/takt-marp-cli.mjs +90 -44
  7. package/scripts/lib/takt-marp-errors.mjs +11 -0
  8. package/scripts/lib/takt-marp-project-eject.mjs +136 -0
  9. package/scripts/lib/takt-marp-project-templates.mjs +108 -1
  10. package/scripts/lib/takt-marp-runtime-context.mjs +1 -0
  11. package/scripts/lib/takt-marp-slide-artifact-target.mjs +70 -0
  12. package/scripts/lib/takt-marp-slide-workflow.mjs +177 -43
  13. package/scripts/takt-marp-build-slide-artifact.mjs +9 -69
  14. package/scripts/takt-marp-preview-slide.mjs +91 -0
  15. package/scripts/takt-marp-run-slide-workflow.mjs +106 -16
  16. package/scripts/takt-marp-sync-project-templates.mjs +5 -16
  17. package/scripts/takt-marp-validate-global-install.mjs +426 -99
  18. package/scripts/takt-marp-validate-installer-ci-entrypoint.mjs +96 -0
  19. package/scripts/takt-marp-validate-package-boundary.mjs +19 -8
  20. package/scripts/takt-marp-validate-slide-workflow-foundation.mjs +2920 -50
  21. package/scripts/takt-marp-validate-slide-workflow-smoke.mjs +1052 -78
  22. package/templates/project/facets/instructions/takt-marp-adapt-research.md +35 -0
  23. package/templates/project/facets/instructions/takt-marp-ai-antipattern-fix.md +3 -3
  24. package/templates/project/facets/instructions/takt-marp-analyze-reference-deck.md +40 -0
  25. package/templates/project/facets/instructions/takt-marp-assemble-slides.md +36 -0
  26. package/templates/project/facets/instructions/takt-marp-compose-fix.md +2 -2
  27. package/templates/project/facets/instructions/takt-marp-compose-review.md +7 -6
  28. package/templates/project/facets/instructions/takt-marp-compose-sections.md +31 -0
  29. package/templates/project/facets/instructions/takt-marp-compose-work-summary.md +6 -3
  30. package/templates/project/facets/instructions/takt-marp-deliver-build.md +1 -1
  31. package/templates/project/facets/instructions/takt-marp-design-system.md +6 -4
  32. package/templates/project/facets/instructions/takt-marp-normalize-brief.md +8 -2
  33. package/templates/project/facets/instructions/takt-marp-plan-fix.md +4 -3
  34. package/templates/project/facets/instructions/takt-marp-plan-review.md +20 -4
  35. package/templates/project/facets/instructions/takt-marp-plan-work-summary.md +12 -5
  36. package/templates/project/facets/instructions/takt-marp-plan.md +30 -8
  37. package/templates/project/facets/instructions/takt-marp-polish-fix.md +2 -2
  38. package/templates/project/facets/instructions/takt-marp-polish-inspect.md +1 -1
  39. package/templates/project/facets/instructions/takt-marp-supervise-research.md +23 -0
  40. package/templates/project/facets/instructions/takt-marp-visual-generate.md +15 -15
  41. package/templates/project/facets/knowledge/takt-marp-repo-conventions.md +26 -4
  42. package/templates/project/facets/output-contracts/takt-marp-normalized-brief.md +19 -1
  43. package/templates/project/facets/output-contracts/takt-marp-open-questions.md +48 -0
  44. package/templates/project/facets/output-contracts/takt-marp-reference-analysis.md +52 -0
  45. package/templates/project/facets/output-contracts/takt-marp-research-claims.md +50 -0
  46. package/templates/project/facets/output-contracts/takt-marp-research-sources.md +50 -0
  47. package/templates/project/facets/output-contracts/takt-marp-research-supervision.md +49 -0
  48. package/templates/project/facets/output-contracts/takt-marp-section-compose.md +36 -0
  49. package/templates/project/facets/output-contracts/takt-marp-slide-blueprint.md +44 -0
  50. package/templates/project/facets/output-contracts/takt-marp-slide-plan.md +30 -2
  51. package/templates/project/facets/policies/takt-marp-general-slide-quality.md +1 -1
  52. package/templates/project/facets/policies/takt-marp-slide-quality.md +6 -4
  53. package/templates/project/facets/policies/takt-marp-visual-composition.md +87 -0
  54. package/templates/project/workflows/takt-marp-slide-compose.yaml +37 -18
  55. package/templates/project/workflows/takt-marp-slide-plan.yaml +32 -4
  56. package/templates/project/workflows/takt-marp-slide-polish.yaml +5 -5
  57. package/templates/project/workflows/takt-marp-slide-research.yaml +81 -0
  58. package/scripts/lib/takt-marp-project-init.mjs +0 -81
  59. package/templates/project/facets/instructions/takt-marp-compose-slides.md +0 -35
  60. package/templates/project/facets/policies/takt-marp-svg-first-visual.md +0 -68
package/README.ja.md CHANGED
@@ -6,7 +6,7 @@ Marpスライドデッキと、半自動でデッキを生成するためのTAKT
6
6
 
7
7
  ## TAKT Marp workflow
8
8
 
9
- このworkflowは `slides/<deck>/brief.md` を起点に、`plan`、`compose`、`polish`、`deliver` の状態へ進めます。
9
+ このworkflowは `slides/<deck>/brief.md` を起点に、`plan`、`compose`、`polish`、`deliver` の状態へ進めます。外部調査が必要な deck だけ、任意で先に `research` を実行します。
10
10
 
11
11
  詳細なworkflow contract: [docs/marp-slide-workflow.md](docs/marp-slide-workflow.md)
12
12
 
@@ -34,21 +34,23 @@ Output Requirementsの例:
34
34
  ### 2. workflowを実行する
35
35
 
36
36
  ```bash
37
- npm run slide:plan -- "slides/<deck>"
38
- npm run slide:approve -- "slides/<deck>" plan --by <name>
39
- npm run slide:compose -- "slides/<deck>"
40
- npm run slide:approve -- "slides/<deck>" compose --by <name>
41
- npm run slide:polish -- "slides/<deck>"
42
- npm run slide:deliver -- "slides/<deck>"
37
+ takt-marp research "slides/<deck>"
38
+ takt-marp plan "slides/<deck>"
39
+ takt-marp approve "slides/<deck>" plan --by <name>
40
+ takt-marp compose "slides/<deck>"
41
+ takt-marp approve "slides/<deck>" compose --by <name>
42
+ takt-marp polish "slides/<deck>"
43
+ takt-marp deliver "slides/<deck>"
43
44
  ```
44
45
 
45
46
  targetは `slides/<deck>` を指定します。
46
47
 
47
48
  ```bash
48
- npm run slide:plan -- "slides/<deck>"
49
+ takt-marp plan "slides/<deck>"
49
50
  ```
50
51
 
51
- 人間承認は `plan` と `compose` に対してのみ `slide:approve` で記録します。`review`、`revise`、`qa`、`build-qa` はworkflow内部の責務であり、トップレベルコマンドではありません。
52
+ 人間承認は `plan` と `compose` に対してのみ `takt-marp approve` で記録します。`review`、`revise`、`qa`、`build-qa` はworkflow内部の責務であり、トップレベルコマンドではありません。
53
+ `research` は `slides/<deck>/research/research-brief.md` を読み、`plan` の必須前提ではありません。
52
54
 
53
55
  ### 3. 生成されるファイル
54
56
 
@@ -59,6 +61,7 @@ slides/<deck>/
59
61
  design-system.md
60
62
  SLIDES.md
61
63
  images/*.svg
64
+ research/*.md
62
65
  review/*.md
63
66
  ```
64
67
 
@@ -75,24 +78,21 @@ slides/<deck>/
75
78
  - spatial balance: 上寄り、左寄り、大きな意図しない余白、視覚重心
76
79
  - design-system usage: token化されたCSS、スライドごとのstyle drift防止
77
80
 
78
- `deliver` は要求された成果物を生成します。PDF生成は対象deckの `SLIDES.md` だけをbuildします。
81
+ `deliver` は要求された成果物を生成し、delivery verification と supervision まで行います。
82
+ 単純なローカル生成や確認だけなら、workflow state を変更しない utility command を使います。
79
83
 
80
84
  ```bash
81
- npm run build:pdf -- <deck>
85
+ takt-marp build:html <deck>
86
+ takt-marp build:pdf <deck>
87
+ takt-marp preview <deck>
82
88
  ```
83
89
 
84
90
  ### 5. 検証
85
91
 
86
- 軽量なローカル確認には foundation validation を使います。
87
-
88
- ```bash
89
- npm test
90
- ```
91
-
92
92
  workflow routing、state gate、render evidence、delivery verification、approval handling を変更した場合は smoke validation を実行します。
93
93
 
94
94
  ```bash
95
- npm run slide:smoke -- --keep
95
+ takt-marp smoke --keep
96
96
  ```
97
97
 
98
98
  smoke validation は fixture から一時的な `_workflow-smoke` deck を作成し、invalid target、approval failure path、`plan` -> `compose` -> `polish` -> `deliver` の一連の実行、render evidence metadata、delivery artifact、rerun/force behavior を検証します。`--keep` を付けると、生成された deck と report を `slides/_workflow-smoke/` に残して確認できます。
package/README.md CHANGED
@@ -6,7 +6,7 @@ Marp slide decks and a TAKT workflow for semi-automated deck generation.
6
6
 
7
7
  ## TAKT Marp workflow
8
8
 
9
- The workflow starts from `slides/<deck>/brief.md` and moves through `plan`, `compose`, `polish`, and `deliver`.
9
+ The workflow starts from `slides/<deck>/brief.md` and moves through `plan`, `compose`, `polish`, and `deliver`. Use optional `research` first only when a deck needs external research context.
10
10
 
11
11
  Detailed workflow contract: [docs/marp-slide-workflow.md](docs/marp-slide-workflow.md)
12
12
 
@@ -34,21 +34,23 @@ Example output requirement:
34
34
  ### 2. Run the workflows
35
35
 
36
36
  ```bash
37
- npm run slide:plan -- "slides/<deck>"
38
- npm run slide:approve -- "slides/<deck>" plan --by <name>
39
- npm run slide:compose -- "slides/<deck>"
40
- npm run slide:approve -- "slides/<deck>" compose --by <name>
41
- npm run slide:polish -- "slides/<deck>"
42
- npm run slide:deliver -- "slides/<deck>"
37
+ takt-marp research "slides/<deck>"
38
+ takt-marp plan "slides/<deck>"
39
+ takt-marp approve "slides/<deck>" plan --by <name>
40
+ takt-marp compose "slides/<deck>"
41
+ takt-marp approve "slides/<deck>" compose --by <name>
42
+ takt-marp polish "slides/<deck>"
43
+ takt-marp deliver "slides/<deck>"
43
44
  ```
44
45
 
45
46
  Use `slides/<deck>` as the target:
46
47
 
47
48
  ```bash
48
- npm run slide:plan -- "slides/<deck>"
49
+ takt-marp plan "slides/<deck>"
49
50
  ```
50
51
 
51
- Human approval is recorded by `slide:approve` for `plan` and `compose` only. `review`, `revise`, `qa`, and `build-qa` are internal workflow responsibilities, not top-level commands.
52
+ Human approval is recorded by `takt-marp approve` for `plan` and `compose` only. `review`, `revise`, `qa`, and `build-qa` are internal workflow responsibilities, not top-level commands.
53
+ `research` reads `slides/<deck>/research/research-brief.md` and is not required before `plan`.
52
54
 
53
55
  ### 3. Generated files
54
56
 
@@ -59,6 +61,7 @@ slides/<deck>/
59
61
  design-system.md
60
62
  SLIDES.md
61
63
  images/*.svg
64
+ research/*.md
62
65
  review/*.md
63
66
  ```
64
67
 
@@ -75,24 +78,21 @@ slides/<deck>/
75
78
  - spatial balance: top/left bias, large unintended blank areas, visual center of gravity
76
79
  - design-system usage: tokenized CSS, no per-slide style drift
77
80
 
78
- `deliver` is responsible for requested artifacts. PDF generation builds only the target deck's `SLIDES.md`:
81
+ `deliver` is responsible for requested artifacts, delivery verification, and final supervision.
82
+ For simple local generation or inspection, use utility commands that do not change workflow state:
79
83
 
80
84
  ```bash
81
- npm run build:pdf -- <deck>
85
+ takt-marp build:html <deck>
86
+ takt-marp build:pdf <deck>
87
+ takt-marp preview <deck>
82
88
  ```
83
89
 
84
90
  ### 5. Validation
85
91
 
86
- Use the foundation validation for fast local checks:
87
-
88
- ```bash
89
- npm test
90
- ```
91
-
92
92
  Use the smoke validation when changing workflow routing, state gates, render evidence, delivery verification, or approval handling:
93
93
 
94
94
  ```bash
95
- npm run slide:smoke -- --keep
95
+ takt-marp smoke --keep
96
96
  ```
97
97
 
98
98
  The smoke validation creates a temporary `_workflow-smoke` deck from the fixture, exercises invalid target and approval failure paths, runs the `plan` -> `compose` -> `polish` -> `deliver` sequence, verifies render evidence metadata, checks delivery artifacts, and covers rerun/force behavior. `--keep` leaves the generated deck and reports under `slides/_workflow-smoke/` for inspection.
@@ -1,26 +1,65 @@
1
- # Brief
1
+ # Workflow Smoke Deck Brief
2
2
 
3
3
  ## Event
4
- - Name: Workflow smoke test
5
- - Date:
6
- - Duration: 5 minutes
7
- - Venue: local
8
- - Audience: maintainer
4
+ - Name: 架空研修ラボ ドメインモデリング講座
5
+ - Date: 2031年4月17日(木)10:00〜16:30
6
+ - Duration: 360 minutes
7
+ - Venue: ミラージュホール A / サンプル配信スタジオ
8
+ - Organizer: サンプル研修ラボ株式会社
9
+ - Audience: メンテナとワークフロー検証者
9
10
 
10
11
  ## Goal
11
- Marp slide TAKT workflow brief から plandraft、SVG、review、build QA まで接続できることを確認する。
12
+ Marp slide TAKT workflow が、情報量の多い講義ブリーフから normalized brief、reference analysis、coverage matrixslide blueprintsection source、HTML/CSS visual、SVG visual、review、build QA まで接続できることを確認する。
13
+
14
+ ## Critical Constraints
15
+ - Official Title: 変更に強いドメインモデリングの実践ワークショップ
16
+ - Speaker Name: 山田 サンプル
17
+ - Speaker Affiliation: サンプルデザイン合同会社
18
+ - Design: 白基調だが白黒ではない。カラー印刷を前提に、青・緑・橙・赤を意味づけて使う。
19
+ - Information Density: 投影だけでなく印刷配布テキストとして読める密度を許容する。
20
+
21
+ ### Fixed Outline
22
+ 1. 入力を正にする
23
+ (1)briefを保全する
24
+ a. 正式タイトル、講師名、所属を落とさない
25
+ b. 禁止語と避けるべき表現を保持する
26
+ (2)事実を棚卸しする
27
+ a. 架空の日時、主催、形式、対象、場所をFact Inventoryに残す
28
+ b. Target slide countと要求密度の矛盾をfindingにする
29
+ 2. 設計をplanへ渡す
30
+ (1)coverage matrixを作る
31
+ a. 固定アウトラインの全leaf項目をslide IDへ対応させる
32
+ b. 未対応項目はneeds_inputではなくPlan Findingsへ残す
33
+ (2)visual strategyを決める
34
+ a. カード、比較、表、軽量フローはhtml:で構成する
35
+ b. 座標制御や複雑な矢印だけsvg:またはinline-svg:にする
36
+ 3. section sourceからassembleする
37
+ (1)blueprintを分ける
38
+ a. slide-blueprint.mdにcontent atomsとsection manifestを残す
39
+ b. sections/*.mdからSLIDES.mdへassembleする
40
+ (2)deliveryを検証する
41
+ a. HTMLとPDFをbuildできることを確認する
42
+ b. generated artifactをsource artifactへ混ぜない
12
43
 
13
44
  ## Core Message
14
- 半自動のMarp生成workflowは、入力、構成、visual、レビュー、QAを分離すると安定する。
45
+ 半自動のMarp生成workflowは、入力、coverage、blueprint、section source、visual、レビュー、QAを分離すると安定する。
15
46
 
16
47
  ## Audience Context
17
48
  聴衆はこのリポジトリのメンテナであり、TAKTとMarpの基本を理解している。
18
49
 
19
50
  ## Required Topics
20
- - briefを入力の正にする
21
- - SVG-firstで図を管理する
22
- - plan後とdraft後に人間確認を挟む
23
- - build QAまでworkflowに含める
51
+ - 1. 入力を正にする > (1)briefを保全する > a. 正式タイトル、講師名、所属を落とさない
52
+ - 1. 入力を正にする > (1)briefを保全する > b. 禁止語と避けるべき表現を保持する
53
+ - 1. 入力を正にする > (2)事実を棚卸しする > a. 架空の日時、主催、形式、対象、場所をFact Inventoryに残す
54
+ - 1. 入力を正にする > (2)事実を棚卸しする > b. Target slide countと要求密度の矛盾をfindingにする
55
+ - 2. 設計をplanへ渡す > (1)coverage matrixを作る > a. 固定アウトラインの全leaf項目をslide IDへ対応させる
56
+ - 2. 設計をplanへ渡す > (1)coverage matrixを作る > b. 未対応項目はneeds_inputではなくPlan Findingsへ残す
57
+ - 2. 設計をplanへ渡す > (2)visual strategyを決める > a. カード、比較、表、軽量フローはhtml:で構成する
58
+ - 2. 設計をplanへ渡す > (2)visual strategyを決める > b. 座標制御や複雑な矢印だけsvg:またはinline-svg:にする
59
+ - 3. section sourceからassembleする > (1)blueprintを分ける > a. slide-blueprint.mdにcontent atomsとsection manifestを残す
60
+ - 3. section sourceからassembleする > (1)blueprintを分ける > b. sections/*.mdからSLIDES.mdへassembleする
61
+ - 3. section sourceからassembleする > (2)deliveryを検証する > a. HTMLとPDFをbuildできることを確認する
62
+ - 3. section sourceからassembleする > (2)deliveryを検証する > b. generated artifactをsource artifactへ混ぜない
24
63
 
25
64
  ## Optional Topics
26
65
  - appendixは必要な場合だけ作る
@@ -29,16 +68,63 @@ Marp slide TAKT workflow が brief から plan、draft、SVG、review、build QA
29
68
  - Web画像の自動取得
30
69
  - 他deck画像の自動流用
31
70
  - 長い本文をスライドに詰め込むこと
71
+ - SVG-firstという方針に戻すこと
72
+ - htmlで十分なカード、比較、表、軽量フローをSVG化すること
73
+ - サンプル主催名、架空日付、架空場所を実在情報に置き換えること
32
74
 
33
75
  ## Source Materials
34
76
  - docs/marp-slide-workflow.md
77
+ - _workflow-smoke internal synthetic brief only
35
78
 
36
79
  ## Speaker Notes
37
- 短い確認用deckなので、各スライドのnotesは2-3文でよい。
80
+ 短い確認用deckなので、各スライドのnotesは2-3文でよい。Durationが分単位で指定されているため、notesには尺マーカーを付ける。
38
81
 
39
82
  ## Output Requirements
40
83
  - Format: Marp
41
84
  - Language: Japanese
42
85
  - Target slide count: 5
86
+ - Deck Mode: overview
43
87
  - Deliverables: html, pdf
44
- - Visual scope: use exactly one SVG for the workflow overview slide. For paired discipline slides, use text-only split columns with Visual: none; do not plan unused SVG placeholders.
88
+ - Slide Count Consistency Scenario: Target slide count: 5 は概要版として扱う。講義本体を要求する場合は100〜140または期待値相当へ修正する必要がある、というPlan Findingを作れること。
89
+ - Visual scope: html: cards/comparison/table/light-flow を優先し、座標制御が必要な1箇所だけ inline-svg: を使う。未使用SVG placeholderを計画しない。
90
+
91
+ ## Fact Inventory
92
+ - 主催: サンプル研修ラボ株式会社
93
+ - 形式: ミラージュホール A / サンプル配信スタジオ
94
+ - 日時: 2031年4月17日(木)10:00〜16:30
95
+ - 対象: メンテナとワークフロー検証者
96
+ - 場所: ミラージュホール A
97
+ - 講師所属: サンプルデザイン合同会社
98
+
99
+ ## Terminology Policy
100
+ - Domain-Driven Design はドメイン駆動設計と表記する。
101
+ - Workflow は workflow と英字表記で統一する。
102
+ - Fixed Outline の語句は言い換えない。
103
+
104
+ ## Example Policy
105
+ - 共通題材は「備品購入申請・承認」とし、章をまたいで一貫利用する。
106
+
107
+ ## Code Example Policy
108
+ - Java風の疑似コードでBefore / Afterを示す。
109
+ - 業務の意味がコード構造へ表れることを示す。
110
+ - フレームワーク固有APIへ寄せすぎない。
111
+
112
+ ## Exercise Policy
113
+ - 短時間の個人演習にする。
114
+ - 模範回答または解説を巻末またはnotesに残す。
115
+
116
+ ## Appendix Requirements
117
+ - 用語集
118
+ - 実践チェックリスト
119
+ - 演習模範回答
120
+
121
+ ## Quality Checklist
122
+ - 正式タイトル完全一致
123
+ - 講師所属がサンプルデザイン合同会社
124
+ - 禁止語を使わない
125
+ - 固定アウトラインを変更しない
126
+ - 白基調だが白黒ではない
127
+ - coverage matrixに全leaf項目がある
128
+ - html: visual と svg:/inline-svg: visual の責務が分かれている
129
+ - sections/*.mdからSLIDES.mdへassembleできる
130
+ - build:html / build:pdf が成功する
@@ -0,0 +1,12 @@
1
+ # Workflow Smoke Research Brief
2
+
3
+ ## Research Goal
4
+ Validate that the optional research command can synchronize built-in deep research output into deck-local research artifacts before planning.
5
+
6
+ ## Scope
7
+ - Use only deterministic mock research content.
8
+ - Preserve missing source URL, retrieval time, confidence, and claim-source mapping as absent information.
9
+ - Do not infer or supplement facts that are not present in the built-in research report.
10
+
11
+ ## Expected Consumer
12
+ The subsequent plan command may read the generated research artifacts as optional context, while still using `brief.md` as the primary input.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "takt-marp",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "takt-marp",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,6 +20,7 @@
20
20
  "node": ">=24"
21
21
  },
22
22
  "scripts": {
23
+ "slide:research": "node scripts/takt-marp-run-slide-workflow.mjs research",
23
24
  "slide:plan": "node scripts/takt-marp-run-slide-workflow.mjs plan",
24
25
  "slide:compose": "node scripts/takt-marp-run-slide-workflow.mjs compose",
25
26
  "slide:polish": "node scripts/takt-marp-run-slide-workflow.mjs polish",
@@ -29,12 +30,14 @@
29
30
  "slide:render-evidence": "node scripts/takt-marp-render-slide-workflow-evidence.mjs",
30
31
  "slide:validate-foundation": "node scripts/takt-marp-validate-slide-workflow-foundation.mjs",
31
32
  "slide:smoke": "node scripts/takt-marp-validate-slide-workflow-smoke.mjs",
32
- "test": "npm run slide:validate-foundation",
33
+ "test": "npm run slide:validate-foundation && npm run slide:smoke -- --provider mock",
33
34
  "build": "npm run build:html && npm run build:pdf",
34
- "build:html": "marp slides/takt-sdd/SLIDES.md --html --allow-local-files -o dist/takt-sdd/SLIDES.html",
35
- "build:pptx": "marp slides/takt-sdd/SLIDES.md --html --allow-local-files --pptx -o dist/takt-sdd/SLIDES.pptx",
36
- "build:pdf": "marp slides/takt-sdd/SLIDES.md --html --allow-local-files --pdf -o dist/takt-sdd/SLIDES.pdf",
37
- "preview": "marp -s . --html",
35
+ "build:html": "node scripts/takt-marp-build-slide-artifact.mjs html",
36
+ "build:pptx": "node scripts/takt-marp-build-slide-artifact.mjs pptx",
37
+ "build:pdf": "node scripts/takt-marp-build-slide-artifact.mjs pdf",
38
+ "preview": "node scripts/takt-marp-preview-slide.mjs takt-sdd",
39
+ "installer:ci": "npm run slide:validate-foundation && npm run installer:check-templates && npm run installer:check-package && npm run installer:validate && npm run slide:smoke -- --provider mock",
40
+ "installer:check-ci": "node scripts/takt-marp-validate-installer-ci-entrypoint.mjs",
38
41
  "installer:sync-templates": "node scripts/takt-marp-sync-project-templates.mjs --write",
39
42
  "installer:check-templates": "node scripts/takt-marp-sync-project-templates.mjs",
40
43
  "installer:check-package": "node scripts/takt-marp-validate-package-boundary.mjs",
@@ -1,10 +1,10 @@
1
1
  import { spawn } from "node:child_process";
2
- import { statSync } from "node:fs";
3
2
  import { mkdtemp } from "node:fs/promises";
4
3
  import os from "node:os";
5
4
  import path from "node:path";
6
5
  import { parseArgs } from "node:util";
7
- import { initializeProject } from "./takt-marp-project-init.mjs";
6
+ import { ejectProject } from "./takt-marp-project-eject.mjs";
7
+ import { resolveTemplateSource, workflowFilePath } from "./takt-marp-project-templates.mjs";
8
8
  import { packageScriptPath } from "./takt-marp-runtime-context.mjs";
9
9
  import {
10
10
  APPROVAL_COMMANDS,
@@ -12,19 +12,29 @@ import {
12
12
  SlideWorkflowError,
13
13
  } from "./takt-marp-slide-workflow.mjs";
14
14
 
15
- const WORKFLOW_COMMANDS = ["plan", "compose", "polish", "deliver"];
16
- const VALID_COMMANDS = ["init", ...WORKFLOW_COMMANDS, "approve", "smoke"];
15
+ const RESEARCH_COMMANDS = ["research"];
16
+ const WORKFLOW_COMMANDS = [...RESEARCH_COMMANDS, "plan", "compose", "polish", "deliver"];
17
+ const BUILD_COMMANDS = Object.freeze({
18
+ "build:html": "html",
19
+ "build:pdf": "pdf",
20
+ "build:pptx": "pptx",
21
+ });
22
+ const UTILITY_COMMANDS = [...Object.keys(BUILD_COMMANDS), "preview"];
23
+ const VALID_COMMANDS = ["eject", ...WORKFLOW_COMMANDS, "approve", "smoke", ...UTILITY_COMMANDS];
17
24
  const RUNNER_SCRIPT = "scripts/takt-marp-run-slide-workflow.mjs";
18
25
  const APPROVE_SCRIPT = "scripts/takt-marp-approve-slide-workflow-state.mjs";
19
26
  const SMOKE_SCRIPT = "scripts/takt-marp-validate-slide-workflow-smoke.mjs";
20
- const REQUIRED_PROJECT_DIRS = [".takt/workflows", ".takt/facets"];
27
+ const BUILD_SCRIPT = "scripts/takt-marp-build-slide-artifact.mjs";
28
+ const PREVIEW_SCRIPT = "scripts/takt-marp-preview-slide.mjs";
29
+ const FORWARDED_SIGNALS = new Set(["SIGINT", "SIGTERM"]);
21
30
 
22
31
  function usage() {
23
32
  return [
24
33
  "Usage: takt-marp <command> [arguments]",
25
34
  "",
26
35
  "Commands:",
27
- " init [dir] [--force|--overwrite] Install .takt/workflows and .takt/facets templates into <dir> (default: .)",
36
+ " eject [dir] [--force|--overwrite] Copy .takt/workflows and .takt/facets templates into <dir> (default: .)",
37
+ " research <slides/deck> [options] Optional pre-research command before slide planning",
28
38
  " plan <slides/deck> [options] Run the plan workflow for a deck in the current project",
29
39
  " compose <slides/deck> [options] Run the compose workflow for a deck in the current project",
30
40
  " polish <slides/deck> [options] Run the polish workflow for a deck in the current project",
@@ -32,6 +42,14 @@ function usage() {
32
42
  " approve <slides/deck> <command> --by <name> [--force]",
33
43
  " Approve a workflow state (command: plan or compose)",
34
44
  " smoke [--provider <name>] Run smoke validation in a temporary project (default provider: mock)",
45
+ " build:html [deck|slides/<deck>|slides/<deck>/SLIDES.md]",
46
+ " Build HTML artifact without changing workflow state",
47
+ " build:pdf [deck|slides/<deck>|slides/<deck>/SLIDES.md]",
48
+ " Build PDF artifact without changing workflow state",
49
+ " build:pptx [deck|slides/<deck>|slides/<deck>/SLIDES.md]",
50
+ " Build PPTX artifact without changing workflow state",
51
+ " preview <deck|slides/<deck>|slides/<deck>/SLIDES.md>",
52
+ " Start Marp server mode without changing workflow state",
35
53
  "",
36
54
  "Workflow options (passed through to the workflow runner unchanged):",
37
55
  " --force Invalidate an already-successful state and rerun",
@@ -39,11 +57,11 @@ function usage() {
39
57
  ].join("\n");
40
58
  }
41
59
 
42
- function initUsage() {
60
+ function ejectUsage() {
43
61
  return [
44
- "Usage: takt-marp init [dir] [--force|--overwrite]",
62
+ "Usage: takt-marp eject [dir] [--force|--overwrite]",
45
63
  "",
46
- "Installs .takt/workflows/** and .takt/facets/** templates into <dir> (default: current directory).",
64
+ "Copies .takt/workflows/** and .takt/facets/** templates into <dir> (default: current directory).",
47
65
  "",
48
66
  "Options:",
49
67
  " --force Overwrite existing template-owned files",
@@ -52,43 +70,61 @@ function initUsage() {
52
70
  ].join("\n");
53
71
  }
54
72
 
55
- function isDirectory(candidatePath) {
56
- const stats = statSync(candidatePath, { throwIfNoEntry: false });
57
- return stats !== undefined && stats.isDirectory();
58
- }
59
-
60
- function assertProjectInitialized() {
61
- const cwd = process.cwd();
62
- const missing = REQUIRED_PROJECT_DIRS.filter(
63
- (relative) => !isDirectory(path.join(cwd, ...relative.split("/"))),
64
- );
65
- if (missing.length > 0) {
66
- throw new SlideWorkflowError(
67
- `Target project is not initialized: missing ${missing.join(" and ")} in ${cwd}. Run 'takt-marp init .' first.`,
68
- "PROJECT_NOT_INITIALIZED",
69
- );
70
- }
71
- }
72
-
73
73
  function runPackageScript(relativeScriptPath, args, options = {}) {
74
74
  return new Promise((resolve, reject) => {
75
+ let stopping = false;
75
76
  const child = spawn(process.execPath, [packageScriptPath(relativeScriptPath), ...args], {
76
77
  cwd: options.cwd ?? process.cwd(),
77
78
  stdio: "inherit",
78
79
  });
79
- child.on("error", reject);
80
- child.on("close", (code) => {
80
+ const signalHandlers = [];
81
+ if (options.successOnSignal) {
82
+ for (const signal of FORWARDED_SIGNALS) {
83
+ const handler = () => {
84
+ stopping = true;
85
+ if (!child.killed) {
86
+ child.kill(signal);
87
+ }
88
+ };
89
+ process.once(signal, handler);
90
+ signalHandlers.push([signal, handler]);
91
+ }
92
+ }
93
+ const cleanup = () => {
94
+ for (const [signal, handler] of signalHandlers) {
95
+ process.off(signal, handler);
96
+ }
97
+ };
98
+ child.on("error", (error) => {
99
+ cleanup();
100
+ reject(error);
101
+ });
102
+ child.on("close", (code, signal) => {
103
+ cleanup();
104
+ if (options.successOnSignal && (stopping || FORWARDED_SIGNALS.has(signal))) {
105
+ resolve(0);
106
+ return;
107
+ }
81
108
  resolve(code ?? 1);
82
109
  });
83
110
  });
84
111
  }
85
112
 
86
113
  async function runWorkflowCommand(command, args) {
87
- assertProjectInitialized();
88
- return runPackageScript(RUNNER_SCRIPT, [command, ...args]);
114
+ const source = resolveTemplateSource({ projectRoot: process.cwd() });
115
+ const selectedWorkflowFilePath = workflowFilePath(source, command);
116
+ return runPackageScript(RUNNER_SCRIPT, [command, ...args, "--workflow-file", selectedWorkflowFilePath]);
89
117
  }
90
118
 
91
- async function runInit(args) {
119
+ async function runBuildCommand(command, args) {
120
+ return runPackageScript(BUILD_SCRIPT, [BUILD_COMMANDS[command], ...args]);
121
+ }
122
+
123
+ async function runPreview(args) {
124
+ return runPackageScript(PREVIEW_SCRIPT, args, { successOnSignal: true });
125
+ }
126
+
127
+ async function runEject(args) {
92
128
  let parsed;
93
129
  try {
94
130
  parsed = parseArgs({
@@ -102,26 +138,26 @@ async function runInit(args) {
102
138
  });
103
139
  } catch (error) {
104
140
  throw new SlideWorkflowError(
105
- `Invalid init arguments: ${error.message}. Run 'takt-marp init --help' for usage.`,
141
+ `Invalid eject arguments: ${error.message}. Run 'takt-marp eject --help' for usage.`,
106
142
  "INVALID_ARGS",
107
143
  );
108
144
  }
109
145
  if (parsed.values.help) {
110
- console.log(initUsage());
146
+ console.log(ejectUsage());
111
147
  return 0;
112
148
  }
113
149
  if (parsed.positionals.length > 1) {
114
150
  throw new SlideWorkflowError(
115
- `Unexpected extra init arguments: ${parsed.positionals.slice(1).join(" ")}. Run 'takt-marp init --help' for usage.`,
151
+ `Unexpected extra eject arguments: ${parsed.positionals.slice(1).join(" ")}. Run 'takt-marp eject --help' for usage.`,
116
152
  "INVALID_ARGS",
117
153
  );
118
154
  }
119
155
 
120
156
  const targetDir = path.resolve(process.cwd(), parsed.positionals[0] ?? ".");
121
157
  const force = parsed.values.force || parsed.values.overwrite;
122
- const { created, overwritten } = await initializeProject({ targetDir, force });
158
+ const { created, overwritten } = await ejectProject({ targetDir, force });
123
159
 
124
- const lines = [`Initialized takt-marp templates in ${targetDir}`];
160
+ const lines = [`Ejected takt-marp templates in ${targetDir}`];
125
161
  lines.push(`Created ${created.length} file(s)${created.length > 0 ? ":" : "."}`);
126
162
  for (const relativePath of created) {
127
163
  lines.push(` ${relativePath}`);
@@ -137,7 +173,7 @@ async function runInit(args) {
137
173
  "Next steps:",
138
174
  " - Provider configuration stays under your ownership: takt-marp does not create or modify",
139
175
  " TAKT provider settings, API keys, or credentials.",
140
- " - Configure your TAKT provider before running workflows.",
176
+ " - Edit ejected workflow/facet templates only when you need project-local customization.",
141
177
  ` - Run a workflow from the project root, e.g.: takt-marp plan slides/<deck>`,
142
178
  );
143
179
  console.log(lines.join("\n"));
@@ -146,8 +182,8 @@ async function runInit(args) {
146
182
 
147
183
  async function runSmoke(args) {
148
184
  // Smoke runs in a freshly created temporary project so the user's current
149
- // project is never touched. The temp project is retained after the run as
150
- // the home of the provider-specific smoke summaries.
185
+ // project is never touched. Template source selection stays no-copy by
186
+ // default; only the smoke validator may create smoke deck artifacts.
151
187
  let tempProject;
152
188
  try {
153
189
  tempProject = await mkdtemp(path.join(os.tmpdir(), "takt-marp-smoke-"));
@@ -157,7 +193,6 @@ async function runSmoke(args) {
157
193
  "SMOKE_PREPARE_FAILED",
158
194
  );
159
195
  }
160
- await initializeProject({ targetDir: tempProject, force: false });
161
196
  console.log(`Temporary smoke project: ${tempProject}`);
162
197
 
163
198
  // Pass argv through unchanged: provider selection (--provider) and the
@@ -213,7 +248,6 @@ async function runApprove(args) {
213
248
  console.log(approveUsage());
214
249
  return 0;
215
250
  }
216
- assertProjectInitialized();
217
251
  if (parsed.positionals.length !== 2) {
218
252
  throw new SlideWorkflowError(
219
253
  `Expected <slides/deck> and <command>. Run 'takt-marp approve --help' for usage.`,
@@ -242,14 +276,20 @@ export async function runCli(argv) {
242
276
  }
243
277
 
244
278
  try {
279
+ if (command === "init") {
280
+ throw new SlideWorkflowError(
281
+ "`init` has been removed. Use `takt-marp eject .` to copy template assets.",
282
+ "COMMAND_REMOVED",
283
+ );
284
+ }
245
285
  if (!VALID_COMMANDS.includes(command)) {
246
286
  throw new SlideWorkflowError(
247
287
  `'${command}' is not a takt-marp command. Valid commands: ${VALID_COMMANDS.join(", ")}. Run 'takt-marp --help' for usage.`,
248
288
  "UNKNOWN_COMMAND",
249
289
  );
250
290
  }
251
- if (command === "init") {
252
- return await runInit(rest);
291
+ if (command === "eject") {
292
+ return await runEject(rest);
253
293
  }
254
294
  if (command === "approve") {
255
295
  return await runApprove(rest);
@@ -257,6 +297,12 @@ export async function runCli(argv) {
257
297
  if (command === "smoke") {
258
298
  return await runSmoke(rest);
259
299
  }
300
+ if (Object.hasOwn(BUILD_COMMANDS, command)) {
301
+ return await runBuildCommand(command, rest);
302
+ }
303
+ if (command === "preview") {
304
+ return await runPreview(rest);
305
+ }
260
306
  return await runWorkflowCommand(command, rest);
261
307
  } catch (error) {
262
308
  console.error(formatError(error));
@@ -0,0 +1,11 @@
1
+ export class SlideWorkflowError extends Error {
2
+ constructor(message, code = "SLIDE_WORKFLOW_ERROR") {
3
+ super(message);
4
+ this.name = "SlideWorkflowError";
5
+ this.code = code;
6
+ }
7
+ }
8
+
9
+ export function formatError(error) {
10
+ return error instanceof SlideWorkflowError ? `${error.code}: ${error.message}` : String(error?.stack ?? error);
11
+ }