@agimon-ai/po-config 0.0.0-alpha.80 → 0.0.0-alpha.82
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 +50 -20
- package/dist/{config-BKBk2p6v.mjs → config-C-dgx_54.mjs} +77 -3
- package/dist/config-C-dgx_54.mjs.map +1 -0
- package/dist/{config-DdvV_R4Q.d.mts → config-PGy7mpmC.d.mts} +7 -2
- package/dist/{config-DdvV_R4Q.d.mts.map → config-PGy7mpmC.d.mts.map} +1 -1
- package/dist/{config-B75TDv35.cjs → config-ch_DJeTs.cjs} +83 -2
- package/dist/config-ch_DJeTs.cjs.map +1 -0
- package/dist/config.cjs +3 -2
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +3 -3
- package/dist/{core-B0RBX1-I.mjs → core-BOyti7Xw.mjs} +2 -2
- package/dist/{core-B0RBX1-I.mjs.map → core-BOyti7Xw.mjs.map} +1 -1
- package/dist/{core-CWPpoX0B.cjs → core-DDqyXIMP.cjs} +2 -2
- package/dist/{core-CWPpoX0B.cjs.map → core-DDqyXIMP.cjs.map} +1 -1
- package/dist/{domains-CyLUOwPp.cjs → domains-DB86Kbky.cjs} +4 -4
- package/dist/{domains-CyLUOwPp.cjs.map → domains-DB86Kbky.cjs.map} +1 -1
- package/dist/{domains-kCa6tLxF.mjs → domains-DYqoL3VY.mjs} +4 -4
- package/dist/{domains-kCa6tLxF.mjs.map → domains-DYqoL3VY.mjs.map} +1 -1
- package/dist/domains.cjs +2 -2
- package/dist/domains.mjs +2 -2
- package/dist/extensions/server.cjs +2 -2
- package/dist/extensions/server.mjs +2 -2
- package/dist/harnessState.d.mts +1 -1
- package/dist/harnessStore.d.mts +1 -1
- package/dist/{index-LVklWqVp.d.mts → index-CFYBuxgr.d.mts} +2 -2
- package/dist/{index-LVklWqVp.d.mts.map → index-CFYBuxgr.d.mts.map} +1 -1
- package/dist/{index-BQZolhwB.d.mts → index-CWhsqHSI.d.mts} +2 -2
- package/dist/{index-BQZolhwB.d.mts.map → index-CWhsqHSI.d.mts.map} +1 -1
- package/dist/{index-DxRjrpTC.d.mts → index-D2c9ew7Y.d.mts} +15 -3
- package/dist/index-D2c9ew7Y.d.mts.map +1 -0
- package/dist/{index-DLt5gipX.d.mts → index-UOxWvyxC.d.mts} +2 -2
- package/dist/{index-DLt5gipX.d.mts.map → index-UOxWvyxC.d.mts.map} +1 -1
- package/dist/{index-BqEBQ2Uz.d.mts → index-cxAbT63p.d.mts} +3 -3
- package/dist/{index-BqEBQ2Uz.d.mts.map → index-cxAbT63p.d.mts.map} +1 -1
- package/dist/index-nVcEC1jO.d.mts.map +1 -1
- package/dist/index.cjs +10 -9
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +10 -10
- package/dist/{init-4E4W_fl1.cjs → init-BYASUiO4.cjs} +5 -3
- package/dist/init-BYASUiO4.cjs.map +1 -0
- package/dist/{init-BlopOLXb.mjs → init-CGXq_W_m.mjs} +5 -3
- package/dist/init-CGXq_W_m.mjs.map +1 -0
- package/dist/init.cjs +1 -1
- package/dist/init.mjs +1 -1
- package/dist/{layeredConfig-BczonW-E.cjs → layeredConfig-DF0RPFCT.cjs} +2 -2
- package/dist/{layeredConfig-BczonW-E.cjs.map → layeredConfig-DF0RPFCT.cjs.map} +1 -1
- package/dist/{layeredConfig-CdvkyGXV.mjs → layeredConfig-DMXpx0Rh.mjs} +2 -2
- package/dist/{layeredConfig-CdvkyGXV.mjs.map → layeredConfig-DMXpx0Rh.mjs.map} +1 -1
- package/dist/layeredConfig.cjs +1 -1
- package/dist/layeredConfig.mjs +1 -1
- package/dist/{majorModes-B9FkUfa_.mjs → majorModes-CFJGjbyH.mjs} +2 -2
- package/dist/{majorModes-B9FkUfa_.mjs.map → majorModes-CFJGjbyH.mjs.map} +1 -1
- package/dist/{majorModes-BkVSvdF4.cjs → majorModes-KB_WjyGY.cjs} +2 -2
- package/dist/{majorModes-BkVSvdF4.cjs.map → majorModes-KB_WjyGY.cjs.map} +1 -1
- package/dist/majorModes.cjs +1 -1
- package/dist/majorModes.d.mts +1 -1
- package/dist/majorModes.mjs +1 -1
- package/dist/piContext.cjs +1 -1
- package/dist/piContext.d.mts +2 -2
- package/dist/piContext.mjs +1 -1
- package/dist/{profiles-Bwkq759J.cjs → profiles-CXGWdK4E.cjs} +2 -2
- package/dist/{profiles-Bwkq759J.cjs.map → profiles-CXGWdK4E.cjs.map} +1 -1
- package/dist/{profiles-BKJckZka.mjs → profiles-CbTR2tNE.mjs} +2 -2
- package/dist/{profiles-BKJckZka.mjs.map → profiles-CbTR2tNE.mjs.map} +1 -1
- package/dist/profiles.cjs +1 -1
- package/dist/profiles.mjs +1 -1
- package/dist/selectionSwitch.cjs +2 -2
- package/dist/selectionSwitch.d.mts +2 -2
- package/dist/selectionSwitch.mjs +2 -2
- package/dist/{sessionConfig-eC7B43xB.mjs → sessionConfig-BgPh8Uv6.mjs} +2 -2
- package/dist/{sessionConfig-eC7B43xB.mjs.map → sessionConfig-BgPh8Uv6.mjs.map} +1 -1
- package/dist/{sessionConfig-CRgjesgD.cjs → sessionConfig-Dp3I3TH2.cjs} +2 -2
- package/dist/{sessionConfig-CRgjesgD.cjs.map → sessionConfig-Dp3I3TH2.cjs.map} +1 -1
- package/dist/{settingsApi-BbDdtEWq.mjs → settingsApi-3v_F0XRz.mjs} +6 -6
- package/dist/{settingsApi-BbDdtEWq.mjs.map → settingsApi-3v_F0XRz.mjs.map} +1 -1
- package/dist/{settingsApi-DMNAPMIe.cjs → settingsApi-DQrXSdCR.cjs} +6 -6
- package/dist/{settingsApi-DMNAPMIe.cjs.map → settingsApi-DQrXSdCR.cjs.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/llms.txt +2 -2
- package/package.json +4 -4
- package/src/prompts/help-how-to-config/SKILL.md +11 -3
- package/src/prompts/help-how-to-config/references/config-contract.md +43 -14
- package/dist/config-B75TDv35.cjs.map +0 -1
- package/dist/config-BKBk2p6v.mjs.map +0 -1
- package/dist/index-DxRjrpTC.d.mts.map +0 -1
- package/dist/init-4E4W_fl1.cjs.map +0 -1
- package/dist/init-BlopOLXb.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -28,25 +28,21 @@ so the rest of the parent session can consume one resolved configuration snapsho
|
|
|
28
28
|
Po reads `~/.po/config.yaml` first and `<repoRoot>/.po/config.yaml` second. Merge policy
|
|
29
29
|
is field-specific because some settings are personal and others are repository policy:
|
|
30
30
|
|
|
31
|
-
| Setting
|
|
32
|
-
|
|
|
33
|
-
| `projectTrust`
|
|
34
|
-
|
|
|
35
|
-
| `editor`
|
|
36
|
-
| `modes.planning`
|
|
37
|
-
| `voice`
|
|
38
|
-
| `voice.autoCapture`
|
|
39
|
-
| `selection`
|
|
40
|
-
|
|
41
|
-
Supported root keys include `modes`, `projectTrust`, `
|
|
42
|
-
Unknown keys and invalid values fail during loading.
|
|
31
|
+
| Setting | Effective source policy |
|
|
32
|
+
| ---------------------- | ----------------------------------------------------------------------------- |
|
|
33
|
+
| `projectTrust` | Repository value, defaulting to `ask` |
|
|
34
|
+
| Workspace declarations | Repository `.po/workspaces.yaml`, or legacy repository `config.yaml` fallback |
|
|
35
|
+
| `editor` | Personal config only |
|
|
36
|
+
| `modes.planning` | Personal and repository fields merge, with repository values winning |
|
|
37
|
+
| `voice` | Personal and repository fields merge, with repository values winning |
|
|
38
|
+
| `voice.autoCapture` | Personal config only |
|
|
39
|
+
| `selection` | Per-axis merge, with repository values winning |
|
|
40
|
+
|
|
41
|
+
Supported runtime root keys include `modes`, `projectTrust`, `editor`, `voice`, and `selection`.
|
|
42
|
+
The deprecated `workspaces` key remains readable for compatibility. Unknown keys and invalid values fail during loading.
|
|
43
43
|
|
|
44
44
|
```yaml
|
|
45
45
|
projectTrust: ask
|
|
46
|
-
workspaces:
|
|
47
|
-
- name: Review
|
|
48
|
-
instructions: Focus on correctness and tests.
|
|
49
|
-
- name: Build
|
|
50
46
|
modes:
|
|
51
47
|
planning:
|
|
52
48
|
main:
|
|
@@ -62,10 +58,44 @@ selection:
|
|
|
62
58
|
profile: reviewer
|
|
63
59
|
```
|
|
64
60
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
### Workspace declarations
|
|
62
|
+
|
|
63
|
+
Declare selectable workspaces in `<repoRoot>/.po/workspaces.yaml`:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
workspaces:
|
|
67
|
+
- name: Agiflow
|
|
68
|
+
path: .
|
|
69
|
+
alias: af
|
|
70
|
+
instructions: Work on the Agiflow product.
|
|
71
|
+
metadata:
|
|
72
|
+
'@agimon-ai/po-agiflow': { projectId: 'your-project-id' }
|
|
73
|
+
- name: Unsendbox
|
|
74
|
+
path: .
|
|
75
|
+
alias: ub
|
|
76
|
+
metadata: {}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Names are trimmed, case-insensitively unique within the file, and use the admission naming rules
|
|
80
|
+
(letters, numbers, spaces, dots, dashes or underscores, starting with a letter or number, at most
|
|
81
|
+
80 characters, no `..`). Aliases are optional non-empty strings, unique within the file.
|
|
82
|
+
`path` defaults to `.` and resolves from the repository root. This version supports only paths
|
|
83
|
+
canonically equal to that root, including equivalent symlinks; product-folder and cross-repository
|
|
84
|
+
paths are rejected rather than silently normalized. Distinct declarations create distinct workspace
|
|
85
|
+
ids sharing that root. Instructions are copied on first creation, not overwritten on re-admission.
|
|
86
|
+
|
|
87
|
+
`metadata` is a free-form JSON object. Plugin namespacing is a convention, not a schema restriction.
|
|
88
|
+
Each plugin validates its own values and decides whether they are defaults or enforced scope.
|
|
89
|
+
Keep credentials in the existing vault or credential services, not metadata.
|
|
90
|
+
|
|
91
|
+
The new file is repository-only and authoritative, including `workspaces: []`. Invalid or blank
|
|
92
|
+
new files report an error, never silently fall back. Only when it is absent does Po read the old
|
|
93
|
+
repository `config.yaml` list of `{ name, instructions? }` and emit a deprecation notice. Personal
|
|
94
|
+
declarations are ignored. Po never rewrites either file automatically.
|
|
95
|
+
|
|
96
|
+
Hosts call `readWorkspaceDeclarations({ fs, repositoryRoot, context })` from the root or `/config`
|
|
97
|
+
export. It returns `{ declarations, source, notices }`. Plugins use the host-provided
|
|
98
|
+
[`po/workspace-registry`](../../core/po-core/README.md#workspace-registry) service instead of rereading YAML.
|
|
69
99
|
|
|
70
100
|
The `selection` mapping names defaults. Definitions for those axes live in `modes.yaml`,
|
|
71
101
|
`domains.yaml`, and `profiles.yaml` and are documented by their owning package Help skills.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as parsePoConfig } from "./configPolicy-BADJDi8o.mjs";
|
|
2
|
+
import { c as layerFromText, d as mergeLenientLayers, f as repositoryConfigFor, i as defaultPoConfig, l as lenientConfigFromText, n as composeConfigLayers, o as globalPoConfigPath, r as configFromText, t as absentRepositoryLayer, u as mergeConfigLayers } from "./core-BOyti7Xw.mjs";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
import { nodeHost, readTextIfExists } from "@agimon-ai/po-core/platform";
|
|
3
5
|
import fs from "node:fs";
|
|
6
|
+
import { parse } from "yaml";
|
|
4
7
|
//#region src/services/config/sync.ts
|
|
5
8
|
function readTextSync(filePath) {
|
|
6
9
|
if (filePath === void 0) return void 0;
|
|
@@ -59,6 +62,77 @@ function loadPoConfigLayers(repoRoot, homeDirectory = nodeHost.homeDirectory(),
|
|
|
59
62
|
}
|
|
60
63
|
//#endregion
|
|
61
64
|
//#region src/services/config/index.ts
|
|
65
|
+
const object = (value) => typeof value === "object" && value !== null && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
66
|
+
function jsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
67
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
68
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
69
|
+
if (typeof value !== "object" || !Array.isArray(value) && !object(value) || seen.has(value)) return false;
|
|
70
|
+
seen.add(value);
|
|
71
|
+
const valid = (Array.isArray(value) ? value : Object.values(value)).every((entry) => jsonValue(entry, seen));
|
|
72
|
+
seen.delete(value);
|
|
73
|
+
return valid;
|
|
74
|
+
}
|
|
75
|
+
/** Repository-only declarations. An existing new document is authoritative, even when empty. */
|
|
76
|
+
async function readWorkspaceDeclarations({ fs, repositoryRoot, context }) {
|
|
77
|
+
const filePath = path.join(repositoryRoot, ".po", "workspaces.yaml");
|
|
78
|
+
const text = await readTextIfExists(fs, filePath, context);
|
|
79
|
+
if (text === void 0) {
|
|
80
|
+
const legacyPath = path.join(repositoryRoot, ".po", "config.yaml");
|
|
81
|
+
const legacy = await readTextIfExists(fs, legacyPath, context);
|
|
82
|
+
const declarations = legacy === void 0 ? void 0 : configFromText(legacy, legacyPath).workspaces;
|
|
83
|
+
return {
|
|
84
|
+
declarations: declarations ?? [],
|
|
85
|
+
source: declarations === void 0 ? void 0 : "config.yaml",
|
|
86
|
+
notices: declarations === void 0 ? [] : [`Move workspaces from ${legacyPath} to ${filePath}; config.yaml workspaces is deprecated.`]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
let document;
|
|
90
|
+
try {
|
|
91
|
+
document = parse(text);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
throw new Error(`Could not parse workspace declarations at ${filePath}`, { cause: error });
|
|
94
|
+
}
|
|
95
|
+
if (!object(document) || Object.keys(document).some((key) => key !== "workspaces") || !Array.isArray(document.workspaces)) throw new Error(`Workspace declarations at ${filePath} must be an object containing a workspaces list`);
|
|
96
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
97
|
+
const declarations = document.workspaces.map((entry, index) => {
|
|
98
|
+
const location = `workspaces[${String(index)}]`;
|
|
99
|
+
if (!object(entry) || Object.keys(entry).some((key) => ![
|
|
100
|
+
"name",
|
|
101
|
+
"path",
|
|
102
|
+
"alias",
|
|
103
|
+
"instructions",
|
|
104
|
+
"metadata"
|
|
105
|
+
].includes(key))) throw new Error(`Workspace declarations at ${filePath} require ${location} to contain only name, path, alias, instructions, metadata`);
|
|
106
|
+
const base = parsePoConfig(JSON.stringify({ workspaces: [{
|
|
107
|
+
name: entry.name,
|
|
108
|
+
instructions: entry.instructions
|
|
109
|
+
}] }), filePath).workspaces[0];
|
|
110
|
+
if (base.name.length > 80 || !/^[A-Za-z0-9][A-Za-z0-9 ._-]*$/u.test(base.name) || base.name.includes("..")) throw new Error(`Workspace declarations at ${filePath} require ${location}.name to use letters, numbers, spaces, dots, dashes, or underscores (up to 80 characters)`);
|
|
111
|
+
if (entry.path !== void 0 && (typeof entry.path !== "string" || entry.path.trim() === "" || entry.path.includes("\0"))) throw new Error(`Workspace declarations at ${filePath} require ${location}.path to be a non-empty path`);
|
|
112
|
+
if (entry.alias !== void 0 && (typeof entry.alias !== "string" || entry.alias.trim() === "")) throw new Error(`Workspace declarations at ${filePath} require ${location}.alias to be a non-empty string`);
|
|
113
|
+
const alias = typeof entry.alias === "string" ? entry.alias.trim() : void 0;
|
|
114
|
+
if (alias !== void 0) {
|
|
115
|
+
if (aliases.has(alias)) throw new Error(`Workspace declarations at ${filePath} have duplicate alias: ${alias}`);
|
|
116
|
+
aliases.add(alias);
|
|
117
|
+
}
|
|
118
|
+
if (entry.metadata !== void 0 && (!object(entry.metadata) || !jsonValue(entry.metadata))) throw new Error(`Workspace declarations at ${filePath} require ${location}.metadata to be a JSON object`);
|
|
119
|
+
return {
|
|
120
|
+
...base,
|
|
121
|
+
...entry.path === void 0 ? {} : { path: entry.path },
|
|
122
|
+
...alias === void 0 ? {} : { alias },
|
|
123
|
+
...entry.metadata === void 0 ? {} : { metadata: entry.metadata }
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
parsePoConfig(JSON.stringify({ workspaces: declarations.map(({ name, instructions }) => ({
|
|
127
|
+
name,
|
|
128
|
+
instructions
|
|
129
|
+
})) }), filePath);
|
|
130
|
+
return {
|
|
131
|
+
declarations,
|
|
132
|
+
source: "workspaces.yaml",
|
|
133
|
+
notices: []
|
|
134
|
+
};
|
|
135
|
+
}
|
|
62
136
|
function resolved(options) {
|
|
63
137
|
return {
|
|
64
138
|
homeDirectory: options.homeDirectory ?? nodeHost.homeDirectory(),
|
|
@@ -107,6 +181,6 @@ async function readPoConfigLayers(fs, repoRoot, context, options = {}) {
|
|
|
107
181
|
return composeConfigLayers(globalLayer, repositoryLayer, effective);
|
|
108
182
|
}
|
|
109
183
|
//#endregion
|
|
110
|
-
export {
|
|
184
|
+
export { loadPoConfig as a, loadPoConfigLenient as c, readWorkspaceDeclarations as i, readPoConfigLayers as n, loadPoConfigAsync as o, readPoConfigLenient as r, loadPoConfigLayers as s, readPoConfig as t };
|
|
111
185
|
|
|
112
|
-
//# sourceMappingURL=config-
|
|
186
|
+
//# sourceMappingURL=config-C-dgx_54.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-C-dgx_54.mjs","names":["readText","parseYaml"],"sources":["../src/services/config/sync.ts","../src/services/config/index.ts"],"sourcesContent":["// sync: readTextSync supports exported Node-only synchronous config readers retained for phase 2.\nimport fs from 'node:fs';\n\nimport { nodeHost } from '@agimon-ai/po-core/platform';\n\nimport type { PoConfig, PoConfigLayers, LenientParseResult } from '../../types/config';\nimport {\n absentRepositoryLayer,\n composeConfigLayers,\n configFromText,\n defaultPoConfig,\n globalPoConfigPath,\n layerFromText,\n lenientConfigFromText,\n mergeConfigLayers,\n mergeLenientLayers,\n repositoryConfigFor,\n} from './core';\n\nfunction readTextSync(filePath: string | undefined): string | undefined {\n if (filePath === undefined) return undefined;\n try {\n return fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\nasync function readText(filePath: string): Promise<string | undefined> {\n try {\n return await fs.promises.readFile(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\n/** @deprecated Node-only sync shim; use readPoConfig. Removed in M2. */\nexport function loadPoConfig(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): PoConfig {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n return mergeConfigLayers(\n configFromText(readTextSync(globalPath), globalPath),\n repositoryPath === undefined ? defaultPoConfig() : configFromText(readTextSync(repositoryPath), repositoryPath),\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 * `loadPoConfig`, 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 *\n * @deprecated Node-only sync shim; use readPoConfigLenient. Removed in M2.\n */\nexport function loadPoConfigLenient(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n return mergeLenientLayers(\n lenientConfigFromText(readTextSync(globalPath), globalPath),\n lenientConfigFromText(readTextSync(repositoryPath), repositoryPath ?? ''),\n environment,\n );\n}\n\n/** @deprecated Node-only shim over node:fs; use readPoConfig. Removed in M2. */\nexport async function loadPoConfigAsync(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<PoConfig> {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalConfig = configFromText(await readText(globalPath), globalPath);\n const repositoryConfig =\n repositoryPath === undefined ? defaultPoConfig() : configFromText(await readText(repositoryPath), repositoryPath);\n return mergeConfigLayers(globalConfig, repositoryConfig, environment);\n}\n\n/** @deprecated Node-only sync shim; use readPoConfigLayers. Removed in M2. */\nexport function loadPoConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): PoConfigLayers {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalText = readTextSync(globalPath);\n const repositoryText = readTextSync(repositoryPath);\n const repositoryConfig =\n repositoryPath === undefined ? defaultPoConfig() : configFromText(repositoryText, repositoryPath);\n return composeConfigLayers(\n layerFromText(globalPath, globalText),\n repositoryPath === undefined ? absentRepositoryLayer() : layerFromText(repositoryPath, repositoryText),\n mergeConfigLayers(configFromText(globalText, globalPath), repositoryConfig, environment),\n );\n}\n","import path from 'node:path';\n\nimport { nodeHost, readTextIfExists, type FileSystem } from '@agimon-ai/po-core/platform';\nimport { parse as parseYaml } from 'yaml';\n\nimport type { PoConfig, PoConfigLayers, LenientParseResult, WorkspaceDeclaration } from '../../types/config';\nimport { parsePoConfig } from '../configPolicy';\nimport {\n absentRepositoryLayer,\n composeConfigLayers,\n configFromText,\n defaultPoConfig,\n globalPoConfigPath,\n layerFromText,\n lenientConfigFromText,\n mergeConfigLayers,\n mergeLenientLayers,\n repositoryConfigFor,\n type ConfigEnvironment,\n} from './core';\n\ntype IoContext = Parameters<FileSystem['readTextFile']>[1];\n\nexport interface ReadWorkspaceDeclarationsOptions {\n fs: FileSystem;\n repositoryRoot: string;\n context: IoContext;\n}\n\nexport interface WorkspaceDeclarationsResult {\n declarations: WorkspaceDeclaration[];\n source: 'workspaces.yaml' | 'config.yaml' | undefined;\n notices: string[];\n}\n\nconst object = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' &&\n value !== null &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n\nfunction jsonValue(value: unknown, seen = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || (!Array.isArray(value) && !object(value)) || seen.has(value)) return false;\n seen.add(value);\n const valid = (Array.isArray(value) ? value : Object.values(value)).every((entry) => jsonValue(entry, seen));\n seen.delete(value);\n return valid;\n}\n\n/** Repository-only declarations. An existing new document is authoritative, even when empty. */\nexport async function readWorkspaceDeclarations({\n fs,\n repositoryRoot,\n context,\n}: ReadWorkspaceDeclarationsOptions): Promise<WorkspaceDeclarationsResult> {\n const filePath = path.join(repositoryRoot, '.po', 'workspaces.yaml');\n const text = await readTextIfExists(fs, filePath, context);\n if (text === undefined) {\n const legacyPath = path.join(repositoryRoot, '.po', 'config.yaml');\n const legacy = await readTextIfExists(fs, legacyPath, context);\n const declarations = legacy === undefined ? undefined : configFromText(legacy, legacyPath).workspaces;\n return {\n declarations: declarations ?? [],\n source: declarations === undefined ? undefined : 'config.yaml',\n notices:\n declarations === undefined\n ? []\n : [`Move workspaces from ${legacyPath} to ${filePath}; config.yaml workspaces is deprecated.`],\n };\n }\n let document: unknown;\n try {\n document = parseYaml(text);\n } catch (error) {\n throw new Error(`Could not parse workspace declarations at ${filePath}`, { cause: error });\n }\n if (\n !object(document) ||\n Object.keys(document).some((key) => key !== 'workspaces') ||\n !Array.isArray(document.workspaces)\n )\n throw new Error(`Workspace declarations at ${filePath} must be an object containing a workspaces list`);\n const aliases = new Set<string>();\n const declarations = document.workspaces.map((entry: unknown, index): WorkspaceDeclaration => {\n const location = `workspaces[${String(index)}]`;\n if (\n !object(entry) ||\n Object.keys(entry).some((key) => !['name', 'path', 'alias', 'instructions', 'metadata'].includes(key))\n )\n throw new Error(\n `Workspace declarations at ${filePath} require ${location} to contain only name, path, alias, instructions, metadata`,\n );\n // Reuse the established declaration name/instructions parser, without changing the legacy config contract.\n const base = parsePoConfig(\n JSON.stringify({ workspaces: [{ name: entry.name, instructions: entry.instructions }] }),\n filePath,\n ).workspaces![0]!;\n if (base.name.length > 80 || !/^[A-Za-z0-9][A-Za-z0-9 ._-]*$/u.test(base.name) || base.name.includes('..'))\n throw new Error(\n `Workspace declarations at ${filePath} require ${location}.name to use letters, numbers, spaces, dots, dashes, or underscores (up to 80 characters)`,\n );\n if (\n entry.path !== undefined &&\n (typeof entry.path !== 'string' || entry.path.trim() === '' || entry.path.includes('\\0'))\n )\n throw new Error(`Workspace declarations at ${filePath} require ${location}.path to be a non-empty path`);\n if (entry.alias !== undefined && (typeof entry.alias !== 'string' || entry.alias.trim() === ''))\n throw new Error(`Workspace declarations at ${filePath} require ${location}.alias to be a non-empty string`);\n const alias = typeof entry.alias === 'string' ? entry.alias.trim() : undefined;\n if (alias !== undefined) {\n if (aliases.has(alias)) throw new Error(`Workspace declarations at ${filePath} have duplicate alias: ${alias}`);\n aliases.add(alias);\n }\n if (entry.metadata !== undefined && (!object(entry.metadata) || !jsonValue(entry.metadata)))\n throw new Error(`Workspace declarations at ${filePath} require ${location}.metadata to be a JSON object`);\n return {\n ...base,\n ...(entry.path === undefined ? {} : { path: entry.path as string }),\n ...(alias === undefined ? {} : { alias }),\n ...(entry.metadata === undefined ? {} : { metadata: entry.metadata as Record<string, unknown> }),\n };\n });\n // Retain the legacy parser's case-insensitive duplicate-name rule across the entire document.\n parsePoConfig(\n JSON.stringify({ workspaces: declarations.map(({ name, instructions }) => ({ name, instructions })) }),\n filePath,\n );\n return { declarations, source: 'workspaces.yaml', notices: [] };\n}\n\nexport interface ReadPoConfigOptions {\n /** Defaults to the host's home directory. */\n readonly homeDirectory?: string;\n /** Defaults to `process.env`. */\n readonly environment?: ConfigEnvironment;\n}\n\nfunction resolved(options: ReadPoConfigOptions): { homeDirectory: string; environment: ConfigEnvironment } {\n return {\n homeDirectory: options.homeDirectory ?? nodeHost.homeDirectory(),\n environment: options.environment ?? process.env,\n };\n}\n\nconst readText = (fs: FileSystem, filePath: string | undefined, context: IoContext) =>\n filePath === undefined ? Promise.resolve(undefined) : readTextIfExists(fs, filePath, context);\n\n/**\n * Loads the merged global and repository config over a FileSystem. A missing\n * file contributes the defaults, so a host with neither file, such as a fresh\n * Durable Object filesystem, reads the same config as an empty Node home.\n */\nexport async function readPoConfig(\n fs: FileSystem,\n repoRoot: string,\n context: IoContext,\n options: ReadPoConfigOptions = {},\n): Promise<PoConfig> {\n const { homeDirectory, environment } = resolved(options);\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalConfig = configFromText(await readText(fs, globalPath, context), globalPath);\n const repositoryConfig =\n repositoryPath === undefined\n ? defaultPoConfig()\n : configFromText(await readText(fs, repositoryPath, context), repositoryPath);\n return mergeConfigLayers(globalConfig, repositoryConfig, environment);\n}\n\n/** As `readPoConfig`, tolerating unknown keys in either file and reporting them. */\nexport async function readPoConfigLenient(\n fs: FileSystem,\n repoRoot: string,\n context: IoContext,\n options: ReadPoConfigOptions = {},\n): Promise<LenientParseResult> {\n const { homeDirectory, environment } = resolved(options);\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalConfig = lenientConfigFromText(await readText(fs, globalPath, context), globalPath);\n const repositoryConfig =\n repositoryPath === undefined\n ? lenientConfigFromText(undefined, '')\n : lenientConfigFromText(await readText(fs, repositoryPath, context), repositoryPath);\n return mergeLenientLayers(globalConfig, repositoryConfig, environment);\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.\n */\nexport async function readPoConfigLayers(\n fs: FileSystem,\n repoRoot: string | undefined,\n context: IoContext,\n options: ReadPoConfigOptions = {},\n): Promise<PoConfigLayers> {\n const { homeDirectory, environment } = resolved(options);\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalText = await readText(fs, globalPath, context);\n const repositoryText = await readText(fs, repositoryPath, context);\n const globalLayer = layerFromText(globalPath, globalText);\n const repositoryLayer =\n repositoryPath === undefined ? absentRepositoryLayer() : layerFromText(repositoryPath, repositoryText);\n const repositoryConfig =\n repositoryPath === undefined ? defaultPoConfig() : configFromText(repositoryText, repositoryPath);\n const effective = mergeConfigLayers(configFromText(globalText, globalPath), repositoryConfig, environment);\n return composeConfigLayers(globalLayer, repositoryLayer, effective);\n}\n\nexport {\n globalPoConfigDirectory,\n globalPoConfigPath,\n isGlobalPoConfigRoot,\n repositoryPoConfigPath,\n resolvePlanningPlansDirectory,\n} from './core';\nexport type { ConfigEnvironment } from './core';\nexport { loadPoConfig, loadPoConfigAsync, loadPoConfigLayers, loadPoConfigLenient } from './sync';\n"],"mappings":"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"}
|
|
@@ -237,10 +237,15 @@ interface PoConfigTransitionRecord {
|
|
|
237
237
|
type PoConfigPendingSelection = PoConfigTransitionRecord & {
|
|
238
238
|
readonly phase: 'pending';
|
|
239
239
|
};
|
|
240
|
-
/** A repository workspace
|
|
240
|
+
/** A named repository workspace, declared in `.po/workspaces.yaml`. */
|
|
241
241
|
interface WorkspaceDeclaration {
|
|
242
242
|
name: string;
|
|
243
|
+
/** Repository-root-relative workspace path, defaulting to `.`. */
|
|
244
|
+
path?: string;
|
|
245
|
+
alias?: string;
|
|
243
246
|
instructions?: string;
|
|
247
|
+
/** Free-form JSON data. Each plugin validates and interprets its own values. */
|
|
248
|
+
metadata?: Record<string, unknown>;
|
|
244
249
|
}
|
|
245
250
|
interface PoConfig {
|
|
246
251
|
/** Repository-only workspace declarations, never inherited from personal config. */
|
|
@@ -390,4 +395,4 @@ interface LenientParseResult {
|
|
|
390
395
|
}
|
|
391
396
|
//#endregion
|
|
392
397
|
export { PoSelectionConfig as A, VoiceTtsConfig as B, PoConfigLayers as C, PoConfigTransitionRecord as D, PoConfigTransitionPhase as E, VoiceAutoCaptureConfig as F, WorkspaceDeclaration as H, VoiceConfig as I, VoiceEngine as L, ResolvedVoiceAutoCaptureConfig as M, ResolvedVoiceConfig as N, PoConfigTransitionStrategy as O, VoiceAdapterConfig as P, VoiceMode as R, PoConfigLayer as S, PoConfigSelection as T, VoiceTtsEngine as V, PlanningAgentConfig as _, ConfigDiagnostic as a, PoConfig as b, DesktopEnvironmentConfig as c, IPoConfigLoader as d, IPoConfigService$1 as f, PackageAttribution$1 as g, PO_CONFIG_SERVICE as h, AutocompactTokenConfig as i, ProjectTrust as j, PoHarnessContext as k, EditorConfig as l, LenientParseResult as m, AutocompactOverrideConfig as n, ConfigValueOrigin as o, LenientParseOptions as p, AutocompactThresholdConfig as r, DeepReadonly as s, AutocompactModeConfig as t, HarnessState as u, PlanningModeConfig as v, PoConfigPendingSelection as w, PoConfigContext as x, PlanningThinkingLevel as y, VoiceModelConfig as z };
|
|
393
|
-
//# sourceMappingURL=config-
|
|
398
|
+
//# sourceMappingURL=config-PGy7mpmC.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-
|
|
1
|
+
{"version":3,"file":"config-PGy7mpmC.d.mts","names":["IPoConfigService","PoConfigServiceContract"],"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;;;UAGG;EACf;;;;;;UAMe;EACf;EACA,WAAW;EACX;EACA;;UAEe;EACf;;;;;;;UAOe;;EAEf;;EAEA;;EAEA;;EAEA,MAAM;;UAGS;EACf;;;UAGe;;EAEf;;EAEA;;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;UAGe;EACf,OAAO;;EAEP;EACA;;IAEE;;IAEA,eAAe;;;UAGF;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;IACE;IACA;;IAEA,eAAe;;;UAGF;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,2BAA2B;WAAsC;;;UAG5D;EACf;;EAEA;EACA;EACA;;EAEA,WAAW;;UAGI;;EAEf,aAAa;EACb;IAAU,WAAW;IAAoB,cAAc;;EACvD,cAAc;EACd,qBAAqB;EACrB,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,SAAS;EACT,SAAS;EACT,MAAM;EACN,QAAQ;EACR,YAAY;;EAEZ;IAAQ;;;EAER;IAAW;;;UAMI;EACf;;EAEA;EACA;EACA;;EAEA;;;;;;;;;;;EAWA,qBAAqB,eAAe;;EAEpC;EACA;EACA,oBAAoB;EACpB;EACA;EACA;EACA;EACA;;EAEA,gBAAgB;EAChB;EACA;;;;;;EAMA,kBAAkB;;EAElB,eAAe;EACf;EACA;EACA;;KAGU,aAAa,UAAU,oBAAmB,6BAClD,SACA,+BAA+B,oBACpB,aAAa,WACtB,oCACc,cAAc,SAAS,aAAa,OAAO,YACvD;KAEI,mBAAmB,aAAa;UAE3B;WACN,UAAU,aAAa;WACvB,SAAS;;WAET,mBAAmB,aAAa;;WAEhC;;;UAIM;EACf,KAAK,kBAAkB,yBAAyB;;;UAIjCA,2BAAyBC,iBAAwB,iBAAiB;;YAGvE;IACR,aAAaD;;;;KAQL;;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"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const
|
|
2
|
+
const require_configPolicy = require("./configPolicy-BsQTmDKr.cjs");
|
|
3
|
+
const require_core = require("./core-DDqyXIMP.cjs");
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
3
6
|
let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
|
|
4
7
|
let node_fs = require("node:fs");
|
|
5
8
|
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
9
|
+
let yaml = require("yaml");
|
|
6
10
|
//#region src/services/config/sync.ts
|
|
7
11
|
function readTextSync(filePath) {
|
|
8
12
|
if (filePath === void 0) return void 0;
|
|
@@ -61,6 +65,77 @@ function loadPoConfigLayers(repoRoot, homeDirectory = _agimon_ai_po_core_platfor
|
|
|
61
65
|
}
|
|
62
66
|
//#endregion
|
|
63
67
|
//#region src/services/config/index.ts
|
|
68
|
+
const object = (value) => typeof value === "object" && value !== null && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
69
|
+
function jsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
70
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
71
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
72
|
+
if (typeof value !== "object" || !Array.isArray(value) && !object(value) || seen.has(value)) return false;
|
|
73
|
+
seen.add(value);
|
|
74
|
+
const valid = (Array.isArray(value) ? value : Object.values(value)).every((entry) => jsonValue(entry, seen));
|
|
75
|
+
seen.delete(value);
|
|
76
|
+
return valid;
|
|
77
|
+
}
|
|
78
|
+
/** Repository-only declarations. An existing new document is authoritative, even when empty. */
|
|
79
|
+
async function readWorkspaceDeclarations({ fs, repositoryRoot, context }) {
|
|
80
|
+
const filePath = node_path.default.join(repositoryRoot, ".po", "workspaces.yaml");
|
|
81
|
+
const text = await (0, _agimon_ai_po_core_platform.readTextIfExists)(fs, filePath, context);
|
|
82
|
+
if (text === void 0) {
|
|
83
|
+
const legacyPath = node_path.default.join(repositoryRoot, ".po", "config.yaml");
|
|
84
|
+
const legacy = await (0, _agimon_ai_po_core_platform.readTextIfExists)(fs, legacyPath, context);
|
|
85
|
+
const declarations = legacy === void 0 ? void 0 : require_core.configFromText(legacy, legacyPath).workspaces;
|
|
86
|
+
return {
|
|
87
|
+
declarations: declarations ?? [],
|
|
88
|
+
source: declarations === void 0 ? void 0 : "config.yaml",
|
|
89
|
+
notices: declarations === void 0 ? [] : [`Move workspaces from ${legacyPath} to ${filePath}; config.yaml workspaces is deprecated.`]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
let document;
|
|
93
|
+
try {
|
|
94
|
+
document = (0, yaml.parse)(text);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw new Error(`Could not parse workspace declarations at ${filePath}`, { cause: error });
|
|
97
|
+
}
|
|
98
|
+
if (!object(document) || Object.keys(document).some((key) => key !== "workspaces") || !Array.isArray(document.workspaces)) throw new Error(`Workspace declarations at ${filePath} must be an object containing a workspaces list`);
|
|
99
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
100
|
+
const declarations = document.workspaces.map((entry, index) => {
|
|
101
|
+
const location = `workspaces[${String(index)}]`;
|
|
102
|
+
if (!object(entry) || Object.keys(entry).some((key) => ![
|
|
103
|
+
"name",
|
|
104
|
+
"path",
|
|
105
|
+
"alias",
|
|
106
|
+
"instructions",
|
|
107
|
+
"metadata"
|
|
108
|
+
].includes(key))) throw new Error(`Workspace declarations at ${filePath} require ${location} to contain only name, path, alias, instructions, metadata`);
|
|
109
|
+
const base = require_configPolicy.parsePoConfig(JSON.stringify({ workspaces: [{
|
|
110
|
+
name: entry.name,
|
|
111
|
+
instructions: entry.instructions
|
|
112
|
+
}] }), filePath).workspaces[0];
|
|
113
|
+
if (base.name.length > 80 || !/^[A-Za-z0-9][A-Za-z0-9 ._-]*$/u.test(base.name) || base.name.includes("..")) throw new Error(`Workspace declarations at ${filePath} require ${location}.name to use letters, numbers, spaces, dots, dashes, or underscores (up to 80 characters)`);
|
|
114
|
+
if (entry.path !== void 0 && (typeof entry.path !== "string" || entry.path.trim() === "" || entry.path.includes("\0"))) throw new Error(`Workspace declarations at ${filePath} require ${location}.path to be a non-empty path`);
|
|
115
|
+
if (entry.alias !== void 0 && (typeof entry.alias !== "string" || entry.alias.trim() === "")) throw new Error(`Workspace declarations at ${filePath} require ${location}.alias to be a non-empty string`);
|
|
116
|
+
const alias = typeof entry.alias === "string" ? entry.alias.trim() : void 0;
|
|
117
|
+
if (alias !== void 0) {
|
|
118
|
+
if (aliases.has(alias)) throw new Error(`Workspace declarations at ${filePath} have duplicate alias: ${alias}`);
|
|
119
|
+
aliases.add(alias);
|
|
120
|
+
}
|
|
121
|
+
if (entry.metadata !== void 0 && (!object(entry.metadata) || !jsonValue(entry.metadata))) throw new Error(`Workspace declarations at ${filePath} require ${location}.metadata to be a JSON object`);
|
|
122
|
+
return {
|
|
123
|
+
...base,
|
|
124
|
+
...entry.path === void 0 ? {} : { path: entry.path },
|
|
125
|
+
...alias === void 0 ? {} : { alias },
|
|
126
|
+
...entry.metadata === void 0 ? {} : { metadata: entry.metadata }
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
require_configPolicy.parsePoConfig(JSON.stringify({ workspaces: declarations.map(({ name, instructions }) => ({
|
|
130
|
+
name,
|
|
131
|
+
instructions
|
|
132
|
+
})) }), filePath);
|
|
133
|
+
return {
|
|
134
|
+
declarations,
|
|
135
|
+
source: "workspaces.yaml",
|
|
136
|
+
notices: []
|
|
137
|
+
};
|
|
138
|
+
}
|
|
64
139
|
function resolved(options) {
|
|
65
140
|
return {
|
|
66
141
|
homeDirectory: options.homeDirectory ?? _agimon_ai_po_core_platform.nodeHost.homeDirectory(),
|
|
@@ -151,5 +226,11 @@ Object.defineProperty(exports, "readPoConfigLenient", {
|
|
|
151
226
|
return readPoConfigLenient;
|
|
152
227
|
}
|
|
153
228
|
});
|
|
229
|
+
Object.defineProperty(exports, "readWorkspaceDeclarations", {
|
|
230
|
+
enumerable: true,
|
|
231
|
+
get: function() {
|
|
232
|
+
return readWorkspaceDeclarations;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
154
235
|
|
|
155
|
-
//# sourceMappingURL=config-
|
|
236
|
+
//# sourceMappingURL=config-ch_DJeTs.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-ch_DJeTs.cjs","names":["fs","readText","nodeHost","globalPoConfigPath","repositoryConfigFor","mergeConfigLayers","configFromText","defaultPoConfig","mergeLenientLayers","lenientConfigFromText","composeConfigLayers","layerFromText","absentRepositoryLayer","path","readTextIfExists","configFromText","parseYaml","parsePoConfig","nodeHost","globalPoConfigPath","repositoryConfigFor","defaultPoConfig","mergeConfigLayers","lenientConfigFromText","mergeLenientLayers","layerFromText","absentRepositoryLayer","composeConfigLayers"],"sources":["../src/services/config/sync.ts","../src/services/config/index.ts"],"sourcesContent":["// sync: readTextSync supports exported Node-only synchronous config readers retained for phase 2.\nimport fs from 'node:fs';\n\nimport { nodeHost } from '@agimon-ai/po-core/platform';\n\nimport type { PoConfig, PoConfigLayers, LenientParseResult } from '../../types/config';\nimport {\n absentRepositoryLayer,\n composeConfigLayers,\n configFromText,\n defaultPoConfig,\n globalPoConfigPath,\n layerFromText,\n lenientConfigFromText,\n mergeConfigLayers,\n mergeLenientLayers,\n repositoryConfigFor,\n} from './core';\n\nfunction readTextSync(filePath: string | undefined): string | undefined {\n if (filePath === undefined) return undefined;\n try {\n return fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\nasync function readText(filePath: string): Promise<string | undefined> {\n try {\n return await fs.promises.readFile(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\n/** @deprecated Node-only sync shim; use readPoConfig. Removed in M2. */\nexport function loadPoConfig(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): PoConfig {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n return mergeConfigLayers(\n configFromText(readTextSync(globalPath), globalPath),\n repositoryPath === undefined ? defaultPoConfig() : configFromText(readTextSync(repositoryPath), repositoryPath),\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 * `loadPoConfig`, 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 *\n * @deprecated Node-only sync shim; use readPoConfigLenient. Removed in M2.\n */\nexport function loadPoConfigLenient(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n return mergeLenientLayers(\n lenientConfigFromText(readTextSync(globalPath), globalPath),\n lenientConfigFromText(readTextSync(repositoryPath), repositoryPath ?? ''),\n environment,\n );\n}\n\n/** @deprecated Node-only shim over node:fs; use readPoConfig. Removed in M2. */\nexport async function loadPoConfigAsync(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<PoConfig> {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalConfig = configFromText(await readText(globalPath), globalPath);\n const repositoryConfig =\n repositoryPath === undefined ? defaultPoConfig() : configFromText(await readText(repositoryPath), repositoryPath);\n return mergeConfigLayers(globalConfig, repositoryConfig, environment);\n}\n\n/** @deprecated Node-only sync shim; use readPoConfigLayers. Removed in M2. */\nexport function loadPoConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = nodeHost.homeDirectory(),\n environment: NodeJS.ProcessEnv = process.env,\n): PoConfigLayers {\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalText = readTextSync(globalPath);\n const repositoryText = readTextSync(repositoryPath);\n const repositoryConfig =\n repositoryPath === undefined ? defaultPoConfig() : configFromText(repositoryText, repositoryPath);\n return composeConfigLayers(\n layerFromText(globalPath, globalText),\n repositoryPath === undefined ? absentRepositoryLayer() : layerFromText(repositoryPath, repositoryText),\n mergeConfigLayers(configFromText(globalText, globalPath), repositoryConfig, environment),\n );\n}\n","import path from 'node:path';\n\nimport { nodeHost, readTextIfExists, type FileSystem } from '@agimon-ai/po-core/platform';\nimport { parse as parseYaml } from 'yaml';\n\nimport type { PoConfig, PoConfigLayers, LenientParseResult, WorkspaceDeclaration } from '../../types/config';\nimport { parsePoConfig } from '../configPolicy';\nimport {\n absentRepositoryLayer,\n composeConfigLayers,\n configFromText,\n defaultPoConfig,\n globalPoConfigPath,\n layerFromText,\n lenientConfigFromText,\n mergeConfigLayers,\n mergeLenientLayers,\n repositoryConfigFor,\n type ConfigEnvironment,\n} from './core';\n\ntype IoContext = Parameters<FileSystem['readTextFile']>[1];\n\nexport interface ReadWorkspaceDeclarationsOptions {\n fs: FileSystem;\n repositoryRoot: string;\n context: IoContext;\n}\n\nexport interface WorkspaceDeclarationsResult {\n declarations: WorkspaceDeclaration[];\n source: 'workspaces.yaml' | 'config.yaml' | undefined;\n notices: string[];\n}\n\nconst object = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' &&\n value !== null &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n\nfunction jsonValue(value: unknown, seen = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || (!Array.isArray(value) && !object(value)) || seen.has(value)) return false;\n seen.add(value);\n const valid = (Array.isArray(value) ? value : Object.values(value)).every((entry) => jsonValue(entry, seen));\n seen.delete(value);\n return valid;\n}\n\n/** Repository-only declarations. An existing new document is authoritative, even when empty. */\nexport async function readWorkspaceDeclarations({\n fs,\n repositoryRoot,\n context,\n}: ReadWorkspaceDeclarationsOptions): Promise<WorkspaceDeclarationsResult> {\n const filePath = path.join(repositoryRoot, '.po', 'workspaces.yaml');\n const text = await readTextIfExists(fs, filePath, context);\n if (text === undefined) {\n const legacyPath = path.join(repositoryRoot, '.po', 'config.yaml');\n const legacy = await readTextIfExists(fs, legacyPath, context);\n const declarations = legacy === undefined ? undefined : configFromText(legacy, legacyPath).workspaces;\n return {\n declarations: declarations ?? [],\n source: declarations === undefined ? undefined : 'config.yaml',\n notices:\n declarations === undefined\n ? []\n : [`Move workspaces from ${legacyPath} to ${filePath}; config.yaml workspaces is deprecated.`],\n };\n }\n let document: unknown;\n try {\n document = parseYaml(text);\n } catch (error) {\n throw new Error(`Could not parse workspace declarations at ${filePath}`, { cause: error });\n }\n if (\n !object(document) ||\n Object.keys(document).some((key) => key !== 'workspaces') ||\n !Array.isArray(document.workspaces)\n )\n throw new Error(`Workspace declarations at ${filePath} must be an object containing a workspaces list`);\n const aliases = new Set<string>();\n const declarations = document.workspaces.map((entry: unknown, index): WorkspaceDeclaration => {\n const location = `workspaces[${String(index)}]`;\n if (\n !object(entry) ||\n Object.keys(entry).some((key) => !['name', 'path', 'alias', 'instructions', 'metadata'].includes(key))\n )\n throw new Error(\n `Workspace declarations at ${filePath} require ${location} to contain only name, path, alias, instructions, metadata`,\n );\n // Reuse the established declaration name/instructions parser, without changing the legacy config contract.\n const base = parsePoConfig(\n JSON.stringify({ workspaces: [{ name: entry.name, instructions: entry.instructions }] }),\n filePath,\n ).workspaces![0]!;\n if (base.name.length > 80 || !/^[A-Za-z0-9][A-Za-z0-9 ._-]*$/u.test(base.name) || base.name.includes('..'))\n throw new Error(\n `Workspace declarations at ${filePath} require ${location}.name to use letters, numbers, spaces, dots, dashes, or underscores (up to 80 characters)`,\n );\n if (\n entry.path !== undefined &&\n (typeof entry.path !== 'string' || entry.path.trim() === '' || entry.path.includes('\\0'))\n )\n throw new Error(`Workspace declarations at ${filePath} require ${location}.path to be a non-empty path`);\n if (entry.alias !== undefined && (typeof entry.alias !== 'string' || entry.alias.trim() === ''))\n throw new Error(`Workspace declarations at ${filePath} require ${location}.alias to be a non-empty string`);\n const alias = typeof entry.alias === 'string' ? entry.alias.trim() : undefined;\n if (alias !== undefined) {\n if (aliases.has(alias)) throw new Error(`Workspace declarations at ${filePath} have duplicate alias: ${alias}`);\n aliases.add(alias);\n }\n if (entry.metadata !== undefined && (!object(entry.metadata) || !jsonValue(entry.metadata)))\n throw new Error(`Workspace declarations at ${filePath} require ${location}.metadata to be a JSON object`);\n return {\n ...base,\n ...(entry.path === undefined ? {} : { path: entry.path as string }),\n ...(alias === undefined ? {} : { alias }),\n ...(entry.metadata === undefined ? {} : { metadata: entry.metadata as Record<string, unknown> }),\n };\n });\n // Retain the legacy parser's case-insensitive duplicate-name rule across the entire document.\n parsePoConfig(\n JSON.stringify({ workspaces: declarations.map(({ name, instructions }) => ({ name, instructions })) }),\n filePath,\n );\n return { declarations, source: 'workspaces.yaml', notices: [] };\n}\n\nexport interface ReadPoConfigOptions {\n /** Defaults to the host's home directory. */\n readonly homeDirectory?: string;\n /** Defaults to `process.env`. */\n readonly environment?: ConfigEnvironment;\n}\n\nfunction resolved(options: ReadPoConfigOptions): { homeDirectory: string; environment: ConfigEnvironment } {\n return {\n homeDirectory: options.homeDirectory ?? nodeHost.homeDirectory(),\n environment: options.environment ?? process.env,\n };\n}\n\nconst readText = (fs: FileSystem, filePath: string | undefined, context: IoContext) =>\n filePath === undefined ? Promise.resolve(undefined) : readTextIfExists(fs, filePath, context);\n\n/**\n * Loads the merged global and repository config over a FileSystem. A missing\n * file contributes the defaults, so a host with neither file, such as a fresh\n * Durable Object filesystem, reads the same config as an empty Node home.\n */\nexport async function readPoConfig(\n fs: FileSystem,\n repoRoot: string,\n context: IoContext,\n options: ReadPoConfigOptions = {},\n): Promise<PoConfig> {\n const { homeDirectory, environment } = resolved(options);\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalConfig = configFromText(await readText(fs, globalPath, context), globalPath);\n const repositoryConfig =\n repositoryPath === undefined\n ? defaultPoConfig()\n : configFromText(await readText(fs, repositoryPath, context), repositoryPath);\n return mergeConfigLayers(globalConfig, repositoryConfig, environment);\n}\n\n/** As `readPoConfig`, tolerating unknown keys in either file and reporting them. */\nexport async function readPoConfigLenient(\n fs: FileSystem,\n repoRoot: string,\n context: IoContext,\n options: ReadPoConfigOptions = {},\n): Promise<LenientParseResult> {\n const { homeDirectory, environment } = resolved(options);\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalConfig = lenientConfigFromText(await readText(fs, globalPath, context), globalPath);\n const repositoryConfig =\n repositoryPath === undefined\n ? lenientConfigFromText(undefined, '')\n : lenientConfigFromText(await readText(fs, repositoryPath, context), repositoryPath);\n return mergeLenientLayers(globalConfig, repositoryConfig, environment);\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.\n */\nexport async function readPoConfigLayers(\n fs: FileSystem,\n repoRoot: string | undefined,\n context: IoContext,\n options: ReadPoConfigOptions = {},\n): Promise<PoConfigLayers> {\n const { homeDirectory, environment } = resolved(options);\n const globalPath = globalPoConfigPath(homeDirectory, environment);\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory, environment);\n const globalText = await readText(fs, globalPath, context);\n const repositoryText = await readText(fs, repositoryPath, context);\n const globalLayer = layerFromText(globalPath, globalText);\n const repositoryLayer =\n repositoryPath === undefined ? absentRepositoryLayer() : layerFromText(repositoryPath, repositoryText);\n const repositoryConfig =\n repositoryPath === undefined ? defaultPoConfig() : configFromText(repositoryText, repositoryPath);\n const effective = mergeConfigLayers(configFromText(globalText, globalPath), repositoryConfig, environment);\n return composeConfigLayers(globalLayer, repositoryLayer, effective);\n}\n\nexport {\n globalPoConfigDirectory,\n globalPoConfigPath,\n isGlobalPoConfigRoot,\n repositoryPoConfigPath,\n resolvePlanningPlansDirectory,\n} from './core';\nexport type { ConfigEnvironment } from './core';\nexport { loadPoConfig, loadPoConfigAsync, loadPoConfigLayers, loadPoConfigLenient } from './sync';\n"],"mappings":"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"}
|
package/dist/config.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_configPolicy = require("./configPolicy-BsQTmDKr.cjs");
|
|
3
|
-
const require_core = require("./core-
|
|
4
|
-
const require_config = require("./config-
|
|
3
|
+
const require_core = require("./core-DDqyXIMP.cjs");
|
|
4
|
+
const require_config = require("./config-ch_DJeTs.cjs");
|
|
5
5
|
exports.PO_PLANNING_THINKING_LEVELS = require_configPolicy.PO_PLANNING_THINKING_LEVELS;
|
|
6
6
|
exports.PO_VOICE_ENGINES = require_configPolicy.PO_VOICE_ENGINES;
|
|
7
7
|
exports.PO_VOICE_LIVE_VOICES = require_configPolicy.PO_VOICE_LIVE_VOICES;
|
|
@@ -23,6 +23,7 @@ exports.parsePoConfig = require_configPolicy.parsePoConfig;
|
|
|
23
23
|
exports.readPoConfig = require_config.readPoConfig;
|
|
24
24
|
exports.readPoConfigLayers = require_config.readPoConfigLayers;
|
|
25
25
|
exports.readPoConfigLenient = require_config.readPoConfigLenient;
|
|
26
|
+
exports.readWorkspaceDeclarations = require_config.readWorkspaceDeclarations;
|
|
26
27
|
exports.repositoryPoConfigPath = require_core.repositoryPoConfigPath;
|
|
27
28
|
exports.resolvePlanningPlansDirectory = require_core.resolvePlanningPlansDirectory;
|
|
28
29
|
exports.resolveVoiceConfig = require_configPolicy.resolveVoiceConfig;
|
package/dist/config.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as PoConfigLayers, S as PoConfigLayer, a as ConfigDiagnostic, m as LenientParseResult, o as ConfigValueOrigin, p as LenientParseOptions } from "./config-
|
|
2
|
-
import { C as
|
|
3
|
-
export { type ConfigDiagnostic, type ConfigKeyScope, type ConfigValueOrigin, type LenientParseOptions, type LenientParseResult, PO_PLANNING_THINKING_LEVELS, PO_VOICE_ENGINES, PO_VOICE_LIVE_VOICES, PO_VOICE_MODES, PO_VOICE_TTS_ENGINES, type PoConfigLayer, type PoConfigLayers, type ReadPoConfigOptions, configLeafKeys, configRootKeys, configScopeOf, globalPoConfigDirectory, globalPoConfigPath, loadPoConfig, loadPoConfigAsync, loadPoConfigLayers, loadPoConfigLenient, mergePoConfigs, parseAutocompactModeConfig, parsePlanningModeConfig, parsePoConfig, readPoConfig, readPoConfigLayers, readPoConfigLenient, repositoryPoConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
1
|
+
import { C as PoConfigLayers, S as PoConfigLayer, a as ConfigDiagnostic, m as LenientParseResult, o as ConfigValueOrigin, p as LenientParseOptions } from "./config-PGy7mpmC.mjs";
|
|
2
|
+
import { A as resolvePlanningPlansDirectory, C as loadPoConfig, D as globalPoConfigDirectory, E as loadPoConfigLenient, O as globalPoConfigPath, S as readWorkspaceDeclarations, T as loadPoConfigLayers, _ as ReadWorkspaceDeclarationsOptions, a as PO_VOICE_MODES, b as readPoConfigLayers, c as configRootKeys, d as parseAutocompactModeConfig, f as parsePlanningModeConfig, g as ReadPoConfigOptions, h as valueAtKeyPath, i as PO_VOICE_LIVE_VOICES, k as repositoryPoConfigPath, l as configScopeOf, m as resolveVoiceConfig, n as PO_PLANNING_THINKING_LEVELS, o as PO_VOICE_TTS_ENGINES, p as parsePoConfig, r as PO_VOICE_ENGINES, s as configLeafKeys, t as ConfigKeyScope, u as mergePoConfigs, v as WorkspaceDeclarationsResult, w as loadPoConfigAsync, x as readPoConfigLenient, y as readPoConfig } from "./index-D2c9ew7Y.mjs";
|
|
3
|
+
export { type ConfigDiagnostic, type ConfigKeyScope, type ConfigValueOrigin, type LenientParseOptions, type LenientParseResult, PO_PLANNING_THINKING_LEVELS, PO_VOICE_ENGINES, PO_VOICE_LIVE_VOICES, PO_VOICE_MODES, PO_VOICE_TTS_ENGINES, type PoConfigLayer, type PoConfigLayers, type ReadPoConfigOptions, type ReadWorkspaceDeclarationsOptions, type WorkspaceDeclarationsResult, configLeafKeys, configRootKeys, configScopeOf, globalPoConfigDirectory, globalPoConfigPath, loadPoConfig, loadPoConfigAsync, loadPoConfigLayers, loadPoConfigLenient, mergePoConfigs, parseAutocompactModeConfig, parsePlanningModeConfig, parsePoConfig, readPoConfig, readPoConfigLayers, readPoConfigLenient, readWorkspaceDeclarations, repositoryPoConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
package/dist/config.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { a as PO_VOICE_TTS_ENGINES, c as configScopeOf, d as parsePlanningModeConfig, f as parsePoConfig, i as PO_VOICE_MODES, l as mergePoConfigs, m as valueAtKeyPath, n as PO_VOICE_ENGINES, o as configLeafKeys, p as resolveVoiceConfig, r as PO_VOICE_LIVE_VOICES, s as configRootKeys, t as PO_PLANNING_THINKING_LEVELS, u as parseAutocompactModeConfig } from "./configPolicy-BADJDi8o.mjs";
|
|
2
|
-
import { a as globalPoConfigDirectory, m as resolvePlanningPlansDirectory, o as globalPoConfigPath, p as repositoryPoConfigPath } from "./core-
|
|
3
|
-
import { a as
|
|
4
|
-
export { PO_PLANNING_THINKING_LEVELS, PO_VOICE_ENGINES, PO_VOICE_LIVE_VOICES, PO_VOICE_MODES, PO_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, globalPoConfigDirectory, globalPoConfigPath, loadPoConfig, loadPoConfigAsync, loadPoConfigLayers, loadPoConfigLenient, mergePoConfigs, parseAutocompactModeConfig, parsePlanningModeConfig, parsePoConfig, readPoConfig, readPoConfigLayers, readPoConfigLenient, repositoryPoConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
2
|
+
import { a as globalPoConfigDirectory, m as resolvePlanningPlansDirectory, o as globalPoConfigPath, p as repositoryPoConfigPath } from "./core-BOyti7Xw.mjs";
|
|
3
|
+
import { a as loadPoConfig, c as loadPoConfigLenient, i as readWorkspaceDeclarations, n as readPoConfigLayers, o as loadPoConfigAsync, r as readPoConfigLenient, s as loadPoConfigLayers, t as readPoConfig } from "./config-C-dgx_54.mjs";
|
|
4
|
+
export { PO_PLANNING_THINKING_LEVELS, PO_VOICE_ENGINES, PO_VOICE_LIVE_VOICES, PO_VOICE_MODES, PO_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, globalPoConfigDirectory, globalPoConfigPath, loadPoConfig, loadPoConfigAsync, loadPoConfigLayers, loadPoConfigLenient, mergePoConfigs, parseAutocompactModeConfig, parsePlanningModeConfig, parsePoConfig, readPoConfig, readPoConfigLayers, readPoConfigLenient, readWorkspaceDeclarations, repositoryPoConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
@@ -2,8 +2,8 @@ import { c as configScopeOf, f as parsePoConfig, l as mergePoConfigs, m as value
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { nodeHost } from "@agimon-ai/po-core/platform";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
|
-
import { poHomeDirectory } from "@agimon-ai/po-core/piSettings";
|
|
6
5
|
import { parse } from "yaml";
|
|
6
|
+
import { poHomeDirectory } from "@agimon-ai/po-core/piSettings";
|
|
7
7
|
//#region src/services/config/core.ts
|
|
8
8
|
/**
|
|
9
9
|
* Paths and pure parse/merge steps for the two Po config files. The readers
|
|
@@ -137,4 +137,4 @@ function composeConfigLayers(globalLayer, repositoryLayer, effective) {
|
|
|
137
137
|
//#endregion
|
|
138
138
|
export { globalPoConfigDirectory as a, layerFromText as c, mergeLenientLayers as d, repositoryConfigFor as f, defaultPoConfig as i, lenientConfigFromText as l, resolvePlanningPlansDirectory as m, composeConfigLayers as n, globalPoConfigPath as o, repositoryPoConfigPath as p, configFromText as r, isGlobalPoConfigRoot as s, absentRepositoryLayer as t, mergeConfigLayers as u };
|
|
139
139
|
|
|
140
|
-
//# sourceMappingURL=core-
|
|
140
|
+
//# sourceMappingURL=core-BOyti7Xw.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-
|
|
1
|
+
{"version":3,"file":"core-BOyti7Xw.mjs","names":["parseYaml"],"sources":["../src/services/config/core.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { nodeHost } from '@agimon-ai/po-core/platform';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n PoConfig,\n PoConfigLayer,\n PoConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergePoConfigs, parsePoConfig, valueAtKeyPath } from '../configPolicy';\n\n/**\n * Paths and pure parse/merge steps for the two Po config files. The readers\n * in `read.ts` (async, over a FileSystem) and `sync.ts` (Node-only shims) only\n * fetch file text and hand it here, so both produce identical results.\n */\n\nconst PO_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nexport type ConfigEnvironment = Readonly<Record<string, string | undefined>>;\n\n/** Runtime callers pass admitted environment; omission retains the legacy host lookup. */\nexport function globalPoConfigDirectory(\n homeDirectory = nodeHost.homeDirectory(),\n environment?: ConfigEnvironment,\n): string {\n return poHomeDirectory(homeDirectory, environment);\n}\n\nexport function globalPoConfigPath(homeDirectory = nodeHost.homeDirectory(), environment?: ConfigEnvironment): string {\n return path.join(globalPoConfigDirectory(homeDirectory, environment), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalPoConfigDirectory(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(\"Po planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryPoConfigPath(repoRoot: string): string {\n return path.join(repoRoot, PO_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 isGlobalPoConfigRoot(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment?: ConfigEnvironment,\n): boolean {\n return path.resolve(repoRoot, PO_DIR) === path.resolve(globalPoConfigDirectory(homeDirectory, environment));\n}\n\nexport function repositoryConfigFor(\n repoRoot: string,\n homeDirectory: string,\n environment?: ConfigEnvironment,\n): string | undefined {\n return isGlobalPoConfigRoot(repoRoot, homeDirectory, environment) ? undefined : repositoryPoConfigPath(repoRoot);\n}\n\n/** The config a missing file stands for. */\nexport function defaultPoConfig(): PoConfig {\n return { projectTrust: 'ask' };\n}\n\n/** Parses one file's text strictly; `undefined` text means the file is absent. */\nexport function configFromText(text: string | undefined, filePath: string): PoConfig {\n return text === undefined ? defaultPoConfig() : parsePoConfig(text, filePath);\n}\n\n/** Parses one file's text leniently; `undefined` text means the file is absent. */\nexport function lenientConfigFromText(text: string | undefined, filePath: string): LenientParseResult {\n return text === undefined\n ? { config: defaultPoConfig(), diagnostics: [] }\n : parsePoConfig(text, filePath, { lenient: true });\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nexport function distributionDefaults(config: PoConfig, environment: ConfigEnvironment): PoConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\n/** Merges the global and repository files, then applies distribution defaults. */\nexport function mergeConfigLayers(\n globalConfig: PoConfig,\n repositoryConfig: PoConfig,\n environment: ConfigEnvironment,\n): PoConfig {\n return distributionDefaults(mergePoConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/** Merges lenient parses; the merge itself stays strict about cross-file scope. */\nexport function mergeLenientLayers(\n globalConfig: LenientParseResult,\n repositoryConfig: LenientParseResult,\n environment: ConfigEnvironment,\n): LenientParseResult {\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergePoConfigs 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 { config: mergeConfigLayers(globalConfig.config, repositoryConfig.config, environment), diagnostics };\n}\n\n/**\n * One config file as a layer: what it is, what it sets, and the bytes it held.\n * A file that does not exist is a layer that sets nothing, which is a normal\n * state rather than an error.\n */\nexport function layerFromText(filePath: string, text: string | undefined): PoConfigLayer {\n if (text === undefined) return { filePath, exists: false, hash: '', keys: [] };\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\nexport function absentRepositoryLayer(): PoConfigLayer {\n return { filePath: '', exists: false, hash: '', keys: [] };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\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 composeConfigLayers(\n globalLayer: PoConfigLayer,\n repositoryLayer: PoConfigLayer,\n effective: PoConfig,\n): PoConfigLayers {\n const sets = (layer: PoConfigLayer, 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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"}
|
|
@@ -4,8 +4,8 @@ let node_path = require("node:path");
|
|
|
4
4
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
5
5
|
let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
|
-
let _agimon_ai_po_core_piSettings = require("@agimon-ai/po-core/piSettings");
|
|
8
7
|
let yaml = require("yaml");
|
|
8
|
+
let _agimon_ai_po_core_piSettings = require("@agimon-ai/po-core/piSettings");
|
|
9
9
|
//#region src/services/config/core.ts
|
|
10
10
|
/**
|
|
11
11
|
* Paths and pure parse/merge steps for the two Po config files. The readers
|
|
@@ -222,4 +222,4 @@ Object.defineProperty(exports, "resolvePlanningPlansDirectory", {
|
|
|
222
222
|
}
|
|
223
223
|
});
|
|
224
224
|
|
|
225
|
-
//# sourceMappingURL=core-
|
|
225
|
+
//# sourceMappingURL=core-DDqyXIMP.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-CWPpoX0B.cjs","names":["nodeHost","poHomeDirectory","path","parsePoConfig","mergePoConfigs","parseYaml","createHash","configLeafKeys","configScopeOf","valueAtKeyPath"],"sources":["../src/services/config/core.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { nodeHost } from '@agimon-ai/po-core/platform';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n PoConfig,\n PoConfigLayer,\n PoConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergePoConfigs, parsePoConfig, valueAtKeyPath } from '../configPolicy';\n\n/**\n * Paths and pure parse/merge steps for the two Po config files. The readers\n * in `read.ts` (async, over a FileSystem) and `sync.ts` (Node-only shims) only\n * fetch file text and hand it here, so both produce identical results.\n */\n\nconst PO_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nexport type ConfigEnvironment = Readonly<Record<string, string | undefined>>;\n\n/** Runtime callers pass admitted environment; omission retains the legacy host lookup. */\nexport function globalPoConfigDirectory(\n homeDirectory = nodeHost.homeDirectory(),\n environment?: ConfigEnvironment,\n): string {\n return poHomeDirectory(homeDirectory, environment);\n}\n\nexport function globalPoConfigPath(homeDirectory = nodeHost.homeDirectory(), environment?: ConfigEnvironment): string {\n return path.join(globalPoConfigDirectory(homeDirectory, environment), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalPoConfigDirectory(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(\"Po planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryPoConfigPath(repoRoot: string): string {\n return path.join(repoRoot, PO_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 isGlobalPoConfigRoot(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment?: ConfigEnvironment,\n): boolean {\n return path.resolve(repoRoot, PO_DIR) === path.resolve(globalPoConfigDirectory(homeDirectory, environment));\n}\n\nexport function repositoryConfigFor(\n repoRoot: string,\n homeDirectory: string,\n environment?: ConfigEnvironment,\n): string | undefined {\n return isGlobalPoConfigRoot(repoRoot, homeDirectory, environment) ? undefined : repositoryPoConfigPath(repoRoot);\n}\n\n/** The config a missing file stands for. */\nexport function defaultPoConfig(): PoConfig {\n return { projectTrust: 'ask' };\n}\n\n/** Parses one file's text strictly; `undefined` text means the file is absent. */\nexport function configFromText(text: string | undefined, filePath: string): PoConfig {\n return text === undefined ? defaultPoConfig() : parsePoConfig(text, filePath);\n}\n\n/** Parses one file's text leniently; `undefined` text means the file is absent. */\nexport function lenientConfigFromText(text: string | undefined, filePath: string): LenientParseResult {\n return text === undefined\n ? { config: defaultPoConfig(), diagnostics: [] }\n : parsePoConfig(text, filePath, { lenient: true });\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nexport function distributionDefaults(config: PoConfig, environment: ConfigEnvironment): PoConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\n/** Merges the global and repository files, then applies distribution defaults. */\nexport function mergeConfigLayers(\n globalConfig: PoConfig,\n repositoryConfig: PoConfig,\n environment: ConfigEnvironment,\n): PoConfig {\n return distributionDefaults(mergePoConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/** Merges lenient parses; the merge itself stays strict about cross-file scope. */\nexport function mergeLenientLayers(\n globalConfig: LenientParseResult,\n repositoryConfig: LenientParseResult,\n environment: ConfigEnvironment,\n): LenientParseResult {\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergePoConfigs 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 { config: mergeConfigLayers(globalConfig.config, repositoryConfig.config, environment), diagnostics };\n}\n\n/**\n * One config file as a layer: what it is, what it sets, and the bytes it held.\n * A file that does not exist is a layer that sets nothing, which is a normal\n * state rather than an error.\n */\nexport function layerFromText(filePath: string, text: string | undefined): PoConfigLayer {\n if (text === undefined) return { filePath, exists: false, hash: '', keys: [] };\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\nexport function absentRepositoryLayer(): PoConfigLayer {\n return { filePath: '', exists: false, hash: '', keys: [] };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\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 composeConfigLayers(\n globalLayer: PoConfigLayer,\n repositoryLayer: PoConfigLayer,\n effective: PoConfig,\n): PoConfigLayers {\n const sets = (layer: PoConfigLayer, 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
|
+
{"version":3,"file":"core-DDqyXIMP.cjs","names":["nodeHost","poHomeDirectory","path","parsePoConfig","mergePoConfigs","parseYaml","createHash","configLeafKeys","configScopeOf","valueAtKeyPath"],"sources":["../src/services/config/core.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { nodeHost } from '@agimon-ai/po-core/platform';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n PoConfig,\n PoConfigLayer,\n PoConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergePoConfigs, parsePoConfig, valueAtKeyPath } from '../configPolicy';\n\n/**\n * Paths and pure parse/merge steps for the two Po config files. The readers\n * in `read.ts` (async, over a FileSystem) and `sync.ts` (Node-only shims) only\n * fetch file text and hand it here, so both produce identical results.\n */\n\nconst PO_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nexport type ConfigEnvironment = Readonly<Record<string, string | undefined>>;\n\n/** Runtime callers pass admitted environment; omission retains the legacy host lookup. */\nexport function globalPoConfigDirectory(\n homeDirectory = nodeHost.homeDirectory(),\n environment?: ConfigEnvironment,\n): string {\n return poHomeDirectory(homeDirectory, environment);\n}\n\nexport function globalPoConfigPath(homeDirectory = nodeHost.homeDirectory(), environment?: ConfigEnvironment): string {\n return path.join(globalPoConfigDirectory(homeDirectory, environment), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalPoConfigDirectory(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(\"Po planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryPoConfigPath(repoRoot: string): string {\n return path.join(repoRoot, PO_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 isGlobalPoConfigRoot(\n repoRoot: string,\n homeDirectory = nodeHost.homeDirectory(),\n environment?: ConfigEnvironment,\n): boolean {\n return path.resolve(repoRoot, PO_DIR) === path.resolve(globalPoConfigDirectory(homeDirectory, environment));\n}\n\nexport function repositoryConfigFor(\n repoRoot: string,\n homeDirectory: string,\n environment?: ConfigEnvironment,\n): string | undefined {\n return isGlobalPoConfigRoot(repoRoot, homeDirectory, environment) ? undefined : repositoryPoConfigPath(repoRoot);\n}\n\n/** The config a missing file stands for. */\nexport function defaultPoConfig(): PoConfig {\n return { projectTrust: 'ask' };\n}\n\n/** Parses one file's text strictly; `undefined` text means the file is absent. */\nexport function configFromText(text: string | undefined, filePath: string): PoConfig {\n return text === undefined ? defaultPoConfig() : parsePoConfig(text, filePath);\n}\n\n/** Parses one file's text leniently; `undefined` text means the file is absent. */\nexport function lenientConfigFromText(text: string | undefined, filePath: string): LenientParseResult {\n return text === undefined\n ? { config: defaultPoConfig(), diagnostics: [] }\n : parsePoConfig(text, filePath, { lenient: true });\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nexport function distributionDefaults(config: PoConfig, environment: ConfigEnvironment): PoConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\n/** Merges the global and repository files, then applies distribution defaults. */\nexport function mergeConfigLayers(\n globalConfig: PoConfig,\n repositoryConfig: PoConfig,\n environment: ConfigEnvironment,\n): PoConfig {\n return distributionDefaults(mergePoConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/** Merges lenient parses; the merge itself stays strict about cross-file scope. */\nexport function mergeLenientLayers(\n globalConfig: LenientParseResult,\n repositoryConfig: LenientParseResult,\n environment: ConfigEnvironment,\n): LenientParseResult {\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergePoConfigs 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 { config: mergeConfigLayers(globalConfig.config, repositoryConfig.config, environment), diagnostics };\n}\n\n/**\n * One config file as a layer: what it is, what it sets, and the bytes it held.\n * A file that does not exist is a layer that sets nothing, which is a normal\n * state rather than an error.\n */\nexport function layerFromText(filePath: string, text: string | undefined): PoConfigLayer {\n if (text === undefined) return { filePath, exists: false, hash: '', keys: [] };\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\nexport function absentRepositoryLayer(): PoConfigLayer {\n return { filePath: '', exists: false, hash: '', keys: [] };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\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 composeConfigLayers(\n globalLayer: PoConfigLayer,\n repositoryLayer: PoConfigLayer,\n effective: PoConfig,\n): PoConfigLayers {\n const sets = (layer: PoConfigLayer, 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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"}
|