create-promptex-js 1.0.0 → 1.1.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 (32) hide show
  1. package/README.md +102 -18
  2. package/dist/contract.generated.d.ts +24 -0
  3. package/dist/contract.generated.js +59 -0
  4. package/dist/index.js +356 -176
  5. package/dist/messages.generated.js +145 -61
  6. package/dist/plan.d.ts +105 -0
  7. package/dist/plan.js +327 -0
  8. package/package.json +3 -2
  9. package/templates/adapter-starter/README.md +45 -0
  10. package/templates/adapter-starter/_gitignore +6 -0
  11. package/templates/adapter-starter/example/promptex.config.ts +12 -0
  12. package/templates/adapter-starter/example/prompts/nodes.ts +18 -0
  13. package/templates/adapter-starter/package.json +28 -0
  14. package/templates/adapter-starter/promptex.config.schema.json +12 -0
  15. package/templates/adapter-starter/src/index.ts +93 -0
  16. package/templates/adapter-starter/tsconfig.json +14 -0
  17. package/templates/plugin-starter/README.md +40 -0
  18. package/templates/plugin-starter/_gitignore +5 -0
  19. package/templates/plugin-starter/example/promptex.config.ts +12 -0
  20. package/templates/plugin-starter/example/prompts/nodes.ts +16 -0
  21. package/templates/plugin-starter/package.json +28 -0
  22. package/templates/plugin-starter/promptex.config.schema.json +12 -0
  23. package/templates/plugin-starter/src/index.ts +63 -0
  24. package/templates/plugin-starter/tsconfig.json +14 -0
  25. package/templates/project-starter/README.md +30 -0
  26. package/templates/project-starter/_gitignore +11 -0
  27. package/templates/project-starter/package.json +13 -0
  28. package/templates/project-starter/promptex.config.ts +8 -0
  29. package/templates/project-starter/prompts/example-skill.ts +14 -0
  30. package/templates/project-starter/prompts/example.ts +14 -0
  31. package/dist/default-ref.d.ts +0 -6
  32. package/dist/default-ref.js +0 -14
@@ -7,6 +7,26 @@ export const MESSAGES = {
7
7
  "en": ", ",
8
8
  "zh-Hant": "、",
9
9
  },
10
+ "scaffold.action.append": {
11
+ "en": "append",
12
+ "zh-Hant": "追加",
13
+ },
14
+ "scaffold.action.create": {
15
+ "en": "create",
16
+ "zh-Hant": "建立",
17
+ },
18
+ "scaffold.action.overwrite": {
19
+ "en": "overwrite",
20
+ "zh-Hant": "覆寫",
21
+ },
22
+ "scaffold.action.skip": {
23
+ "en": "skip",
24
+ "zh-Hant": "跳過",
25
+ },
26
+ "scaffold.already_initialized": {
27
+ "en": "Already initialized: %{config} exists, so no file was written.",
28
+ "zh-Hant": "已初始化:%{config} 已存在,因此未寫入任何檔案。",
29
+ },
10
30
  "scaffold.cancelled": {
11
31
  "en": "Cancelled, no file was written.",
12
32
  "zh-Hant": "已取消,未寫入任何檔案。",
@@ -19,57 +39,53 @@ export const MESSAGES = {
19
39
  "en": "Wrote %{count} files → %{path} (template source: %{source})",
20
40
  "zh-Hant": "已寫入 %{count} 個檔案 → %{path}(模板來源:%{source})",
21
41
  },
22
- "scaffold.error.clone_failed": {
23
- "en": "git clone promptex-templates@%{ref} failed. %{hint}",
24
- "zh-Hant": "git clone promptex-templates@%{ref} 失敗。%{hint}",
25
- },
26
- "scaffold.error.clone_hint": {
27
- "en": "The tag for this version may not have been created yet: use --ref main to get the latest, or --source <local-path> to take it offline.",
28
- "zh-Hant": "此版本的 tag 可能尚未建立:用 --ref main 抓最新、或 --source <本地路徑> 離線取用。",
29
- },
30
- "scaffold.error.dir_create": {
31
- "en": "Creating %{path} failed: %{reason}",
32
- "zh-Hant": "建立 %{path} 失敗:%{reason}",
33
- },
34
- "scaffold.error.dir_not_empty": {
35
- "en": "Target directory is not empty: %{path}\nExisting entries: %{entries}\nNo file was written.",
36
- "zh-Hant": "目標目錄非空:%{path}\n既有項目:%{entries}\n未寫入任何檔案。",
37
- },
38
- "scaffold.error.file_read": {
39
- "en": "Reading %{path} failed: %{reason}",
40
- "zh-Hant": "讀取 %{path} 失敗:%{reason}",
41
- },
42
- "scaffold.error.file_write": {
43
- "en": "Writing %{path} failed: %{reason}",
44
- "zh-Hant": "寫入 %{path} 失敗:%{reason}",
42
+ "scaffold.dry_run.header": {
43
+ "en": "Dry run, nothing was written. Planned changes in %{path} (template source: %{source}):",
44
+ "zh-Hant": "試跑,未寫入任何檔案。預計對 %{path} 做的變更(模板來源:%{source}):",
45
45
  },
46
46
  "scaffold.error.flag_missing_value": {
47
47
  "en": "%{flag} is missing its value",
48
48
  "zh-Hant": "%{flag} 缺值",
49
49
  },
50
- "scaffold.error.git_required": {
51
- "en": "Getting the template needs git (or give a local promptex-templates path with --source).",
52
- "zh-Hant": "取得模板需要 git(或用 --source 指定本地 promptex-templates 路徑)。",
50
+ "scaffold.error.git_unavailable": {
51
+ "en": "--git was given but no git executable was found. No file was written.",
52
+ "zh-Hant": "給了 --git,但找不到 git 執行檔。未寫入任何檔案。",
53
+ },
54
+ "scaffold.error.install_failed": {
55
+ "en": "%{command} failed; the scaffold files were written, the dependencies were not installed.",
56
+ "zh-Hant": "%{command} 失敗,鷹架檔案已寫入、依賴未裝。",
53
57
  },
54
- "scaffold.error.install_failed.js": {
55
- "en": "npm install failed; the scaffold files were written, the dependencies were not installed.",
56
- "zh-Hant": "npm install 失敗,鷹架檔案已寫入、依賴未裝。",
58
+ "scaffold.error.install_tool_missing": {
59
+ "en": "--install needs %{command}, but it was not found; the scaffold files were written, the dependencies were not installed.",
60
+ "zh-Hant": "--install 需要 %{command},但找不到;鷹架檔案已寫入、依賴未裝。",
57
61
  },
58
- "scaffold.error.install_failed.py": {
59
- "en": "uv sync failed; the scaffold files were written, the dependencies were not installed.",
60
- "zh-Hant": "uv sync 失敗,鷹架檔案已寫入、依賴未裝。",
62
+ "scaffold.error.json_requires_dry_run": {
63
+ "en": "--json only works together with --dry-run",
64
+ "zh-Hant": "--json 要搭配 --dry-run 使用",
61
65
  },
62
- "scaffold.error.install_failed.rs": {
63
- "en": "cargo fetch failed; the scaffold files were written, the dependencies were not fetched.",
64
- "zh-Hant": "cargo fetch 失敗,鷹架檔案已寫入、依賴未取。",
66
+ "scaffold.error.missing_inputs": {
67
+ "en": "Running without a terminal and these inputs have no default, pass them as flags: %{flags}",
68
+ "zh-Hant": "非互動執行時以下輸入沒有預設值,請用旗標給:%{flags}",
69
+ },
70
+ "scaffold.error.read_failed": {
71
+ "en": "Reading %{path} failed: %{detail}",
72
+ "zh-Hant": "讀取 %{path} 失敗:%{detail}",
65
73
  },
66
74
  "scaffold.error.starter_missing": {
67
75
  "en": "The template source has no %{template}-starter: %{path}",
68
76
  "zh-Hant": "模板來源缺 %{template}-starter:%{path}",
69
77
  },
70
- "scaffold.error.template_dir_read": {
71
- "en": "Reading the template directory failed: %{reason}",
72
- "zh-Hant": "讀取模板目錄失敗:%{reason}",
78
+ "scaffold.error.target_is_file": {
79
+ "en": "The target is a file, not a directory: %{path}. No file was written.",
80
+ "zh-Hant": "目標是檔案,不是資料夾:%{path}。未寫入任何檔案。",
81
+ },
82
+ "scaffold.error.target_is_symlink": {
83
+ "en": "The target is a symbolic link: %{path}. Pass the real directory instead. No file was written.",
84
+ "zh-Hant": "目標是符號連結:%{path}。請改傳實際的資料夾。未寫入任何檔案。",
85
+ },
86
+ "scaffold.error.template_needs_empty_dir": {
87
+ "en": "The %{template} template only goes into a new or empty directory, but %{path} already holds %{entries}. No file was written.",
88
+ "zh-Hant": "%{template} 模板只能建在新的或空的資料夾,但 %{path} 已有 %{entries}。未寫入任何檔案。",
73
89
  },
74
90
  "scaffold.error.template_unsupported": {
75
91
  "en": "Unsupported template: %{template} (available: %{choices})",
@@ -79,13 +95,37 @@ export const MESSAGES = {
79
95
  "en": "Unrecognized argument: %{arg}",
80
96
  "zh-Hant": "不認得的引數:%{arg}",
81
97
  },
82
- "scaffold.error.uv_missing": {
83
- "en": "--install needs uv, but no uv executable was found; the scaffold files were written, the dependencies were not installed.",
84
- "zh-Hant": "--install 需要 uv,但找不到 uv 執行檔;鷹架檔案已寫入、依賴未裝。",
98
+ "scaffold.error.write_failed": {
99
+ "en": "Writing %{path} failed: %{detail}. The files and directories this run created were removed, existing files were left as they were.",
100
+ "zh-Hant": "寫入 %{path} 失敗:%{detail}。已移除這次新建的檔案與資料夾,既有檔維持原狀。",
101
+ },
102
+ "scaffold.git.inside_worktree": {
103
+ "en": "git: the target is inside an existing git work tree, so git init is skipped.",
104
+ "zh-Hant": "git:目標位於既有的 git 工作樹內,因此略過 git init。",
105
+ },
106
+ "scaffold.git.will_init": {
107
+ "en": "git: git init runs in the target.",
108
+ "zh-Hant": "git:會在目標執行 git init。",
109
+ },
110
+ "scaffold.help.dry_run": {
111
+ "en": "list the files that would be created, skipped or appended, write nothing",
112
+ "zh-Hant": "列出會建立、跳過、追加的檔,不寫入",
113
+ },
114
+ "scaffold.help.force": {
115
+ "en": "overwrite existing files that clash with the template; never empties the directory or touches the declaration file",
116
+ "zh-Hant": "覆寫與模板同名的既有檔;不清空資料夾,也不動宣告檔",
117
+ },
118
+ "scaffold.help.git": {
119
+ "en": "run git init or not (default yes, skipped inside an existing git work tree; --git fails when git is missing)",
120
+ "zh-Hant": "要不要執行 git init(預設要,位於既有 git 工作樹內時略過;給 --git 但沒裝 git 時報錯)",
85
121
  },
86
122
  "scaffold.help.install": {
87
- "en": "run uv sync right after scaffolding",
88
- "zh-Hant": "鷹架後直接 uv sync",
123
+ "en": "install the dependencies right after scaffolding",
124
+ "zh-Hant": "鷹架後直接安裝依賴",
125
+ },
126
+ "scaffold.help.json": {
127
+ "en": "with --dry-run, print the plan as JSON on stdout",
128
+ "zh-Hant": "搭配 --dry-run,在 stdout 輸出 JSON 格式的計畫",
89
129
  },
90
130
  "scaffold.help.locale": {
91
131
  "en": "message locale (en|zh-Hant), defaults to the environment variables then English",
@@ -95,25 +135,29 @@ export const MESSAGES = {
95
135
  "en": "kebab-case name, defaults to the normalized target directory name",
96
136
  "zh-Hant": "kebab-case 名稱,預設取目標目錄名正規化",
97
137
  },
98
- "scaffold.help.ref": {
99
- "en": "take the given branch/tag of promptex-templates (defaults to v<this package's version>; pre-release versions default to main)",
100
- "zh-Hant": "抓 promptex-templates 的指定 branch/tag(預設 v<本套件版本>;預發布版預設 main)",
101
- },
102
138
  "scaffold.help.source": {
103
- "en": "use a local promptex-templates checkout instead (for offline and development use)",
104
- "zh-Hant": "改用本地 promptex-templates checkout(離線與開發用)",
139
+ "en": "use a local templates directory (the one holding the *-starter folders) instead of the bundled templates, for template development",
140
+ "zh-Hant": "改用本地模板目錄(含各 *-starter 的那一層)取代內附模板,開發模板時用",
105
141
  },
106
142
  "scaffold.help.target_dir": {
107
- "en": "target directory",
108
- "zh-Hant": "目標目錄",
143
+ "en": "target directory: missing or empty for create mode, an existing project for init mode",
144
+ "zh-Hant": "目標目錄。不存在或空的走建立模式,既有專案走初始化模式",
109
145
  },
110
146
  "scaffold.help.template": {
111
- "en": "project|plugin|adapter",
112
- "zh-Hant": "project|plugin|adapter",
147
+ "en": "project|plugin|adapter, init mode only takes project",
148
+ "zh-Hant": "project|plugin|adapter,初始化模式只支援 project",
113
149
  },
114
150
  "scaffold.help.yes": {
115
- "en": "skip the interactive prompts, take defaults or flag values throughout",
116
- "zh-Hant": "跳過互動,全部取預設或旗標值",
151
+ "en": "skip the interactive prompts and take the defaults; does not mean overwrite",
152
+ "zh-Hant": "跳過互動,全部取預設值;不代表同意覆寫",
153
+ },
154
+ "scaffold.mode.create": {
155
+ "en": "Create mode: new project in %{path}",
156
+ "zh-Hant": "建立模式:在 %{path} 建立新專案",
157
+ },
158
+ "scaffold.mode.init": {
159
+ "en": "Init mode: adding promptex to the existing directory %{path} (it already holds %{entries})",
160
+ "zh-Hant": "初始化模式:在既有資料夾 %{path} 加入 promptex(裡面已有 %{entries})",
117
161
  },
118
162
  "scaffold.prompt.git_init": {
119
163
  "en": "Initialize a git repository?",
@@ -139,6 +183,38 @@ export const MESSAGES = {
139
183
  "en": "Template (%{choices})",
140
184
  "zh-Hant": "模板(%{choices})",
141
185
  },
186
+ "scaffold.skip.blocked": {
187
+ "en": "a parent path is not a directory",
188
+ "zh-Hant": "上層路徑不是資料夾",
189
+ },
190
+ "scaffold.skip.example_dir_exists": {
191
+ "en": "example directory already exists, skipped as a whole",
192
+ "zh-Hant": "範例目錄已存在,整個跳過",
193
+ },
194
+ "scaffold.skip.exists": {
195
+ "en": "already exists, pass --force to overwrite",
196
+ "zh-Hant": "已存在,加 --force 才覆寫",
197
+ },
198
+ "scaffold.skip.init_mode": {
199
+ "en": "only written in create mode",
200
+ "zh-Hant": "只在建立模式寫出",
201
+ },
202
+ "scaffold.skip.manifest_kept": {
203
+ "en": "declaration file left as is, add the promptex dependency yourself",
204
+ "zh-Hant": "宣告檔不動,promptex 依賴要自己加",
205
+ },
206
+ "scaffold.skip.marker_present": {
207
+ "en": "the promptex block is already there",
208
+ "zh-Hant": "已有 promptex 區塊",
209
+ },
210
+ "scaffold.skip.symlink": {
211
+ "en": "symbolic link, not followed",
212
+ "zh-Hant": "符號連結,不跟隨",
213
+ },
214
+ "scaffold.source.bundled": {
215
+ "en": "bundled templates (v%{version})",
216
+ "zh-Hant": "內附模板(v%{version})",
217
+ },
142
218
  "scaffold.source.local": {
143
219
  "en": "local template (%{path})",
144
220
  "zh-Hant": "本地模板(%{path})",
@@ -156,16 +232,24 @@ export const MESSAGES = {
156
232
  "zh-Hant": "project:提示詞源碼樹(消費專案)",
157
233
  },
158
234
  "scaffold.usage.js": {
159
- "en": "create-promptex-js [target-dir] --template project|plugin|adapter --name <kebab-name> [--ref <branch|tag>] [--source <local-path>] [--git|--no-git] [--install] [--yes] [--locale <locale>]",
160
- "zh-Hant": "create-promptex-js [目標目錄] --template project|plugin|adapter --name <kebab 名> [--ref <branch|tag>] [--source <本地路徑>] [--git|--no-git] [--install] [--yes] [--locale <語系>]",
235
+ "en": "create-promptex-js [target-dir] [--template project|plugin|adapter] [--name <kebab-name>] [--source <templates-dir>] [--git|--no-git] [--install] [--force] [--dry-run [--json]] [--yes] [--locale <locale>]",
236
+ "zh-Hant": "create-promptex-js [目標目錄] [--template project|plugin|adapter] [--name <kebab 名>] [--source <模板目錄>] [--git|--no-git] [--install] [--force] [--dry-run [--json]] [--yes] [--locale <語系>]",
237
+ },
238
+ "scaffold.usage.modes": {
239
+ "en": "A missing target directory, or one that only holds system, version-control and editor files, gets a new project (create mode). Any other directory gets promptex added in place (init mode). Existing files are never overwritten unless --force is given, and an existing promptex.config.* means the directory is already initialized.",
240
+ "zh-Hant": "目標目錄不存在,或裡面只有系統、版本控制與編輯器的檔案時,建立新專案(建立模式)。其他資料夾在原地加入 promptex(初始化模式)。除非給 --force,既有檔一律不覆寫。已有 promptex.config.* 就判定為已初始化。",
241
+ },
242
+ "scaffold.usage.options": {
243
+ "en": "Options:",
244
+ "zh-Hant": "選項:",
161
245
  },
162
246
  "scaffold.usage.py": {
163
- "en": "uvx create-promptex-py [target-dir] [--template project|plugin|adapter] [--name <kebab-name>] [--ref <branch|tag>] [--source <local-path>] [--git|--no-git] [--install] [--yes] [--locale <locale>]",
164
- "zh-Hant": "uvx create-promptex-py [目標目錄] [--template project|plugin|adapter] [--name <kebab 名>] [--ref <branch|tag>] [--source <本地路徑>] [--git|--no-git] [--install] [--yes] [--locale <語系>]",
247
+ "en": "uvx create-promptex-py [target-dir] [--template project|plugin|adapter] [--name <kebab-name>] [--source <templates-dir>] [--git|--no-git] [--install] [--force] [--dry-run [--json]] [--yes] [--locale <locale>]",
248
+ "zh-Hant": "uvx create-promptex-py [目標目錄] [--template project|plugin|adapter] [--name <kebab 名>] [--source <模板目錄>] [--git|--no-git] [--install] [--force] [--dry-run [--json]] [--yes] [--locale <語系>]",
165
249
  },
166
250
  "scaffold.usage.rs": {
167
- "en": "cargo create-promptex-rs [target-dir] --template project|plugin|adapter --name <kebab-name> [--ref <branch|tag>] [--source <local-path>] [--git|--no-git] [--install] [--yes] [--locale <locale>]",
168
- "zh-Hant": "cargo create-promptex-rs [目標目錄] --template project|plugin|adapter --name <kebab 名> [--ref <branch|tag>] [--source <本地路徑>] [--git|--no-git] [--install] [--yes] [--locale <語系>]",
251
+ "en": "cargo create-promptex-rs [target-dir] [--template project|plugin|adapter] [--name <kebab-name>] [--source <templates-dir>] [--git|--no-git] [--install] [--force] [--dry-run [--json]] [--yes] [--locale <locale>]",
252
+ "zh-Hant": "cargo create-promptex-rs [目標目錄] [--template project|plugin|adapter] [--name <kebab 名>] [--source <模板目錄>] [--git|--no-git] [--install] [--force] [--dry-run [--json]] [--yes] [--locale <語系>]",
169
253
  },
170
254
  "template.adapter_demo.rule_content": {
171
255
  "en": "On the custom platform this rule degrades to always-on, with its scope noted in the body.",
package/dist/plan.d.ts ADDED
@@ -0,0 +1,105 @@
1
+ export type Mode = 'create' | 'init';
2
+ export type SkipReason = 'exists' | 'manifest-kept' | 'example-dir-exists' | 'init-mode' | 'marker-present' | 'symlink' | 'blocked';
3
+ /** 依代碼帶結構化細節的失敗;CLI 依 `contract.generated.ts` 的錯誤表決定訊息與結束碼。 */
4
+ export declare class CreateError extends Error {
5
+ readonly code: string;
6
+ readonly details: Record<string, string | string[]>;
7
+ constructor(code: string, details?: Record<string, string | string[]>);
8
+ }
9
+ /** 目標的狀態。`unlisted` 是第一層不在允許清單內的項目,決定模式也供輸出列出。 */
10
+ export interface TargetState {
11
+ exists: boolean;
12
+ mode: Mode;
13
+ unlisted: string[];
14
+ }
15
+ /**
16
+ * 判斷目標狀態與模式。目標不存在,或第一層只有允許清單裡的項目,就走建立模式。
17
+ * 目標是符號連結或檔案時以用法錯誤拒絕,不寫入任何東西。
18
+ */
19
+ export declare function inspectTarget(target: string): TargetState;
20
+ /** 目標裡已存在的 promptex 設定檔;有就代表已初始化。 */
21
+ export declare function findConfig(target: string): string | null;
22
+ /**
23
+ * 目標是否位於任何 git 工作樹內(含上層資料夾)。往上找 `.git`(資料夾或 worktree 的
24
+ * 檔案),不呼叫 git:沒裝 git 也判得出來,三種語言的結果也因此一致。
25
+ */
26
+ export declare function isInsideGitWorktree(target: string): boolean;
27
+ export declare function commandAvailable(name: string): boolean;
28
+ /** 非互動環境:沒有終端機、帶 --yes,或 CI 環境變數為真(空字串、0、false 不算)。 */
29
+ export declare function isNonInteractive(stdinIsTty: boolean, yes: boolean, env: NodeJS.ProcessEnv): boolean;
30
+ /** 一項使用者輸入:旗標名、這次有沒有給、沒給時有沒有預設值。 */
31
+ export interface InputSpec {
32
+ flag: string;
33
+ provided: boolean;
34
+ hasDefault: boolean;
35
+ }
36
+ /** 非互動時沒給又沒有預設值的輸入,一次全列出(結束碼 2)。互動時會問,因此不算缺。 */
37
+ export declare function missingInputs(inputs: InputSpec[], interactive: boolean): string[];
38
+ /** 範本檔在寫入規則裡的角色。 */
39
+ export type Role = 'manifest' | 'readme' | 'gitignore' | 'example' | 'other';
40
+ export declare function roleOf(rel: string, template: string): Role;
41
+ /** 一個範本檔:目標裡的相對路徑(`/` 分隔)與替換後的內容。 */
42
+ export interface TemplateFile {
43
+ rel: string;
44
+ content: string;
45
+ }
46
+ export type Action = {
47
+ action: 'create';
48
+ path: string;
49
+ content: string;
50
+ } | {
51
+ action: 'overwrite';
52
+ path: string;
53
+ content: string;
54
+ } | {
55
+ action: 'append';
56
+ path: string;
57
+ content: string;
58
+ } | {
59
+ action: 'skip';
60
+ path: string;
61
+ reason: SkipReason;
62
+ };
63
+ /** 逐檔決定動作,不寫入。回傳的順序是範本檔的路徑順序。 */
64
+ export declare function planFiles(target: string, files: TemplateFile[], mode: Mode, template: string, force: boolean): Action[];
65
+ /** 計畫的四類清單,路徑排序後輸出(JSON 與人讀報告共用)。 */
66
+ export declare function summarize(actions: Action[]): {
67
+ create: string[];
68
+ overwrite: string[];
69
+ append: string[];
70
+ skip: {
71
+ path: string;
72
+ reason: SkipReason;
73
+ }[];
74
+ };
75
+ /**
76
+ * 照計畫寫入。先建立與覆寫,最後追加 `.gitignore`,追加之前的失敗因此不會動到既有的
77
+ * `.gitignore`。任何一步失敗時,倒序刪掉這次新建的檔案與資料夾(資料夾只在已清空時刪),
78
+ * 既有檔一律不刪,再以 RUN_WRITE_FAILED 回報。
79
+ *
80
+ * 環境變數 PROMPTEX_CREATE_FAIL_ON 指定一個相對路徑時,寫到那個檔就模擬失敗。只給測試
81
+ * 驗證回復用:真實的寫入失敗(磁碟滿、權限)難以在三種語言穩定重現。
82
+ */
83
+ export declare function applyPlan(target: string, actions: Action[]): void;
84
+ /** JS 的套件管理器:先看鎖定檔(目標或上層),再看有沒有 pnpm,最後退回 npm。 */
85
+ export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
86
+ export declare function detectPackageManager(target: string, pnpmAvailable: () => boolean): PackageManager;
87
+ /** 各套件管理器的四種指令形態。 */
88
+ export declare const PM_COMMANDS: Record<PackageManager, {
89
+ install: string;
90
+ add: string;
91
+ run: string;
92
+ exec: string;
93
+ }>;
94
+ /**
95
+ * 給人看的目標路徑:在工作目錄底下就用相對路徑,目標就是工作目錄時回空字串(不印 `cd .`),
96
+ * 其他情況用絕對路徑。
97
+ */
98
+ export declare function cdPath(target: string, cwd: string): string;
99
+ export declare function nextSteps(opts: {
100
+ template: string;
101
+ cd: string;
102
+ manifestKept: boolean;
103
+ installed: boolean;
104
+ pm: PackageManager;
105
+ }): string[];