@agimon-ai/po-config 0.0.0-alpha.2 → 0.0.0-alpha.21
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/LICENSE +149 -21
- package/README.md +11 -11
- package/dist/agentPluginMcp.cjs +313 -134
- package/dist/agentPluginMcp.cjs.map +1 -1
- package/dist/agentPluginMcp.d.mts +22 -4
- package/dist/agentPluginMcp.d.mts.map +1 -1
- package/dist/agentPluginMcp.mjs +312 -134
- package/dist/agentPluginMcp.mjs.map +1 -1
- package/dist/apiContracts.cjs.map +1 -1
- package/dist/apiContracts.mjs.map +1 -1
- package/dist/atomicJson-D3MHqnLW.cjs +59 -0
- package/dist/atomicJson-D3MHqnLW.cjs.map +1 -0
- package/dist/atomicJson-Dj3rlZbD.mjs +40 -0
- package/dist/atomicJson-Dj3rlZbD.mjs.map +1 -0
- package/dist/atomicJson.cjs +4 -2
- package/dist/atomicJson.d.mts +2 -2
- package/dist/atomicJson.mjs +3 -2
- package/dist/{index-BT29GZx5.d.mts → completion-Ba0TiBHa.d.mts} +58 -27
- package/dist/completion-Ba0TiBHa.d.mts.map +1 -0
- package/dist/config-BBvn_ZLP.mjs +1 -0
- package/dist/config-Cdybp9rT.cjs +155 -0
- package/dist/config-Cdybp9rT.cjs.map +1 -0
- package/dist/config-Cxc2xw54.mjs +112 -0
- package/dist/config-Cxc2xw54.mjs.map +1 -0
- package/dist/{config-D2HbBLzo.d.mts → config-pxC7FyUJ.d.mts} +33 -33
- package/dist/config-pxC7FyUJ.d.mts.map +1 -0
- package/dist/config.cjs +21 -17
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +4 -3
- package/dist/{configPolicy-Ce1QKDxa.cjs → configPolicy-CowlLhK1.cjs} +99 -99
- package/dist/configPolicy-CowlLhK1.cjs.map +1 -0
- package/dist/{configPolicy-DCQgF5-f.mjs → configPolicy-DueX0k6i.mjs} +84 -84
- package/dist/configPolicy-DueX0k6i.mjs.map +1 -0
- package/dist/configSchema.d.mts +2 -2
- package/dist/configWriter-DCASRzr-.mjs +180 -0
- package/dist/configWriter-DCASRzr-.mjs.map +1 -0
- package/dist/configWriter-DGO0gmXo.cjs +218 -0
- package/dist/configWriter-DGO0gmXo.cjs.map +1 -0
- package/dist/configWriter.cjs +7 -4
- package/dist/configWriter.d.mts +2 -2
- package/dist/configWriter.mjs +1 -2
- package/dist/core-B0Qg0Qq2.cjs +224 -0
- package/dist/core-B0Qg0Qq2.cjs.map +1 -0
- package/dist/core-DKWW9gkh.mjs +139 -0
- package/dist/core-DKWW9gkh.mjs.map +1 -0
- package/dist/{domains-DGCb7uMC.cjs → domains-CiDUsRiX.cjs} +473 -171
- package/dist/domains-CiDUsRiX.cjs.map +1 -0
- package/dist/{domains-BroCVHrS.mjs → domains-IlieGHaY.mjs} +437 -170
- package/dist/domains-IlieGHaY.mjs.map +1 -0
- package/dist/domains.cjs +9 -3
- package/dist/domains.d.mts +3 -3
- package/dist/domains.mjs +3 -3
- package/dist/extensions/mcp-ui.mjs +1 -1
- package/dist/extensions/mcp-ui.mjs.map +1 -1
- package/dist/extensions/mcp.cjs +3 -3
- package/dist/extensions/mcp.cjs.map +1 -1
- package/dist/extensions/mcp.d.mts +1 -1
- package/dist/extensions/mcp.mjs +2 -2
- package/dist/extensions/mcp.mjs.map +1 -1
- package/dist/extensions/server.cjs +55 -47
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts +2 -2
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +56 -48
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/{harnessState-Dn_S7fB9.mjs → harnessState-8lZda_8r.mjs} +2 -2
- package/dist/{harnessState-Dn_S7fB9.mjs.map → harnessState-8lZda_8r.mjs.map} +1 -1
- package/dist/{harnessState-CCyBeutB.cjs → harnessState-BrmH0lG5.cjs} +2 -2
- package/dist/{harnessState-CCyBeutB.cjs.map → harnessState-BrmH0lG5.cjs.map} +1 -1
- package/dist/harnessState.cjs +1 -1
- package/dist/harnessState.d.mts +1 -1
- package/dist/harnessState.mjs +1 -2
- package/dist/{harnessStore-CJSxdSkV.cjs → harnessStore-BinxGITh.cjs} +189 -81
- package/dist/harnessStore-BinxGITh.cjs.map +1 -0
- package/dist/{harnessStore-CltwLB7M.mjs → harnessStore-w8zHmJ_H.mjs} +160 -82
- package/dist/harnessStore-w8zHmJ_H.mjs.map +1 -0
- package/dist/harnessStore.cjs +6 -1
- package/dist/harnessStore.d.mts +2 -2
- package/dist/harnessStore.mjs +1 -2
- package/dist/index-7RuIAWX1.d.mts +63 -0
- package/dist/index-7RuIAWX1.d.mts.map +1 -0
- package/dist/{index-CkDDvVQt.d.mts → index-BNcG0voG.d.mts} +61 -16
- package/dist/index-BNcG0voG.d.mts.map +1 -0
- package/dist/{index-Dy_-m7gx.d.mts → index-BTOU4XiI.d.mts} +3 -3
- package/dist/{index-Dy_-m7gx.d.mts.map → index-BTOU4XiI.d.mts.map} +1 -1
- package/dist/index-COokUToB.d.mts +83 -0
- package/dist/index-COokUToB.d.mts.map +1 -0
- package/dist/index-D3vGEYup.d.mts +135 -0
- package/dist/index-D3vGEYup.d.mts.map +1 -0
- package/dist/{index-Ch7ptOkW.d.mts → index-DNEK9W6n.d.mts} +26 -16
- package/dist/index-DNEK9W6n.d.mts.map +1 -0
- package/dist/index-D_OtYtsl.d.mts +37 -0
- package/dist/index-D_OtYtsl.d.mts.map +1 -0
- package/dist/{index-DNk4q0Qm.d.mts → index-Nbj2iQWw.d.mts} +19 -25
- package/dist/index-Nbj2iQWw.d.mts.map +1 -0
- package/dist/{index-CEUc7m16.d.mts → index-dYgF03lE.d.mts} +82 -32
- package/dist/index-dYgF03lE.d.mts.map +1 -0
- package/dist/index-fTuf8tVH.d.mts +34 -0
- package/dist/index-fTuf8tVH.d.mts.map +1 -0
- package/dist/index-nVcEC1jO.d.mts +62 -0
- package/dist/index-nVcEC1jO.d.mts.map +1 -0
- package/dist/index.cjs +81 -59
- package/dist/index.d.mts +16 -15
- package/dist/index.mjs +17 -15
- package/dist/{init-Cd3Ki6Ub.cjs → init-BdZ-gqqk.cjs} +209 -59
- package/dist/init-BdZ-gqqk.cjs.map +1 -0
- package/dist/{init-DVzhiCUE.mjs → init-DG7MxGxC.mjs} +187 -48
- package/dist/init-DG7MxGxC.mjs.map +1 -0
- package/dist/init.cjs +8 -6
- package/dist/init.d.mts +2 -2
- package/dist/init.mjs +1 -2
- package/dist/layeredConfig-BbkoIEfM.mjs +95 -0
- package/dist/layeredConfig-BbkoIEfM.mjs.map +1 -0
- package/dist/layeredConfig-Bs18dXQG.cjs +127 -0
- package/dist/layeredConfig-Bs18dXQG.cjs.map +1 -0
- package/dist/layeredConfig.cjs +5 -4
- package/dist/layeredConfig.d.mts +7 -2
- package/dist/layeredConfig.d.mts.map +1 -0
- package/dist/layeredConfig.mjs +1 -2
- package/dist/{majorModes-D1Itd8SN.mjs → majorModes-B8Km83e1.mjs} +130 -23
- package/dist/majorModes-B8Km83e1.mjs.map +1 -0
- package/dist/{majorModes-DnNSH9ZK.cjs → majorModes-CLccNMZt.cjs} +147 -22
- package/dist/majorModes-CLccNMZt.cjs.map +1 -0
- package/dist/majorModes.cjs +4 -1
- package/dist/majorModes.d.mts +2 -2
- package/dist/majorModes.mjs +1 -2
- package/dist/{piConfig-qGyCbcVj.mjs → piConfig-Bq36PQFF.mjs} +104 -69
- package/dist/piConfig-Bq36PQFF.mjs.map +1 -0
- package/dist/{piConfig-Bx26HMb_.d.mts → piConfig-C9rGUqPe.d.mts} +3 -3
- package/dist/{piConfig-Bx26HMb_.d.mts.map → piConfig-C9rGUqPe.d.mts.map} +1 -1
- package/dist/{piConfig-CCBdZXQr.cjs → piConfig-cluCie5i.cjs} +122 -70
- package/dist/piConfig-cluCie5i.cjs.map +1 -0
- package/dist/piConfig.cjs +4 -1
- package/dist/piConfig.d.mts +2 -2
- package/dist/piConfig.mjs +1 -2
- package/dist/piContext.cjs +27 -16
- package/dist/piContext.d.mts +3 -3
- package/dist/piContext.mjs +1 -2
- package/dist/{profiles-DBcYg5nA.mjs → profiles-CHict0x-.mjs} +322 -101
- package/dist/profiles-CHict0x-.mjs.map +1 -0
- package/dist/{profiles-tpplXY4r.cjs → profiles-t2EUj0aB.cjs} +359 -102
- package/dist/profiles-t2EUj0aB.cjs.map +1 -0
- package/dist/profiles.cjs +7 -1
- package/dist/profiles.d.mts +27 -3
- package/dist/profiles.d.mts.map +1 -1
- package/dist/profiles.mjs +1 -2
- package/dist/selectionSwitch.cjs +88 -22
- package/dist/selectionSwitch.cjs.map +1 -1
- package/dist/selectionSwitch.d.mts +40 -18
- package/dist/selectionSwitch.d.mts.map +1 -1
- package/dist/selectionSwitch.mjs +85 -22
- package/dist/selectionSwitch.mjs.map +1 -1
- package/dist/{sessionConfig-DV5xTRRw.mjs → sessionConfig-DFQF618G.mjs} +48 -47
- package/dist/sessionConfig-DFQF618G.mjs.map +1 -0
- package/dist/{sessionConfig-Bf6xHWLd.cjs → sessionConfig-DeP6pplT.cjs} +74 -85
- package/dist/sessionConfig-DeP6pplT.cjs.map +1 -0
- package/dist/sync-BJ8gCP9s.mjs +29 -0
- package/dist/sync-BJ8gCP9s.mjs.map +1 -0
- package/dist/sync-CC_15kkB.d.mts +46 -0
- package/dist/sync-CC_15kkB.d.mts.map +1 -0
- package/dist/sync-Dlxz2msM.cjs +37 -0
- package/dist/sync-Dlxz2msM.cjs.map +1 -0
- package/dist/types.cjs +2 -2
- package/dist/types.d.mts +2 -2
- package/dist/types.mjs +1 -2
- package/llms.txt +1 -1
- package/package.json +16 -16
- package/src/prompts/po-author-config/SKILL.md +4 -4
- package/src/prompts/po-author-config/agents/openai.yaml +1 -1
- package/src/prompts/po-author-config/references/config-contract.md +5 -5
- package/dist/atomicJson-1W0WhuFF.mjs +0 -44
- package/dist/atomicJson-1W0WhuFF.mjs.map +0 -1
- package/dist/atomicJson-Dt2z_DXl.cjs +0 -52
- package/dist/atomicJson-Dt2z_DXl.cjs.map +0 -1
- package/dist/config-CfTb0_9G.cjs +0 -219
- package/dist/config-CfTb0_9G.cjs.map +0 -1
- package/dist/config-D2HbBLzo.d.mts.map +0 -1
- package/dist/config-DoQWSt1V.mjs +0 -162
- package/dist/config-DoQWSt1V.mjs.map +0 -1
- package/dist/config-NSHRd6na.mjs +0 -2
- package/dist/configPolicy-Ce1QKDxa.cjs.map +0 -1
- package/dist/configPolicy-DCQgF5-f.mjs.map +0 -1
- package/dist/configWriter-B7uO8MuN.cjs +0 -150
- package/dist/configWriter-B7uO8MuN.cjs.map +0 -1
- package/dist/configWriter-DUtLgOlD.mjs +0 -130
- package/dist/configWriter-DUtLgOlD.mjs.map +0 -1
- package/dist/domains-BroCVHrS.mjs.map +0 -1
- package/dist/domains-DGCb7uMC.cjs.map +0 -1
- package/dist/harnessStore-CJSxdSkV.cjs.map +0 -1
- package/dist/harnessStore-CltwLB7M.mjs.map +0 -1
- package/dist/index-78zvoS9s.d.mts +0 -35
- package/dist/index-78zvoS9s.d.mts.map +0 -1
- package/dist/index-BT29GZx5.d.mts.map +0 -1
- package/dist/index-C6GaYjq-.d.mts +0 -6
- package/dist/index-C6GaYjq-.d.mts.map +0 -1
- package/dist/index-CEUc7m16.d.mts.map +0 -1
- package/dist/index-CRcoVYXz.d.mts +0 -39
- package/dist/index-CRcoVYXz.d.mts.map +0 -1
- package/dist/index-CVlciCJF.d.mts +0 -40
- package/dist/index-CVlciCJF.d.mts.map +0 -1
- package/dist/index-Ch7ptOkW.d.mts.map +0 -1
- package/dist/index-CkDDvVQt.d.mts.map +0 -1
- package/dist/index-Cvdt-Y-i.d.mts +0 -66
- package/dist/index-Cvdt-Y-i.d.mts.map +0 -1
- package/dist/index-DNk4q0Qm.d.mts.map +0 -1
- package/dist/index-DdH0w56b.d.mts +0 -116
- package/dist/index-DdH0w56b.d.mts.map +0 -1
- package/dist/init-Cd3Ki6Ub.cjs.map +0 -1
- package/dist/init-DVzhiCUE.mjs.map +0 -1
- package/dist/layeredConfig-fukqN2EA.mjs +0 -67
- package/dist/layeredConfig-fukqN2EA.mjs.map +0 -1
- package/dist/layeredConfig-ol0274TN.cjs +0 -94
- package/dist/layeredConfig-ol0274TN.cjs.map +0 -1
- package/dist/majorModes-D1Itd8SN.mjs.map +0 -1
- package/dist/majorModes-DnNSH9ZK.cjs.map +0 -1
- package/dist/piConfig-CCBdZXQr.cjs.map +0 -1
- package/dist/piConfig-qGyCbcVj.mjs.map +0 -1
- package/dist/profiles-DBcYg5nA.mjs.map +0 -1
- package/dist/profiles-tpplXY4r.cjs.map +0 -1
- package/dist/sessionConfig-Bf6xHWLd.cjs.map +0 -1
- package/dist/sessionConfig-DV5xTRRw.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: po-author-config
|
|
3
|
-
description: Configure Po runtime settings, source precedence, and typed session configuration. Use for config.yaml, the
|
|
3
|
+
description: Configure Po runtime settings, source precedence, and typed session configuration. Use for config.yaml, the po/config Cordis service, immutable context snapshots, or shared selection transition state. Do not use for defining modes.yaml, domains.yaml, or profiles.yaml.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Author Po runtime configuration
|
|
@@ -10,16 +10,16 @@ Configure runtime policy in `config.yaml` and consume one immutable session snap
|
|
|
10
10
|
## Workflow
|
|
11
11
|
|
|
12
12
|
1. Read both `~/.po/config.yaml` and the repository's `.po/config.yaml` before changing effective settings.
|
|
13
|
-
2. Check the `
|
|
13
|
+
2. Check the `PoConfig` types and parser before adding or editing a field. Unknown keys and invalid values fail early
|
|
14
14
|
everywhere a session reads config. `po sync` is the one exception: it reports an unknown key and carries on, so a
|
|
15
15
|
config written for another version cannot break a build. Invalid values for known keys still fail there too. Run
|
|
16
16
|
`po doctor` for the strict check.
|
|
17
17
|
3. Preserve field-specific source policy. Repository settings do not uniformly replace every personal setting.
|
|
18
|
-
4. Consume live state only inside an owning `cordis.inject([
|
|
18
|
+
4. Consume live state only inside an owning `cordis.inject([PO_CONFIG_SERVICE], ...)` callback, using `requirePoConfigContext(cordis)`.
|
|
19
19
|
5. Treat `settings`, `harness`, `pendingSelection`, and nested values as immutable. Do not mutate or cache a snapshot across session replacement.
|
|
20
20
|
6. Route live major-mode, domain, and profile changes through the transition coordinator. Keep append-only selection and transition entries consistent with the active harness.
|
|
21
21
|
7. Keep `process.env` as launcher transport and the controlled live-switch boundary, not as an alternative configuration registry.
|
|
22
|
-
8. Verify parsing and merge behavior with
|
|
22
|
+
8. Verify parsing and merge behavior with Po Config tests, then exercise `po --explain` and a real session when transition behavior changes.
|
|
23
23
|
|
|
24
24
|
Use the package-owned Major Mode, Domain, or Profile Help skill when the task is to define an axis in `modes.yaml`, `domains.yaml`, or `profiles.yaml`.
|
|
25
25
|
|
|
@@ -91,7 +91,7 @@ Autonomous capture is personal-only and belongs in `~/.po/config.yaml`:
|
|
|
91
91
|
voice:
|
|
92
92
|
autoCapture:
|
|
93
93
|
model: openai/gpt-4.1-mini
|
|
94
|
-
startPhrases: [hey
|
|
94
|
+
startPhrases: [hey po]
|
|
95
95
|
stopPhrases: [stop speaking]
|
|
96
96
|
utteranceIdleMs: 3000
|
|
97
97
|
transcriptionTimeoutMs: 120000
|
|
@@ -135,17 +135,17 @@ Merge behavior is field-specific:
|
|
|
135
135
|
mapping supplies the defaults. When the repository declares `selection`, its parsed mapping
|
|
136
136
|
replaces personal values for omitted axes as well as axes it sets.
|
|
137
137
|
|
|
138
|
-
Do not assume one generic deep-merge rule or copy this policy into consumers. Call `
|
|
138
|
+
Do not assume one generic deep-merge rule or copy this policy into consumers. Call `loadPoConfig`
|
|
139
139
|
or use the live service snapshot.
|
|
140
140
|
|
|
141
141
|
## Immutable Cordis context
|
|
142
142
|
|
|
143
|
-
`@agimon-ai/po-config/extensions/pi` provides `
|
|
143
|
+
`@agimon-ai/po-config/extensions/pi` provides `PO_CONFIG_SERVICE` on the runner's shared Cordis
|
|
144
144
|
session branch. Consume it inside an owning injection:
|
|
145
145
|
|
|
146
146
|
```ts
|
|
147
|
-
cordis.inject([
|
|
148
|
-
const snapshot =
|
|
147
|
+
cordis.inject([PO_CONFIG_SERVICE], (configContext) => {
|
|
148
|
+
const snapshot = requirePoConfigContext(configContext);
|
|
149
149
|
const settings = snapshot.settings;
|
|
150
150
|
const active = snapshot.harness;
|
|
151
151
|
const pending = snapshot.pendingSelection;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
//#region src/services/atomicJson/index.ts
|
|
5
|
-
/**
|
|
6
|
-
* Private atomic JSON writes.
|
|
7
|
-
*
|
|
8
|
-
* Write to a uniquely named temporary file in the destination directory, then
|
|
9
|
-
* rename onto the target. Rename is atomic within a filesystem, so a reader
|
|
10
|
-
* sees either the previous file or the complete new one and never a partial
|
|
11
|
-
* write. The temporary name carries the pid and a random suffix, so two
|
|
12
|
-
* processes writing the same target cannot collide on it.
|
|
13
|
-
*
|
|
14
|
-
* This prevents torn reads. It does NOT prevent lost updates: two writers doing
|
|
15
|
-
* read-modify-write still clobber each other, because the rename only publishes
|
|
16
|
-
* what the caller already computed. Harness state avoids that by giving every
|
|
17
|
-
* process a file it owns rather than by locking.
|
|
18
|
-
*
|
|
19
|
-
* AVOID:
|
|
20
|
-
* - Treating this as a lock
|
|
21
|
-
* - Leaving the temporary file behind when the write fails
|
|
22
|
-
*/
|
|
23
|
-
const PRIVATE_FILE_MODE = 384;
|
|
24
|
-
const PRIVATE_DIRECTORY_MODE = 448;
|
|
25
|
-
const TEMPORARY_SUFFIX = ".tmp";
|
|
26
|
-
/** Writes JSON readable by its owner only, replacing the target atomically. */
|
|
27
|
-
function writePrivateAtomicJson(filePath, value) {
|
|
28
|
-
fs.mkdirSync(path.dirname(filePath), {
|
|
29
|
-
mode: PRIVATE_DIRECTORY_MODE,
|
|
30
|
-
recursive: true
|
|
31
|
-
});
|
|
32
|
-
const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}${TEMPORARY_SUFFIX}`;
|
|
33
|
-
try {
|
|
34
|
-
fs.writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}\n`, { mode: PRIVATE_FILE_MODE });
|
|
35
|
-
fs.renameSync(temporaryPath, filePath);
|
|
36
|
-
} catch (error) {
|
|
37
|
-
fs.rmSync(temporaryPath, { force: true });
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
//#endregion
|
|
42
|
-
export { writePrivateAtomicJson as t };
|
|
43
|
-
|
|
44
|
-
//# sourceMappingURL=atomicJson-1W0WhuFF.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"atomicJson-1W0WhuFF.mjs","names":[],"sources":["../src/services/atomicJson/index.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/**\n * Private atomic JSON writes.\n *\n * Write to a uniquely named temporary file in the destination directory, then\n * rename onto the target. Rename is atomic within a filesystem, so a reader\n * sees either the previous file or the complete new one and never a partial\n * write. The temporary name carries the pid and a random suffix, so two\n * processes writing the same target cannot collide on it.\n *\n * This prevents torn reads. It does NOT prevent lost updates: two writers doing\n * read-modify-write still clobber each other, because the rename only publishes\n * what the caller already computed. Harness state avoids that by giving every\n * process a file it owns rather than by locking.\n *\n * AVOID:\n * - Treating this as a lock\n * - Leaving the temporary file behind when the write fails\n */\n\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst TEMPORARY_SUFFIX = '.tmp';\n\n/** Writes JSON readable by its owner only, replacing the target atomically. */\nexport function writePrivateAtomicJson(filePath: string, value: unknown): void {\n fs.mkdirSync(path.dirname(filePath), { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}${TEMPORARY_SUFFIX}`;\n try {\n fs.writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}\\n`, { mode: PRIVATE_FILE_MODE });\n fs.renameSync(temporaryPath, filePath);\n } catch (error) {\n fs.rmSync(temporaryPath, { force: true });\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,mBAAmB;;AAGzB,SAAgB,uBAAuB,UAAkB,OAAsB;CAC7E,GAAG,UAAU,KAAK,QAAQ,QAAQ,GAAG;EAAE,MAAM;EAAwB,WAAW;CAAK,CAAC;CACtF,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,IAAI,GAAG,WAAW,IAAI;CACnE,IAAI;EACF,GAAG,cAAc,eAAe,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;EAClG,GAAG,WAAW,eAAe,QAAQ;CACvC,SAAS,OAAO;EACd,GAAG,OAAO,eAAe,EAAE,OAAO,KAAK,CAAC;EACxC,MAAM;CACR;AACF"}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
let node_crypto = require("node:crypto");
|
|
3
|
-
let node_fs = require("node:fs");
|
|
4
|
-
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
5
|
-
let node_path = require("node:path");
|
|
6
|
-
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
7
|
-
//#region src/services/atomicJson/index.ts
|
|
8
|
-
/**
|
|
9
|
-
* Private atomic JSON writes.
|
|
10
|
-
*
|
|
11
|
-
* Write to a uniquely named temporary file in the destination directory, then
|
|
12
|
-
* rename onto the target. Rename is atomic within a filesystem, so a reader
|
|
13
|
-
* sees either the previous file or the complete new one and never a partial
|
|
14
|
-
* write. The temporary name carries the pid and a random suffix, so two
|
|
15
|
-
* processes writing the same target cannot collide on it.
|
|
16
|
-
*
|
|
17
|
-
* This prevents torn reads. It does NOT prevent lost updates: two writers doing
|
|
18
|
-
* read-modify-write still clobber each other, because the rename only publishes
|
|
19
|
-
* what the caller already computed. Harness state avoids that by giving every
|
|
20
|
-
* process a file it owns rather than by locking.
|
|
21
|
-
*
|
|
22
|
-
* AVOID:
|
|
23
|
-
* - Treating this as a lock
|
|
24
|
-
* - Leaving the temporary file behind when the write fails
|
|
25
|
-
*/
|
|
26
|
-
const PRIVATE_FILE_MODE = 384;
|
|
27
|
-
const PRIVATE_DIRECTORY_MODE = 448;
|
|
28
|
-
const TEMPORARY_SUFFIX = ".tmp";
|
|
29
|
-
/** Writes JSON readable by its owner only, replacing the target atomically. */
|
|
30
|
-
function writePrivateAtomicJson(filePath, value) {
|
|
31
|
-
node_fs.default.mkdirSync(node_path.default.dirname(filePath), {
|
|
32
|
-
mode: PRIVATE_DIRECTORY_MODE,
|
|
33
|
-
recursive: true
|
|
34
|
-
});
|
|
35
|
-
const temporaryPath = `${filePath}.${process.pid}.${(0, node_crypto.randomUUID)()}${TEMPORARY_SUFFIX}`;
|
|
36
|
-
try {
|
|
37
|
-
node_fs.default.writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}\n`, { mode: PRIVATE_FILE_MODE });
|
|
38
|
-
node_fs.default.renameSync(temporaryPath, filePath);
|
|
39
|
-
} catch (error) {
|
|
40
|
-
node_fs.default.rmSync(temporaryPath, { force: true });
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
Object.defineProperty(exports, "writePrivateAtomicJson", {
|
|
46
|
-
enumerable: true,
|
|
47
|
-
get: function() {
|
|
48
|
-
return writePrivateAtomicJson;
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
//# sourceMappingURL=atomicJson-Dt2z_DXl.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"atomicJson-Dt2z_DXl.cjs","names":["path","randomUUID"],"sources":["../src/services/atomicJson/index.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/**\n * Private atomic JSON writes.\n *\n * Write to a uniquely named temporary file in the destination directory, then\n * rename onto the target. Rename is atomic within a filesystem, so a reader\n * sees either the previous file or the complete new one and never a partial\n * write. The temporary name carries the pid and a random suffix, so two\n * processes writing the same target cannot collide on it.\n *\n * This prevents torn reads. It does NOT prevent lost updates: two writers doing\n * read-modify-write still clobber each other, because the rename only publishes\n * what the caller already computed. Harness state avoids that by giving every\n * process a file it owns rather than by locking.\n *\n * AVOID:\n * - Treating this as a lock\n * - Leaving the temporary file behind when the write fails\n */\n\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst TEMPORARY_SUFFIX = '.tmp';\n\n/** Writes JSON readable by its owner only, replacing the target atomically. */\nexport function writePrivateAtomicJson(filePath: string, value: unknown): void {\n fs.mkdirSync(path.dirname(filePath), { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}${TEMPORARY_SUFFIX}`;\n try {\n fs.writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}\\n`, { mode: PRIVATE_FILE_MODE });\n fs.renameSync(temporaryPath, filePath);\n } catch (error) {\n fs.rmSync(temporaryPath, { force: true });\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,mBAAmB;;AAGzB,SAAgB,uBAAuB,UAAkB,OAAsB;CAC7E,QAAA,QAAG,UAAUA,UAAAA,QAAK,QAAQ,QAAQ,GAAG;EAAE,MAAM;EAAwB,WAAW;CAAK,CAAC;CACtF,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,IAAI,IAAA,GAAGC,YAAAA,WAAAA,CAAW,IAAI;CACnE,IAAI;EACF,QAAA,QAAG,cAAc,eAAe,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;EAClG,QAAA,QAAG,WAAW,eAAe,QAAQ;CACvC,SAAS,OAAO;EACd,QAAA,QAAG,OAAO,eAAe,EAAE,OAAO,KAAK,CAAC;EACxC,MAAM;CACR;AACF"}
|
package/dist/config-CfTb0_9G.cjs
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_configPolicy = require("./configPolicy-Ce1QKDxa.cjs");
|
|
3
|
-
let node_crypto = require("node:crypto");
|
|
4
|
-
let node_fs = require("node:fs");
|
|
5
|
-
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
6
|
-
let node_path = require("node:path");
|
|
7
|
-
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
8
|
-
let node_os = require("node:os");
|
|
9
|
-
node_os = require_rolldown_runtime.__toESM(node_os, 1);
|
|
10
|
-
let _agimon_ai_po_core_piSettings = require("@agimon-ai/po-core/piSettings");
|
|
11
|
-
let yaml = require("yaml");
|
|
12
|
-
//#region src/services/config/index.ts
|
|
13
|
-
const DOOM_DIR = ".po";
|
|
14
|
-
const CONFIG_FILE = "config.yaml";
|
|
15
|
-
const PLANS_DIR = "plans";
|
|
16
|
-
function readConfig(filePath) {
|
|
17
|
-
return node_fs.default.existsSync(filePath) ? require_configPolicy.parseDoomConfig(node_fs.default.readFileSync(filePath, "utf8"), filePath) : { projectTrust: "ask" };
|
|
18
|
-
}
|
|
19
|
-
async function readConfigAsync(filePath) {
|
|
20
|
-
try {
|
|
21
|
-
return require_configPolicy.parseDoomConfig(await node_fs.default.promises.readFile(filePath, "utf8"), filePath);
|
|
22
|
-
} catch (error) {
|
|
23
|
-
if (error.code === "ENOENT") return { projectTrust: "ask" };
|
|
24
|
-
throw error;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function globalDoomConfigDirectory(homeDirectory = node_os.default.homedir()) {
|
|
28
|
-
return (0, _agimon_ai_po_core_piSettings.poHomeDirectory)(homeDirectory);
|
|
29
|
-
}
|
|
30
|
-
function globalDoomConfigPath(homeDirectory = node_os.default.homedir()) {
|
|
31
|
-
return node_path.default.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);
|
|
32
|
-
}
|
|
33
|
-
function resolvePlanningPlansDirectory(configured, repoRoot, homeDirectory = node_os.default.homedir()) {
|
|
34
|
-
if (!configured) return node_path.default.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);
|
|
35
|
-
if (configured === "~") return homeDirectory;
|
|
36
|
-
if (configured.startsWith("~/")) return node_path.default.resolve(homeDirectory, configured.slice(2));
|
|
37
|
-
if (configured.startsWith("~")) throw new Error("Doom planning plansDirectory supports only '~' or '~/' home aliases");
|
|
38
|
-
return node_path.default.isAbsolute(configured) ? node_path.default.normalize(configured) : node_path.default.resolve(repoRoot, configured);
|
|
39
|
-
}
|
|
40
|
-
function repositoryDoomConfigPath(repoRoot) {
|
|
41
|
-
return node_path.default.join(repoRoot, DOOM_DIR, CONFIG_FILE);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* True when a repository's `.po` folder is Po's home itself, as it is for a
|
|
45
|
-
* session rooted at home. That folder is already the global layer; reading it
|
|
46
|
-
* again as the repository layer would apply global-only keys at repository scope.
|
|
47
|
-
*/
|
|
48
|
-
function isGlobalDoomConfigRoot(repoRoot, homeDirectory = node_os.default.homedir()) {
|
|
49
|
-
return node_path.default.resolve(repoRoot, DOOM_DIR) === node_path.default.resolve(globalDoomConfigDirectory(homeDirectory));
|
|
50
|
-
}
|
|
51
|
-
function repositoryConfigFor(repoRoot, homeDirectory) {
|
|
52
|
-
return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? void 0 : repositoryDoomConfigPath(repoRoot);
|
|
53
|
-
}
|
|
54
|
-
/** Process-local distribution defaults never grant native authority or modify user files. */
|
|
55
|
-
function distributionDefaults(config, environment) {
|
|
56
|
-
if (environment.PO_DISTRIBUTION !== "desktop") return config;
|
|
57
|
-
return {
|
|
58
|
-
...config,
|
|
59
|
-
computerUse: {
|
|
60
|
-
...config.computerUse,
|
|
61
|
-
enabled: config.computerUse?.enabled ?? true
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
function loadDoomConfig(repoRoot, homeDirectory = node_os.default.homedir(), environment = process.env) {
|
|
66
|
-
const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);
|
|
67
|
-
return distributionDefaults(require_configPolicy.mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), repositoryPath === void 0 ? { projectTrust: "ask" } : readConfig(repositoryPath)), environment);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Loads the merged config, tolerating unknown keys in either file.
|
|
71
|
-
*
|
|
72
|
-
* Only `po sync` uses this. Everything that runs during a session keeps
|
|
73
|
-
* `loadDoomConfig`, because a key a running extension cannot understand is
|
|
74
|
-
* better reported than silently ignored; a build that refuses to start over
|
|
75
|
-
* the same key is not.
|
|
76
|
-
*/
|
|
77
|
-
function loadDoomConfigLenient(repoRoot, homeDirectory = node_os.default.homedir(), environment = process.env) {
|
|
78
|
-
const read = (filePath) => filePath !== void 0 && node_fs.default.existsSync(filePath) ? require_configPolicy.parseDoomConfig(node_fs.default.readFileSync(filePath, "utf8"), filePath, { lenient: true }) : {
|
|
79
|
-
config: { projectTrust: "ask" },
|
|
80
|
-
diagnostics: []
|
|
81
|
-
};
|
|
82
|
-
const globalConfig = read(globalDoomConfigPath(homeDirectory));
|
|
83
|
-
const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));
|
|
84
|
-
const diagnostics = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];
|
|
85
|
-
return {
|
|
86
|
-
config: distributionDefaults(require_configPolicy.mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),
|
|
87
|
-
diagnostics
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
async function loadDoomConfigAsync(repoRoot, homeDirectory = node_os.default.homedir(), environment = process.env) {
|
|
91
|
-
const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));
|
|
92
|
-
const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);
|
|
93
|
-
const repositoryConfig = repositoryPath === void 0 ? { projectTrust: "ask" } : await readConfigAsync(repositoryPath);
|
|
94
|
-
return distributionDefaults(require_configPolicy.mergeDoomConfigs(globalConfig, repositoryConfig), environment);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Reads one config file as a layer: what it is, what it sets, and the bytes it
|
|
98
|
-
* held. A file that does not exist is a layer that sets nothing, which is a
|
|
99
|
-
* normal state rather than an error.
|
|
100
|
-
*/
|
|
101
|
-
function readLayer(filePath) {
|
|
102
|
-
let text;
|
|
103
|
-
try {
|
|
104
|
-
text = node_fs.default.readFileSync(filePath, "utf8");
|
|
105
|
-
} catch (error) {
|
|
106
|
-
if (error.code === "ENOENT") return {
|
|
107
|
-
filePath,
|
|
108
|
-
exists: false,
|
|
109
|
-
hash: "",
|
|
110
|
-
keys: []
|
|
111
|
-
};
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
114
|
-
const document = (0, yaml.parse)(text) ?? {};
|
|
115
|
-
return {
|
|
116
|
-
filePath,
|
|
117
|
-
exists: true,
|
|
118
|
-
hash: (0, node_crypto.createHash)("sha256").update(text, "utf8").digest("hex"),
|
|
119
|
-
keys: require_configPolicy.configLeafKeys(document)
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* The two config files kept apart, with the merge alongside them.
|
|
124
|
-
*
|
|
125
|
-
* `repoRoot` is optional because the global file is complete on its own: a
|
|
126
|
-
* settings surface with no repository in view still has settings to show, and
|
|
127
|
-
* demanding one would leave it with nothing to render rather than with the
|
|
128
|
-
* global half.
|
|
129
|
-
*
|
|
130
|
-
* The origin answer respects the merge's own per-field rules rather than simply
|
|
131
|
-
* preferring the repository: `editor` is read from the global side whatever the
|
|
132
|
-
* repository says, and `projectTrust` from the repository side whatever the
|
|
133
|
-
* global one says. Reporting a file as the source of a value the merge discards
|
|
134
|
-
* is the exact confusion this exists to remove.
|
|
135
|
-
*/
|
|
136
|
-
function loadDoomConfigLayers(repoRoot, homeDirectory = node_os.default.homedir(), environment = process.env) {
|
|
137
|
-
const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));
|
|
138
|
-
const repositoryPath = repoRoot === void 0 ? void 0 : repositoryConfigFor(repoRoot, homeDirectory);
|
|
139
|
-
const repositoryLayer = repositoryPath === void 0 ? {
|
|
140
|
-
filePath: "",
|
|
141
|
-
exists: false,
|
|
142
|
-
hash: "",
|
|
143
|
-
keys: []
|
|
144
|
-
} : readLayer(repositoryPath);
|
|
145
|
-
const effective = repoRoot === void 0 ? distributionDefaults(require_configPolicy.mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: "ask" }), environment) : loadDoomConfig(repoRoot, homeDirectory, environment);
|
|
146
|
-
const sets = (layer, keyPath) => {
|
|
147
|
-
const dotted = keyPath.join(".");
|
|
148
|
-
return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));
|
|
149
|
-
};
|
|
150
|
-
return {
|
|
151
|
-
globalFile: globalLayer,
|
|
152
|
-
repositoryFile: repositoryLayer,
|
|
153
|
-
effective,
|
|
154
|
-
originOf(keyPath) {
|
|
155
|
-
const scope = require_configPolicy.configScopeOf(keyPath);
|
|
156
|
-
if (scope !== "global" && sets(repositoryLayer, keyPath)) return "repository";
|
|
157
|
-
if (scope !== "repository" && sets(globalLayer, keyPath)) return "global";
|
|
158
|
-
return "default";
|
|
159
|
-
},
|
|
160
|
-
valueAt: (keyPath) => require_configPolicy.valueAtKeyPath(effective, keyPath)
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
//#endregion
|
|
164
|
-
Object.defineProperty(exports, "globalDoomConfigDirectory", {
|
|
165
|
-
enumerable: true,
|
|
166
|
-
get: function() {
|
|
167
|
-
return globalDoomConfigDirectory;
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
Object.defineProperty(exports, "globalDoomConfigPath", {
|
|
171
|
-
enumerable: true,
|
|
172
|
-
get: function() {
|
|
173
|
-
return globalDoomConfigPath;
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
Object.defineProperty(exports, "isGlobalDoomConfigRoot", {
|
|
177
|
-
enumerable: true,
|
|
178
|
-
get: function() {
|
|
179
|
-
return isGlobalDoomConfigRoot;
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
Object.defineProperty(exports, "loadDoomConfig", {
|
|
183
|
-
enumerable: true,
|
|
184
|
-
get: function() {
|
|
185
|
-
return loadDoomConfig;
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
Object.defineProperty(exports, "loadDoomConfigAsync", {
|
|
189
|
-
enumerable: true,
|
|
190
|
-
get: function() {
|
|
191
|
-
return loadDoomConfigAsync;
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
Object.defineProperty(exports, "loadDoomConfigLayers", {
|
|
195
|
-
enumerable: true,
|
|
196
|
-
get: function() {
|
|
197
|
-
return loadDoomConfigLayers;
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
Object.defineProperty(exports, "loadDoomConfigLenient", {
|
|
201
|
-
enumerable: true,
|
|
202
|
-
get: function() {
|
|
203
|
-
return loadDoomConfigLenient;
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
Object.defineProperty(exports, "repositoryDoomConfigPath", {
|
|
207
|
-
enumerable: true,
|
|
208
|
-
get: function() {
|
|
209
|
-
return repositoryDoomConfigPath;
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
Object.defineProperty(exports, "resolvePlanningPlansDirectory", {
|
|
213
|
-
enumerable: true,
|
|
214
|
-
get: function() {
|
|
215
|
-
return resolvePlanningPlansDirectory;
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
//# sourceMappingURL=config-CfTb0_9G.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-CfTb0_9G.cjs","names":["fs","parseDoomConfig","os","poHomeDirectory","path","mergeDoomConfigs","parseYaml","createHash","configLeafKeys","configScopeOf","valueAtKeyPath"],"sources":["../src/services/config/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n DoomConfig,\n DoomConfigLayer,\n DoomConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, valueAtKeyPath } from '../configPolicy';\n\nconst DOOM_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nfunction readConfig(filePath: string): DoomConfig {\n return fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath)\n : { projectTrust: 'ask' };\n}\n\nasync function readConfigAsync(filePath: string): Promise<DoomConfig> {\n try {\n return parseDoomConfig(await fs.promises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projectTrust: 'ask' };\n throw error;\n }\n}\n\nexport function globalDoomConfigDirectory(homeDirectory = os.homedir()): string {\n return poHomeDirectory(homeDirectory);\n}\n\nexport function globalDoomConfigPath(homeDirectory = os.homedir()): string {\n return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = os.homedir(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);\n if (configured === '~') return homeDirectory;\n if (configured.startsWith('~/')) return path.resolve(homeDirectory, configured.slice(2));\n if (configured.startsWith('~')) {\n throw new Error(\"Doom planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryDoomConfigPath(repoRoot: string): string {\n return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);\n}\n\n/**\n * True when a repository's `.po` folder is Po's home itself, as it is for a\n * session rooted at home. That folder is already the global layer; reading it\n * again as the repository layer would apply global-only keys at repository scope.\n */\nexport function isGlobalDoomConfigRoot(repoRoot: string, homeDirectory = os.homedir()): boolean {\n return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));\n}\n\nfunction repositoryConfigFor(repoRoot: string, homeDirectory: string): string | undefined {\n return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? undefined : repositoryDoomConfigPath(repoRoot);\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nfunction distributionDefaults(config: DoomConfig, environment: NodeJS.ProcessEnv): DoomConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\nexport function loadDoomConfig(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfig {\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n return distributionDefaults(\n mergeDoomConfigs(\n readConfig(globalDoomConfigPath(homeDirectory)),\n repositoryPath === undefined ? { projectTrust: 'ask' } : readConfig(repositoryPath),\n ),\n environment,\n );\n}\n\n/**\n * Loads the merged config, tolerating unknown keys in either file.\n *\n * Only `po sync` uses this. Everything that runs during a session keeps\n * `loadDoomConfig`, because a key a running extension cannot understand is\n * better reported than silently ignored; a build that refuses to start over\n * the same key is not.\n */\nexport function loadDoomConfigLenient(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const read = (filePath: string | undefined): LenientParseResult =>\n filePath !== undefined && fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath, { lenient: true })\n : { config: { projectTrust: 'ask' }, diagnostics: [] };\n const globalConfig = read(globalDoomConfigPath(homeDirectory));\n const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergeDoomConfigs stays strict on purpose: its errors are cross-file scope\n // violations on known keys, which is a different fault from an unknown key.\n return {\n config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),\n diagnostics,\n };\n}\n\nexport async function loadDoomConfigAsync(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<DoomConfig> {\n const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryConfig: DoomConfig =\n repositoryPath === undefined ? { projectTrust: 'ask' } : await readConfigAsync(repositoryPath);\n return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/**\n * Reads one config file as a layer: what it is, what it sets, and the bytes it\n * held. A file that does not exist is a layer that sets nothing, which is a\n * normal state rather than an error.\n */\nfunction readLayer(filePath: string): DoomConfigLayer {\n let text: string;\n try {\n text = fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { filePath, exists: false, hash: '', keys: [] };\n }\n throw error;\n }\n // The raw document, not the parsed config: this is the one read that has to\n // distinguish a key the file set from a key the parser defaulted.\n const document = (parseYaml(text) ?? {}) as unknown;\n return {\n filePath,\n exists: true,\n hash: createHash('sha256').update(text, 'utf8').digest('hex'),\n keys: configLeafKeys(document),\n };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\n *\n * `repoRoot` is optional because the global file is complete on its own: a\n * settings surface with no repository in view still has settings to show, and\n * demanding one would leave it with nothing to render rather than with the\n * global half.\n *\n * The origin answer respects the merge's own per-field rules rather than simply\n * preferring the repository: `editor` is read from the global side whatever the\n * repository says, and `projectTrust` from the repository side whatever the\n * global one says. Reporting a file as the source of a value the merge discards\n * is the exact confusion this exists to remove.\n */\nexport function loadDoomConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfigLayers {\n const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryLayer =\n repositoryPath === undefined ? { filePath: '', exists: false, hash: '', keys: [] } : readLayer(repositoryPath);\n // With no repository there is nothing to merge, so the global file stands as\n // the effective config on its own.\n const effective =\n repoRoot === undefined\n ? distributionDefaults(\n mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: 'ask' }),\n environment,\n )\n : loadDoomConfig(repoRoot, homeDirectory, environment);\n const sets = (layer: DoomConfigLayer, keyPath: readonly string[]): boolean => {\n const dotted = keyPath.join('.');\n return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));\n };\n return {\n globalFile: globalLayer,\n repositoryFile: repositoryLayer,\n effective,\n originOf(keyPath: readonly string[]): ConfigValueOrigin {\n const scope = configScopeOf(keyPath);\n if (scope !== 'global' && sets(repositoryLayer, keyPath)) return 'repository';\n if (scope !== 'repository' && sets(globalLayer, keyPath)) return 'global';\n return 'default';\n },\n valueAt: (keyPath: readonly string[]) => valueAtKeyPath(effective, keyPath),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-D2HbBLzo.d.mts","names":["IDoomConfigService","DoomConfigServiceContract"],"sources":["../src/types/config.ts"],"mappings":";;;;;KAOY;KACA;KACA;KACA;KACA;UAEK;EACf;EACA,WAAW;;UAEI;EACf,OAAO;EACP,YAAY;EACZ;;;;;;;;;UASe;EACf;EACA;EACA;;;;;;;;;UASe;EACf;EACA;EACA;;;;;;;;;UASe;EACf;EACA,QAAQ;;UAEO;EACf;EACA;EACA,WAAW;EACX,aAAa;EACb,YAAY;;UAEG;EACf;;UAGe;EACf;;;UAGe;;EAEf;;EAEA;;UAEe;EACf;EACA;;UAEe;EACf;EACA,OAAO;;UAEQ;EACf,QAAQ;EACR;EACA;;UAEe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;;UAEU;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;;UAEU;EACf,OAAO;EACP,SAAS;EACT;EACA;IAAa;IAAiB;;EAC9B;IACE,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;;EAElB,cAAc;;EAEd;IAAS;IAAgB;;;UAEV;EACf,MAAM;EACN,QAAQ;EACR;EACA;IAAY;IAAiB;;EAC7B,UAAU,YAAY;EACtB,cAAc;;;;;;;;;UASC;EACf;EACA;EACA;;;UAIe;WACN;WACA;WACA;WACA;;WAEA;;KAGC;KACA;UAEK;WACN;WACA;WACA,QAAQ;WACR,QAAQ;WACR,UAAU;WACV,OAAO;;;KAIN,6BAA6B;WAAwC;;UAEhE;EACf;IAAU,WAAW;IAAoB,cAAc;;EACvD,cAAc;EACd,cAAc;EACd,SAAS;EACT,SAAS;EACT,QAAQ;EACR,YAAY;;EAEZ;IAAQ;;;EAER;IAAW;;;UAGI;EACf;EACA;;UAMe;EACf;;EAEA;EACA;EACA;;EAEA;;;;;;;;;;;EAWA,qBAAqB,eAAe;;EAEpC;EACA;EACA,oBAAoB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;;EAEb,gBAAgB;;EAEhB;IAAgB;;EAChB;EACA;;;;;;EAMA,kBAAkB;;EAElB,eAAe;EACf;EACA;EACA;EACA;;KAGU,aAAa,UAAU,oBAAmB,6BAClD,SACA,+BAA+B,oBACpB,aAAa,WACtB,oCACc,cAAc,SAAS,aAAa,OAAO,YACvD;KAEI,qBAAqB,aAAa;UAE7B;WACN,UAAU,aAAa;WACvB,SAAS;;WAET,mBAAmB,aAAa;;WAEhC;;;UAIM;EACf,KAAK,kBAAkB,yBAAyB;;;UAIjCA,6BAA2BC,mBAA0B,mBAAmB;;YAG7E;IACR,eAAeD;;;;KAQP;;UAGK;EACf;EACA;;;;;;EAMA;;EAEA;;;;;;;;;;UAWe;;EAEf,YAAY;EACZ,gBAAgB;EAChB,WAAW;;EAEX,SAAS,6BAA6B;;EAEtC,QAAQ;;;;;;;;;UAUO;EACf;;EAEA;EACA;;;UAIe;EACf;;;UAIe;EACf,QAAQ;EACR,aAAa"}
|
package/dist/config-DoQWSt1V.mjs
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { c as configScopeOf, d as parseDoomConfig, l as mergeDoomConfigs, m as valueAtKeyPath, o as configLeafKeys } from "./configPolicy-DCQgF5-f.mjs";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import os from "node:os";
|
|
6
|
-
import { poHomeDirectory } from "@agimon-ai/po-core/piSettings";
|
|
7
|
-
import { parse } from "yaml";
|
|
8
|
-
//#region src/services/config/index.ts
|
|
9
|
-
const DOOM_DIR = ".po";
|
|
10
|
-
const CONFIG_FILE = "config.yaml";
|
|
11
|
-
const PLANS_DIR = "plans";
|
|
12
|
-
function readConfig(filePath) {
|
|
13
|
-
return fs.existsSync(filePath) ? parseDoomConfig(fs.readFileSync(filePath, "utf8"), filePath) : { projectTrust: "ask" };
|
|
14
|
-
}
|
|
15
|
-
async function readConfigAsync(filePath) {
|
|
16
|
-
try {
|
|
17
|
-
return parseDoomConfig(await fs.promises.readFile(filePath, "utf8"), filePath);
|
|
18
|
-
} catch (error) {
|
|
19
|
-
if (error.code === "ENOENT") return { projectTrust: "ask" };
|
|
20
|
-
throw error;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function globalDoomConfigDirectory(homeDirectory = os.homedir()) {
|
|
24
|
-
return poHomeDirectory(homeDirectory);
|
|
25
|
-
}
|
|
26
|
-
function globalDoomConfigPath(homeDirectory = os.homedir()) {
|
|
27
|
-
return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);
|
|
28
|
-
}
|
|
29
|
-
function resolvePlanningPlansDirectory(configured, repoRoot, homeDirectory = os.homedir()) {
|
|
30
|
-
if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);
|
|
31
|
-
if (configured === "~") return homeDirectory;
|
|
32
|
-
if (configured.startsWith("~/")) return path.resolve(homeDirectory, configured.slice(2));
|
|
33
|
-
if (configured.startsWith("~")) throw new Error("Doom planning plansDirectory supports only '~' or '~/' home aliases");
|
|
34
|
-
return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);
|
|
35
|
-
}
|
|
36
|
-
function repositoryDoomConfigPath(repoRoot) {
|
|
37
|
-
return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* True when a repository's `.po` folder is Po's home itself, as it is for a
|
|
41
|
-
* session rooted at home. That folder is already the global layer; reading it
|
|
42
|
-
* again as the repository layer would apply global-only keys at repository scope.
|
|
43
|
-
*/
|
|
44
|
-
function isGlobalDoomConfigRoot(repoRoot, homeDirectory = os.homedir()) {
|
|
45
|
-
return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));
|
|
46
|
-
}
|
|
47
|
-
function repositoryConfigFor(repoRoot, homeDirectory) {
|
|
48
|
-
return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? void 0 : repositoryDoomConfigPath(repoRoot);
|
|
49
|
-
}
|
|
50
|
-
/** Process-local distribution defaults never grant native authority or modify user files. */
|
|
51
|
-
function distributionDefaults(config, environment) {
|
|
52
|
-
if (environment.PO_DISTRIBUTION !== "desktop") return config;
|
|
53
|
-
return {
|
|
54
|
-
...config,
|
|
55
|
-
computerUse: {
|
|
56
|
-
...config.computerUse,
|
|
57
|
-
enabled: config.computerUse?.enabled ?? true
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function loadDoomConfig(repoRoot, homeDirectory = os.homedir(), environment = process.env) {
|
|
62
|
-
const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);
|
|
63
|
-
return distributionDefaults(mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), repositoryPath === void 0 ? { projectTrust: "ask" } : readConfig(repositoryPath)), environment);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Loads the merged config, tolerating unknown keys in either file.
|
|
67
|
-
*
|
|
68
|
-
* Only `po sync` uses this. Everything that runs during a session keeps
|
|
69
|
-
* `loadDoomConfig`, because a key a running extension cannot understand is
|
|
70
|
-
* better reported than silently ignored; a build that refuses to start over
|
|
71
|
-
* the same key is not.
|
|
72
|
-
*/
|
|
73
|
-
function loadDoomConfigLenient(repoRoot, homeDirectory = os.homedir(), environment = process.env) {
|
|
74
|
-
const read = (filePath) => filePath !== void 0 && fs.existsSync(filePath) ? parseDoomConfig(fs.readFileSync(filePath, "utf8"), filePath, { lenient: true }) : {
|
|
75
|
-
config: { projectTrust: "ask" },
|
|
76
|
-
diagnostics: []
|
|
77
|
-
};
|
|
78
|
-
const globalConfig = read(globalDoomConfigPath(homeDirectory));
|
|
79
|
-
const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));
|
|
80
|
-
const diagnostics = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];
|
|
81
|
-
return {
|
|
82
|
-
config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),
|
|
83
|
-
diagnostics
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
async function loadDoomConfigAsync(repoRoot, homeDirectory = os.homedir(), environment = process.env) {
|
|
87
|
-
const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));
|
|
88
|
-
const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);
|
|
89
|
-
const repositoryConfig = repositoryPath === void 0 ? { projectTrust: "ask" } : await readConfigAsync(repositoryPath);
|
|
90
|
-
return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Reads one config file as a layer: what it is, what it sets, and the bytes it
|
|
94
|
-
* held. A file that does not exist is a layer that sets nothing, which is a
|
|
95
|
-
* normal state rather than an error.
|
|
96
|
-
*/
|
|
97
|
-
function readLayer(filePath) {
|
|
98
|
-
let text;
|
|
99
|
-
try {
|
|
100
|
-
text = fs.readFileSync(filePath, "utf8");
|
|
101
|
-
} catch (error) {
|
|
102
|
-
if (error.code === "ENOENT") return {
|
|
103
|
-
filePath,
|
|
104
|
-
exists: false,
|
|
105
|
-
hash: "",
|
|
106
|
-
keys: []
|
|
107
|
-
};
|
|
108
|
-
throw error;
|
|
109
|
-
}
|
|
110
|
-
const document = parse(text) ?? {};
|
|
111
|
-
return {
|
|
112
|
-
filePath,
|
|
113
|
-
exists: true,
|
|
114
|
-
hash: createHash("sha256").update(text, "utf8").digest("hex"),
|
|
115
|
-
keys: configLeafKeys(document)
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* The two config files kept apart, with the merge alongside them.
|
|
120
|
-
*
|
|
121
|
-
* `repoRoot` is optional because the global file is complete on its own: a
|
|
122
|
-
* settings surface with no repository in view still has settings to show, and
|
|
123
|
-
* demanding one would leave it with nothing to render rather than with the
|
|
124
|
-
* global half.
|
|
125
|
-
*
|
|
126
|
-
* The origin answer respects the merge's own per-field rules rather than simply
|
|
127
|
-
* preferring the repository: `editor` is read from the global side whatever the
|
|
128
|
-
* repository says, and `projectTrust` from the repository side whatever the
|
|
129
|
-
* global one says. Reporting a file as the source of a value the merge discards
|
|
130
|
-
* is the exact confusion this exists to remove.
|
|
131
|
-
*/
|
|
132
|
-
function loadDoomConfigLayers(repoRoot, homeDirectory = os.homedir(), environment = process.env) {
|
|
133
|
-
const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));
|
|
134
|
-
const repositoryPath = repoRoot === void 0 ? void 0 : repositoryConfigFor(repoRoot, homeDirectory);
|
|
135
|
-
const repositoryLayer = repositoryPath === void 0 ? {
|
|
136
|
-
filePath: "",
|
|
137
|
-
exists: false,
|
|
138
|
-
hash: "",
|
|
139
|
-
keys: []
|
|
140
|
-
} : readLayer(repositoryPath);
|
|
141
|
-
const effective = repoRoot === void 0 ? distributionDefaults(mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: "ask" }), environment) : loadDoomConfig(repoRoot, homeDirectory, environment);
|
|
142
|
-
const sets = (layer, keyPath) => {
|
|
143
|
-
const dotted = keyPath.join(".");
|
|
144
|
-
return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));
|
|
145
|
-
};
|
|
146
|
-
return {
|
|
147
|
-
globalFile: globalLayer,
|
|
148
|
-
repositoryFile: repositoryLayer,
|
|
149
|
-
effective,
|
|
150
|
-
originOf(keyPath) {
|
|
151
|
-
const scope = configScopeOf(keyPath);
|
|
152
|
-
if (scope !== "global" && sets(repositoryLayer, keyPath)) return "repository";
|
|
153
|
-
if (scope !== "repository" && sets(globalLayer, keyPath)) return "global";
|
|
154
|
-
return "default";
|
|
155
|
-
},
|
|
156
|
-
valueAt: (keyPath) => valueAtKeyPath(effective, keyPath)
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
//#endregion
|
|
160
|
-
export { loadDoomConfigAsync as a, repositoryDoomConfigPath as c, loadDoomConfig as i, resolvePlanningPlansDirectory as l, globalDoomConfigPath as n, loadDoomConfigLayers as o, isGlobalDoomConfigRoot as r, loadDoomConfigLenient as s, globalDoomConfigDirectory as t };
|
|
161
|
-
|
|
162
|
-
//# sourceMappingURL=config-DoQWSt1V.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-DoQWSt1V.mjs","names":["parseYaml"],"sources":["../src/services/config/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n DoomConfig,\n DoomConfigLayer,\n DoomConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, valueAtKeyPath } from '../configPolicy';\n\nconst DOOM_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nfunction readConfig(filePath: string): DoomConfig {\n return fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath)\n : { projectTrust: 'ask' };\n}\n\nasync function readConfigAsync(filePath: string): Promise<DoomConfig> {\n try {\n return parseDoomConfig(await fs.promises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projectTrust: 'ask' };\n throw error;\n }\n}\n\nexport function globalDoomConfigDirectory(homeDirectory = os.homedir()): string {\n return poHomeDirectory(homeDirectory);\n}\n\nexport function globalDoomConfigPath(homeDirectory = os.homedir()): string {\n return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = os.homedir(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);\n if (configured === '~') return homeDirectory;\n if (configured.startsWith('~/')) return path.resolve(homeDirectory, configured.slice(2));\n if (configured.startsWith('~')) {\n throw new Error(\"Doom planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryDoomConfigPath(repoRoot: string): string {\n return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);\n}\n\n/**\n * True when a repository's `.po` folder is Po's home itself, as it is for a\n * session rooted at home. That folder is already the global layer; reading it\n * again as the repository layer would apply global-only keys at repository scope.\n */\nexport function isGlobalDoomConfigRoot(repoRoot: string, homeDirectory = os.homedir()): boolean {\n return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));\n}\n\nfunction repositoryConfigFor(repoRoot: string, homeDirectory: string): string | undefined {\n return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? undefined : repositoryDoomConfigPath(repoRoot);\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nfunction distributionDefaults(config: DoomConfig, environment: NodeJS.ProcessEnv): DoomConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\nexport function loadDoomConfig(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfig {\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n return distributionDefaults(\n mergeDoomConfigs(\n readConfig(globalDoomConfigPath(homeDirectory)),\n repositoryPath === undefined ? { projectTrust: 'ask' } : readConfig(repositoryPath),\n ),\n environment,\n );\n}\n\n/**\n * Loads the merged config, tolerating unknown keys in either file.\n *\n * Only `po sync` uses this. Everything that runs during a session keeps\n * `loadDoomConfig`, because a key a running extension cannot understand is\n * better reported than silently ignored; a build that refuses to start over\n * the same key is not.\n */\nexport function loadDoomConfigLenient(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const read = (filePath: string | undefined): LenientParseResult =>\n filePath !== undefined && fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath, { lenient: true })\n : { config: { projectTrust: 'ask' }, diagnostics: [] };\n const globalConfig = read(globalDoomConfigPath(homeDirectory));\n const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergeDoomConfigs stays strict on purpose: its errors are cross-file scope\n // violations on known keys, which is a different fault from an unknown key.\n return {\n config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),\n diagnostics,\n };\n}\n\nexport async function loadDoomConfigAsync(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<DoomConfig> {\n const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryConfig: DoomConfig =\n repositoryPath === undefined ? { projectTrust: 'ask' } : await readConfigAsync(repositoryPath);\n return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/**\n * Reads one config file as a layer: what it is, what it sets, and the bytes it\n * held. A file that does not exist is a layer that sets nothing, which is a\n * normal state rather than an error.\n */\nfunction readLayer(filePath: string): DoomConfigLayer {\n let text: string;\n try {\n text = fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { filePath, exists: false, hash: '', keys: [] };\n }\n throw error;\n }\n // The raw document, not the parsed config: this is the one read that has to\n // distinguish a key the file set from a key the parser defaulted.\n const document = (parseYaml(text) ?? {}) as unknown;\n return {\n filePath,\n exists: true,\n hash: createHash('sha256').update(text, 'utf8').digest('hex'),\n keys: configLeafKeys(document),\n };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\n *\n * `repoRoot` is optional because the global file is complete on its own: a\n * settings surface with no repository in view still has settings to show, and\n * demanding one would leave it with nothing to render rather than with the\n * global half.\n *\n * The origin answer respects the merge's own per-field rules rather than simply\n * preferring the repository: `editor` is read from the global side whatever the\n * repository says, and `projectTrust` from the repository side whatever the\n * global one says. Reporting a file as the source of a value the merge discards\n * is the exact confusion this exists to remove.\n */\nexport function loadDoomConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfigLayers {\n const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryLayer =\n repositoryPath === undefined ? { filePath: '', exists: false, hash: '', keys: [] } : readLayer(repositoryPath);\n // With no repository there is nothing to merge, so the global file stands as\n // the effective config on its own.\n const effective =\n repoRoot === undefined\n ? distributionDefaults(\n mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: 'ask' }),\n environment,\n )\n : loadDoomConfig(repoRoot, homeDirectory, environment);\n const sets = (layer: DoomConfigLayer, keyPath: readonly string[]): boolean => {\n const dotted = keyPath.join('.');\n return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));\n };\n return {\n globalFile: globalLayer,\n repositoryFile: repositoryLayer,\n effective,\n originOf(keyPath: readonly string[]): ConfigValueOrigin {\n const scope = configScopeOf(keyPath);\n if (scope !== 'global' && sets(repositoryLayer, keyPath)) return 'repository';\n if (scope !== 'repository' && sets(globalLayer, keyPath)) return 'global';\n return 'default';\n },\n valueAt: (keyPath: readonly string[]) => valueAtKeyPath(effective, keyPath),\n };\n}\n"],"mappings":"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"}
|
package/dist/config-NSHRd6na.mjs
DELETED