@orizm/cli 3.2.0 → 3.3.0-beta.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.
- package/dist/{agent-Bd30EhQC.mjs → agent-Kf8iuW2I.mjs} +2 -2
- package/dist/{agent-Bd30EhQC.mjs.map → agent-Kf8iuW2I.mjs.map} +1 -1
- package/dist/{agent-vC2-9rjt.cjs → agent-UZZtdOZS.cjs} +2 -2
- package/dist/{agent-vC2-9rjt.cjs.map → agent-UZZtdOZS.cjs.map} +1 -1
- package/dist/cli/main.cjs +4 -4
- package/dist/cli/main.mjs +4 -4
- package/dist/{cms-DLOypcw8.mjs → cms-8XZhxwsM.mjs} +5 -2
- package/dist/{cms-DLOypcw8.mjs.map → cms-8XZhxwsM.mjs.map} +1 -1
- package/dist/{cms-CId7jg5l.cjs → cms-C4zEtppZ.cjs} +5 -2
- package/dist/{cms-CId7jg5l.cjs.map → cms-C4zEtppZ.cjs.map} +1 -1
- package/dist/{codegen-kbbIwPbb.cjs → codegen-Cypg4O3L.cjs} +3 -3
- package/dist/{codegen-kbbIwPbb.cjs.map → codegen-Cypg4O3L.cjs.map} +1 -1
- package/dist/{codegen-BKE_IYoM.mjs → codegen-Dnjv7zfm.mjs} +3 -3
- package/dist/{codegen-BKE_IYoM.mjs.map → codegen-Dnjv7zfm.mjs.map} +1 -1
- package/dist/config/index.cjs +4 -2
- package/dist/config/index.cjs.map +1 -1
- package/dist/config/index.d.mts +8 -1
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +4 -2
- package/dist/config/index.mjs.map +1 -1
- package/dist/{config-loader-D8x32gEU.cjs → config-loader-CZfANHBf.cjs} +2 -2
- package/dist/config-loader-CZfANHBf.cjs.map +1 -0
- package/dist/{config-loader-BEgS869e.mjs → config-loader-CtbZOGjc.mjs} +3 -3
- package/dist/config-loader-CtbZOGjc.mjs.map +1 -0
- package/dist/{consumer-OG6IEJun.cjs → consumer-BSgriLn0.cjs} +2 -2
- package/dist/{consumer-OG6IEJun.cjs.map → consumer-BSgriLn0.cjs.map} +1 -1
- package/dist/{consumer-CqyZdG9v.mjs → consumer-s8LnLw4e.mjs} +2 -2
- package/dist/{consumer-CqyZdG9v.mjs.map → consumer-s8LnLw4e.mjs.map} +1 -1
- package/dist/docs/features/cli/commands/schema.md +3 -2
- package/dist/docs/features/cms-sdk/install.md +1 -1
- package/dist/docs/features/console/audit-logs.md +3 -0
- package/dist/docs/features/consumer-sdk/install.md +1 -1
- package/dist/docs/features/dictionary.md +268 -0
- package/dist/docs/features/full-text-search/local-development.md +145 -0
- package/dist/docs/features/full-text-search.md +146 -0
- package/dist/docs/features/schema/database.md +9 -8
- package/dist/docs/index.md +3 -1
- package/dist/docs/manifest.json +3 -3
- package/dist/{erd-BNv5Th6z.mjs → erd-BihhEfZ_.mjs} +2 -2
- package/dist/{erd-BNv5Th6z.mjs.map → erd-BihhEfZ_.mjs.map} +1 -1
- package/dist/{erd-ByuVMQ5n.cjs → erd-DmnB1v2c.cjs} +2 -2
- package/dist/{erd-ByuVMQ5n.cjs.map → erd-DmnB1v2c.cjs.map} +1 -1
- package/dist/{init-CPfpVlUN.mjs → init-BpKpTQ0z.mjs} +66 -13
- package/dist/init-BpKpTQ0z.mjs.map +1 -0
- package/dist/{init-NaL2N3Go.cjs → init-BrZCChEG.cjs} +66 -13
- package/dist/init-BrZCChEG.cjs.map +1 -0
- package/dist/{push-9fPpd4U8.cjs → push-BggkrD0g.cjs} +28 -10
- package/dist/push-BggkrD0g.cjs.map +1 -0
- package/dist/{push-54rmb0T0.mjs → push-xWnD9oov.mjs} +28 -10
- package/dist/push-xWnD9oov.mjs.map +1 -0
- package/dist/{run-codegen-mclysZuT.cjs → run-codegen-B-90rvjk.cjs} +2 -2
- package/dist/run-codegen-B-90rvjk.cjs.map +1 -0
- package/dist/{run-codegen-DjnV60bE.mjs → run-codegen-CrO08jJT.mjs} +2 -2
- package/dist/run-codegen-CrO08jJT.mjs.map +1 -0
- package/dist/{schema-CNSTXsVa.cjs → schema-CUVTXrHk.cjs} +4 -4
- package/dist/{schema-CNSTXsVa.cjs.map → schema-CUVTXrHk.cjs.map} +1 -1
- package/dist/{schema-BL6SlLtH.mjs → schema-DlUWHV_t.mjs} +4 -4
- package/dist/{schema-BL6SlLtH.mjs.map → schema-DlUWHV_t.mjs.map} +1 -1
- package/dist/{validate-BpxZ8LTl.cjs → validate-BH8jqdqq.cjs} +2 -2
- package/dist/{validate-BpxZ8LTl.cjs.map → validate-BH8jqdqq.cjs.map} +1 -1
- package/dist/{validate-Ca0CRo16.mjs → validate-COS4bfr0.mjs} +2 -2
- package/dist/{validate-Ca0CRo16.mjs.map → validate-COS4bfr0.mjs.map} +1 -1
- package/package.json +8 -8
- package/dist/config-loader-BEgS869e.mjs.map +0 -1
- package/dist/config-loader-D8x32gEU.cjs.map +0 -1
- package/dist/init-CPfpVlUN.mjs.map +0 -1
- package/dist/init-NaL2N3Go.cjs.map +0 -1
- package/dist/push-54rmb0T0.mjs.map +0 -1
- package/dist/push-9fPpd4U8.cjs.map +0 -1
- package/dist/run-codegen-DjnV60bE.mjs.map +0 -1
- package/dist/run-codegen-mclysZuT.cjs.map +0 -1
|
@@ -62,3 +62,149 @@ await cmsClient.tables.blog.search({ query: "キーワード1 キーワード2"
|
|
|
62
62
|
|
|
63
63
|
- **Consumer SDK**: 公開データのみ検索可能
|
|
64
64
|
- **CMS SDK**: 下書きデータも検索可能(主にCMS上での管理用途)
|
|
65
|
+
|
|
66
|
+
## 検索モード(セマンティック検索)
|
|
67
|
+
|
|
68
|
+
`search()` の `mode` パラメータで検索方式を選択できます。
|
|
69
|
+
|
|
70
|
+
| mode | 説明 |
|
|
71
|
+
| ----------------- | ----------------------------------------------------------------- |
|
|
72
|
+
| `keyword`(既定) | 従来の全文検索。`mode` を省略した場合もこの方式です |
|
|
73
|
+
| `semantic` | 意味検索。クエリとコンテンツの埋め込みベクトルの近さで検索します |
|
|
74
|
+
| `hybrid` | keyword と semantic の融合(RRF)。字面一致と意味の両方を拾います |
|
|
75
|
+
|
|
76
|
+
```ts copy
|
|
77
|
+
await cmsClient.tables.blog.search({ query: "経費の精算", mode: "hybrid" });
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`semantic` / `hybrid` はプロジェクトでセマンティック検索が有効な場合のみ利用できます(無効なプロジェクトではエラーになります)。有効化は `orizm.config.ts` に `semanticSearch: { enabled: true }` を宣言して `orizm schema push` で反映します(無効に戻すときは `enabled: false` を明示します。宣言を省略した定義は現状維持です)。有効化の直後はベクトルインデックスの構築が完了するまで `semantic` / `hybrid` が 403 になります(構築が終わり次第利用できます)。`semantic` / `hybrid` で検索した場合は、検索結果の各行に `_semantic`(スコア・ヒットに寄与したチャンク・レーン別順位)が付与されます(`keyword` では付きません)。
|
|
81
|
+
|
|
82
|
+
### 対象の列を指定する(`semanticSearch: true`)
|
|
83
|
+
|
|
84
|
+
`semantic` / `hybrid` で検索できるのは、`semanticSearch: true` を付けた string 列を 1 つ以上持つテーブルだけです(付いていないテーブルは `enableSearch: true` があっても `keyword` のみで、`semantic` / `hybrid` は 403 `search index not found (no column has semanticSearch: true)` になります)。`semanticSearch: true` の列を持つテーブルには `enableSearch: true` が必要です(無いと push が失敗します)。`tableModules` 内の string 列にも付けられ、そのモジュールを使うテーブルの対象になります。
|
|
85
|
+
|
|
86
|
+
```ts copy filename="orizm.config.ts" showLineNumbers {6,10}
|
|
87
|
+
export default defineConfig({
|
|
88
|
+
semanticSearch: { enabled: true },
|
|
89
|
+
tables: {
|
|
90
|
+
blog: {
|
|
91
|
+
columns: {
|
|
92
|
+
title: { type: "string", required: true, semanticSearch: true },
|
|
93
|
+
body: { type: "string", required: true, semanticSearch: true },
|
|
94
|
+
slug: { type: "string", required: true }, // keyword 検索の対象にはなるが、埋め込みには載らない
|
|
95
|
+
},
|
|
96
|
+
enableSearch: true,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
埋め込み(ベクトル)の元になる本文は、`semanticSearch: true` の列の値を定義順につないだテキストです。検索結果の `_semantic.chunks` に返るチャンクもこの本文を分割したもので、`keyword` の検索対象(全テキスト列)とは一致しません。埋め込みの費用はこの本文の量で決まるので、意味検索に要らない列(slug・型番の一覧・機械的なコード)には付けないでください。列の付け外しは、そのテーブルのベクトルインデックスの再構築を伴います(完了までは 403 になります。最後の `semanticSearch: true` を外すとベクトルインデックスは削除されます)。
|
|
103
|
+
|
|
104
|
+
> [!WARNING]
|
|
105
|
+
> 列を絞れば精度が上がる、というものではありません。意味検索は文脈の量で効きます。`title`
|
|
106
|
+
> だけを対象にすると十数文字の埋め込みになり、言い換えや課題表現との距離が出にくくなります。また列をまたぐ手掛かり(製品名は
|
|
107
|
+
> `title`、用途は
|
|
108
|
+
> `body`)も失われます。人が読んで内容を表す列(タイトル・本文・説明)はまとめて付け、識別子や機械的な値だけを外すのが目安です。
|
|
109
|
+
|
|
110
|
+
> [!WARNING]
|
|
111
|
+
> セマンティック検索を利用できるかどうかは、プロジェクトの設定に加えてシステム側の設定でも決まります。システム側で有効になっていない環境では、`semanticSearch: { enabled: true }` の push は成功しますが `semantic` / `hybrid` の検索は利用できません(ベクトルインデックスが作られていない場合は 403 になり、過去に作られたインデックスが残っている場合は `keyword` の結果に劣化します)。利用中の環境で使えるかは管理者に確認してください。
|
|
112
|
+
|
|
113
|
+
CMS SDK の `semantic` / `hybrid` では、プロジェクトの [検索辞書](./dictionary.md) に説明を付けた有効なエントリがあれば、検索結果に辞書のヒット(`_dictionary`)も付与されます(説明付きのエントリが無いプロジェクトではキー自体が付きません。また [権限](./schema/authority.md) でどのテーブルも読めないキーの検索にも付きません)。検索辞書に同義語を登録しておくと、`hybrid` の検索クエリに表記の言い換えが足され、社内の俗称や型番の表記ゆれでも目的のコンテンツに当たるようになります。
|
|
114
|
+
|
|
115
|
+
フォーム投稿(submissions)の検索は `keyword` のみ対応です(`semantic` / `hybrid` を指定すると 403 になります)。
|
|
116
|
+
|
|
117
|
+
ページングの制約は mode ごとに異なります(超過はいずれも 400 になります)。
|
|
118
|
+
|
|
119
|
+
| mode | `offset + limit` | `limit: 0`(件数だけ取る) |
|
|
120
|
+
| ---------- | ---------------- | -------------------------------- |
|
|
121
|
+
| `keyword` | 10000 まで | 使えます(正確な件数が返ります) |
|
|
122
|
+
| `semantic` | 100 まで | 使えません |
|
|
123
|
+
| `hybrid` | 100 まで | 使えません |
|
|
124
|
+
|
|
125
|
+
`semantic` / `hybrid` の上限が小さいのは、`semantic` では近傍探索(ANN)の候補プールが深い窓を安定して裏付けられない(加えて窓の各行にチャンク本文を付けて返す)ため、`hybrid` では融合(RRF)が固定ランク窓の中でだけページ間の順序を安定して定義できるためです。深いページングや件数だけの取得が必要な場合は `keyword` を使ってください。`limit` / `offset` は mode を問わず整数かつ 0 以上のみ受け付けます。
|
|
126
|
+
|
|
127
|
+
`query` は `semantic` / `hybrid` では 512 文字までです(超過は 400 になります)。`keyword` には文字数の上限がありません。空文字や空白だけの `query` は mode を問わず検索せず、0 件(`contents: []`, `totalCount: 0`)を返します。
|
|
128
|
+
|
|
129
|
+
> [!WARNING]
|
|
130
|
+
> `semantic` / `hybrid` の `totalCount`
|
|
131
|
+
> は正確な件数ではなく、**ページ数の計算には使えません**。 `semantic` の
|
|
132
|
+
> `totalCount`
|
|
133
|
+
> は近傍探索(ANN)の候補プールに入ったコンテンツ数です。候補プールの大きさは固定なのでページを進めても値は変わりませんが、`offset
|
|
134
|
+
> + limit`
|
|
135
|
+
> の上限(100)を超える値になることがあり、該当するコンテンツが無いクエリでも 0
|
|
136
|
+
> にはなりません(ANN は常に最も近いものを返すため)。`hybrid` の `totalCount`
|
|
137
|
+
> は下界(2 レーンの大きい方。返した行数を下回ることはありません)です。`limit:
|
|
138
|
+
> 0` が `keyword` 専用なのも同じ理由です。正確な件数やページ数が必要な場合は
|
|
139
|
+
> `keyword` を使ってください。
|
|
140
|
+
|
|
141
|
+
> [!NOTE]
|
|
142
|
+
> 埋め込み基盤の一時的な障害時は、検索を失敗させる代わりに `keyword`
|
|
143
|
+
> の結果に劣化して応答します(このとき `_semantic` と `_dictionary`
|
|
144
|
+
> は付かず、`hybrid` で効いていた検索辞書によるクエリの言い換えも外れます)。
|
|
145
|
+
|
|
146
|
+
### 検索結果の `_semantic`
|
|
147
|
+
|
|
148
|
+
`semantic` / `hybrid` で検索すると、`contents` の各行に `_semantic` が付きます。コンテンツは埋め込みを作る前に一定の長さの断片(チャンク)に分割され、検索はチャンク単位で近さを測ります。`chunks` にはその行でクエリに近かったチャンクが入るので、長い本文のどこが当たったのかを画面で示すのに使えます。
|
|
149
|
+
|
|
150
|
+
| フィールド | 説明 |
|
|
151
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
152
|
+
| `score` | 行のスコア。`semantic` ではベクトル検索(kNN)の近さ、`hybrid` では 2 つのレーンを融合した RRF の値です。尺度が違うため mode をまたいで比較できません |
|
|
153
|
+
| `chunks` | ヒットに寄与したチャンクの配列。各要素は `text`(チャンク本文)と `score`(チャンク単位の近さ)を持ちます |
|
|
154
|
+
| `keywordRank` | キーワード検索のレーンでの順位。`hybrid` でそのレーンにヒットした行にだけ付きます。ヒットしなかった行と `semantic` ではキー自体が省略されます |
|
|
155
|
+
| `vectorRank` | ベクトル検索のレーンでの順位。`semantic` では常に付き、`hybrid` でそのレーンにヒットしなかった行ではキー自体が省略されます |
|
|
156
|
+
|
|
157
|
+
```ts copy
|
|
158
|
+
const result = await cmsClient.tables.blog.search({
|
|
159
|
+
query: "寒さで壊れる",
|
|
160
|
+
mode: "hybrid",
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
for (const row of result.contents) {
|
|
164
|
+
console.log(row.title, row._semantic?.score, row._semantic?.chunks[0]?.text);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`_semantic` は上で説明した劣化時には付きません。常に省略され得るものとして扱ってください。`hybrid` で `keywordRank` と `vectorRank` の両方が付いている行は、字面と意味の両方で当たった行です(`null` は入らないので、有無は `undefined` との比較で判定してください)。
|
|
169
|
+
|
|
170
|
+
## 検索への反映タイミング
|
|
171
|
+
|
|
172
|
+
コンテンツの作成・更新・削除は、保存が完了したあと非同期で検索インデックスに反映されます。所要時間の目安は以下のとおりです(Orizm のステージング環境での実測値。混雑時や埋め込み基盤の遅延時はこれより長くなります)。
|
|
173
|
+
|
|
174
|
+
| 操作 | 反映先 | 目安 |
|
|
175
|
+
| -------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------ |
|
|
176
|
+
| コンテンツの作成・更新 | `keyword` | 数秒(実測 1.5〜4 秒) |
|
|
177
|
+
| コンテンツの作成・更新(埋め込みの生成を含む) | `semantic` / `hybrid` | 数秒(実測 2 秒程度。本文を書き換えた再生成も同程度) |
|
|
178
|
+
| 公開 | Consumer SDK の検索(全 mode) | 数秒(実測 2 秒程度。公開したコンテンツはインデックスの同期を待ってから現れます) |
|
|
179
|
+
| 非公開・削除 | Consumer SDK の検索(全 mode) | 1 秒未満(結果の行は DB から引き直すため、公開ビューから消えた行は即座に消えます) |
|
|
180
|
+
| セマンティック検索の有効化・テーブルへの `semanticSearch: true` の新規付与 | `semantic` / `hybrid` | コンテンツ量に比例(既存コンテンツ全件の埋め込みを作り直します。実測 76 件で約 1 分) |
|
|
181
|
+
| `semanticSearch: true` の列(モジュール内を含む)の追加・削除・順序変更 | `semantic` / `hybrid` | コンテンツ量に比例(索引を作り直します。埋め込みを作り直すのは本文が変わったコンテンツだけです) |
|
|
182
|
+
|
|
183
|
+
CMS SDK の検索は下書きも対象にするため、コンテンツを非公開にしても CMS SDK の検索結果からは消えません。公開状態で結果を絞りたい場合は Consumer SDK の検索を使ってください。
|
|
184
|
+
|
|
185
|
+
有効化の直後や、テーブルの列に `semanticSearch: true` を初めて付けた直後は、既存コンテンツ全件の埋め込みを作り直す処理(再構築)がバックグラウンドで走ります。完了するまで `semantic` / `hybrid` は 403 になり、完了すると利用できます。再構築の進み具合は、開発者コンソールのテーブル画面にある検索インデックス(`published_vector`。`enableDrafts` のテーブルでは `draft_vector` も)のドキュメント数で確認できます。`enableDrafts` を付けたり外したりしたときも `draft_vector` の作成・削除が走り、付けた直後は `draft_vector` が出来上がるまで CMS SDK の `semantic` / `hybrid` は 403 になります。付けたときは、そのテーブルの既存コンテンツ全件の埋め込みを作り直します(埋め込みモデルの推論費用が掛かります)。
|
|
186
|
+
|
|
187
|
+
`semanticSearch: true` の列(モジュール内の列を含む)を追加・削除したり順序を変えたりしたときも、フラグの付いた列が 1 つ以上残っていれば、スキーマを push すると再構築が走ります。こちらは既存の索引で検索を受け続けながら裏で作り直し、完了した時点で切り替わります(403 にはなりません)。切り替わるまでは、外した列の本文が `_semantic.chunks` に残ることがあります。フラグの無い列(`json` や他の型の列を含む)は本文に含まれないため、追加・削除しても再構築は走りません。最後のフラグを外すとベクトルインデックスは削除され、`semantic` / `hybrid` は 403 になります。
|
|
188
|
+
|
|
189
|
+
[検索辞書](./dictionary.md) の反映タイミングは辞書の記事を参照してください(同義語による言い換えは即時、用語解説の検索対象化は非同期です)。
|
|
190
|
+
|
|
191
|
+
## セルフホスト環境での前提
|
|
192
|
+
|
|
193
|
+
Orizm をセルフホストしている場合、セマンティック検索を使うにはシステム側の準備が必要です。マネージドの Orizm(app.orizm.com)では不要で、プロジェクトの有効化だけで利用できます。
|
|
194
|
+
|
|
195
|
+
- **OpenSearch**: 2 系の公式ディストリビューションが必要です。ベクトル検索(k-NN)、埋め込みの推論(ml-commons)、ベクトル索引への取り込み(neural-search)の 3 つのプラグインを使いますが、いずれも公式ディストリビューションに同梱されています。日本語の全文検索には kuromoji と ICU の解析プラグインも必要です(Orizm 付属の docker compose 用イメージはこれらを追加したものです)
|
|
196
|
+
- **推論経路の設定**: サーバーとワーカーの環境変数 `ORIZM_EMBEDDING_SEARCH` で埋め込みの推論経路を選びます
|
|
197
|
+
|
|
198
|
+
| 値 | 動作 |
|
|
199
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
200
|
+
| `off`(既定) | セマンティック検索を無効にします。ベクトルインデックスは作られず、`semantic` / `hybrid` は利用できません |
|
|
201
|
+
| `local` | OpenSearch クラスタ内のローカルモデル(多言語 MiniLM・384 次元)で推論します。開発や小規模な検証向けで、外部サービスは不要です |
|
|
202
|
+
| `bedrock` | Amazon Bedrock の埋め込みモデル(既定 `amazon.titan-embed-text-v2:0`・1024 次元)に推論を外出しします。本番向けの方式です |
|
|
203
|
+
|
|
204
|
+
- **`bedrock` のときの追加設定**: `AWS_REGION`、`BEDROCK_EMBEDDING_MODEL`、`BEDROCK_EMBEDDING_DIMENSION` でモデルと次元を指定します。マネージドの OpenSearch(Amazon OpenSearch Service)では、Bedrock を呼び出すときに OpenSearch 側が引き受ける IAM ロールを `BEDROCK_CONNECTOR_ROLE_ARN` に指定します。未設定の場合は `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` が接続情報として使われます
|
|
205
|
+
- **埋め込み基盤の準備**: 埋め込みモデルの登録・配備と取り込みパイプラインの作成は、マイグレーションタスクが行います(冪等で、既にあれば再利用します)。サーバーとワーカーを起動する前にマイグレーションを実行してください。推論経路やモデルの設定を変えたときも同様です。準備ができていない状態でサーバーを起動すると、起動ログにモデルが見つからない旨の error が出て、`semantic` / `hybrid` は 403 になります
|
|
206
|
+
- **`off` は非破壊の停止スイッチ**: 一時的に `off` にしても既存のベクトルインデックスと埋め込み済みデータは残り、埋め込みの生成(書き込み時の同期と再構築)だけが止まります。この間の `semantic` / `hybrid` は `keyword` の結果に劣化して応答します。`local` / `bedrock` に戻してワーカーを起動すると、止まっていた間に古くなったインデックスは起動時の突き合わせで自動的に再構築されます
|
|
207
|
+
|
|
208
|
+
> [!WARNING]
|
|
209
|
+
> `local` と `bedrock`
|
|
210
|
+
> では埋め込みモデルも次元も違うため、スコアの値や順位は環境間で一致しません。品質の確認は本番と同じ推論経路で行ってください。推論経路やモデルを切り替えると、既存のベクトルインデックスはすべて作り直されます。
|
|
@@ -58,14 +58,15 @@ export default defineConfig({
|
|
|
58
58
|
|
|
59
59
|
以下のオプションが設定できます。
|
|
60
60
|
|
|
61
|
-
| オプション
|
|
62
|
-
|
|
|
63
|
-
| required
|
|
64
|
-
| readonly
|
|
65
|
-
| pattern
|
|
66
|
-
| minLength
|
|
67
|
-
| maxLength
|
|
68
|
-
| default
|
|
61
|
+
| オプション | 説明 | 型 | デフォルト |
|
|
62
|
+
| -------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------- | ---------- |
|
|
63
|
+
| required | 必須項目であることを示します。 | boolean | false |
|
|
64
|
+
| readonly | 読み取り専用であることを示します。 | boolean | false |
|
|
65
|
+
| pattern | 正規表現を用いて文字列のパターンを指定します。 | string | - |
|
|
66
|
+
| minLength | 文字列の最小長を指定します。 | number | - |
|
|
67
|
+
| maxLength | 文字列の最大長を指定します。 | number | - |
|
|
68
|
+
| default | デフォルト値を指定します。 | string | - |
|
|
69
|
+
| semanticSearch | セマンティック検索の埋め込み対象にします。string 列のみ。テーブルに `enableSearch: true` が必要です(無いと push が失敗します)。 | boolean | false |
|
|
69
70
|
|
|
70
71
|
```ts copy
|
|
71
72
|
{
|
package/dist/docs/index.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Orizm docs (v3.
|
|
1
|
+
# Orizm docs (v3.3.0-beta.1)
|
|
2
2
|
|
|
3
3
|
Bundled Orizm docs, version-matched to the installed `@orizm/cli`.
|
|
4
4
|
Read the relevant page before generating Orizm code. Files are relative to this directory.
|
|
@@ -54,11 +54,13 @@ Starter Kit v2: edit only `apps/cms`, `apps/consumer`, `packages/design-editor`.
|
|
|
54
54
|
- [インストール](./features/design-editor/install.md)
|
|
55
55
|
- [プロパティエディター](./features/design-editor/prop-editor.md)
|
|
56
56
|
- [スキーマ定義ガイド](./features/design-editor/schema.md)
|
|
57
|
+
- [検索辞書](./features/dictionary.md)
|
|
57
58
|
- [下書き管理](./features/draft.md)
|
|
58
59
|
- [フォーム管理の概要](./features/form/about.md)
|
|
59
60
|
- [フォームエディター](./features/form/editor.md)
|
|
60
61
|
- [受信データの管理](./features/form/submission.md)
|
|
61
62
|
- [全文検索](./features/full-text-search.md)
|
|
63
|
+
- [セマンティック検索をローカルで動かす](./features/full-text-search/local-development.md)
|
|
62
64
|
- [履歴管理](./features/history.md)
|
|
63
65
|
- [スキーマとは](./features/schema/about.md)
|
|
64
66
|
- [権限](./features/schema/authority.md)
|
package/dist/docs/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as defineCommand } from "./cli/main.mjs";
|
|
2
2
|
import { i as globalArgs, n as configFileArg, t as DEFAULT_CONFIG_FILE } from "./shared-CZZimGxc.mjs";
|
|
3
|
-
import { n as configLoadFailure, t as loadConfig } from "./config-loader-
|
|
3
|
+
import { n as configLoadFailure, t as loadConfig } from "./config-loader-CtbZOGjc.mjs";
|
|
4
4
|
import { Result } from "@praha/byethrow";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
@@ -120,4 +120,4 @@ var erd_default = defineCommand({
|
|
|
120
120
|
|
|
121
121
|
//#endregion
|
|
122
122
|
export { erd_default as default };
|
|
123
|
-
//# sourceMappingURL=erd-
|
|
123
|
+
//# sourceMappingURL=erd-BihhEfZ_.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erd-
|
|
1
|
+
{"version":3,"file":"erd-BihhEfZ_.mjs","names":[],"sources":["../src/cli/erd.ts","../src/cli/commands/schema/erd.ts"],"sourcesContent":["import { CommonOrizmConfig } from \"./types.js\";\n\ntype TableInput = {\n name: string;\n columns: ColumnInput[];\n};\n\ntype ColumnInput = {\n name: string;\n type: string;\n isForeignKey: boolean;\n};\n\ntype RelationInput = {\n from: string;\n to: string;\n type: string;\n comment: string;\n};\n\ntype TemplateInput = {\n tables: TableInput[];\n relations: RelationInput[];\n};\n\nconst RELATION = {\n ONE_TO_MANY: \"||--o{\",\n ONE_TO_ONE: \"||--||\",\n} as const;\n\nfunction convertToInput(config: CommonOrizmConfig): TemplateInput {\n const tables: TableInput[] = [];\n const relations: RelationInput[] = [];\n\n for (const table of config.tables) {\n const modules: TableInput[] = [];\n const erdTable: TableInput = { name: table.name, columns: [] };\n\n for (const column of table.columns) {\n erdTable.columns.push({\n name: column.name,\n type: column.type,\n isForeignKey: column.type === \"reference\",\n });\n\n if (column.type === \"reference\") {\n relations.push({\n from: column.tableName,\n to: table.name,\n type: RELATION.ONE_TO_MANY,\n comment: \"reference\",\n });\n }\n\n if (column.type === \"module\" || column.type === \"module-array\") {\n const module = config.tableModules.find(\n (m) => m.name === column.moduleName,\n );\n if (!module) {\n continue;\n }\n\n const moduleTableName = `${table.name}_${column.name}_${column.moduleName}`;\n modules.push({\n name: moduleTableName,\n columns: module.columns.map((c) => ({\n name: c.name,\n type: c.type,\n isForeignKey: c.type === \"reference\",\n })),\n });\n\n relations.push({\n from: table.name,\n to: moduleTableName,\n type:\n column.type === \"module\"\n ? RELATION.ONE_TO_ONE\n : RELATION.ONE_TO_MANY,\n comment: column.type === \"module\" ? \"module\" : \"module-array\",\n });\n\n for (const moduleColumn of module.columns) {\n if (moduleColumn.type === \"reference\") {\n relations.push({\n from: moduleTableName,\n to: moduleColumn.tableName,\n type: RELATION.ONE_TO_MANY,\n comment: \"reference\",\n });\n }\n }\n }\n }\n\n tables.push(erdTable);\n tables.push(...modules);\n }\n\n return { tables, relations };\n}\n\nfunction renderMermaid(input: TemplateInput): string {\n const tables = input.tables\n .map((table) => {\n const columns = [\n \" id string PK\",\n ...table.columns.map(\n (col) =>\n ` ${col.name} ${col.type}${col.isForeignKey ? \" FK\" : \"\"}`,\n ),\n ].join(\"\\n\");\n return ` ${table.name} {\\n${columns}\\n }`;\n })\n .join(\"\\n\");\n\n const relations = input.relations\n .map((rel) => ` ${rel.from} ${rel.type} ${rel.to} : ${rel.comment}`)\n .join(\"\\n\");\n\n return `generated by @orizm/cli\n\n\\`\\`\\`mermaid\nerDiagram\n${tables}\n\n${relations}\n\\`\\`\\``;\n}\n\nexport function generateErd(config: CommonOrizmConfig): string {\n return renderMermaid(convertToInput(config));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Result } from \"@praha/byethrow\";\nimport { defineCommand } from \"../define-command.js\";\nimport { globalArgs, configFileArg, DEFAULT_CONFIG_FILE } from \"../shared.js\";\nimport { configLoadFailure } from \"../config-errors.js\";\nimport { loadConfig } from \"../../config-loader.js\";\nimport { generateErd } from \"../../erd.js\";\n\nexport default defineCommand({\n meta: {\n name: \"erd\",\n description: \"Generate an ERD in Mermaid format from orizm.config.ts\",\n },\n args: {\n ...globalArgs,\n \"config-file\": configFileArg,\n output: {\n type: \"string\",\n alias: \"o\",\n description: \"Output file path (defaults to stdout)\",\n },\n },\n run: async ({ args }) => {\n const loaded = await loadConfig(args[\"config-file\"] ?? DEFAULT_CONFIG_FILE);\n if (Result.isFailure(loaded)) return configLoadFailure(loaded.error);\n\n const mermaid = generateErd(loaded.value);\n\n if (args.output != null && args.output !== \"\") {\n const output = args.output;\n await mkdir(path.dirname(output), { recursive: true });\n await writeFile(output, mermaid + \"\\n\", \"utf-8\");\n return Result.succeed({\n json: { output },\n text: () => `ERD written to ${output}`,\n });\n }\n\n return Result.succeed({ json: { erd: mermaid }, text: () => mermaid });\n },\n});\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_cli_main = require('./cli/main.cjs');
|
|
2
2
|
const require_shared = require('./shared-DHRPzzKl.cjs');
|
|
3
|
-
const require_config_loader = require('./config-loader-
|
|
3
|
+
const require_config_loader = require('./config-loader-CZfANHBf.cjs');
|
|
4
4
|
let _praha_byethrow = require("@praha/byethrow");
|
|
5
5
|
let node_path = require("node:path");
|
|
6
6
|
node_path = require_cli_main.__toESM(node_path, 1);
|
|
@@ -121,4 +121,4 @@ var erd_default = require_cli_main.defineCommand({
|
|
|
121
121
|
|
|
122
122
|
//#endregion
|
|
123
123
|
exports.default = erd_default;
|
|
124
|
-
//# sourceMappingURL=erd-
|
|
124
|
+
//# sourceMappingURL=erd-DmnB1v2c.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erd-
|
|
1
|
+
{"version":3,"file":"erd-DmnB1v2c.cjs","names":["defineCommand","globalArgs","configFileArg","loadConfig","Result","configLoadFailure","path"],"sources":["../src/cli/erd.ts","../src/cli/commands/schema/erd.ts"],"sourcesContent":["import { CommonOrizmConfig } from \"./types.js\";\n\ntype TableInput = {\n name: string;\n columns: ColumnInput[];\n};\n\ntype ColumnInput = {\n name: string;\n type: string;\n isForeignKey: boolean;\n};\n\ntype RelationInput = {\n from: string;\n to: string;\n type: string;\n comment: string;\n};\n\ntype TemplateInput = {\n tables: TableInput[];\n relations: RelationInput[];\n};\n\nconst RELATION = {\n ONE_TO_MANY: \"||--o{\",\n ONE_TO_ONE: \"||--||\",\n} as const;\n\nfunction convertToInput(config: CommonOrizmConfig): TemplateInput {\n const tables: TableInput[] = [];\n const relations: RelationInput[] = [];\n\n for (const table of config.tables) {\n const modules: TableInput[] = [];\n const erdTable: TableInput = { name: table.name, columns: [] };\n\n for (const column of table.columns) {\n erdTable.columns.push({\n name: column.name,\n type: column.type,\n isForeignKey: column.type === \"reference\",\n });\n\n if (column.type === \"reference\") {\n relations.push({\n from: column.tableName,\n to: table.name,\n type: RELATION.ONE_TO_MANY,\n comment: \"reference\",\n });\n }\n\n if (column.type === \"module\" || column.type === \"module-array\") {\n const module = config.tableModules.find(\n (m) => m.name === column.moduleName,\n );\n if (!module) {\n continue;\n }\n\n const moduleTableName = `${table.name}_${column.name}_${column.moduleName}`;\n modules.push({\n name: moduleTableName,\n columns: module.columns.map((c) => ({\n name: c.name,\n type: c.type,\n isForeignKey: c.type === \"reference\",\n })),\n });\n\n relations.push({\n from: table.name,\n to: moduleTableName,\n type:\n column.type === \"module\"\n ? RELATION.ONE_TO_ONE\n : RELATION.ONE_TO_MANY,\n comment: column.type === \"module\" ? \"module\" : \"module-array\",\n });\n\n for (const moduleColumn of module.columns) {\n if (moduleColumn.type === \"reference\") {\n relations.push({\n from: moduleTableName,\n to: moduleColumn.tableName,\n type: RELATION.ONE_TO_MANY,\n comment: \"reference\",\n });\n }\n }\n }\n }\n\n tables.push(erdTable);\n tables.push(...modules);\n }\n\n return { tables, relations };\n}\n\nfunction renderMermaid(input: TemplateInput): string {\n const tables = input.tables\n .map((table) => {\n const columns = [\n \" id string PK\",\n ...table.columns.map(\n (col) =>\n ` ${col.name} ${col.type}${col.isForeignKey ? \" FK\" : \"\"}`,\n ),\n ].join(\"\\n\");\n return ` ${table.name} {\\n${columns}\\n }`;\n })\n .join(\"\\n\");\n\n const relations = input.relations\n .map((rel) => ` ${rel.from} ${rel.type} ${rel.to} : ${rel.comment}`)\n .join(\"\\n\");\n\n return `generated by @orizm/cli\n\n\\`\\`\\`mermaid\nerDiagram\n${tables}\n\n${relations}\n\\`\\`\\``;\n}\n\nexport function generateErd(config: CommonOrizmConfig): string {\n return renderMermaid(convertToInput(config));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Result } from \"@praha/byethrow\";\nimport { defineCommand } from \"../define-command.js\";\nimport { globalArgs, configFileArg, DEFAULT_CONFIG_FILE } from \"../shared.js\";\nimport { configLoadFailure } from \"../config-errors.js\";\nimport { loadConfig } from \"../../config-loader.js\";\nimport { generateErd } from \"../../erd.js\";\n\nexport default defineCommand({\n meta: {\n name: \"erd\",\n description: \"Generate an ERD in Mermaid format from orizm.config.ts\",\n },\n args: {\n ...globalArgs,\n \"config-file\": configFileArg,\n output: {\n type: \"string\",\n alias: \"o\",\n description: \"Output file path (defaults to stdout)\",\n },\n },\n run: async ({ args }) => {\n const loaded = await loadConfig(args[\"config-file\"] ?? DEFAULT_CONFIG_FILE);\n if (Result.isFailure(loaded)) return configLoadFailure(loaded.error);\n\n const mermaid = generateErd(loaded.value);\n\n if (args.output != null && args.output !== \"\") {\n const output = args.output;\n await mkdir(path.dirname(output), { recursive: true });\n await writeFile(output, mermaid + \"\\n\", \"utf-8\");\n return Result.succeed({\n json: { output },\n text: () => `ERD written to ${output}`,\n });\n }\n\n return Result.succeed({ json: { erd: mermaid }, text: () => mermaid });\n },\n});\n"],"mappings":"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"}
|
|
@@ -181,22 +181,57 @@ function renderClaudeImportInner() {
|
|
|
181
181
|
const START_TOKEN = "<!-- orizm-agent:start";
|
|
182
182
|
const MARKER_START = "<!-- orizm-agent:start (managed by `orizm agent` — do not edit manually) -->";
|
|
183
183
|
const MARKER_END = "<!-- orizm-agent:end -->";
|
|
184
|
+
var BrokenManagedBlockError = class extends Error {
|
|
185
|
+
reason;
|
|
186
|
+
constructor(reason) {
|
|
187
|
+
super(`managed block is broken (${reason})`);
|
|
188
|
+
this.name = "BrokenManagedBlockError";
|
|
189
|
+
this.reason = reason;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
function indexOfAll(text, token) {
|
|
193
|
+
const found = [];
|
|
194
|
+
let from = 0;
|
|
195
|
+
while (true) {
|
|
196
|
+
const idx = text.indexOf(token, from);
|
|
197
|
+
if (idx === -1) return found;
|
|
198
|
+
found.push(idx);
|
|
199
|
+
from = idx + token.length;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function inspectManagedBlock(text) {
|
|
203
|
+
const starts = indexOfAll(text, START_TOKEN);
|
|
204
|
+
if (starts.length === 0) return { kind: "absent" };
|
|
205
|
+
if (starts.length > 1) return {
|
|
206
|
+
kind: "broken",
|
|
207
|
+
reason: `found ${starts.length} start markers, expected at most 1`
|
|
208
|
+
};
|
|
209
|
+
const start = starts[0];
|
|
210
|
+
const endIdx = text.indexOf(MARKER_END, start);
|
|
211
|
+
if (endIdx === -1) return {
|
|
212
|
+
kind: "broken",
|
|
213
|
+
reason: "found a start marker without a matching end marker after it"
|
|
214
|
+
};
|
|
215
|
+
return {
|
|
216
|
+
kind: "present",
|
|
217
|
+
start,
|
|
218
|
+
end: endIdx + 24
|
|
219
|
+
};
|
|
220
|
+
}
|
|
184
221
|
function wrapBlock(inner) {
|
|
185
222
|
return `${MARKER_START}\n${inner.trim()}\n${MARKER_END}`;
|
|
186
223
|
}
|
|
187
224
|
function extractBlock(text) {
|
|
188
|
-
const
|
|
189
|
-
if (
|
|
190
|
-
|
|
191
|
-
if (endIdx === -1) return void 0;
|
|
192
|
-
return text.slice(startIdx, endIdx + 24);
|
|
225
|
+
const state = inspectManagedBlock(text);
|
|
226
|
+
if (state.kind !== "present") return void 0;
|
|
227
|
+
return text.slice(state.start, state.end);
|
|
193
228
|
}
|
|
194
229
|
function upsertBlock(existing, block) {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
const before = existing.slice(0,
|
|
199
|
-
const after = existing.slice(
|
|
230
|
+
const state = inspectManagedBlock(existing);
|
|
231
|
+
if (state.kind === "broken") throw new BrokenManagedBlockError(state.reason);
|
|
232
|
+
if (state.kind === "present") {
|
|
233
|
+
const before = existing.slice(0, state.start);
|
|
234
|
+
const after = existing.slice(state.end);
|
|
200
235
|
const content = before + block + after;
|
|
201
236
|
return {
|
|
202
237
|
content,
|
|
@@ -232,12 +267,23 @@ async function applyWrite(filePath, content) {
|
|
|
232
267
|
|
|
233
268
|
//#endregion
|
|
234
269
|
//#region src/cli/commands/agent/init.ts
|
|
270
|
+
function describeExisting(existing) {
|
|
271
|
+
const state = inspectManagedBlock(existing);
|
|
272
|
+
switch (state.kind) {
|
|
273
|
+
case "present": return "exists (managed block present — will update)";
|
|
274
|
+
case "absent": return "exists (no managed block — will append)";
|
|
275
|
+
case "broken": return `exists (broken managed block: ${state.reason} — cannot update)`;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function renderBrokenManagedBlock(fileName, error) {
|
|
279
|
+
return `${fileName}: ${error.message}. Nothing was written. Repair the file by hand — keep exactly one \`<!-- orizm-agent:start ... -->\` marker followed by one \`<!-- orizm-agent:end -->\` marker, or remove both — then re-run \`orizm agent init\`.`;
|
|
280
|
+
}
|
|
235
281
|
async function showDetectedContext(cwd, version, targets) {
|
|
236
282
|
const lines = [`Detected bundled Orizm docs v${version} (shipped with @orizm/cli).`, `Project root: ${cwd}`];
|
|
237
283
|
for (const target of targets) {
|
|
238
284
|
const fileName = target.fileName;
|
|
239
285
|
const existing = await readTextFile(target.path);
|
|
240
|
-
const status = existing === "" ? "not found (will be created)" :
|
|
286
|
+
const status = existing === "" ? "not found (will be created)" : describeExisting(existing);
|
|
241
287
|
lines.push(`- ${fileName}: ${status}`);
|
|
242
288
|
}
|
|
243
289
|
notice(lines.join("\n"));
|
|
@@ -318,7 +364,14 @@ var init_default = defineCommand({
|
|
|
318
364
|
} else inner = renderClaudeImportInner();
|
|
319
365
|
const existing = await readTextFile(target.path);
|
|
320
366
|
const newBlock = wrapBlock(inner);
|
|
321
|
-
|
|
367
|
+
let upserted;
|
|
368
|
+
try {
|
|
369
|
+
upserted = upsertBlock(existing, newBlock);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (error instanceof BrokenManagedBlockError) return Result.fail({ message: renderBrokenManagedBlock(target.fileName, error) });
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
const { content, action } = upserted;
|
|
322
375
|
plans.push({
|
|
323
376
|
target,
|
|
324
377
|
content,
|
|
@@ -369,4 +422,4 @@ var init_default = defineCommand({
|
|
|
369
422
|
|
|
370
423
|
//#endregion
|
|
371
424
|
export { init_default as default };
|
|
372
|
-
//# sourceMappingURL=init-
|
|
425
|
+
//# sourceMappingURL=init-BpKpTQ0z.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-BpKpTQ0z.mjs","names":["cliVersion"],"sources":["../src/cli/agent/resolve-docs.ts","../src/cli/agent/resolve-target.ts","../src/cli/agent/execution-mode.ts","../src/cli/agent/preview.ts","../src/cli/agent/template.ts","../src/cli/agent/write-reference.ts","../src/cli/commands/agent/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as v from \"valibot\";\nimport { Result } from \"@praha/byethrow\";\nimport { version as cliVersion } from \"../version.js\";\n\n// きれいに辿れる場合に優先する公開パス(トップレベル/ホイスト済みインストール)。\nconst PRETTY_DOCS_SUBPATH = \"node_modules/@orizm/cli/dist/docs\";\n\nexport type BundledDocs = {\n docsDir: string;\n version: string;\n pages: number;\n};\n\nexport type ResolveDocsError = {\n type: \"docs_not_resolved\";\n reason: \"manifest_missing\" | \"manifest_invalid\";\n manifestPath: string;\n};\n\nconst ManifestSchema = v.object({\n version: v.pipe(v.string(), v.nonEmpty()),\n generatedAt: v.string(),\n pages: v.optional(v.number(), 0),\n});\n\nfunction findPackageRoot(start: string): string | undefined {\n let dir = start;\n for (;;) {\n if (existsSync(path.join(dir, \"package.json\"))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\n// 実行中の CLI ファイル位置から自パッケージルートをたどるため、プロジェクト側 node_modules の\n// レイアウト(hoisting / pnpm)に依存しない。\nfunction defaultPackageRoot(): string {\n const from = path.dirname(fileURLToPath(import.meta.url));\n const root = findPackageRoot(from);\n if (root === undefined) {\n throw new Error(\n `@orizm/cli の package.json が ${from} から上に見つかりません。`,\n );\n }\n return root;\n}\n\nfunction safeJsonParse(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return undefined;\n }\n}\n\n// 同梱 docs の存在を manifest.json で確認し、参照文言に載せる version を得る。\nexport async function resolveDocs(\n packageRoot: string = defaultPackageRoot(),\n): Promise<Result.Result<BundledDocs, ResolveDocsError>> {\n const docsDir = path.join(packageRoot, \"dist\", \"docs\");\n const manifestPath = path.join(docsDir, \"manifest.json\");\n const raw = await readFile(manifestPath, \"utf-8\").catch(\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return undefined;\n throw error;\n },\n );\n if (raw === undefined) {\n return Result.fail({\n type: \"docs_not_resolved\",\n reason: \"manifest_missing\",\n manifestPath,\n });\n }\n\n const parsed = v.safeParse(ManifestSchema, safeJsonParse(raw));\n if (!parsed.success) {\n return Result.fail({\n type: \"docs_not_resolved\",\n reason: \"manifest_invalid\",\n manifestPath,\n });\n }\n\n return Result.succeed({\n docsDir,\n version: parsed.output.version,\n pages: parsed.output.pages,\n });\n}\n\n// 指示ファイルに書く docs 参照は常に `node_modules/@orizm/cli/dist/docs` の公開パスにする\n// (相対パスや .pnpm の実体パスは書かない。Next.js の `node_modules/next/dist/docs` と同方式)。\n// `resolves` は targetDir 直下からそのパスが実在するか。false の場合、呼び出し側で警告する\n// (@orizm/cli が targetDir を起点に解決できない配置。プロジェクトの依存に加えるか、\n// 解決できる場所で実行する必要がある)。\nexport function docsReference(targetDir: string): {\n docsDir: string;\n docsIndex: string;\n resolves: boolean;\n} {\n const base = `./${PRETTY_DOCS_SUBPATH}`;\n return {\n docsDir: `${base}/`,\n docsIndex: `${base}/index.md`,\n resolves: existsSync(path.join(targetDir, PRETTY_DOCS_SUBPATH)),\n };\n}\n\n// docs_not_resolved の表示文。原因ごとに復旧手段を添える(commands.md の仕様)。\n// 公開パスが辿れない問題は独立して起こるため、成功時の警告(init.ts)で扱う。\nexport function renderDocsNotResolved(error: ResolveDocsError): string {\n switch (error.reason) {\n case \"manifest_missing\":\n return (\n `Could not find the bundled Orizm docs (looked in ${error.manifestPath}). ` +\n `The installed @orizm/cli ${cliVersion} does not ship docs. ` +\n \"Run `pnpm update @orizm/cli`.\"\n );\n case \"manifest_invalid\":\n return (\n `Could not read the bundled Orizm docs manifest (${error.manifestPath}). ` +\n `The @orizm/cli ${cliVersion} install looks incomplete. ` +\n \"Run `pnpm install --force`.\"\n );\n }\n}\n","import path from \"node:path\";\n\nexport const CLAUDE_FILE = \"CLAUDE.md\";\nexport const AGENTS_FILE = \"AGENTS.md\";\n\n// canonical: docs 参照の本文そのものを書くファイル(AGENTS.md)。\n// claude-import: 本文を持たず AGENTS.md を `@` import するファイル(CLAUDE.md)。\nexport type TargetKind = \"canonical\" | \"claude-import\";\n\nexport type Target = {\n path: string;\n fileName: string;\n kind: TargetKind;\n};\n\n// 書き込み対象の決定。\n// - --target 明示: そのファイル 1 つに本文(canonical)を書く。\n// - 省略時: AGENTS.md を正本(canonical)に、CLAUDE.md は @AGENTS.md import として\n// 両方を管理する。どちらも無ければ両方新規作成する。\nexport function resolveTargets(cwd: string, targetFlag?: string): Target[] {\n if (targetFlag != null && targetFlag !== \"\") {\n const resolved = path.resolve(cwd, targetFlag);\n return [\n { path: resolved, fileName: path.basename(resolved), kind: \"canonical\" },\n ];\n }\n\n return [\n { path: path.join(cwd, AGENTS_FILE), fileName: AGENTS_FILE, kind: \"canonical\" },\n {\n path: path.join(cwd, CLAUDE_FILE),\n fileName: CLAUDE_FILE,\n kind: \"claude-import\",\n },\n ];\n}\n","// orizm agent init の実行モード判定(純関数)。\n// 解決順序は「フラグ > 対話 (TTY) > 既定/エラー (非 TTY)」で ADR-004 のコンテキスト解決と揃える。\n// - interactive: TTY かつ --yes / --json / --dry-run のいずれも無いとき。npx skills 風ウィザードを出す。\n// - non-interactive: それ以外(CI・スクリプト・--yes・非 TTY・--json・--dry-run)。プロンプトを出さない。\n// --json は stdout を機械可読結果専用に空けるため、--dry-run はプレビューのみで書き込まないため、\n// どちらも非対話に倒してウィザードを出さない。\nexport type ExecutionMode = \"interactive\" | \"non-interactive\";\n\nexport function resolveExecutionMode(opts: {\n isTTY: boolean;\n yes: boolean;\n json: boolean;\n dryRun: boolean;\n}): ExecutionMode {\n if (opts.isTTY && !opts.yes && !opts.json && !opts.dryRun) {\n return \"interactive\";\n }\n return \"non-interactive\";\n}\n\n// 対話ウィザードの「書き込み対象の選択」を --target フラグ相当へ写像する。\n// \"both\"(既定=両方)は --target 未指定と同じ = undefined。単一選択はそのファイル名を返す。\nexport function targetChoiceToFlag(choice: string): string | undefined {\n if (choice === \"agents\") return \"AGENTS.md\";\n if (choice === \"claude\") return \"CLAUDE.md\";\n return undefined;\n}\n","import type { UpsertAction } from \"./write-reference.js\";\n\n// 変更プレビューの 1 対象分。書き換わるのは自機能の管理ブロックだけなので、\n// 旧ブロック↔新ブロックの差分だけを見せる(ファイル全文は出さない)。\nexport type PreviewItem = {\n fileName: string;\n action: UpsertAction;\n // 既存の管理ブロック(updated のとき)。新規作成・ブロック未存在なら undefined。\n oldBlock?: string;\n // 書き込む新しい管理ブロック。\n newBlock: string;\n};\n\n// 旧・新ブロックの共通の先頭行 / 末尾行を除いた「変わった行」だけを -/+ で返す。\n// created(oldBlock=undefined)は新ブロック全行が追加 (+) になる。\nexport function diffBlockLines(\n oldBlock: string | undefined,\n newBlock: string,\n): string[] {\n const oldLines = oldBlock != null ? oldBlock.split(\"\\n\") : [];\n const newLines = newBlock.split(\"\\n\");\n\n let start = 0;\n while (\n start < oldLines.length &&\n start < newLines.length &&\n oldLines[start] === newLines[start]\n ) {\n start++;\n }\n\n let oldEnd = oldLines.length;\n let newEnd = newLines.length;\n while (\n oldEnd > start &&\n newEnd > start &&\n oldLines[oldEnd - 1] === newLines[newEnd - 1]\n ) {\n oldEnd--;\n newEnd--;\n }\n\n const removed = oldLines.slice(start, oldEnd).map((line) => `- ${line}`);\n const added = newLines.slice(start, newEnd).map((line) => `+ ${line}`);\n return [...removed, ...added];\n}\n\n// 対象ごとの操作(create / update / unchanged)とブロック差分を組み立てた表示用文字列。\n// 対話ウィザードのプレビュー、および --dry-run の出力に共通で使う。\nexport function renderPlanPreview(items: PreviewItem[]): string {\n const sections = items.map((item) => {\n if (item.action === \"unchanged\") {\n return `= ${item.fileName} (unchanged)`;\n }\n const marker = item.action === \"created\" ? \"+\" : \"~\";\n const verb = item.action === \"created\" ? \"create\" : \"update\";\n const header = `${marker} ${verb} ${item.fileName}`;\n const body = diffBlockLines(item.oldBlock, item.newBlock).map(\n (line) => ` ${line}`,\n );\n return [header, ...body].join(\"\\n\");\n });\n return sections.join(\"\\n\\n\");\n}\n","import { AGENTS_FILE } from \"./resolve-target.js\";\n\n// 指示ファイルに書き込む参照ブロックの本文(マーカーは write-reference が付ける)。\n// docs 全文は inline せず、docs へのポインタと索引だけを渡してコンテキストを圧迫しない。\n// パスは resolve-docs.docsReference が算出した「実際に解決できる相対パス」を受け取る。\n// バージョン数字は書かない(パス先の docs が常に整合するため。数字を書くと再実行漏れで嘘になる)。\n// 代わりに SDK ページのバージョン表記と package.json を突き合わせさせる(SDK は CLI と別版で進む)。\n// docs.orizm.com への誘導はこのブロックにだけ置く(同梱 docs 本文は外部 URL を持たない)。\nexport function renderReferenceInner(params: {\n docsDir: string;\n docsIndex: string;\n}): string {\n return [\n \"## Orizm\",\n \"\",\n \"You are working in an Orizm project (Starter Kit v2). Before generating or editing\",\n \"any Orizm code, read the bundled docs below. They are a snapshot of\",\n \"https://docs.orizm.com, bundled with and version-matched to the `@orizm/cli`\",\n \"installed in this project. Do NOT rely on your training data — Orizm is a private\",\n \"product and your built-in knowledge is likely stale or wrong.\",\n \"\",\n `- Docs: \\`${params.docsDir}\\``,\n `- Index (start here): \\`${params.docsIndex}\\``,\n \"\",\n \"The path above assumes `@orizm/cli` is installed as a project devDependency\",\n \"(a global-only install is not resolved by this project-relative path).\",\n \"\",\n \"`@orizm/cms-sdk` / `@orizm/consumer-sdk` are versioned separately from\",\n \"`@orizm/cli`, so check the version each SDK page documents against this\",\n \"project's `package.json`.\",\n \"\",\n \"For the latest release, upgrades, or migrations, see https://docs.orizm.com.\",\n \"\",\n \"Starter Kit v2 conventions:\",\n \"\",\n \"- Edit only `apps/cms`, `apps/consumer`, and `packages/design-editor`.\",\n \"- `packages/orizm` is generated from `orizm.config.ts` — never edit it by hand.\",\n ].join(\"\\n\");\n}\n\n// CLAUDE.md 用のブロック本文。正本は AGENTS.md に置き、CLAUDE.md は Claude Code の\n// `@` import でそれを取り込む(内容の重複を避け、AGENTS.md を単一の情報源にする)。\nexport function renderClaudeImportInner(): string {\n return [\n \"## Orizm\",\n \"\",\n `Orizm docs and conventions are maintained in ${AGENTS_FILE} (managed by \\`orizm agent\\`).`,\n \"Claude Code imports it here:\",\n \"\",\n `@${AGENTS_FILE}`,\n ].join(\"\\n\");\n}\n","import { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n// エージェント指示ファイル内で自機能が管理する領域の境界。start はプレフィックスで検出し、\n// 「do not edit」の文言をユーザーが多少書き換えても再検出できるようにする。\nconst START_TOKEN = \"<!-- orizm-agent:start\";\nexport const MARKER_START =\n \"<!-- orizm-agent:start (managed by `orizm agent` — do not edit manually) -->\";\nexport const MARKER_END = \"<!-- orizm-agent:end -->\";\n\nexport type UpsertAction = \"created\" | \"updated\" | \"unchanged\";\n\n// 既存内容の中での管理ブロックの状態。\n// - absent: 開始マーカーが無い(末尾に追記する)\n// - present: 開始マーカー 1 つと、その後ろに終了マーカーがある(置換する)\n// - broken: 開始マーカーはあるが対応する終了マーカーが無い、または開始マーカーが複数ある\n// (どちらも人手で直してもらう。追記で「開始マーカーが 2 つ」の状態を作ると、次回の実行で\n// 2 つのマーカーに挟まれたユーザー本文を丸ごと置換してしまうため、機械的には触らない)\nexport type ManagedBlockState =\n | { kind: \"absent\" }\n | { kind: \"present\"; start: number; end: number }\n | { kind: \"broken\"; reason: string };\n\n// 管理ブロックが壊れていて安全に更新できないことを表す。呼び出し側(init コマンド)が\n// 捕まえて、対象ファイル名と直し方を添えたエラーにする\nexport class BrokenManagedBlockError extends Error {\n readonly reason: string;\n\n constructor(reason: string) {\n super(`managed block is broken (${reason})`);\n this.name = \"BrokenManagedBlockError\";\n this.reason = reason;\n }\n}\n\nfunction indexOfAll(text: string, token: string): number[] {\n const found: number[] = [];\n let from = 0;\n while (true) {\n const idx = text.indexOf(token, from);\n if (idx === -1) return found;\n found.push(idx);\n from = idx + token.length;\n }\n}\n\n// 既存内容の管理ブロックの状態を判定する。extractBlock / upsertBlock と、\n// 対話モードのコンテキスト表示が同じ判定を共有する\nexport function inspectManagedBlock(text: string): ManagedBlockState {\n const starts = indexOfAll(text, START_TOKEN);\n if (starts.length === 0) return { kind: \"absent\" };\n if (starts.length > 1) {\n return {\n kind: \"broken\",\n reason: `found ${starts.length} start markers, expected at most 1`,\n };\n }\n const start = starts[0];\n const endIdx = text.indexOf(MARKER_END, start);\n if (endIdx === -1) {\n return {\n kind: \"broken\",\n reason: \"found a start marker without a matching end marker after it\",\n };\n }\n return { kind: \"present\", start, end: endIdx + MARKER_END.length };\n}\n\n// 参照本文をマーカーで囲んだ 1 ブロックにする。前後の余分な空白は落として揺れを防ぐ。\nexport function wrapBlock(inner: string): string {\n return `${MARKER_START}\\n${inner.trim()}\\n${MARKER_END}`;\n}\n\n// 既存内容から自機能の管理ブロック(マーカー含む)を抜き出す。無い・壊れているなら undefined。\n// プレビューの差分表示やコンテキスト表示で「既存ブロックの有無」を判定するのに使う。\nexport function extractBlock(text: string): string | undefined {\n const state = inspectManagedBlock(text);\n if (state.kind !== \"present\") return undefined;\n return text.slice(state.start, state.end);\n}\n\n// 既存内容にマーカーブロックがあれば置換、無ければ末尾に追記する純関数。\n// 置換後が元と完全一致なら unchanged とし、呼び出し側が書き込みを省ける。\n// 管理ブロックが壊れている(inspectManagedBlock 参照)ときは BrokenManagedBlockError を投げる。\nexport function upsertBlock(\n existing: string,\n block: string,\n): { content: string; action: UpsertAction } {\n const state = inspectManagedBlock(existing);\n\n if (state.kind === \"broken\") {\n throw new BrokenManagedBlockError(state.reason);\n }\n\n if (state.kind === \"present\") {\n const before = existing.slice(0, state.start);\n const after = existing.slice(state.end);\n const content = before + block + after;\n return { content, action: content === existing ? \"unchanged\" : \"updated\" };\n }\n\n if (existing === \"\") {\n return { content: `${block}\\n`, action: \"created\" };\n }\n\n // 既存本文とブロックの間は 1 行空ける。末尾改行がない既存にも改行を補う。\n const prefix = existing.endsWith(\"\\n\") ? existing : `${existing}\\n`;\n return { content: `${prefix}\\n${block}\\n`, action: \"updated\" };\n}\n\nfunction enoentToUndefined(error: NodeJS.ErrnoException): undefined {\n if (error.code === \"ENOENT\") return undefined;\n throw error;\n}\n\n// 対象ファイルを読む。存在しなければ空文字(= 新規作成扱い)。\nexport async function readTextFile(filePath: string): Promise<string> {\n const existing = await readFile(filePath, \"utf-8\").catch(enoentToUndefined);\n return existing ?? \"\";\n}\n\n// 一時ファイルへ書いてから rename で差し替える。直書きだと中断時に既存の\n// AGENTS.md / CLAUDE.md の本文を失う(architecture.md の非破壊要件)。\nexport async function applyWrite(\n filePath: string,\n content: string,\n): Promise<void> {\n const dir = path.dirname(filePath);\n await mkdir(dir, { recursive: true });\n const temp = path.join(\n dir,\n `${path.basename(filePath)}.${globalThis.crypto.randomUUID()}.tmp`,\n );\n await writeFile(temp, content, \"utf-8\");\n await rename(temp, filePath).catch(async (error: unknown) => {\n await rm(temp, { force: true });\n throw error;\n });\n}\n","import path from \"node:path\";\nimport { Result } from \"@praha/byethrow\";\nimport { defineCommand } from \"../define-command.js\";\nimport { globalArgs } from \"../shared.js\";\nimport { confirm, select } from \"../../ui/prompt.js\";\nimport { logger, notice, warn } from \"../../ui/output.js\";\nimport {\n docsReference,\n renderDocsNotResolved,\n resolveDocs,\n} from \"../../agent/resolve-docs.js\";\nimport { resolveTargets, type Target } from \"../../agent/resolve-target.js\";\nimport {\n resolveExecutionMode,\n targetChoiceToFlag,\n} from \"../../agent/execution-mode.js\";\nimport { renderPlanPreview, type PreviewItem } from \"../../agent/preview.js\";\nimport {\n renderClaudeImportInner,\n renderReferenceInner,\n} from \"../../agent/template.js\";\nimport {\n applyWrite,\n BrokenManagedBlockError,\n extractBlock,\n inspectManagedBlock,\n readTextFile,\n upsertBlock,\n wrapBlock,\n type UpsertAction,\n} from \"../../agent/write-reference.js\";\n\ntype TargetPlan = {\n target: Target;\n content: string;\n action: UpsertAction;\n oldBlock: string | undefined;\n newBlock: string;\n};\n\n// 既存ファイルの管理ブロックの状態を、検出コンテキスト表示の 1 行に写す。\n// 壊れているときは「ここで止まる」ことが読めるようにする(実際の中断は plan 組み立て側)。\nfunction describeExisting(existing: string): string {\n const state = inspectManagedBlock(existing);\n switch (state.kind) {\n case \"present\":\n return \"exists (managed block present — will update)\";\n case \"absent\":\n return \"exists (no managed block — will append)\";\n case \"broken\":\n return `exists (broken managed block: ${state.reason} — cannot update)`;\n }\n}\n\n// 壊れた管理ブロックを見つけたときの失敗メッセージ。追記も置換もせず、人手での修復を促す\nfunction renderBrokenManagedBlock(\n fileName: string,\n error: BrokenManagedBlockError,\n): string {\n return (\n `${fileName}: ${error.message}. ` +\n \"Nothing was written. Repair the file by hand — keep exactly one \" +\n \"`<!-- orizm-agent:start ... -->` marker followed by one `<!-- orizm-agent:end -->` \" +\n \"marker, or remove both — then re-run `orizm agent init`.\"\n );\n}\n\n// 対話ウィザードの (1) 検出コンテキスト表示。docs version / プロジェクトルート /\n// 書き込み対象の有無・既存ブロックの有無を stderr に出す。\nasync function showDetectedContext(\n cwd: string,\n version: string,\n targets: Target[],\n): Promise<void> {\n const lines = [\n `Detected bundled Orizm docs v${version} (shipped with @orizm/cli).`,\n `Project root: ${cwd}`,\n ];\n for (const target of targets) {\n const fileName = target.fileName;\n const existing = await readTextFile(target.path);\n const status =\n existing === \"\"\n ? \"not found (will be created)\"\n : describeExisting(existing);\n lines.push(`- ${fileName}: ${status}`);\n }\n notice(lines.join(\"\\n\"));\n}\n\nexport default defineCommand({\n meta: {\n name: \"init\",\n description:\n \"Add a reference to the bundled Orizm docs into AGENTS.md / CLAUDE.md\",\n },\n args: {\n ...globalArgs,\n target: {\n type: \"string\",\n description:\n \"Write only this file (e.g. AGENTS.md). Default: manage both AGENTS.md and CLAUDE.md\",\n },\n cwd: {\n type: \"string\",\n description: \"Project root directory (defaults to the current directory)\",\n },\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would change without writing\",\n default: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Skip the confirmation prompt (non-interactive)\",\n default: false,\n },\n },\n run: async ({ args }) => {\n const cwd = args.cwd != null && args.cwd !== \"\" ? args.cwd : process.cwd();\n\n const docs = await resolveDocs();\n if (Result.isFailure(docs)) {\n // version と manifest パスはエラー本文に出るので、ここは本文にない情報だけ出す。\n logger.debug(`import.meta.url: ${import.meta.url}`);\n return Result.fail({ message: renderDocsNotResolved(docs.error) });\n }\n const version = docs.value.version;\n\n // 実行モードを解決(フラグ > 対話(TTY) > 既定/エラー(非TTY))。\n // 非対話ではプロンプトを一切出さず、フラグ指定のまま処理する。\n const mode = resolveExecutionMode({\n isTTY: process.stdin.isTTY === true,\n yes: args.yes === true,\n json: args.json === true,\n dryRun: args[\"dry-run\"] === true,\n });\n\n // 対話モード: (1) コンテキスト表示 →(2) 書き込み対象の選択(--target 未指定時のみ)。\n // フラグで与えた項目はウィザードで再質問しない(フラグが対話を上書き)。\n let targetFlag = args.target;\n if (mode === \"interactive\") {\n await showDetectedContext(cwd, version, resolveTargets(cwd, targetFlag));\n if (targetFlag == null || targetFlag === \"\") {\n const choice = await select(\n \"Which files should reference the Orizm docs?\",\n [\n {\n label: \"AGENTS.md and CLAUDE.md (recommended)\",\n value: \"both\",\n },\n { label: \"AGENTS.md only\", value: \"agents\" },\n { label: \"CLAUDE.md only\", value: \"claude\" },\n ],\n );\n if (choice == null) return Result.fail({ message: \"Aborted.\" });\n targetFlag = targetChoiceToFlag(choice);\n }\n }\n\n // 各ターゲットの適用結果を先に計算し、書き込みは確認後にまとめて行う。\n const targets = resolveTargets(cwd, targetFlag);\n const plans: TargetPlan[] = [];\n for (const target of targets) {\n let inner: string;\n if (target.kind === \"canonical\") {\n const ref = docsReference(path.dirname(target.path));\n if (!ref.resolves) {\n warn(\n `node_modules/@orizm/cli was not found from ${path.dirname(target.path)} ` +\n \"(it may be installed globally only, or not a dependency). \" +\n \"To let agents reference version-aligned docs, \" +\n \"add @orizm/cli to this project's devDependencies \" +\n \"(a global install cannot be resolved via a project-relative reference path). \" +\n \"If it is already a dependency, check where it resolves with `pnpm why @orizm/cli`. \" +\n \"The reference path itself will still be written.\",\n );\n }\n inner = renderReferenceInner({\n docsDir: ref.docsDir,\n docsIndex: ref.docsIndex,\n });\n } else {\n inner = renderClaudeImportInner();\n }\n const existing = await readTextFile(target.path);\n const newBlock = wrapBlock(inner);\n let upserted: ReturnType<typeof upsertBlock>;\n try {\n upserted = upsertBlock(existing, newBlock);\n } catch (error) {\n // 開始マーカーだけが残ったファイルに追記すると開始マーカーが 2 つになり、次回の\n // 実行(CI の --yes)で 2 つのマーカーに挟まれたユーザー本文を丸ごと消してしまう。\n // 壊れた形は機械的に触らず、他の対象にも書き込まずに中断する\n if (error instanceof BrokenManagedBlockError) {\n return Result.fail({\n message: renderBrokenManagedBlock(target.fileName, error),\n });\n }\n throw error;\n }\n const { content, action } = upserted;\n plans.push({\n target,\n content,\n action,\n oldBlock: extractBlock(existing),\n newBlock,\n });\n }\n\n const toJson = (): {\n version: string;\n dryRun: boolean;\n results: { target: string; action: UpsertAction }[];\n } => ({\n version,\n dryRun: args[\"dry-run\"] === true,\n results: plans.map((plan) => ({\n target: plan.target.path,\n action: plan.action,\n })),\n });\n\n const changed = plans.filter((plan) => plan.action !== \"unchanged\");\n\n if (changed.length === 0) {\n const names = plans.map((plan) => plan.target.fileName).join(\", \");\n return Result.succeed({\n json: toJson(),\n text: () => `Orizm docs reference already up to date in ${names}.`,\n });\n }\n\n const previewItems: PreviewItem[] = changed.map((plan) => ({\n fileName: plan.target.fileName,\n action: plan.action,\n oldBlock: plan.oldBlock,\n newBlock: plan.newBlock,\n }));\n\n // --dry-run はどちらのモードでも書き込まずプレビューのみ。\n if (args[\"dry-run\"] === true) {\n return Result.succeed({\n json: toJson(),\n text: () => renderPlanPreview(previewItems),\n });\n }\n\n // 対話モード: (3) 変更プレビュー →(4) 確定。非対話はフラグ指定のまま書き込む。\n if (mode === \"interactive\") {\n notice(renderPlanPreview(previewItems));\n const summary = changed\n .map(\n (plan) =>\n `${plan.action === \"created\" ? \"create\" : \"update\"} ${plan.target.fileName}`,\n )\n .join(\", \");\n const approved = await confirm(\n `Write the Orizm docs reference (${summary})?`,\n true,\n );\n if (!approved) return Result.fail({ message: \"Aborted.\" });\n }\n\n for (const plan of changed) {\n await applyWrite(plan.target.path, plan.content);\n }\n\n return Result.succeed({\n json: toJson(),\n text: () => {\n const lines = changed.map(\n (plan) =>\n `${plan.action === \"created\" ? \"Created\" : \"Updated\"} ${plan.target.fileName}`,\n );\n return `${lines.join(\"\\n\")} (Orizm docs v${version}).`;\n },\n });\n },\n});\n"],"mappings":"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"}
|