promptex-js 1.1.1-rc.2 → 1.2.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.
package/README.md CHANGED
@@ -89,14 +89,14 @@ Common flags: `--out <install root>` (single-directory mode), `--platform <name>
89
89
  ## Machine-readable output
90
90
 
91
91
  `--json` makes a command print one JSON document on stdout. Every document, and every
92
- file the tool writes under `.promptex/`, carries `formatVersion` (currently `"1.1"`).
92
+ file the tool writes under `.promptex/`, carries `formatVersion` (currently `"1.2"`).
93
93
  Within 1.x the version only gains keys, so read the keys you know and ignore the rest.
94
94
 
95
95
  `promptex version --json` reports the package, the language and what this CLI
96
96
  supports, so a caller can check a feature before using it:
97
97
 
98
98
  ```json
99
- {"formatVersion":"1.1","package":{"name":"promptex-js","version":"1.0.1"},"language":"ts",
99
+ {"formatVersion":"1.2","package":{"name":"promptex-js","version":"1.0.1"},"language":"ts",
100
100
  "capabilities":{"verbs":{"build":{"flags":["--install","--dry-run","…"]},"version":{"flags":[]}},
101
101
  "globalFlags":["--json","--locale"]}}
102
102
  ```
@@ -105,7 +105,7 @@ A failing command with `--json` prints an error document on stdout and the same
105
105
  message on one line of stderr:
106
106
 
107
107
  ```json
108
- {"formatVersion":"1.1","error":{"code":"USAGE_UNKNOWN_FLAG","message":"Unknown flag: --foo","details":{"flag":"--foo","usage":"…"}}}
108
+ {"formatVersion":"1.2","error":{"code":"USAGE_UNKNOWN_FLAG","message":"Unknown flag: --foo","details":{"flag":"--foo","usage":"…"}}}
109
109
  ```
110
110
 
111
111
  - `code` is stable. A `USAGE_` code means the call was wrong. A `RUN_` code means the
@@ -64,6 +64,8 @@ export interface ResolvedUnitLike {
64
64
  }[];
65
65
  /** 該單元各目標宣告的平台原生設定(ADR-006);無宣告時缺席。 */
66
66
  readonly settings?: unknown;
67
+ /** 該單元各目標宣告的平台 plugin(`{ 平台名: [宣告] }`,ADR-044);無宣告時缺席。 */
68
+ readonly plugins?: unknown;
67
69
  }
68
70
  export interface WatchTarget {
69
71
  readonly promptDir: string;
@@ -76,6 +78,8 @@ export interface WatchTarget {
76
78
  readonly targetPlan: unknown;
77
79
  /** 該單元各目標宣告的平台原生設定(`{ 平台名: 設定 }`);無宣告時為 null。 */
78
80
  readonly settings: unknown;
81
+ /** 該單元各目標宣告的平台 plugin(`{ 平台名: [宣告] }`);無宣告時為 null。 */
82
+ readonly plugins: unknown;
79
83
  readonly opts: {
80
84
  readonly select?: unknown;
81
85
  readonly externals: readonly unknown[];
@@ -96,6 +100,8 @@ export interface WatchInstallSpec {
96
100
  readonly installRoot: string;
97
101
  readonly targetPlan: unknown;
98
102
  readonly settings: unknown;
103
+ /** 平台 plugin 宣告(`{ 平台名: [宣告] }`,ADR-044);無宣告時為 null 或缺席。 */
104
+ readonly plugins?: unknown;
99
105
  /** 每輪重跑的寫入模式(`build`/`install`/`export`,ADR-035);省略時為安裝。 */
100
106
  readonly mode?: string;
101
107
  /** 單元的範圍(AC-538)。 */
@@ -148,6 +154,8 @@ export interface CoreArgs {
148
154
  readonly irPath: string;
149
155
  readonly settingsPath?: string;
150
156
  readonly externalsPath?: string;
157
+ /** 旁置的平台 plugin 宣告檔(ADR-044);無宣告時為空字串或缺席。 */
158
+ readonly pluginsPath?: string;
151
159
  readonly root: string;
152
160
  readonly platform: string;
153
161
  readonly sourceRoot?: string;
@@ -57,6 +57,14 @@ export declare const SWITCH_FIELDS: Readonly<Record<string, 'assumeYes' | 'json'
57
57
  * 多個目標因此共用同一份輸入而不互相覆寫。
58
58
  */
59
59
  export declare function writeSettingsFile(dir: string, settings: unknown): string;
60
+ /**
61
+ * 寫出本單元的旁置平台 plugin 宣告檔,回傳路徑(無宣告時回空字串、不寫檔)。
62
+ *
63
+ * 內容即核心算好的 `{ 平台名: [宣告] }`(見 `orchestrate::unit_plugins`),形態與
64
+ * 平台設定的旁置檔相同、但分開成另一份(ADR-044):平台設定逐字寫進平台的設定檔,
65
+ * 混進 plugin 宣告會被一起寫出去。
66
+ */
67
+ export declare function writePluginsFile(dir: string, plugins: unknown): string;
60
68
  /**
61
69
  * 一個單元 × 一個目標的投影與落地,回傳結束碼(0 為成功)。
62
70
  *
@@ -85,7 +93,7 @@ export declare function writeSettingsFile(dir: string, settings: unknown): strin
85
93
  * 寫出的 `externalsPath`,其餘一律由核心的 `projection_entries` 算出本目標
86
94
  * 實際用得到的落點子集。
87
95
  */
88
- export declare function distributeTarget({ mode, scope, target, targetPlan, usedJson, externalsDir, irPath, settingsPath, externalsPath: fallbackExternalsPath, unitOutDir, unitName, installRoot, sourceRoot, select, }: {
96
+ export declare function distributeTarget({ mode, scope, target, targetPlan, usedJson, externalsDir, irPath, settingsPath, pluginsPath, externalsPath: fallbackExternalsPath, unitOutDir, unitName, installRoot, sourceRoot, select, }: {
89
97
  mode: string;
90
98
  /** 單元的範圍(AC-538);單一目錄模式與省略時為專案層。 */
91
99
  scope?: string;
@@ -96,6 +104,8 @@ export declare function distributeTarget({ mode, scope, target, targetPlan, used
96
104
  externalsDir: string;
97
105
  irPath: string;
98
106
  settingsPath: string;
107
+ /** 旁置的平台 plugin 宣告檔(ADR-044);無宣告時為空字串或缺席。 */
108
+ pluginsPath?: string;
99
109
  externalsPath?: string;
100
110
  unitOutDir: string;
101
111
  unitName: string;
@@ -108,7 +118,7 @@ export declare function distributeTarget({ mode, scope, target, targetPlan, used
108
118
  *
109
119
  * 由 `src/cli/main.ts` 轉發呼叫。本檔被 import 而不呼叫本函式時(監看的求值
110
120
  * 子行程),上方那批模組層狀態維持初始值、不執行任何命令列行為 ── 那正是子
111
- * 行程要的:它只取用 `distributeTarget` 與 `writeSettingsFile`。
121
+ * 行程要的:它只取用 `distributeTarget`、`writeSettingsFile` 與 `writePluginsFile`。
112
122
  *
113
123
  * 賦值順序與此前的模組層敘述逐條相同:`configAction` 要早於 `parseCliArgs`
114
124
  * (後者讀它判斷第二個位置參數是否合法),`config` 分派要早於動詞白名單檢查
package/dist/cli/main.js CHANGED
@@ -868,11 +868,14 @@ function emitStructured(out, targetPlatform, queryMeta, contents) {
868
868
  outcome: out,
869
869
  }), LOCALE));
870
870
  }
871
- /** `invokeCore`/`coreOutcome`/`runExtendedTarget` 共用的三份輸入讀法。 */
872
- function readNativeInputs(irPath, settingsPath, externalsPath) {
871
+ /** `invokeCore`/`coreOutcome`/`runExtendedTarget` 共用的四份輸入讀法。 */
872
+ function readNativeInputs(irPath, settingsPath, externalsPath, pluginsPath) {
873
873
  return {
874
874
  irJson: readFileSync(irPath, 'utf8'),
875
875
  settingsJson: readIfPresent(settingsPath),
876
+ // 平台 plugin 宣告(ADR-044):與平台設定分開成另一份旁置檔,因為平台設定逐字
877
+ // 寫進平台的設定檔,混進 plugin 宣告會被一起寫出去。
878
+ pluginsJson: readIfPresent(pluginsPath),
876
879
  // 外部引用(AC-056 至 AC-060):build 與 install/dry-run/manifest 走同一張
877
880
  // 落點表。build 不落地平台產物不代表它不需要落點資訊:省略的話引用外部目標
878
881
  // 的節點會渲染成 `[名稱](id)` 占位形態而非算出的相對路徑,而寫進框架中繼
@@ -889,17 +892,17 @@ function readNativeInputs(irPath, settingsPath, externalsPath) {
889
892
  * 呼叫核心的這一步因此必須與單獨執行 `build --install` 時完全相同,而非讀本檔
890
893
  * 頂層的 `command`(該值此時是 `'watch'`,不是綁定認得的動詞)。
891
894
  */
892
- function invokeCore({ irPath, settingsPath, externalsPath, root, platform, sourceRoot, unitName, mode = MODE, scope = 'project', queryMeta }) {
893
- const result = coreOutcome({ irPath, settingsPath, externalsPath, root, platform, sourceRoot, unitName, mode, scope });
895
+ function invokeCore({ irPath, settingsPath, externalsPath, pluginsPath, root, platform, sourceRoot, unitName, mode = MODE, scope = 'project', queryMeta }) {
896
+ const result = coreOutcome({ irPath, settingsPath, externalsPath, pluginsPath, root, platform, sourceRoot, unitName, mode, scope });
894
897
  if (!result.ok) {
895
898
  failOps(result.message);
896
899
  }
897
900
  // 沒有擴充的目標,核心的投影樹即最終落地的那一棵,取它就是安裝結果本身。
898
901
  let contents;
899
902
  if (CONTENT_REQUESTED) {
900
- const { irJson, settingsJson, externalsJson } = readNativeInputs(irPath, settingsPath, externalsPath);
903
+ const { irJson, settingsJson, externalsJson, pluginsJson } = readNativeInputs(irPath, settingsPath, externalsPath, pluginsPath);
901
904
  try {
902
- contents = JSON.parse(loadNativeCore().projectionTree(mode, root, irJson, platform, sourceRoot ?? '', settingsJson, externalsJson, unitName, LOCALE, scope));
905
+ contents = JSON.parse(loadNativeCore().projectionTree(mode, root, irJson, platform, sourceRoot ?? '', settingsJson, externalsJson, unitName, LOCALE, scope, pluginsJson));
903
906
  }
904
907
  catch (e) {
905
908
  failOps(e instanceof Error ? e.message : String(e));
@@ -917,19 +920,19 @@ function invokeCore({ irPath, settingsPath, externalsPath, root, platform, sourc
917
920
  * 兩者的結果形態不同(`BuildOutcome` 對 `DistributeOutcome`),由呼叫端依
918
921
  * `mode` 分流(`present` 的無標籤形態比對)。
919
922
  */
920
- function coreOutcome({ irPath, settingsPath, externalsPath, root, platform, sourceRoot, unitName: unit, mode = MODE, scope = 'project', }) {
923
+ function coreOutcome({ irPath, settingsPath, externalsPath, pluginsPath, root, platform, sourceRoot, unitName: unit, mode = MODE, scope = 'project', }) {
921
924
  const native = loadNativeCore();
922
- const { irJson, settingsJson, externalsJson } = readNativeInputs(irPath, settingsPath, externalsPath);
925
+ const { irJson, settingsJson, externalsJson, pluginsJson } = readNativeInputs(irPath, settingsPath, externalsPath, pluginsPath);
923
926
  try {
924
927
  if (mode === 'build') {
925
- // `unit` 是最後一個引數:框架中繼住 `.promptex/{單元}/`(ADR-027),
926
- // 省略它會讓每個單元都寫進預設單元的目錄而互相覆蓋。
928
+ // 框架中繼住 `.promptex/{單元}/`(ADR-027),省略 `unit` 會讓每個單元都寫進
929
+ // 預設單元的目錄而互相覆蓋。
927
930
  //
928
- // 不傳 `sourceRoot`:那個引數只在拷貝型素材落地時當解析基準,而本動詞
929
- // 不拷貝素材(ADR-028),綁定與核心都已不收它。`distribute` 那條仍要它。
930
- return { ok: true, outcome: JSON.parse(native.build(irJson, root, platform, settingsJson, externalsJson, unit, LOCALE, scope)) };
931
+ // `sourceRoot` 排在最後:本動詞不拷貝素材(ADR-028),它只用來核對平台
932
+ // plugin 的 `modules` 檔案存在(ADR-044)。
933
+ return { ok: true, outcome: JSON.parse(native.build(irJson, root, platform, settingsJson, externalsJson, unit, LOCALE, scope, pluginsJson, sourceRoot ?? '')) };
931
934
  }
932
- return { ok: true, outcome: JSON.parse(native.distribute(mode, irJson, root, platform, sourceRoot ?? '', settingsJson, unit, externalsJson, LOCALE, scope)) };
935
+ return { ok: true, outcome: JSON.parse(native.distribute(mode, irJson, root, platform, sourceRoot ?? '', settingsJson, unit, externalsJson, LOCALE, scope, pluginsJson)) };
933
936
  }
934
937
  catch (e) {
935
938
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
@@ -1123,10 +1126,10 @@ async function runExtendedTarget(target, mode, coreArgs, unitOutDir, unitName, q
1123
1126
  const root = unitOutDir;
1124
1127
  const unit = unitName;
1125
1128
  const sourceRoot = coreArgs.sourceRoot;
1126
- const { irJson, settingsJson, externalsJson } = readNativeInputs(coreArgs.irPath, coreArgs.settingsPath, coreArgs.externalsPath);
1129
+ const { irJson, settingsJson, externalsJson, pluginsJson } = readNativeInputs(coreArgs.irPath, coreArgs.settingsPath, coreArgs.externalsPath, coreArgs.pluginsPath);
1127
1130
  let beforeJson;
1128
1131
  try {
1129
- beforeJson = native.projectionTree(mode, root, irJson, target.platform, sourceRoot ?? '', settingsJson, externalsJson, unit, LOCALE, coreArgs.scope ?? 'project');
1132
+ beforeJson = native.projectionTree(mode, root, irJson, target.platform, sourceRoot ?? '', settingsJson, externalsJson, unit, LOCALE, coreArgs.scope ?? 'project', pluginsJson);
1130
1133
  }
1131
1134
  catch (e) {
1132
1135
  failOps(e instanceof Error ? e.message : String(e));
@@ -1475,6 +1478,21 @@ export function writeSettingsFile(dir, settings) {
1475
1478
  dumpHandoff('PROMPTEX_DUMP_SETTINGS', text);
1476
1479
  return path;
1477
1480
  }
1481
+ /**
1482
+ * 寫出本單元的旁置平台 plugin 宣告檔,回傳路徑(無宣告時回空字串、不寫檔)。
1483
+ *
1484
+ * 內容即核心算好的 `{ 平台名: [宣告] }`(見 `orchestrate::unit_plugins`),形態與
1485
+ * 平台設定的旁置檔相同、但分開成另一份(ADR-044):平台設定逐字寫進平台的設定檔,
1486
+ * 混進 plugin 宣告會被一起寫出去。
1487
+ */
1488
+ export function writePluginsFile(dir, plugins) {
1489
+ if (!plugins)
1490
+ return '';
1491
+ mkdirSync(dir, { recursive: true });
1492
+ const path = join(dir, 'plugins.json');
1493
+ writeFileSync(path, `${JSON.stringify(plugins, null, 2)}\n`);
1494
+ return path;
1495
+ }
1478
1496
  /**
1479
1497
  * 既有單一目錄模式:srcDir/root/platform/unit 均取 CLI 旗標,行為與配置
1480
1498
  * 單元系統實作前逐字相同。
@@ -1509,9 +1527,10 @@ async function runSingleDir() {
1509
1527
  const status = invokeCore({
1510
1528
  irPath,
1511
1529
  // 單一目錄模式沒有配置檔,也就沒有 target 可宣告平台原生設定
1512
- // (ADR-006「平台設定住目標」):這裡恆為空。
1530
+ // (ADR-006「平台設定住目標」),平台 plugin 同理(ADR-044):這裡恆為空。
1513
1531
  settingsPath: '',
1514
1532
  externalsPath: '',
1533
+ pluginsPath: '',
1515
1534
  root: singleRoot,
1516
1535
  platform,
1517
1536
  sourceRoot: srcDir,
@@ -1548,7 +1567,7 @@ async function runSingleDir() {
1548
1567
  * 寫出的 `externalsPath`,其餘一律由核心的 `projection_entries` 算出本目標
1549
1568
  * 實際用得到的落點子集。
1550
1569
  */
1551
- export async function distributeTarget({ mode, scope = 'project', target, targetPlan, usedJson, externalsDir, irPath, settingsPath, externalsPath: fallbackExternalsPath = '', unitOutDir, unitName, installRoot, sourceRoot, select, }) {
1570
+ export async function distributeTarget({ mode, scope = 'project', target, targetPlan, usedJson, externalsDir, irPath, settingsPath, pluginsPath = '', externalsPath: fallbackExternalsPath = '', unitOutDir, unitName, installRoot, sourceRoot, select, }) {
1552
1571
  present({ kind: 'unitHeader', unit: unitName, platform: target.platform, outDir: unitOutDir });
1553
1572
  const queryMeta = { unit: unitName, installRoot };
1554
1573
  if ('emit' in target && typeof target.emit === 'function') {
@@ -1559,7 +1578,7 @@ export async function distributeTarget({ mode, scope = 'project', target, target
1559
1578
  const externalsPath = targetPlan
1560
1579
  ? writeExternalsFile(externalsDir, target.platform, JSON.parse(loadNativeCore().orchestrateProjectionEntries(targetJson, usedJson, LOCALE)))
1561
1580
  : fallbackExternalsPath;
1562
- const coreArgs = { irPath, settingsPath, externalsPath, platform: target.platform, sourceRoot, unitName, scope };
1581
+ const coreArgs = { irPath, settingsPath, externalsPath, pluginsPath, platform: target.platform, sourceRoot, unitName, scope };
1563
1582
  // 平台適配的擴充(AC 無對應條款,依 promptex-prototype 原型行為實作):
1564
1583
  // 各寫入模式一律走同一條路,起點與落地方式的差異由核心承擔(見
1565
1584
  // `runExtendedTarget`)。
@@ -1659,6 +1678,8 @@ async function runConfigUnits(configPath) {
1659
1678
  // 平台原生設定由核心從各目標的宣告合成(ADR-006「平台設定住目標」),本層
1660
1679
  // 只把它原樣寫成投影要吃的旁置檔,不自行從配置物件取一次。
1661
1680
  const settingsPath = writeSettingsFile(compileDir, resolved.settings);
1681
+ // 平台 plugin 宣告同樣由核心合成(ADR-044),寫成另一份旁置檔。
1682
+ const pluginsPath = writePluginsFile(compileDir, resolved.plugins);
1662
1683
  const { irPath, diagnostics } = await compile(resolved.srcDir, compileDir, {
1663
1684
  // 專案根即配置檔所在目錄(PDR-003),與下方呼叫核心時傳的 sourceRoot
1664
1685
  // 同一個值:plugin 的快取目錄與 asset 素材的換算基準因此不會分家。
@@ -1700,6 +1721,7 @@ async function runConfigUnits(configPath) {
1700
1721
  externalsDir: compileDir,
1701
1722
  irPath,
1702
1723
  settingsPath,
1724
+ pluginsPath,
1703
1725
  unitOutDir: targetOutDir,
1704
1726
  unitName,
1705
1727
  installRoot: MODE === 'export' ? targetOutDir : resolved.installRoot,
@@ -1724,7 +1746,7 @@ async function runConfigUnits(configPath) {
1724
1746
  *
1725
1747
  * 由 `src/cli/main.ts` 轉發呼叫。本檔被 import 而不呼叫本函式時(監看的求值
1726
1748
  * 子行程),上方那批模組層狀態維持初始值、不執行任何命令列行為 ── 那正是子
1727
- * 行程要的:它只取用 `distributeTarget` 與 `writeSettingsFile`。
1749
+ * 行程要的:它只取用 `distributeTarget`、`writeSettingsFile` 與 `writePluginsFile`。
1728
1750
  *
1729
1751
  * 賦值順序與此前的模組層敘述逐條相同:`configAction` 要早於 `parseCliArgs`
1730
1752
  * (後者讀它判斷第二個位置參數是否合法),`config` 分派要早於動詞白名單檢查
@@ -1827,6 +1849,8 @@ export async function main(argv) {
1827
1849
  let watchTargetPlan = null;
1828
1850
  // 單一目錄模式沒有配置檔、也就沒有 target 可宣告平台原生設定(ADR-006)。
1829
1851
  let watchSettings = null;
1852
+ // 平台 plugin 同理只住目標(ADR-044)。
1853
+ let watchPlugins = null;
1830
1854
  // 單元的範圍(AC-538):單一目錄模式固定專案層,配置單元模式取解析結果。
1831
1855
  let watchScope = 'project';
1832
1856
  if (existsSync(configPath)) {
@@ -1858,7 +1882,8 @@ export async function main(argv) {
1858
1882
  }
1859
1883
  ;
1860
1884
  ({ promptDir: watchPromptDir, root: watchRoot, platform: watchPlatform, unitName: watchUnit,
1861
- installRoot: watchInstallRoot, targetPlan: watchTargetPlan, settings: watchSettings, opts: watchOpts } = target);
1885
+ installRoot: watchInstallRoot, targetPlan: watchTargetPlan, settings: watchSettings, plugins: watchPlugins,
1886
+ opts: watchOpts } = target);
1862
1887
  watchScope = resolution.units.find((u) => u.name === watchUnit)?.scope ?? 'project';
1863
1888
  // 素材相對路徑的換算基準是專案根(配置檔所在目錄),與 runConfigUnits
1864
1889
  // 呼叫核心時傳的 sourceRoot 同一個值:監看沿用安裝流程,不另立一套換算
@@ -1894,6 +1919,7 @@ export async function main(argv) {
1894
1919
  installRoot: watchInstallRoot,
1895
1920
  targetPlan: watchTargetPlan,
1896
1921
  settings: watchSettings,
1922
+ plugins: watchPlugins,
1897
1923
  mode: MODE,
1898
1924
  scope: watchScope,
1899
1925
  },
@@ -106,7 +106,7 @@ async function unitDef() {
106
106
  * 作者改完檔案永遠等不到下一輪)。本輪安裝成功與否由行程的結束碼帶回。
107
107
  */
108
108
  async function installTarget(unit, result, spec) {
109
- const { distributeTarget, writeSettingsFile } = await import('./main.js');
109
+ const { distributeTarget, writePluginsFile, writeSettingsFile } = await import('./main.js');
110
110
  const { engine } = await import('../index.js');
111
111
  // 無配置檔時目標就是命令列指定的那個平台,沒有 emit 也沒有 extend;有配置
112
112
  // 檔時取回作者宣告的那一筆(帶不經序列化的閉包)。
@@ -124,6 +124,8 @@ async function installTarget(unit, result, spec) {
124
124
  // 平台設定由父行程從核心的單元解析結果帶過來(ADR-006「平台設定住目標」),
125
125
  // 不由本輪求值產出:它是配置的宣告,重新求值不會改變它。
126
126
  settingsPath: writeSettingsFile(workDir, spec.settings ?? null),
127
+ // 平台 plugin 宣告與平台設定同一條(ADR-044),分開成另一份旁置檔。
128
+ pluginsPath: writePluginsFile(workDir, spec.plugins ?? null),
127
129
  externalsPath: result.externalsPath,
128
130
  unitOutDir: spec.root,
129
131
  unitName: spec.unitName,
package/dist/cli/watch.js CHANGED
@@ -291,6 +291,8 @@ export function resolveWatchTarget(resolved, rawUnits = []) {
291
291
  // 平台原生設定隨單元的解析結果一起帶過去(ADR-006「平台設定住目標」):
292
292
  // 監看沿用安裝流程,設定的來源因此也與 安裝模式(`--install`)同一個。
293
293
  settings: only.settings ?? null,
294
+ // 平台 plugin 宣告同理(ADR-044)。
295
+ plugins: only.plugins ?? null,
294
296
  opts: {
295
297
  select: rawUnits[target.unitIndex]?.select,
296
298
  externals: target.evaluationExternals,
@@ -1,5 +1,5 @@
1
1
  /** 核心的格式版本(`crates/promptex-core/src/graph.rs` 的 `FORMAT_VERSION`),不載入原生綁定即可取得。 */
2
- export declare const FORMAT_VERSION = "1.1";
2
+ export declare const FORMAT_VERSION = "1.2";
3
3
  export type Ecosystem = 'js' | 'py' | 'rs';
4
4
  export interface VerbSpec {
5
5
  name: string;
@@ -4,7 +4,7 @@
4
4
  // crates/promptex-core/src/graph.rs 的 FORMAT_VERSION。要改內容就改來源,
5
5
  // 再跑 `pnpm run gen:cli-contract` 重新生成;直接改本檔會被核對閘擋下。
6
6
  /** 核心的格式版本(`crates/promptex-core/src/graph.rs` 的 `FORMAT_VERSION`),不載入原生綁定即可取得。 */
7
- export const FORMAT_VERSION = '1.1';
7
+ export const FORMAT_VERSION = '1.2';
8
8
  export const VERBS = [
9
9
  {
10
10
  name: 'build',
package/dist/config.d.ts CHANGED
@@ -80,16 +80,49 @@ export interface Target {
80
80
  readonly extend?: readonly AdapterExtension[];
81
81
  /** 該平台的原生設定;鍵值逐字寫入該平台的設定檔。 */
82
82
  readonly settings?: Record<string, unknown>;
83
+ /**
84
+ * 平台 plugin 的分組(ADR-044),只有內建 `claude()`/`codex()` 收這個選項;
85
+ * 第三方適配(`defineTarget`)不提供它,核心對第三方目標的宣告以 E219 阻斷。
86
+ */
87
+ readonly plugins?: readonly PlatformPlugin[];
88
+ }
89
+ /**
90
+ * 目標上的一個平台 plugin(ADR-044):把一組節點打包成平台原生的 plugin。
91
+ *
92
+ * `select` 沿用單元的 `SelectSpec`,但只決定歸屬:它在單元的 `select` 已選出的
93
+ * 節點裡分組,選不到單元沒選的節點。沒被任何 plugin 選到的節點照常各自安裝;
94
+ * 一個節點在同一目標最多屬於一個 plugin。
95
+ *
96
+ * 這和單元的 `plugins`(解析期擴充,`Plugin`)是兩件事:這裡的產物是平台的 plugin
97
+ * 目錄,那裡是解析節點時執行的擴充。
98
+ */
99
+ export interface PlatformPlugin {
100
+ /** plugin 名稱:小寫英數加 `-`,長度 1 至 64,不含 `--`,不用 Claude 保留名。 */
101
+ readonly name: string;
102
+ /** 版本字串,不核對格式;省略時不寫進 manifest。 */
103
+ readonly version?: string;
104
+ readonly description?: string;
105
+ readonly select: SelectSpec;
106
+ /** 原樣帶進 manifest 的其他欄位;不得覆寫框架產生的鍵(name、元件路徑等)。 */
107
+ readonly manifest?: Record<string, unknown>;
108
+ /** mod 的 hooks module 路徑,相對 plugin 根目錄,指向同一個 plugin 內 dir 節點的檔案(只屬於 Claude)。 */
109
+ readonly modules?: string;
83
110
  }
111
+ /** codex 目標的平台 plugin:mod 只屬於 Claude,因此沒有 `modules`。 */
112
+ export type CodexPlatformPlugin = Omit<PlatformPlugin, 'modules'>;
84
113
  /** claude target 建構器的選項。 */
85
114
  export interface ClaudeTargetOptions {
86
115
  readonly extend?: readonly AdapterExtension[];
87
116
  readonly settings?: ClaudeSettings;
117
+ /** 打包成 Claude plugin 的節點分組(ADR-044)。 */
118
+ readonly plugins?: readonly PlatformPlugin[];
88
119
  }
89
120
  /** codex target 建構器的選項。 */
90
121
  export interface CodexTargetOptions {
91
122
  readonly extend?: readonly AdapterExtension[];
92
123
  readonly settings?: CodexSettings;
124
+ /** 打包成 Codex plugin 的節點分組(ADR-044)。 */
125
+ readonly plugins?: readonly CodexPlatformPlugin[];
93
126
  }
94
127
  /** claude target 建構器:求值為 `{ platform: 'claude' }`(AC-086),可選帶 `extend` 擴充既有平台的產物形態、`settings` 宣告平台原生設定。 */
95
128
  export declare const claude: (options?: ClaudeTargetOptions) => Target;
@@ -190,6 +223,16 @@ export interface TargetIR {
190
223
  readonly settings?: Record<string, unknown>;
191
224
  readonly configSchema?: unknown;
192
225
  readonly configSchemaLocales?: Record<string, unknown>;
226
+ readonly plugins?: readonly PlatformPluginIR[];
227
+ }
228
+ /** 中介表示裡的一個平台 plugin:欄位順序與核心的 `PluginDecl` 相同,三語言逐字一致。 */
229
+ export interface PlatformPluginIR {
230
+ readonly name: string;
231
+ readonly version?: string;
232
+ readonly description?: string;
233
+ readonly select: SelectSpec;
234
+ readonly manifest?: Record<string, unknown>;
235
+ readonly modules?: string;
193
236
  }
194
237
  /** 中介表示裡的一個擴充:求值期的名字,加上它的參數宣告(ADR-013) */
195
238
  export interface PluginIR {
package/dist/config.js CHANGED
@@ -13,6 +13,7 @@ function builtinTarget(platform, options) {
13
13
  platform,
14
14
  ...(options?.extend?.length ? { extend: options.extend } : {}),
15
15
  ...(options?.settings ? { settings: options.settings } : {}),
16
+ ...(options?.plugins?.length ? { plugins: options.plugins } : {}),
16
17
  };
17
18
  }
18
19
  /** claude target 建構器:求值為 `{ platform: 'claude' }`(AC-086),可選帶 `extend` 擴充既有平台的產物形態、`settings` 宣告平台原生設定。 */
@@ -35,6 +36,20 @@ export function isExternalConfigRef(spec) {
35
36
  export function defineConfig(unit) {
36
37
  return Array.isArray(unit) ? [...unit] : [unit];
37
38
  }
39
+ /** 平台 plugin → 中介表示:鍵序固定、省略的欄位不帶,`select` 只留宣告了的兩個欄位。 */
40
+ function platformPluginToIR(p) {
41
+ return {
42
+ name: p.name,
43
+ ...(p.version !== undefined ? { version: p.version } : {}),
44
+ ...(p.description !== undefined ? { description: p.description } : {}),
45
+ select: {
46
+ ...(p.select.tags !== undefined ? { tags: p.select.tags } : {}),
47
+ ...(p.select.exclude !== undefined ? { exclude: p.select.exclude } : {}),
48
+ },
49
+ ...(p.manifest !== undefined ? { manifest: p.manifest } : {}),
50
+ ...(p.modules !== undefined ? { modules: p.modules } : {}),
51
+ };
52
+ }
38
53
  /**
39
54
  * 命令列工具交給核心編排入口的配置形態(ADR-008 協作形態第 1 步)。
40
55
  *
@@ -67,6 +82,9 @@ export function configToOrchestrationIR(units) {
67
82
  ...(t.settings ? { settings: t.settings } : {}),
68
83
  ...(t.configSchema !== undefined ? { configSchema: t.configSchema } : {}),
69
84
  ...(t.configSchemaLocales ? { configSchemaLocales: t.configSchemaLocales } : {}),
85
+ // 平台 plugin 是純資料(ADR-044),進中介表示交給核心分組;無宣告時不帶這一鍵,
86
+ // 未使用它的既有配置求值結果逐字不變。
87
+ ...(t.plugins?.length ? { plugins: t.plugins.map(platformPluginToIR) } : {}),
70
88
  })),
71
89
  // 擴充帶名字與它的參數宣告(ADR-013):宣告由擴充自己 import 進來,隨中介表示
72
90
  // 交給讀取端,讀取端因此不必知道它裝在哪裡。未宣告時該欄省略而非填 null:
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export type { Content, ContentPiece, Ref, SelectSpec } from './registry.js';
3
3
  export type { Ir, Kind, Node, Piece, Provenance, RefTarget } from './ir.js';
4
4
  export type { MDNode } from './content.js';
5
5
  export { engine, registerExternal } from './registry.js';
6
- export { claude, codex, configToIR, configToOrchestrationIR, defineConfig, isExternalConfigRef, type AdapterExtension, type ClaudeSettings, type ClaudeTargetOptions, type CodexSettings, type CodexTargetOptions, type ConfigIr, type ConfigUnit, type ConfigUnitIR, type ExternalConfigRef, type ExternalEntry as ConfigExternalEntry, type ExternalSpec, type Target, } from './config.js';
6
+ export { claude, codex, configToIR, configToOrchestrationIR, defineConfig, isExternalConfigRef, type AdapterExtension, type ClaudeSettings, type ClaudeTargetOptions, type CodexSettings, type CodexPlatformPlugin, type CodexTargetOptions, type ConfigIr, type ConfigUnit, type ConfigUnitIR, type ExternalConfigRef, type ExternalEntry as ConfigExternalEntry, type ExternalSpec, type PlatformPlugin, type PlatformPluginIR, type Target, } from './config.js';
7
7
  export type { ManifestNode, ManifestQuery } from './externals.js';
8
8
  export { readConfig, REFUSAL_MESSAGES, declaredSchema, RefusalError, SCHEMA_FILE, writeConfig, type ConfigView, type Entry, type EntryField, type ImportStyle, type Op, type Refusal, type RefusalCode, type RewriteOutcome, type UnitView, } from './config-rewrite.js';
9
9
  export type { LockEntry, Plugin, PluginEntry, PrepareContext, TransformContext, ValidateContext } from './plugin.js';
package/dist/native.d.ts CHANGED
@@ -17,9 +17,15 @@
17
17
  */
18
18
  export interface NativeCore {
19
19
  /** 編譯:完整投影計算,只寫框架中繼、不落平台產物(ADR-028)。 */
20
- build(irJson: string, root: string, platform: string, settingsJson: string | null | undefined, externalsJson: string | null | undefined, unit: string | null | undefined, locale: string, scope?: string | null): string;
20
+ build(irJson: string, root: string, platform: string, settingsJson: string | null | undefined, externalsJson: string | null | undefined, unit: string | null | undefined, locale: string, scope?: string | null,
21
+ /** 旁置的平台 plugin 宣告(`{ 平台名: [宣告] }`,ADR-044)。 */
22
+ pluginsJson?: string | null,
23
+ /** 只用來核對平台 plugin 的 `modules` 檔案存在;本動詞不拷貝素材。 */
24
+ sourceRoot?: string | null): string;
21
25
  /** 安裝/預覽/查詢:`mode` 決定副作用範圍。 */
22
- distribute(mode: string, irJson: string, root: string, platform: string, sourceRoot: string, settingsJson: string | null | undefined, unit: string, externalsJson: string | null | undefined, locale: string, scope?: string | null): string;
26
+ distribute(mode: string, irJson: string, root: string, platform: string, sourceRoot: string, settingsJson: string | null | undefined, unit: string, externalsJson: string | null | undefined, locale: string, scope?: string | null,
27
+ /** 旁置的平台 plugin 宣告(ADR-044)。 */
28
+ pluginsJson?: string | null): string;
23
29
  /** 第三方適配的產物落地(AC-244):`emit` 回傳的檔案表交回核心。 */
24
30
  thirdPartyDistribute(mode: string, filesJson: string, irJson: string, reportJson: string, root: string, unit: string, platform: string, locale: string): string;
25
31
  /**
@@ -31,7 +37,9 @@ export interface NativeCore {
31
37
  */
32
38
  projectionTree(mode: string, root: string, irJson: string, platform: string, sourceRoot: string, settingsJson: string | null | undefined, externalsJson: string | null | undefined, unit: string | null | undefined, locale: string,
33
39
  /** 單元的範圍(`user`/`project`,AC-538);省略時視為專案層。 */
34
- scope?: string | null): string;
40
+ scope?: string | null,
41
+ /** 旁置的平台 plugin 宣告(ADR-044)。 */
42
+ pluginsJson?: string | null): string;
35
43
  /** 平台擴充的落地:比對擴充前後的產物樹並寫入。 */
36
44
  extensionApply(mode: string, root: string, unit: string, platform: string, beforeJson: string, afterJson: string, baselineJson: string, locale: string): string;
37
45
  /** 人讀版面(ADR-030):版面住核心,三個生態印出同一份。 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptex-js",
3
- "version": "1.1.1-rc.2",
3
+ "version": "1.2.0",
4
4
  "description": "TypeScript SDK、核心的預編譯二進位綁定與命令列工具,三者為同一次發布產出",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "promptex-ai",
@@ -74,11 +74,11 @@
74
74
  "vitest": "^4.1.11"
75
75
  },
76
76
  "optionalDependencies": {
77
- "promptex-js-darwin-arm64": "1.1.1-rc.2",
78
- "promptex-js-darwin-x64": "1.1.1-rc.2",
79
- "promptex-js-linux-arm64-gnu": "1.1.1-rc.2",
80
- "promptex-js-linux-x64-gnu": "1.1.1-rc.2",
81
- "promptex-js-win32-arm64-msvc": "1.1.1-rc.2",
82
- "promptex-js-win32-x64-msvc": "1.1.1-rc.2"
77
+ "promptex-js-darwin-arm64": "1.2.0",
78
+ "promptex-js-darwin-x64": "1.2.0",
79
+ "promptex-js-linux-arm64-gnu": "1.2.0",
80
+ "promptex-js-linux-x64-gnu": "1.2.0",
81
+ "promptex-js-win32-arm64-msvc": "1.2.0",
82
+ "promptex-js-win32-x64-msvc": "1.2.0"
83
83
  }
84
84
  }