@agimon-ai/po-config 0.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/dist/agentPluginMcp.cjs +322 -0
  4. package/dist/agentPluginMcp.cjs.map +1 -0
  5. package/dist/agentPluginMcp.d.mts +38 -0
  6. package/dist/agentPluginMcp.d.mts.map +1 -0
  7. package/dist/agentPluginMcp.mjs +318 -0
  8. package/dist/agentPluginMcp.mjs.map +1 -0
  9. package/dist/apiContracts.cjs +203 -0
  10. package/dist/apiContracts.cjs.map +1 -0
  11. package/dist/apiContracts.d.mts +53 -0
  12. package/dist/apiContracts.d.mts.map +1 -0
  13. package/dist/apiContracts.mjs +198 -0
  14. package/dist/apiContracts.mjs.map +1 -0
  15. package/dist/atomicJson-1W0WhuFF.mjs +44 -0
  16. package/dist/atomicJson-1W0WhuFF.mjs.map +1 -0
  17. package/dist/atomicJson-Dt2z_DXl.cjs +52 -0
  18. package/dist/atomicJson-Dt2z_DXl.cjs.map +1 -0
  19. package/dist/atomicJson.cjs +3 -0
  20. package/dist/atomicJson.d.mts +2 -0
  21. package/dist/atomicJson.mjs +2 -0
  22. package/dist/config-BUw5kHsx.cjs +219 -0
  23. package/dist/config-BUw5kHsx.cjs.map +1 -0
  24. package/dist/config-CKA07FxG.mjs +162 -0
  25. package/dist/config-CKA07FxG.mjs.map +1 -0
  26. package/dist/config-Cm3EV1jp.d.mts +320 -0
  27. package/dist/config-Cm3EV1jp.d.mts.map +1 -0
  28. package/dist/config-NSHRd6na.mjs +2 -0
  29. package/dist/config-zZz80Mh5.cjs +1 -0
  30. package/dist/config.cjs +24 -0
  31. package/dist/config.d.mts +3 -0
  32. package/dist/config.mjs +3 -0
  33. package/dist/configPolicy--TNX7feH.mjs +718 -0
  34. package/dist/configPolicy--TNX7feH.mjs.map +1 -0
  35. package/dist/configPolicy-DmsZEp0t.cjs +795 -0
  36. package/dist/configPolicy-DmsZEp0t.cjs.map +1 -0
  37. package/dist/configSchema.cjs +0 -0
  38. package/dist/configSchema.d.mts +2 -0
  39. package/dist/configSchema.mjs +1 -0
  40. package/dist/configWriter-BTuinLjs.cjs +150 -0
  41. package/dist/configWriter-BTuinLjs.cjs.map +1 -0
  42. package/dist/configWriter-BgkGaLrf.mjs +130 -0
  43. package/dist/configWriter-BgkGaLrf.mjs.map +1 -0
  44. package/dist/configWriter.cjs +5 -0
  45. package/dist/configWriter.d.mts +2 -0
  46. package/dist/configWriter.mjs +2 -0
  47. package/dist/domains-CBYkuxs5.cjs +727 -0
  48. package/dist/domains-CBYkuxs5.cjs.map +1 -0
  49. package/dist/domains-DZOu9vYM.mjs +633 -0
  50. package/dist/domains-DZOu9vYM.mjs.map +1 -0
  51. package/dist/domains.cjs +19 -0
  52. package/dist/domains.d.mts +3 -0
  53. package/dist/domains.mjs +3 -0
  54. package/dist/extensions/mcp-ui.mjs +101 -0
  55. package/dist/extensions/mcp-ui.mjs.map +1 -0
  56. package/dist/extensions/mcp.cjs +171 -0
  57. package/dist/extensions/mcp.cjs.map +1 -0
  58. package/dist/extensions/mcp.d.mts +5 -0
  59. package/dist/extensions/mcp.d.mts.map +1 -0
  60. package/dist/extensions/mcp.mjs +166 -0
  61. package/dist/extensions/mcp.mjs.map +1 -0
  62. package/dist/extensions/server.cjs +504 -0
  63. package/dist/extensions/server.cjs.map +1 -0
  64. package/dist/extensions/server.d.mts +5 -0
  65. package/dist/extensions/server.d.mts.map +1 -0
  66. package/dist/extensions/server.mjs +499 -0
  67. package/dist/extensions/server.mjs.map +1 -0
  68. package/dist/harnessState-CCyBeutB.cjs +188 -0
  69. package/dist/harnessState-CCyBeutB.cjs.map +1 -0
  70. package/dist/harnessState-Dn_S7fB9.mjs +163 -0
  71. package/dist/harnessState-Dn_S7fB9.mjs.map +1 -0
  72. package/dist/harnessState.cjs +6 -0
  73. package/dist/harnessState.d.mts +2 -0
  74. package/dist/harnessState.mjs +2 -0
  75. package/dist/harnessStore-CJSxdSkV.cjs +343 -0
  76. package/dist/harnessStore-CJSxdSkV.cjs.map +1 -0
  77. package/dist/harnessStore-CltwLB7M.mjs +262 -0
  78. package/dist/harnessStore-CltwLB7M.mjs.map +1 -0
  79. package/dist/harnessStore.cjs +15 -0
  80. package/dist/harnessStore.d.mts +2 -0
  81. package/dist/harnessStore.mjs +2 -0
  82. package/dist/index-BAaTySaM.d.mts +35 -0
  83. package/dist/index-BAaTySaM.d.mts.map +1 -0
  84. package/dist/index-BT29GZx5.d.mts +142 -0
  85. package/dist/index-BT29GZx5.d.mts.map +1 -0
  86. package/dist/index-B_lp0W3U.d.mts +114 -0
  87. package/dist/index-B_lp0W3U.d.mts.map +1 -0
  88. package/dist/index-C6GaYjq-.d.mts +6 -0
  89. package/dist/index-C6GaYjq-.d.mts.map +1 -0
  90. package/dist/index-CIQrKS1A.d.mts +50 -0
  91. package/dist/index-CIQrKS1A.d.mts.map +1 -0
  92. package/dist/index-CRcoVYXz.d.mts +39 -0
  93. package/dist/index-CRcoVYXz.d.mts.map +1 -0
  94. package/dist/index-CVlciCJF.d.mts +40 -0
  95. package/dist/index-CVlciCJF.d.mts.map +1 -0
  96. package/dist/index-CeOk2kqs.d.mts +118 -0
  97. package/dist/index-CeOk2kqs.d.mts.map +1 -0
  98. package/dist/index-Ch7ptOkW.d.mts +54 -0
  99. package/dist/index-Ch7ptOkW.d.mts.map +1 -0
  100. package/dist/index-Cvdt-Y-i.d.mts +66 -0
  101. package/dist/index-Cvdt-Y-i.d.mts.map +1 -0
  102. package/dist/index-DJpG-I9K.d.mts +122 -0
  103. package/dist/index-DJpG-I9K.d.mts.map +1 -0
  104. package/dist/index-DNk4q0Qm.d.mts +81 -0
  105. package/dist/index-DNk4q0Qm.d.mts.map +1 -0
  106. package/dist/index.cjs +121 -0
  107. package/dist/index.d.mts +15 -0
  108. package/dist/index.mjs +15 -0
  109. package/dist/init-C_9nyp3-.cjs +448 -0
  110. package/dist/init-C_9nyp3-.cjs.map +1 -0
  111. package/dist/init-DJ6wm-dr.mjs +415 -0
  112. package/dist/init-DJ6wm-dr.mjs.map +1 -0
  113. package/dist/init.cjs +7 -0
  114. package/dist/init.d.mts +2 -0
  115. package/dist/init.mjs +2 -0
  116. package/dist/layeredConfig-B922ibgn.mjs +67 -0
  117. package/dist/layeredConfig-B922ibgn.mjs.map +1 -0
  118. package/dist/layeredConfig-DdI5ysUf.cjs +94 -0
  119. package/dist/layeredConfig-DdI5ysUf.cjs.map +1 -0
  120. package/dist/layeredConfig.cjs +6 -0
  121. package/dist/layeredConfig.d.mts +2 -0
  122. package/dist/layeredConfig.mjs +2 -0
  123. package/dist/majorModes-CmPLEpMT.mjs +333 -0
  124. package/dist/majorModes-CmPLEpMT.mjs.map +1 -0
  125. package/dist/majorModes-DPhVMuhT.cjs +383 -0
  126. package/dist/majorModes-DPhVMuhT.cjs.map +1 -0
  127. package/dist/majorModes.cjs +10 -0
  128. package/dist/majorModes.d.mts +2 -0
  129. package/dist/majorModes.mjs +2 -0
  130. package/dist/piConfig-Bx26HMb_.d.mts +33 -0
  131. package/dist/piConfig-Bx26HMb_.d.mts.map +1 -0
  132. package/dist/piConfig-CCBdZXQr.cjs +260 -0
  133. package/dist/piConfig-CCBdZXQr.cjs.map +1 -0
  134. package/dist/piConfig-qGyCbcVj.mjs +197 -0
  135. package/dist/piConfig-qGyCbcVj.mjs.map +1 -0
  136. package/dist/piConfig.cjs +12 -0
  137. package/dist/piConfig.d.mts +2 -0
  138. package/dist/piConfig.mjs +2 -0
  139. package/dist/piContext.cjs +18 -0
  140. package/dist/piContext.d.mts +3 -0
  141. package/dist/piContext.mjs +2 -0
  142. package/dist/profiles-CTrUCmIh.d.mts +27 -0
  143. package/dist/profiles-CTrUCmIh.d.mts.map +1 -0
  144. package/dist/profiles-DnF9DBpd.cjs +552 -0
  145. package/dist/profiles-DnF9DBpd.cjs.map +1 -0
  146. package/dist/profiles-fujQKrS0.mjs +483 -0
  147. package/dist/profiles-fujQKrS0.mjs.map +1 -0
  148. package/dist/profiles.cjs +13 -0
  149. package/dist/profiles.d.mts +25 -0
  150. package/dist/profiles.d.mts.map +1 -0
  151. package/dist/profiles.mjs +2 -0
  152. package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
  153. package/dist/selectionSwitch.cjs +70 -0
  154. package/dist/selectionSwitch.cjs.map +1 -0
  155. package/dist/selectionSwitch.d.mts +30 -0
  156. package/dist/selectionSwitch.d.mts.map +1 -0
  157. package/dist/selectionSwitch.mjs +64 -0
  158. package/dist/selectionSwitch.mjs.map +1 -0
  159. package/dist/sessionConfig-Boh4Fdje.cjs +342 -0
  160. package/dist/sessionConfig-Boh4Fdje.cjs.map +1 -0
  161. package/dist/sessionConfig-CtLoc-lO.mjs +240 -0
  162. package/dist/sessionConfig-CtLoc-lO.mjs.map +1 -0
  163. package/dist/types.cjs +9 -0
  164. package/dist/types.d.mts +2 -0
  165. package/dist/types.mjs +2 -0
  166. package/llms.txt +12 -0
  167. package/package.json +206 -0
  168. package/src/prompts/po-author-config/SKILL.md +26 -0
  169. package/src/prompts/po-author-config/agents/openai.yaml +4 -0
  170. package/src/prompts/po-author-config/references/config-contract.md +201 -0
@@ -0,0 +1,260 @@
1
+ const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
2
+ const require_atomicJson = require("./atomicJson-Dt2z_DXl.cjs");
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
+ let node_os = require("node:os");
8
+ node_os = require_rolldown_runtime.__toESM(node_os, 1);
9
+ let _agimon_ai_po_core_piSettings = require("@agimon-ai/po-core/piSettings");
10
+ //#region src/services/imageSettings/index.ts
11
+ const IMAGE_SETTINGS_KEY = "images";
12
+ const IMAGE_AUTO_RESIZE_KEY = "autoResize";
13
+ const IMAGE_MAX_DIMENSION_KEY = "maxDimension";
14
+ /** Pi's own cap, from its resize core; also the largest value worth writing. */
15
+ const DEFAULT_IMAGE_MAX_DIMENSION = 2e3;
16
+ /** Below this a screenshot stops being readable, which is what reads are for. */
17
+ const MIN_IMAGE_MAX_DIMENSION = 256;
18
+ function clampImageMaxDimension(value) {
19
+ const rounded = Math.round(value);
20
+ if (rounded < 256) return 256;
21
+ if (rounded > 2e3) return DEFAULT_IMAGE_MAX_DIMENSION;
22
+ return rounded;
23
+ }
24
+ function isRecord(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ /** Resolves the effective limits, defaulting anything absent or unusable. */
28
+ function parsePiImageSettings(config) {
29
+ const images = config[IMAGE_SETTINGS_KEY];
30
+ if (!isRecord(images)) return {
31
+ autoResize: true,
32
+ maxDimension: DEFAULT_IMAGE_MAX_DIMENSION
33
+ };
34
+ const autoResize = images[IMAGE_AUTO_RESIZE_KEY];
35
+ const maxDimension = images[IMAGE_MAX_DIMENSION_KEY];
36
+ return {
37
+ autoResize: typeof autoResize === "boolean" ? autoResize : true,
38
+ maxDimension: typeof maxDimension === "number" && Number.isFinite(maxDimension) ? clampImageMaxDimension(maxDimension) : DEFAULT_IMAGE_MAX_DIMENSION
39
+ };
40
+ }
41
+ /**
42
+ * Folds a change into the `images` object of a settings document, leaving every
43
+ * other key of that document, and of `images` itself, as it was.
44
+ */
45
+ function applyPiImageSettings(config, update) {
46
+ const existing = config[IMAGE_SETTINGS_KEY];
47
+ const images = isRecord(existing) ? { ...existing } : {};
48
+ if (update.autoResize !== void 0) images[IMAGE_AUTO_RESIZE_KEY] = update.autoResize;
49
+ if (update.maxDimension !== void 0) images[IMAGE_MAX_DIMENSION_KEY] = clampImageMaxDimension(update.maxDimension);
50
+ return {
51
+ ...config,
52
+ [IMAGE_SETTINGS_KEY]: images
53
+ };
54
+ }
55
+ //#endregion
56
+ //#region src/services/piConfig/index.ts
57
+ const SETTINGS_FILE_NAME = "settings.json";
58
+ const CONFIG_DIR_NAME = ".pi";
59
+ const LEGACY_CONFIG_DIR_NAME = "pi";
60
+ /** An explicit home other than the real one is isolated from the process environment. */
61
+ function defaultAgentDirectory(homeDirectory) {
62
+ return (0, _agimon_ai_po_core_piSettings.piAgentDirectory)(homeDirectory === node_os.default.homedir() ? process.env : {}, homeDirectory);
63
+ }
64
+ function isObject(value) {
65
+ return typeof value === "object" && value !== null && !Array.isArray(value);
66
+ }
67
+ function mergeConfig(base, override) {
68
+ const result = { ...base };
69
+ for (const [key, value] of Object.entries(override)) {
70
+ const current = result[key];
71
+ result[key] = isObject(current) && isObject(value) ? mergeConfig(current, value) : value;
72
+ }
73
+ return result;
74
+ }
75
+ function readConfig(filePath) {
76
+ if (!node_fs.default.existsSync(filePath)) return {};
77
+ let parsed;
78
+ try {
79
+ parsed = JSON.parse(node_fs.default.readFileSync(filePath, "utf8"));
80
+ } catch (error) {
81
+ throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });
82
+ }
83
+ if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);
84
+ return parsed;
85
+ }
86
+ async function readConfigAsync(filePath) {
87
+ let parsed;
88
+ try {
89
+ parsed = JSON.parse(await node_fs.default.promises.readFile(filePath, "utf8"));
90
+ } catch (error) {
91
+ if (error.code === "ENOENT") return {};
92
+ throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });
93
+ }
94
+ if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);
95
+ return parsed;
96
+ }
97
+ function readConfigPaths(paths) {
98
+ return paths.reduce((config, filePath) => mergeConfig(config, readConfig(filePath)), {});
99
+ }
100
+ async function readConfigPathsAsync(paths) {
101
+ return (await Promise.all(paths.map(readConfigAsync))).reduce(mergeConfig, {});
102
+ }
103
+ function projectIsTrusted(value) {
104
+ return typeof value === "function" ? value() : value;
105
+ }
106
+ function piConfigPaths(repoRoot, homeDirectory = node_os.default.homedir(), agentDirectory = defaultAgentDirectory(homeDirectory)) {
107
+ return {
108
+ canonicalUser: node_path.default.join(agentDirectory, SETTINGS_FILE_NAME),
109
+ canonicalProject: node_path.default.join(repoRoot, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),
110
+ legacyUser: [node_path.default.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],
111
+ legacyProject: [node_path.default.join(repoRoot, LEGACY_CONFIG_DIR_NAME, SETTINGS_FILE_NAME)]
112
+ };
113
+ }
114
+ function loadPiConfig(options) {
115
+ const paths = piConfigPaths(options.repoRoot, options.homeDirectory);
116
+ const userPaths = [
117
+ ...paths.legacyUser,
118
+ ...options.userConfigPaths ?? [],
119
+ paths.canonicalUser
120
+ ];
121
+ const projectPaths = [
122
+ ...paths.legacyProject,
123
+ ...options.projectConfigPaths ?? [],
124
+ paths.canonicalProject
125
+ ];
126
+ const defaults = options.defaults ?? {};
127
+ const user = readConfigPaths(userPaths);
128
+ const trustedProject = projectIsTrusted(options.isProjectTrusted) ? readConfigPaths(projectPaths) : {};
129
+ return [
130
+ defaults,
131
+ user,
132
+ options.overlay ?? {},
133
+ trustedProject,
134
+ options.environment ?? {},
135
+ options.cli ?? {},
136
+ options.programmatic ?? {}
137
+ ].reduce(mergeConfig, {});
138
+ }
139
+ async function loadPiConfigAsync(options) {
140
+ const paths = piConfigPaths(options.repoRoot, options.homeDirectory);
141
+ const userPaths = [
142
+ ...paths.legacyUser,
143
+ ...options.userConfigPaths ?? [],
144
+ paths.canonicalUser
145
+ ];
146
+ const projectPaths = [
147
+ ...paths.legacyProject,
148
+ ...options.projectConfigPaths ?? [],
149
+ paths.canonicalProject
150
+ ];
151
+ const [user, trustedProject] = await Promise.all([readConfigPathsAsync(userPaths), projectIsTrusted(options.isProjectTrusted) ? readConfigPathsAsync(projectPaths) : Promise.resolve({})]);
152
+ return [
153
+ options.defaults ?? {},
154
+ user,
155
+ options.overlay ?? {},
156
+ trustedProject,
157
+ options.environment ?? {},
158
+ options.cli ?? {},
159
+ options.programmatic ?? {}
160
+ ].reduce(mergeConfig, {});
161
+ }
162
+ /**
163
+ * Where the image limits are read from and written to.
164
+ *
165
+ * The user layer only. Pi merges a trusted project settings.json over it, but
166
+ * these limits describe one machine's tolerance for image payloads rather than
167
+ * one repository's, and the cockpit page that writes them has no repository
168
+ * scope to offer. The legacy user path is still read, because a machine that
169
+ * has not been migrated still answers from it.
170
+ */
171
+ function userSettingsPaths(homeDirectory) {
172
+ return {
173
+ legacy: node_path.default.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),
174
+ canonical: node_path.default.join(defaultAgentDirectory(homeDirectory), SETTINGS_FILE_NAME)
175
+ };
176
+ }
177
+ /** The file a change lands in; Pi's own settings toggle writes the same one. */
178
+ function piImageSettingsPath(homeDirectory = node_os.default.homedir()) {
179
+ return userSettingsPaths(homeDirectory).canonical;
180
+ }
181
+ function loadPiImageSettings(homeDirectory = node_os.default.homedir()) {
182
+ const paths = userSettingsPaths(homeDirectory);
183
+ return parsePiImageSettings(readConfigPaths([paths.legacy, paths.canonical]));
184
+ }
185
+ /**
186
+ * Writes the changed keys back and reports the limits that now apply.
187
+ *
188
+ * Read-modify-write on Pi's own file, so a save races a concurrent Pi settings
189
+ * save rather than merging with it. Pi writes only the fields its UI touched,
190
+ * as this does, which keeps the window to the one setting being changed on
191
+ * both sides at once.
192
+ */
193
+ function savePiImageSettings(update, homeDirectory = node_os.default.homedir()) {
194
+ const paths = userSettingsPaths(homeDirectory);
195
+ require_atomicJson.writePrivateAtomicJson(paths.canonical, applyPiImageSettings(readConfig(paths.canonical), update));
196
+ return loadPiImageSettings(homeDirectory);
197
+ }
198
+ //#endregion
199
+ Object.defineProperty(exports, "DEFAULT_IMAGE_MAX_DIMENSION", {
200
+ enumerable: true,
201
+ get: function() {
202
+ return DEFAULT_IMAGE_MAX_DIMENSION;
203
+ }
204
+ });
205
+ Object.defineProperty(exports, "MIN_IMAGE_MAX_DIMENSION", {
206
+ enumerable: true,
207
+ get: function() {
208
+ return MIN_IMAGE_MAX_DIMENSION;
209
+ }
210
+ });
211
+ Object.defineProperty(exports, "clampImageMaxDimension", {
212
+ enumerable: true,
213
+ get: function() {
214
+ return clampImageMaxDimension;
215
+ }
216
+ });
217
+ Object.defineProperty(exports, "loadPiConfig", {
218
+ enumerable: true,
219
+ get: function() {
220
+ return loadPiConfig;
221
+ }
222
+ });
223
+ Object.defineProperty(exports, "loadPiConfigAsync", {
224
+ enumerable: true,
225
+ get: function() {
226
+ return loadPiConfigAsync;
227
+ }
228
+ });
229
+ Object.defineProperty(exports, "loadPiImageSettings", {
230
+ enumerable: true,
231
+ get: function() {
232
+ return loadPiImageSettings;
233
+ }
234
+ });
235
+ Object.defineProperty(exports, "parsePiImageSettings", {
236
+ enumerable: true,
237
+ get: function() {
238
+ return parsePiImageSettings;
239
+ }
240
+ });
241
+ Object.defineProperty(exports, "piConfigPaths", {
242
+ enumerable: true,
243
+ get: function() {
244
+ return piConfigPaths;
245
+ }
246
+ });
247
+ Object.defineProperty(exports, "piImageSettingsPath", {
248
+ enumerable: true,
249
+ get: function() {
250
+ return piImageSettingsPath;
251
+ }
252
+ });
253
+ Object.defineProperty(exports, "savePiImageSettings", {
254
+ enumerable: true,
255
+ get: function() {
256
+ return savePiImageSettings;
257
+ }
258
+ });
259
+
260
+ //# sourceMappingURL=piConfig-CCBdZXQr.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piConfig-CCBdZXQr.cjs","names":["piAgentDirectory","os","fs","path"],"sources":["../src/services/imageSettings/index.ts","../src/services/piConfig/index.ts"],"sourcesContent":["/**\n * The image limits every Po surface applies before an image reaches a model.\n *\n * Pi already owns half of this: `images.autoResize` lives in its settings.json\n * and its resize core hardcodes a 2000px cap. What Pi has no place for is a\n * smaller cap, so `images.maxDimension` is Doom's key written into the same\n * file, because a machine should describe how images reach a model in one\n * place rather than two.\n *\n * A cap above Pi's own is not offered. Pi normalizes every tool result image at\n * 2000px as it enters session history, so a larger number would hold on a\n * pasted image and be silently undone on a read. Clamping says so instead of\n * letting the two surfaces disagree.\n *\n * AVOID:\n * - Reading these keys straight off a config record; a hand-written file holds\n * strings, nulls and negative numbers, and only this parser answers for them.\n */\n\nimport type { PiConfig } from '../../types/piConfig';\n\nexport const IMAGE_SETTINGS_KEY = 'images';\nexport const IMAGE_AUTO_RESIZE_KEY = 'autoResize';\nexport const IMAGE_MAX_DIMENSION_KEY = 'maxDimension';\n\n/** Pi's own cap, from its resize core; also the largest value worth writing. */\nexport const DEFAULT_IMAGE_MAX_DIMENSION = 2000;\n/** Below this a screenshot stops being readable, which is what reads are for. */\nexport const MIN_IMAGE_MAX_DIMENSION = 256;\n\nexport interface PiImageSettings {\n /** Pi's own toggle. Unset is on, matching Pi's default. */\n autoResize: boolean;\n /** The longest edge an image keeps once resizing is on. */\n maxDimension: number;\n}\n\n/** The written form of a change; an absent field leaves that key alone. */\nexport interface PiImageSettingsUpdate {\n autoResize?: boolean;\n maxDimension?: number;\n}\n\nexport function clampImageMaxDimension(value: number): number {\n const rounded = Math.round(value);\n if (rounded < MIN_IMAGE_MAX_DIMENSION) return MIN_IMAGE_MAX_DIMENSION;\n if (rounded > DEFAULT_IMAGE_MAX_DIMENSION) return DEFAULT_IMAGE_MAX_DIMENSION;\n return rounded;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Resolves the effective limits, defaulting anything absent or unusable. */\nexport function parsePiImageSettings(config: PiConfig): PiImageSettings {\n const images = config[IMAGE_SETTINGS_KEY];\n if (!isRecord(images)) return { autoResize: true, maxDimension: DEFAULT_IMAGE_MAX_DIMENSION };\n const autoResize = images[IMAGE_AUTO_RESIZE_KEY];\n const maxDimension = images[IMAGE_MAX_DIMENSION_KEY];\n return {\n autoResize: typeof autoResize === 'boolean' ? autoResize : true,\n maxDimension:\n typeof maxDimension === 'number' && Number.isFinite(maxDimension)\n ? clampImageMaxDimension(maxDimension)\n : DEFAULT_IMAGE_MAX_DIMENSION,\n };\n}\n\n/**\n * Folds a change into the `images` object of a settings document, leaving every\n * other key of that document, and of `images` itself, as it was.\n */\nexport function applyPiImageSettings(config: PiConfig, update: PiImageSettingsUpdate): PiConfig {\n const existing = config[IMAGE_SETTINGS_KEY];\n const images: Record<string, unknown> = isRecord(existing) ? { ...existing } : {};\n if (update.autoResize !== undefined) images[IMAGE_AUTO_RESIZE_KEY] = update.autoResize;\n if (update.maxDimension !== undefined) images[IMAGE_MAX_DIMENSION_KEY] = clampImageMaxDimension(update.maxDimension);\n return { ...config, [IMAGE_SETTINGS_KEY]: images };\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { piAgentDirectory } from '@agimon-ai/po-core/piSettings';\n\nimport type { PiConfig, PiConfigLoadOptions, PiConfigPaths } from '../../types/piConfig';\nimport { writePrivateAtomicJson } from '../atomicJson';\nimport {\n applyPiImageSettings,\n parsePiImageSettings,\n type PiImageSettings,\n type PiImageSettingsUpdate,\n} from '../imageSettings';\n\nconst SETTINGS_FILE_NAME = 'settings.json';\nconst CONFIG_DIR_NAME = '.pi';\nconst LEGACY_CONFIG_DIR_NAME = 'pi';\n\n/** An explicit home other than the real one is isolated from the process environment. */\nfunction defaultAgentDirectory(homeDirectory: string): string {\n return piAgentDirectory(homeDirectory === os.homedir() ? process.env : {}, homeDirectory);\n}\nfunction isObject(value: unknown): value is PiConfig {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeConfig(base: PiConfig, override: PiConfig): PiConfig {\n const result: PiConfig = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const current = result[key];\n result[key] = isObject(current) && isObject(value) ? mergeConfig(current, value) : value;\n }\n return result;\n}\n\nfunction readConfig(filePath: string): PiConfig {\n if (!fs.existsSync(filePath)) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n } catch (error) {\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nasync function readConfigAsync(filePath: string): Promise<PiConfig> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(await fs.promises.readFile(filePath, 'utf8'));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nfunction readConfigPaths(paths: readonly string[]): PiConfig {\n return paths.reduce<PiConfig>((config, filePath) => mergeConfig(config, readConfig(filePath)), {});\n}\n\nasync function readConfigPathsAsync(paths: readonly string[]): Promise<PiConfig> {\n const layers = await Promise.all(paths.map(readConfigAsync));\n return layers.reduce<PiConfig>(mergeConfig, {});\n}\n\nfunction projectIsTrusted(value: PiConfigLoadOptions['isProjectTrusted']): boolean {\n return typeof value === 'function' ? value() : value;\n}\n\nexport function piConfigPaths(\n repoRoot: string,\n homeDirectory = os.homedir(),\n agentDirectory = defaultAgentDirectory(homeDirectory),\n): PiConfigPaths {\n return {\n canonicalUser: path.join(agentDirectory, SETTINGS_FILE_NAME),\n canonicalProject: path.join(repoRoot, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),\n legacyUser: [path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n legacyProject: [path.join(repoRoot, LEGACY_CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n };\n}\n\nexport function loadPiConfig(options: PiConfigLoadOptions): PiConfig {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const defaults = options.defaults ?? {};\n const user = readConfigPaths(userPaths);\n const trustedProject = projectIsTrusted(options.isProjectTrusted) ? readConfigPaths(projectPaths) : {};\n return [\n defaults,\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n\nexport async function loadPiConfigAsync(options: PiConfigLoadOptions): Promise<PiConfig> {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const [user, trustedProject] = await Promise.all([\n readConfigPathsAsync(userPaths),\n projectIsTrusted(options.isProjectTrusted) ? readConfigPathsAsync(projectPaths) : Promise.resolve({}),\n ]);\n return [\n options.defaults ?? {},\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n\n/**\n * Where the image limits are read from and written to.\n *\n * The user layer only. Pi merges a trusted project settings.json over it, but\n * these limits describe one machine's tolerance for image payloads rather than\n * one repository's, and the cockpit page that writes them has no repository\n * scope to offer. The legacy user path is still read, because a machine that\n * has not been migrated still answers from it.\n */\nfunction userSettingsPaths(homeDirectory: string): { legacy: string; canonical: string } {\n return {\n legacy: path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),\n canonical: path.join(defaultAgentDirectory(homeDirectory), SETTINGS_FILE_NAME),\n };\n}\n\n/** The file a change lands in; Pi's own settings toggle writes the same one. */\nexport function piImageSettingsPath(homeDirectory = os.homedir()): string {\n return userSettingsPaths(homeDirectory).canonical;\n}\n\nexport function loadPiImageSettings(homeDirectory = os.homedir()): PiImageSettings {\n const paths = userSettingsPaths(homeDirectory);\n return parsePiImageSettings(readConfigPaths([paths.legacy, paths.canonical]));\n}\n\n/**\n * Writes the changed keys back and reports the limits that now apply.\n *\n * Read-modify-write on Pi's own file, so a save races a concurrent Pi settings\n * save rather than merging with it. Pi writes only the fields its UI touched,\n * as this does, which keeps the window to the one setting being changed on\n * both sides at once.\n */\nexport function savePiImageSettings(update: PiImageSettingsUpdate, homeDirectory = os.homedir()): PiImageSettings {\n const paths = userSettingsPaths(homeDirectory);\n writePrivateAtomicJson(paths.canonical, applyPiImageSettings(readConfig(paths.canonical), update));\n return loadPiImageSettings(homeDirectory);\n}\n"],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ import { t as writePrivateAtomicJson } from "./atomicJson-1W0WhuFF.mjs";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { piAgentDirectory } from "@agimon-ai/po-core/piSettings";
6
+ //#region src/services/imageSettings/index.ts
7
+ const IMAGE_SETTINGS_KEY = "images";
8
+ const IMAGE_AUTO_RESIZE_KEY = "autoResize";
9
+ const IMAGE_MAX_DIMENSION_KEY = "maxDimension";
10
+ /** Pi's own cap, from its resize core; also the largest value worth writing. */
11
+ const DEFAULT_IMAGE_MAX_DIMENSION = 2e3;
12
+ /** Below this a screenshot stops being readable, which is what reads are for. */
13
+ const MIN_IMAGE_MAX_DIMENSION = 256;
14
+ function clampImageMaxDimension(value) {
15
+ const rounded = Math.round(value);
16
+ if (rounded < 256) return 256;
17
+ if (rounded > 2e3) return DEFAULT_IMAGE_MAX_DIMENSION;
18
+ return rounded;
19
+ }
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22
+ }
23
+ /** Resolves the effective limits, defaulting anything absent or unusable. */
24
+ function parsePiImageSettings(config) {
25
+ const images = config[IMAGE_SETTINGS_KEY];
26
+ if (!isRecord(images)) return {
27
+ autoResize: true,
28
+ maxDimension: DEFAULT_IMAGE_MAX_DIMENSION
29
+ };
30
+ const autoResize = images[IMAGE_AUTO_RESIZE_KEY];
31
+ const maxDimension = images[IMAGE_MAX_DIMENSION_KEY];
32
+ return {
33
+ autoResize: typeof autoResize === "boolean" ? autoResize : true,
34
+ maxDimension: typeof maxDimension === "number" && Number.isFinite(maxDimension) ? clampImageMaxDimension(maxDimension) : DEFAULT_IMAGE_MAX_DIMENSION
35
+ };
36
+ }
37
+ /**
38
+ * Folds a change into the `images` object of a settings document, leaving every
39
+ * other key of that document, and of `images` itself, as it was.
40
+ */
41
+ function applyPiImageSettings(config, update) {
42
+ const existing = config[IMAGE_SETTINGS_KEY];
43
+ const images = isRecord(existing) ? { ...existing } : {};
44
+ if (update.autoResize !== void 0) images[IMAGE_AUTO_RESIZE_KEY] = update.autoResize;
45
+ if (update.maxDimension !== void 0) images[IMAGE_MAX_DIMENSION_KEY] = clampImageMaxDimension(update.maxDimension);
46
+ return {
47
+ ...config,
48
+ [IMAGE_SETTINGS_KEY]: images
49
+ };
50
+ }
51
+ //#endregion
52
+ //#region src/services/piConfig/index.ts
53
+ const SETTINGS_FILE_NAME = "settings.json";
54
+ const CONFIG_DIR_NAME = ".pi";
55
+ const LEGACY_CONFIG_DIR_NAME = "pi";
56
+ /** An explicit home other than the real one is isolated from the process environment. */
57
+ function defaultAgentDirectory(homeDirectory) {
58
+ return piAgentDirectory(homeDirectory === os.homedir() ? process.env : {}, homeDirectory);
59
+ }
60
+ function isObject(value) {
61
+ return typeof value === "object" && value !== null && !Array.isArray(value);
62
+ }
63
+ function mergeConfig(base, override) {
64
+ const result = { ...base };
65
+ for (const [key, value] of Object.entries(override)) {
66
+ const current = result[key];
67
+ result[key] = isObject(current) && isObject(value) ? mergeConfig(current, value) : value;
68
+ }
69
+ return result;
70
+ }
71
+ function readConfig(filePath) {
72
+ if (!fs.existsSync(filePath)) return {};
73
+ let parsed;
74
+ try {
75
+ parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
76
+ } catch (error) {
77
+ throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });
78
+ }
79
+ if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);
80
+ return parsed;
81
+ }
82
+ async function readConfigAsync(filePath) {
83
+ let parsed;
84
+ try {
85
+ parsed = JSON.parse(await fs.promises.readFile(filePath, "utf8"));
86
+ } catch (error) {
87
+ if (error.code === "ENOENT") return {};
88
+ throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });
89
+ }
90
+ if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);
91
+ return parsed;
92
+ }
93
+ function readConfigPaths(paths) {
94
+ return paths.reduce((config, filePath) => mergeConfig(config, readConfig(filePath)), {});
95
+ }
96
+ async function readConfigPathsAsync(paths) {
97
+ return (await Promise.all(paths.map(readConfigAsync))).reduce(mergeConfig, {});
98
+ }
99
+ function projectIsTrusted(value) {
100
+ return typeof value === "function" ? value() : value;
101
+ }
102
+ function piConfigPaths(repoRoot, homeDirectory = os.homedir(), agentDirectory = defaultAgentDirectory(homeDirectory)) {
103
+ return {
104
+ canonicalUser: path.join(agentDirectory, SETTINGS_FILE_NAME),
105
+ canonicalProject: path.join(repoRoot, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),
106
+ legacyUser: [path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],
107
+ legacyProject: [path.join(repoRoot, LEGACY_CONFIG_DIR_NAME, SETTINGS_FILE_NAME)]
108
+ };
109
+ }
110
+ function loadPiConfig(options) {
111
+ const paths = piConfigPaths(options.repoRoot, options.homeDirectory);
112
+ const userPaths = [
113
+ ...paths.legacyUser,
114
+ ...options.userConfigPaths ?? [],
115
+ paths.canonicalUser
116
+ ];
117
+ const projectPaths = [
118
+ ...paths.legacyProject,
119
+ ...options.projectConfigPaths ?? [],
120
+ paths.canonicalProject
121
+ ];
122
+ const defaults = options.defaults ?? {};
123
+ const user = readConfigPaths(userPaths);
124
+ const trustedProject = projectIsTrusted(options.isProjectTrusted) ? readConfigPaths(projectPaths) : {};
125
+ return [
126
+ defaults,
127
+ user,
128
+ options.overlay ?? {},
129
+ trustedProject,
130
+ options.environment ?? {},
131
+ options.cli ?? {},
132
+ options.programmatic ?? {}
133
+ ].reduce(mergeConfig, {});
134
+ }
135
+ async function loadPiConfigAsync(options) {
136
+ const paths = piConfigPaths(options.repoRoot, options.homeDirectory);
137
+ const userPaths = [
138
+ ...paths.legacyUser,
139
+ ...options.userConfigPaths ?? [],
140
+ paths.canonicalUser
141
+ ];
142
+ const projectPaths = [
143
+ ...paths.legacyProject,
144
+ ...options.projectConfigPaths ?? [],
145
+ paths.canonicalProject
146
+ ];
147
+ const [user, trustedProject] = await Promise.all([readConfigPathsAsync(userPaths), projectIsTrusted(options.isProjectTrusted) ? readConfigPathsAsync(projectPaths) : Promise.resolve({})]);
148
+ return [
149
+ options.defaults ?? {},
150
+ user,
151
+ options.overlay ?? {},
152
+ trustedProject,
153
+ options.environment ?? {},
154
+ options.cli ?? {},
155
+ options.programmatic ?? {}
156
+ ].reduce(mergeConfig, {});
157
+ }
158
+ /**
159
+ * Where the image limits are read from and written to.
160
+ *
161
+ * The user layer only. Pi merges a trusted project settings.json over it, but
162
+ * these limits describe one machine's tolerance for image payloads rather than
163
+ * one repository's, and the cockpit page that writes them has no repository
164
+ * scope to offer. The legacy user path is still read, because a machine that
165
+ * has not been migrated still answers from it.
166
+ */
167
+ function userSettingsPaths(homeDirectory) {
168
+ return {
169
+ legacy: path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),
170
+ canonical: path.join(defaultAgentDirectory(homeDirectory), SETTINGS_FILE_NAME)
171
+ };
172
+ }
173
+ /** The file a change lands in; Pi's own settings toggle writes the same one. */
174
+ function piImageSettingsPath(homeDirectory = os.homedir()) {
175
+ return userSettingsPaths(homeDirectory).canonical;
176
+ }
177
+ function loadPiImageSettings(homeDirectory = os.homedir()) {
178
+ const paths = userSettingsPaths(homeDirectory);
179
+ return parsePiImageSettings(readConfigPaths([paths.legacy, paths.canonical]));
180
+ }
181
+ /**
182
+ * Writes the changed keys back and reports the limits that now apply.
183
+ *
184
+ * Read-modify-write on Pi's own file, so a save races a concurrent Pi settings
185
+ * save rather than merging with it. Pi writes only the fields its UI touched,
186
+ * as this does, which keeps the window to the one setting being changed on
187
+ * both sides at once.
188
+ */
189
+ function savePiImageSettings(update, homeDirectory = os.homedir()) {
190
+ const paths = userSettingsPaths(homeDirectory);
191
+ writePrivateAtomicJson(paths.canonical, applyPiImageSettings(readConfig(paths.canonical), update));
192
+ return loadPiImageSettings(homeDirectory);
193
+ }
194
+ //#endregion
195
+ export { piImageSettingsPath as a, MIN_IMAGE_MAX_DIMENSION as c, piConfigPaths as i, clampImageMaxDimension as l, loadPiConfigAsync as n, savePiImageSettings as o, loadPiImageSettings as r, DEFAULT_IMAGE_MAX_DIMENSION as s, loadPiConfig as t, parsePiImageSettings as u };
196
+
197
+ //# sourceMappingURL=piConfig-qGyCbcVj.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piConfig-qGyCbcVj.mjs","names":[],"sources":["../src/services/imageSettings/index.ts","../src/services/piConfig/index.ts"],"sourcesContent":["/**\n * The image limits every Po surface applies before an image reaches a model.\n *\n * Pi already owns half of this: `images.autoResize` lives in its settings.json\n * and its resize core hardcodes a 2000px cap. What Pi has no place for is a\n * smaller cap, so `images.maxDimension` is Doom's key written into the same\n * file, because a machine should describe how images reach a model in one\n * place rather than two.\n *\n * A cap above Pi's own is not offered. Pi normalizes every tool result image at\n * 2000px as it enters session history, so a larger number would hold on a\n * pasted image and be silently undone on a read. Clamping says so instead of\n * letting the two surfaces disagree.\n *\n * AVOID:\n * - Reading these keys straight off a config record; a hand-written file holds\n * strings, nulls and negative numbers, and only this parser answers for them.\n */\n\nimport type { PiConfig } from '../../types/piConfig';\n\nexport const IMAGE_SETTINGS_KEY = 'images';\nexport const IMAGE_AUTO_RESIZE_KEY = 'autoResize';\nexport const IMAGE_MAX_DIMENSION_KEY = 'maxDimension';\n\n/** Pi's own cap, from its resize core; also the largest value worth writing. */\nexport const DEFAULT_IMAGE_MAX_DIMENSION = 2000;\n/** Below this a screenshot stops being readable, which is what reads are for. */\nexport const MIN_IMAGE_MAX_DIMENSION = 256;\n\nexport interface PiImageSettings {\n /** Pi's own toggle. Unset is on, matching Pi's default. */\n autoResize: boolean;\n /** The longest edge an image keeps once resizing is on. */\n maxDimension: number;\n}\n\n/** The written form of a change; an absent field leaves that key alone. */\nexport interface PiImageSettingsUpdate {\n autoResize?: boolean;\n maxDimension?: number;\n}\n\nexport function clampImageMaxDimension(value: number): number {\n const rounded = Math.round(value);\n if (rounded < MIN_IMAGE_MAX_DIMENSION) return MIN_IMAGE_MAX_DIMENSION;\n if (rounded > DEFAULT_IMAGE_MAX_DIMENSION) return DEFAULT_IMAGE_MAX_DIMENSION;\n return rounded;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Resolves the effective limits, defaulting anything absent or unusable. */\nexport function parsePiImageSettings(config: PiConfig): PiImageSettings {\n const images = config[IMAGE_SETTINGS_KEY];\n if (!isRecord(images)) return { autoResize: true, maxDimension: DEFAULT_IMAGE_MAX_DIMENSION };\n const autoResize = images[IMAGE_AUTO_RESIZE_KEY];\n const maxDimension = images[IMAGE_MAX_DIMENSION_KEY];\n return {\n autoResize: typeof autoResize === 'boolean' ? autoResize : true,\n maxDimension:\n typeof maxDimension === 'number' && Number.isFinite(maxDimension)\n ? clampImageMaxDimension(maxDimension)\n : DEFAULT_IMAGE_MAX_DIMENSION,\n };\n}\n\n/**\n * Folds a change into the `images` object of a settings document, leaving every\n * other key of that document, and of `images` itself, as it was.\n */\nexport function applyPiImageSettings(config: PiConfig, update: PiImageSettingsUpdate): PiConfig {\n const existing = config[IMAGE_SETTINGS_KEY];\n const images: Record<string, unknown> = isRecord(existing) ? { ...existing } : {};\n if (update.autoResize !== undefined) images[IMAGE_AUTO_RESIZE_KEY] = update.autoResize;\n if (update.maxDimension !== undefined) images[IMAGE_MAX_DIMENSION_KEY] = clampImageMaxDimension(update.maxDimension);\n return { ...config, [IMAGE_SETTINGS_KEY]: images };\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { piAgentDirectory } from '@agimon-ai/po-core/piSettings';\n\nimport type { PiConfig, PiConfigLoadOptions, PiConfigPaths } from '../../types/piConfig';\nimport { writePrivateAtomicJson } from '../atomicJson';\nimport {\n applyPiImageSettings,\n parsePiImageSettings,\n type PiImageSettings,\n type PiImageSettingsUpdate,\n} from '../imageSettings';\n\nconst SETTINGS_FILE_NAME = 'settings.json';\nconst CONFIG_DIR_NAME = '.pi';\nconst LEGACY_CONFIG_DIR_NAME = 'pi';\n\n/** An explicit home other than the real one is isolated from the process environment. */\nfunction defaultAgentDirectory(homeDirectory: string): string {\n return piAgentDirectory(homeDirectory === os.homedir() ? process.env : {}, homeDirectory);\n}\nfunction isObject(value: unknown): value is PiConfig {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeConfig(base: PiConfig, override: PiConfig): PiConfig {\n const result: PiConfig = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const current = result[key];\n result[key] = isObject(current) && isObject(value) ? mergeConfig(current, value) : value;\n }\n return result;\n}\n\nfunction readConfig(filePath: string): PiConfig {\n if (!fs.existsSync(filePath)) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n } catch (error) {\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nasync function readConfigAsync(filePath: string): Promise<PiConfig> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(await fs.promises.readFile(filePath, 'utf8'));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw new Error(`Could not parse Pi settings at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Pi settings at ${filePath} must be a JSON object`);\n return parsed;\n}\n\nfunction readConfigPaths(paths: readonly string[]): PiConfig {\n return paths.reduce<PiConfig>((config, filePath) => mergeConfig(config, readConfig(filePath)), {});\n}\n\nasync function readConfigPathsAsync(paths: readonly string[]): Promise<PiConfig> {\n const layers = await Promise.all(paths.map(readConfigAsync));\n return layers.reduce<PiConfig>(mergeConfig, {});\n}\n\nfunction projectIsTrusted(value: PiConfigLoadOptions['isProjectTrusted']): boolean {\n return typeof value === 'function' ? value() : value;\n}\n\nexport function piConfigPaths(\n repoRoot: string,\n homeDirectory = os.homedir(),\n agentDirectory = defaultAgentDirectory(homeDirectory),\n): PiConfigPaths {\n return {\n canonicalUser: path.join(agentDirectory, SETTINGS_FILE_NAME),\n canonicalProject: path.join(repoRoot, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),\n legacyUser: [path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n legacyProject: [path.join(repoRoot, LEGACY_CONFIG_DIR_NAME, SETTINGS_FILE_NAME)],\n };\n}\n\nexport function loadPiConfig(options: PiConfigLoadOptions): PiConfig {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const defaults = options.defaults ?? {};\n const user = readConfigPaths(userPaths);\n const trustedProject = projectIsTrusted(options.isProjectTrusted) ? readConfigPaths(projectPaths) : {};\n return [\n defaults,\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n\nexport async function loadPiConfigAsync(options: PiConfigLoadOptions): Promise<PiConfig> {\n const paths = piConfigPaths(options.repoRoot, options.homeDirectory);\n const userPaths = [...paths.legacyUser, ...(options.userConfigPaths ?? []), paths.canonicalUser];\n const projectPaths = [...paths.legacyProject, ...(options.projectConfigPaths ?? []), paths.canonicalProject];\n const [user, trustedProject] = await Promise.all([\n readConfigPathsAsync(userPaths),\n projectIsTrusted(options.isProjectTrusted) ? readConfigPathsAsync(projectPaths) : Promise.resolve({}),\n ]);\n return [\n options.defaults ?? {},\n user,\n options.overlay ?? {},\n trustedProject,\n options.environment ?? {},\n options.cli ?? {},\n options.programmatic ?? {},\n ].reduce(mergeConfig, {});\n}\n\n/**\n * Where the image limits are read from and written to.\n *\n * The user layer only. Pi merges a trusted project settings.json over it, but\n * these limits describe one machine's tolerance for image payloads rather than\n * one repository's, and the cockpit page that writes them has no repository\n * scope to offer. The legacy user path is still read, because a machine that\n * has not been migrated still answers from it.\n */\nfunction userSettingsPaths(homeDirectory: string): { legacy: string; canonical: string } {\n return {\n legacy: path.join(homeDirectory, CONFIG_DIR_NAME, SETTINGS_FILE_NAME),\n canonical: path.join(defaultAgentDirectory(homeDirectory), SETTINGS_FILE_NAME),\n };\n}\n\n/** The file a change lands in; Pi's own settings toggle writes the same one. */\nexport function piImageSettingsPath(homeDirectory = os.homedir()): string {\n return userSettingsPaths(homeDirectory).canonical;\n}\n\nexport function loadPiImageSettings(homeDirectory = os.homedir()): PiImageSettings {\n const paths = userSettingsPaths(homeDirectory);\n return parsePiImageSettings(readConfigPaths([paths.legacy, paths.canonical]));\n}\n\n/**\n * Writes the changed keys back and reports the limits that now apply.\n *\n * Read-modify-write on Pi's own file, so a save races a concurrent Pi settings\n * save rather than merging with it. Pi writes only the fields its UI touched,\n * as this does, which keeps the window to the one setting being changed on\n * both sides at once.\n */\nexport function savePiImageSettings(update: PiImageSettingsUpdate, homeDirectory = os.homedir()): PiImageSettings {\n const paths = userSettingsPaths(homeDirectory);\n writePrivateAtomicJson(paths.canonical, applyPiImageSettings(readConfig(paths.canonical), update));\n return loadPiImageSettings(homeDirectory);\n}\n"],"mappings":";;;;;;AAqBA,MAAa,qBAAqB;AAClC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;;AAGvC,MAAa,8BAA8B;;AAE3C,MAAa,0BAA0B;AAevC,SAAgB,uBAAuB,OAAuB;CAC5D,MAAM,UAAU,KAAK,MAAM,KAAK;CAChC,IAAI,UAAA,KAAmC,OAAA;CACvC,IAAI,UAAA,KAAuC,OAAO;CAClD,OAAO;AACT;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;AAGA,SAAgB,qBAAqB,QAAmC;CACtE,MAAM,SAAS,OAAO;CACtB,IAAI,CAAC,SAAS,MAAM,GAAG,OAAO;EAAE,YAAY;EAAM,cAAc;CAA4B;CAC5F,MAAM,aAAa,OAAO;CAC1B,MAAM,eAAe,OAAO;CAC5B,OAAO;EACL,YAAY,OAAO,eAAe,YAAY,aAAa;EAC3D,cACE,OAAO,iBAAiB,YAAY,OAAO,SAAS,YAAY,IAC5D,uBAAuB,YAAY,IACnC;CACR;AACF;;;;;AAMA,SAAgB,qBAAqB,QAAkB,QAAyC;CAC9F,MAAM,WAAW,OAAO;CACxB,MAAM,SAAkC,SAAS,QAAQ,IAAI,EAAE,GAAG,SAAS,IAAI,CAAC;CAChF,IAAI,OAAO,eAAe,KAAA,GAAW,OAAO,yBAAyB,OAAO;CAC5E,IAAI,OAAO,iBAAiB,KAAA,GAAW,OAAO,2BAA2B,uBAAuB,OAAO,YAAY;CACnH,OAAO;EAAE,GAAG;GAAS,qBAAqB;CAAO;AACnD;;;AChEA,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AACxB,MAAM,yBAAyB;;AAG/B,SAAS,sBAAsB,eAA+B;CAC5D,OAAO,iBAAiB,kBAAkB,GAAG,QAAQ,IAAI,QAAQ,MAAM,CAAC,GAAG,aAAa;AAC1F;AACA,SAAS,SAAS,OAAmC;CACnD,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,YAAY,MAAgB,UAA8B;CACjE,MAAM,SAAmB,EAAE,GAAG,KAAK;CACnC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,GAAG;EACnD,MAAM,UAAU,OAAO;EACvB,OAAO,OAAO,SAAS,OAAO,KAAK,SAAS,KAAK,IAAI,YAAY,SAAS,KAAK,IAAI;CACrF;CACA,OAAO;AACT;AAEA,SAAS,WAAW,UAA4B;CAC9C,IAAI,CAAC,GAAG,WAAW,QAAQ,GAAG,OAAO,CAAC;CACtC,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,GAAG,aAAa,UAAU,MAAM,CAAC;CACvD,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,kCAAkC,YAAY,EAAE,OAAO,MAAM,CAAC;CAChF;CACA,IAAI,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,kBAAkB,SAAS,uBAAuB;CACzF,OAAO;AACT;AAEA,eAAe,gBAAgB,UAAqC;CAClE,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,MAAM,GAAG,SAAS,SAAS,UAAU,MAAM,CAAC;CAClE,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU,OAAO,CAAC;EAChE,MAAM,IAAI,MAAM,kCAAkC,YAAY,EAAE,OAAO,MAAM,CAAC;CAChF;CACA,IAAI,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,kBAAkB,SAAS,uBAAuB;CACzF,OAAO;AACT;AAEA,SAAS,gBAAgB,OAAoC;CAC3D,OAAO,MAAM,QAAkB,QAAQ,aAAa,YAAY,QAAQ,WAAW,QAAQ,CAAC,GAAG,CAAC,CAAC;AACnG;AAEA,eAAe,qBAAqB,OAA6C;CAE/E,QAAO,MADc,QAAQ,IAAI,MAAM,IAAI,eAAe,CAAC,EAAA,CAC7C,OAAiB,aAAa,CAAC,CAAC;AAChD;AAEA,SAAS,iBAAiB,OAAyD;CACjF,OAAO,OAAO,UAAU,aAAa,MAAM,IAAI;AACjD;AAEA,SAAgB,cACd,UACA,gBAAgB,GAAG,QAAQ,GAC3B,iBAAiB,sBAAsB,aAAa,GACrC;CACf,OAAO;EACL,eAAe,KAAK,KAAK,gBAAgB,kBAAkB;EAC3D,kBAAkB,KAAK,KAAK,UAAU,iBAAiB,kBAAkB;EACzE,YAAY,CAAC,KAAK,KAAK,eAAe,iBAAiB,kBAAkB,CAAC;EAC1E,eAAe,CAAC,KAAK,KAAK,UAAU,wBAAwB,kBAAkB,CAAC;CACjF;AACF;AAEA,SAAgB,aAAa,SAAwC;CACnE,MAAM,QAAQ,cAAc,QAAQ,UAAU,QAAQ,aAAa;CACnE,MAAM,YAAY;EAAC,GAAG,MAAM;EAAY,GAAI,QAAQ,mBAAmB,CAAC;EAAI,MAAM;CAAa;CAC/F,MAAM,eAAe;EAAC,GAAG,MAAM;EAAe,GAAI,QAAQ,sBAAsB,CAAC;EAAI,MAAM;CAAgB;CAC3G,MAAM,WAAW,QAAQ,YAAY,CAAC;CACtC,MAAM,OAAO,gBAAgB,SAAS;CACtC,MAAM,iBAAiB,iBAAiB,QAAQ,gBAAgB,IAAI,gBAAgB,YAAY,IAAI,CAAC;CACrG,OAAO;EACL;EACA;EACA,QAAQ,WAAW,CAAC;EACpB;EACA,QAAQ,eAAe,CAAC;EACxB,QAAQ,OAAO,CAAC;EAChB,QAAQ,gBAAgB,CAAC;CAC3B,CAAC,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1B;AAEA,eAAsB,kBAAkB,SAAiD;CACvF,MAAM,QAAQ,cAAc,QAAQ,UAAU,QAAQ,aAAa;CACnE,MAAM,YAAY;EAAC,GAAG,MAAM;EAAY,GAAI,QAAQ,mBAAmB,CAAC;EAAI,MAAM;CAAa;CAC/F,MAAM,eAAe;EAAC,GAAG,MAAM;EAAe,GAAI,QAAQ,sBAAsB,CAAC;EAAI,MAAM;CAAgB;CAC3G,MAAM,CAAC,MAAM,kBAAkB,MAAM,QAAQ,IAAI,CAC/C,qBAAqB,SAAS,GAC9B,iBAAiB,QAAQ,gBAAgB,IAAI,qBAAqB,YAAY,IAAI,QAAQ,QAAQ,CAAC,CAAC,CACtG,CAAC;CACD,OAAO;EACL,QAAQ,YAAY,CAAC;EACrB;EACA,QAAQ,WAAW,CAAC;EACpB;EACA,QAAQ,eAAe,CAAC;EACxB,QAAQ,OAAO,CAAC;EAChB,QAAQ,gBAAgB,CAAC;CAC3B,CAAC,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1B;;;;;;;;;;AAWA,SAAS,kBAAkB,eAA8D;CACvF,OAAO;EACL,QAAQ,KAAK,KAAK,eAAe,iBAAiB,kBAAkB;EACpE,WAAW,KAAK,KAAK,sBAAsB,aAAa,GAAG,kBAAkB;CAC/E;AACF;;AAGA,SAAgB,oBAAoB,gBAAgB,GAAG,QAAQ,GAAW;CACxE,OAAO,kBAAkB,aAAa,CAAC,CAAC;AAC1C;AAEA,SAAgB,oBAAoB,gBAAgB,GAAG,QAAQ,GAAoB;CACjF,MAAM,QAAQ,kBAAkB,aAAa;CAC7C,OAAO,qBAAqB,gBAAgB,CAAC,MAAM,QAAQ,MAAM,SAAS,CAAC,CAAC;AAC9E;;;;;;;;;AAUA,SAAgB,oBAAoB,QAA+B,gBAAgB,GAAG,QAAQ,GAAoB;CAChH,MAAM,QAAQ,kBAAkB,aAAa;CAC7C,uBAAuB,MAAM,WAAW,qBAAqB,WAAW,MAAM,SAAS,GAAG,MAAM,CAAC;CACjG,OAAO,oBAAoB,aAAa;AAC1C"}
@@ -0,0 +1,12 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_piConfig = require("./piConfig-CCBdZXQr.cjs");
3
+ exports.DEFAULT_IMAGE_MAX_DIMENSION = require_piConfig.DEFAULT_IMAGE_MAX_DIMENSION;
4
+ exports.MIN_IMAGE_MAX_DIMENSION = require_piConfig.MIN_IMAGE_MAX_DIMENSION;
5
+ exports.clampImageMaxDimension = require_piConfig.clampImageMaxDimension;
6
+ exports.loadPiConfig = require_piConfig.loadPiConfig;
7
+ exports.loadPiConfigAsync = require_piConfig.loadPiConfigAsync;
8
+ exports.loadPiImageSettings = require_piConfig.loadPiImageSettings;
9
+ exports.parsePiImageSettings = require_piConfig.parsePiImageSettings;
10
+ exports.piConfigPaths = require_piConfig.piConfigPaths;
11
+ exports.piImageSettingsPath = require_piConfig.piImageSettingsPath;
12
+ exports.savePiImageSettings = require_piConfig.savePiImageSettings;
@@ -0,0 +1,2 @@
1
+ import { a as piImageSettingsPath, c as MIN_IMAGE_MAX_DIMENSION, d as clampImageMaxDimension, f as parsePiImageSettings, i as piConfigPaths, l as PiImageSettings, n as loadPiConfigAsync, o as savePiImageSettings, r as loadPiImageSettings, s as DEFAULT_IMAGE_MAX_DIMENSION, t as loadPiConfig, u as PiImageSettingsUpdate } from "./index-CVlciCJF.mjs";
2
+ export { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION, type PiImageSettings, type PiImageSettingsUpdate, clampImageMaxDimension, loadPiConfig, loadPiConfigAsync, loadPiImageSettings, parsePiImageSettings, piConfigPaths, piImageSettingsPath, savePiImageSettings };
@@ -0,0 +1,2 @@
1
+ import { a as piImageSettingsPath, c as MIN_IMAGE_MAX_DIMENSION, i as piConfigPaths, l as clampImageMaxDimension, n as loadPiConfigAsync, o as savePiImageSettings, r as loadPiImageSettings, s as DEFAULT_IMAGE_MAX_DIMENSION, t as loadPiConfig, u as parsePiImageSettings } from "./piConfig-qGyCbcVj.mjs";
2
+ export { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION, clampImageMaxDimension, loadPiConfig, loadPiConfigAsync, loadPiImageSettings, parsePiImageSettings, piConfigPaths, piImageSettingsPath, savePiImageSettings };
@@ -0,0 +1,18 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_sessionConfig = require("./sessionConfig-Boh4Fdje.cjs");
3
+ exports.DOOM_CONFIG_ENTRY_TYPE = require_sessionConfig.DOOM_CONFIG_ENTRY_TYPE;
4
+ exports.DOOM_CONFIG_TRANSITION_ENTRY_TYPE = require_sessionConfig.DOOM_CONFIG_TRANSITION_ENTRY_TYPE;
5
+ exports.acknowledgeDoomConfigTransition = require_sessionConfig.acknowledgeDoomConfigTransition;
6
+ exports.appendDoomConfigSelection = require_sessionConfig.appendDoomConfigSelection;
7
+ exports.appendDoomConfigTransition = require_sessionConfig.appendDoomConfigTransition;
8
+ exports.createDoomConfigContext = require_sessionConfig.createDoomConfigContext;
9
+ exports.createDoomConfigContextAsync = require_sessionConfig.createDoomConfigContextAsync;
10
+ exports.freezeDoomConfigContext = require_sessionConfig.freezeDoomConfigContext;
11
+ exports.persistHarnessSelection = require_sessionConfig.persistHarnessSelection;
12
+ exports.provideDoomConfigContext = require_sessionConfig.provideDoomConfigContext;
13
+ exports.readDoomConfigContextGeneration = require_sessionConfig.readDoomConfigContextGeneration;
14
+ exports.readDoomConfigPendingSelection = require_sessionConfig.readDoomConfigPendingSelection;
15
+ exports.readDoomConfigSelection = require_sessionConfig.readDoomConfigSelection;
16
+ exports.replaceDoomConfigContext = require_sessionConfig.replaceDoomConfigContext;
17
+ exports.requireDoomConfigContext = require_sessionConfig.requireDoomConfigContext;
18
+ exports.supersedeDoomConfigTransition = require_sessionConfig.supersedeDoomConfigTransition;
@@ -0,0 +1,3 @@
1
+ import { _ as DoomConfigTransitionStrategy, g as DoomConfigTransitionRecord, h as DoomConfigTransitionPhase, p as DoomConfigPendingSelection } from "./config-Cm3EV1jp.mjs";
2
+ import { _ as supersedeDoomConfigTransition, a as appendDoomConfigSelection, c as createDoomConfigContextAsync, d as provideDoomConfigContext, f as readDoomConfigContextGeneration, g as requireDoomConfigContext, h as replaceDoomConfigContext, i as acknowledgeDoomConfigTransition, l as freezeDoomConfigContext, m as readDoomConfigSelection, n as DOOM_CONFIG_TRANSITION_ENTRY_TYPE, o as appendDoomConfigTransition, p as readDoomConfigPendingSelection, r as DoomConfigSelection, s as createDoomConfigContext, t as DOOM_CONFIG_ENTRY_TYPE, u as persistHarnessSelection } from "./index-BAaTySaM.mjs";
3
+ export { DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, type DoomConfigPendingSelection, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, createDoomConfigContext, createDoomConfigContextAsync, freezeDoomConfigContext, persistHarnessSelection, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, replaceDoomConfigContext, requireDoomConfigContext, supersedeDoomConfigTransition };
@@ -0,0 +1,2 @@
1
+ import { _ as supersedeDoomConfigTransition, a as appendDoomConfigTransition, d as provideDoomConfigContext, f as readDoomConfigContextGeneration, g as requireDoomConfigContext, h as replaceDoomConfigContext, i as appendDoomConfigSelection, l as freezeDoomConfigContext, m as readDoomConfigSelection, n as DOOM_CONFIG_TRANSITION_ENTRY_TYPE, o as createDoomConfigContext, p as readDoomConfigPendingSelection, r as acknowledgeDoomConfigTransition, s as createDoomConfigContextAsync, t as DOOM_CONFIG_ENTRY_TYPE, u as persistHarnessSelection } from "./sessionConfig-CtLoc-lO.mjs";
2
+ export { DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, createDoomConfigContext, createDoomConfigContextAsync, freezeDoomConfigContext, persistHarnessSelection, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, replaceDoomConfigContext, requireDoomConfigContext, supersedeDoomConfigTransition };
@@ -0,0 +1,27 @@
1
+ //#region src/types/profiles.d.ts
2
+ interface PersonaIdentity {
3
+ name?: string;
4
+ icon?: string;
5
+ }
6
+ interface PersonaVoiceOverride {
7
+ /** Engine voice id, e.g. a macOS `say` voice name. */
8
+ voice?: string;
9
+ /** Words per minute. */
10
+ rate?: number;
11
+ }
12
+ interface PersonaFrontMatter {
13
+ /** Display name shown instead of the profile's directory name. */
14
+ name?: string;
15
+ /** Icon path, relative to the persona directory. */
16
+ icon?: string;
17
+ /** Narrowly scoped TTS override; the engine itself stays global. */
18
+ voice?: PersonaVoiceOverride;
19
+ }
20
+ interface PersonaDocument {
21
+ frontMatter?: PersonaFrontMatter;
22
+ /** The persona text with a recognised block removed, otherwise the input unchanged. */
23
+ body: string;
24
+ }
25
+ //#endregion
26
+ export { PersonaVoiceOverride as i, PersonaFrontMatter as n, PersonaIdentity as r, PersonaDocument as t };
27
+ //# sourceMappingURL=profiles-CTrUCmIh.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles-CTrUCmIh.d.mts","names":[],"sources":["../src/types/profiles.ts"],"mappings":";UAAiB;EACf;EACA;;UAGe;;EAEf;;EAEA;;UAGe;;EAEf;;EAEA;;EAEA,QAAQ;;UAGO;EACf,cAAc;;EAEd"}