@agimon-ai/doompi-profile 0.0.1-alpha.2

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  4. package/dist/adapters/pi/extension.cjs +2 -0
  5. package/dist/adapters/pi/extension.cjs.map +1 -0
  6. package/dist/adapters/pi/extension.d.cts +13 -0
  7. package/dist/adapters/pi/extension.d.cts.map +1 -0
  8. package/dist/adapters/pi/extension.d.mts +13 -0
  9. package/dist/adapters/pi/extension.d.mts.map +1 -0
  10. package/dist/adapters/pi/extension.mjs +2 -0
  11. package/dist/adapters/pi/extension.mjs.map +1 -0
  12. package/dist/adapters/pi/persona.cjs +2 -0
  13. package/dist/adapters/pi/persona.cjs.map +1 -0
  14. package/dist/adapters/pi/persona.d.cts +18 -0
  15. package/dist/adapters/pi/persona.d.cts.map +1 -0
  16. package/dist/adapters/pi/persona.d.mts +18 -0
  17. package/dist/adapters/pi/persona.d.mts.map +1 -0
  18. package/dist/adapters/pi/persona.mjs +2 -0
  19. package/dist/adapters/pi/persona.mjs.map +1 -0
  20. package/dist/adapters/telemetry/logSinkTelemetry.cjs +2 -0
  21. package/dist/adapters/telemetry/logSinkTelemetry.cjs.map +1 -0
  22. package/dist/adapters/telemetry/logSinkTelemetry.d.cts +14 -0
  23. package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +1 -0
  24. package/dist/adapters/telemetry/logSinkTelemetry.d.mts +14 -0
  25. package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +1 -0
  26. package/dist/adapters/telemetry/logSinkTelemetry.mjs +2 -0
  27. package/dist/adapters/telemetry/logSinkTelemetry.mjs.map +1 -0
  28. package/dist/commands/profileCommand.cjs +2 -0
  29. package/dist/commands/profileCommand.cjs.map +1 -0
  30. package/dist/commands/profileCommand.mjs +2 -0
  31. package/dist/commands/profileCommand.mjs.map +1 -0
  32. package/dist/extensions/persona.cjs +1 -0
  33. package/dist/extensions/persona.d.cts +2 -0
  34. package/dist/extensions/persona.d.mts +2 -0
  35. package/dist/extensions/persona.mjs +1 -0
  36. package/dist/extensions/pi.cjs +1 -0
  37. package/dist/extensions/pi.d.cts +2 -0
  38. package/dist/extensions/pi.d.mts +2 -0
  39. package/dist/extensions/pi.mjs +1 -0
  40. package/dist/index.cjs +1 -0
  41. package/dist/index.d.cts +6 -0
  42. package/dist/index.d.mts +6 -0
  43. package/dist/index.mjs +1 -0
  44. package/dist/services/profileText.cjs +3 -0
  45. package/dist/services/profileText.cjs.map +1 -0
  46. package/dist/services/profileText.d.cts +12 -0
  47. package/dist/services/profileText.d.cts.map +1 -0
  48. package/dist/services/profileText.d.mts +12 -0
  49. package/dist/services/profileText.d.mts.map +1 -0
  50. package/dist/services/profileText.mjs +3 -0
  51. package/dist/services/profileText.mjs.map +1 -0
  52. package/dist/types/telemetry.cjs +2 -0
  53. package/dist/types/telemetry.cjs.map +1 -0
  54. package/dist/types/telemetry.d.cts +16 -0
  55. package/dist/types/telemetry.d.cts.map +1 -0
  56. package/dist/types/telemetry.d.mts +16 -0
  57. package/dist/types/telemetry.d.mts.map +1 -0
  58. package/dist/types/telemetry.mjs +2 -0
  59. package/dist/types/telemetry.mjs.map +1 -0
  60. package/llms.txt +7 -0
  61. package/package.json +97 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vuong Ngo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @agimon-ai/doompi-profile
2
+
3
+ Persona and environment profile switching for [DoomPi](https://www.npmjs.com/package/@agimon-ai/doompi)
4
+ sessions.
5
+
6
+ A **profile** is one of the four axes of a DoomPi selection, alongside domains, the major mode and
7
+ the minor modes. It names a persona directory and a set of environment defaults:
8
+
9
+ ```yaml
10
+ # .doom/profiles.yaml
11
+ profiles:
12
+ roots: [agents]
13
+ entries:
14
+ reviewer:
15
+ persona: agents/reviewer
16
+ env:
17
+ REVIEW_STRICTNESS: high
18
+ ```
19
+
20
+ The persona is `profile.md`, `SOUL.md` and `AGENTS.md` concatenated from the named directory. The
21
+ harness assembles them into one file in the run directory and records its path; the persona entry
22
+ appends that file to the system prompt on every agent start, so the repository's own `AGENTS.md`
23
+ keeps applying underneath it.
24
+
25
+ ## What it registers
26
+
27
+ | Entry | Surface |
28
+ | ---------------------- | --------------------------------------------------------------------------------------- |
29
+ | `./extensions/pi` | the `/profile` command — lists profiles, switches persona and environment, then reloads |
30
+ | `./extensions/persona` | a `before_agent_start` hook that appends the active persona to the system prompt |
31
+
32
+ Two entries rather than one because a detached child session needs the persona but has no
33
+ transition coordinator to run a switch through. DoomPi activates `./extensions/pi` in the parent
34
+ and `./extensions/persona` in both.
35
+
36
+ ## Switching
37
+
38
+ `/profile` plans the change through the session's transition coordinator before applying anything.
39
+ A profile change is always a `pi-reload`: the extension set does not change, but module-level caches
40
+ have to be dropped so every extension re-reads the environment. Active minor modes are captured
41
+ before the reload and restored after it.
42
+
43
+ ## Installation
44
+
45
+ DoomPi depends on this package and activates it as fixed host core, so a DoomPi install already has
46
+ it. It is not selectable from `.doom/modes.yaml`.
47
+
48
+ ## License
49
+
50
+ MIT
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));exports.__toESM=s;
@@ -0,0 +1,2 @@
1
+ const e=require("../telemetry/logSinkTelemetry.cjs"),t=require("../../commands/profileCommand.cjs");let n=require("@deepseek-ai/cordis");async function r(r,i=e.createProfileTelemetry()){let a=new n.Context,o,s=()=>(o??=a.fiber.dispose(),o);try{a.effect(function*(){t.registerProfileCommand(r,i),yield()=>void 0},`@agimon-ai/doompi-profile`)}catch(e){throw await s(),e}r.on(`session_shutdown`,s)}exports.default=r,exports.profileExtension=r;
2
+ //# sourceMappingURL=extension.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.cjs","names":["createProfileTelemetry","Context"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerProfileCommand } from '../../commands/profileCommand.ts';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-profile';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\n/**\n * The package's single standard Pi factory, and the owner of the cordis Context.\n *\n * Pi can reload an extension in-process, so every registration is yielded to the\n * fiber and one dispose on session shutdown unwinds them in reverse.\n */\nexport async function profileExtension(\n pi: ExtensionAPI,\n telemetry: ProfileTelemetry = createProfileTelemetry(),\n): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n cordis.effect(function* () {\n registerProfileCommand(pi, telemetry);\n // Pi owns command deregistration across a reload, so the fiber only has to\n // drop this package's own reference to the session.\n yield () => undefined;\n }, PACKAGE_SOURCE);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default profileExtension;\n"],"mappings":"yIAeA,eAAsB,EACpB,EACA,EAA8BA,EAAAA,uBAAuB,EACtC,CACf,IAAM,EAAS,IAAIC,EAAAA,QACf,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAO,OAAO,WAAa,CACzB,EAAA,uBAAuB,EAAI,CAAS,EAGpC,SAAY,IAAA,EACd,EAAG,2BAAc,CACnB,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAwB,CAAO,CACvC"}
@@ -0,0 +1,13 @@
1
+ import { ProfileTelemetry } from "../../types/telemetry.cjs";
2
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ //#region src/adapters/pi/extension.d.ts
4
+ /**
5
+ * The package's single standard Pi factory, and the owner of the cordis Context.
6
+ *
7
+ * Pi can reload an extension in-process, so every registration is yielded to the
8
+ * fiber and one dispose on session shutdown unwinds them in reverse.
9
+ */
10
+ declare function profileExtension(pi: ExtensionAPI, telemetry?: ProfileTelemetry): Promise<void>;
11
+ //#endregion
12
+ export { profileExtension as default, profileExtension };
13
+ //# sourceMappingURL=extension.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;;iBAesB,iBACpB,IAAI,cACJ,YAAW,mBACV"}
@@ -0,0 +1,13 @@
1
+ import { ProfileTelemetry } from "../../types/telemetry.mjs";
2
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ //#region src/adapters/pi/extension.d.ts
4
+ /**
5
+ * The package's single standard Pi factory, and the owner of the cordis Context.
6
+ *
7
+ * Pi can reload an extension in-process, so every registration is yielded to the
8
+ * fiber and one dispose on session shutdown unwinds them in reverse.
9
+ */
10
+ declare function profileExtension(pi: ExtensionAPI, telemetry?: ProfileTelemetry): Promise<void>;
11
+ //#endregion
12
+ export { profileExtension as default, profileExtension };
13
+ //# sourceMappingURL=extension.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;;iBAesB,iBACpB,IAAI,cACJ,YAAW,mBACV"}
@@ -0,0 +1,2 @@
1
+ import{createProfileTelemetry as e}from"../telemetry/logSinkTelemetry.mjs";import{registerProfileCommand as t}from"../../commands/profileCommand.mjs";import{Context as n}from"@deepseek-ai/cordis";async function r(r,i=e()){let a=new n,o,s=()=>(o??=a.fiber.dispose(),o);try{a.effect(function*(){t(r,i),yield()=>void 0},`@agimon-ai/doompi-profile`)}catch(e){throw await s(),e}r.on(`session_shutdown`,s)}export{r as default,r as profileExtension};
2
+ //# sourceMappingURL=extension.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerProfileCommand } from '../../commands/profileCommand.ts';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-profile';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\n/**\n * The package's single standard Pi factory, and the owner of the cordis Context.\n *\n * Pi can reload an extension in-process, so every registration is yielded to the\n * fiber and one dispose on session shutdown unwinds them in reverse.\n */\nexport async function profileExtension(\n pi: ExtensionAPI,\n telemetry: ProfileTelemetry = createProfileTelemetry(),\n): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n cordis.effect(function* () {\n registerProfileCommand(pi, telemetry);\n // Pi owns command deregistration across a reload, so the fiber only has to\n // drop this package's own reference to the session.\n yield () => undefined;\n }, PACKAGE_SOURCE);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default profileExtension;\n"],"mappings":"oMAeA,eAAsB,EACpB,EACA,EAA8B,EAAuB,EACtC,CACf,IAAM,EAAS,IAAI,EACf,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAO,OAAO,WAAa,CACzB,EAAuB,EAAI,CAAS,EAGpC,SAAY,IAAA,EACd,EAAG,2BAAc,CACnB,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAwB,CAAO,CACvC"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../telemetry/logSinkTelemetry.cjs"),n=require("../../types/telemetry.cjs");let r=require("node:fs");r=e.__toESM(r,1);let i=require("@agimon-ai/doompi-config/piContext");function a(e,a=t.createProfileTelemetry()){e.on(`before_agent_start`,async(e,t)=>{let{personaFile:o}=(0,i.requireDoomConfigContext)(t).harness;if(o)try{let t=(await r.default.promises.readFile(o,`utf8`)).trim();return t?{systemPrompt:`${e.systemPrompt}\n\n${t}`}:void 0}catch(e){let t=e instanceof Error?e.message:String(e);a.recordError(n.PROFILE_EVENT.personaReadFailed,e),process.stderr.write(`[pi-persona] could not read ${o}: ${t}\n`);return}})}exports.default=a,exports.personaExtension=a;
2
+ //# sourceMappingURL=persona.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persona.cjs","names":["createProfileTelemetry","requireDoomConfigContext","fs","PROFILE_EVENT"],"sources":["../../../src/adapters/pi/persona.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { PROFILE_EVENT, type ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\n/**\n * Appends the selected profile's persona to the system prompt.\n *\n * The harness writes the assembled persona to a file in the run directory and\n * records the path in the harness state, so agents/ stays the single source of\n * persona material and is never copied into config.\n *\n * This is a separate Pi entry from the /profile command because detached\n * children need the persona without the command: they have no transition\n * coordinator to run a switch through.\n */\nexport function personaExtension(pi: ExtensionAPI, telemetry: ProfileTelemetry = createProfileTelemetry()): void {\n pi.on('before_agent_start', async (event, ctx) => {\n const { personaFile } = requireDoomConfigContext(ctx).harness;\n if (!personaFile) return undefined;\n\n try {\n const content = (await fs.promises.readFile(personaFile, 'utf8')).trim();\n return content ? { systemPrompt: `${event.systemPrompt}\\n\\n${content}` } : undefined;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(PROFILE_EVENT.personaReadFailed, error);\n process.stderr.write(`[pi-persona] could not read ${personaFile}: ${reason}\\n`);\n return undefined;\n }\n });\n}\n\nexport default personaExtension;\n"],"mappings":"4OAiBA,SAAgB,EAAiB,EAAkB,EAA8BA,EAAAA,uBAAuB,EAAS,CAC/G,EAAG,GAAG,qBAAsB,MAAO,EAAO,IAAQ,CAChD,GAAM,CAAE,gBAAA,EAAgBC,EAAAA,yBAAAA,CAAyB,CAAG,CAAC,CAAC,QACjD,KAEL,GAAI,CACF,IAAM,GAAW,MAAMC,EAAAA,QAAG,SAAS,SAAS,EAAa,MAAM,EAAA,CAAG,KAAK,EACvE,OAAO,EAAU,CAAE,aAAc,GAAG,EAAM,aAAa,MAAM,GAAU,EAAI,IAAA,EAC7E,OAAS,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACpE,EAAe,YAAYC,EAAAA,cAAc,kBAAmB,CAAK,EACjE,QAAQ,OAAO,MAAM,+BAA+B,EAAY,IAAI,EAAO,GAAG,EAC9E,MACF,CACF,CAAC,CACH"}
@@ -0,0 +1,18 @@
1
+ import { ProfileTelemetry } from "../../types/telemetry.cjs";
2
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ //#region src/adapters/pi/persona.d.ts
4
+ /**
5
+ * Appends the selected profile's persona to the system prompt.
6
+ *
7
+ * The harness writes the assembled persona to a file in the run directory and
8
+ * records the path in the harness state, so agents/ stays the single source of
9
+ * persona material and is never copied into config.
10
+ *
11
+ * This is a separate Pi entry from the /profile command because detached
12
+ * children need the persona without the command: they have no transition
13
+ * coordinator to run a switch through.
14
+ */
15
+ declare function personaExtension(pi: ExtensionAPI, telemetry?: ProfileTelemetry): void;
16
+ //#endregion
17
+ export { personaExtension as default, personaExtension };
18
+ //# sourceMappingURL=persona.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persona.d.cts","names":[],"sources":["../../../src/adapters/pi/persona.ts"],"mappings":";;;;;;;;;;;;;;iBAiBgB,iBAAiB,IAAI,cAAc,YAAW"}
@@ -0,0 +1,18 @@
1
+ import { ProfileTelemetry } from "../../types/telemetry.mjs";
2
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ //#region src/adapters/pi/persona.d.ts
4
+ /**
5
+ * Appends the selected profile's persona to the system prompt.
6
+ *
7
+ * The harness writes the assembled persona to a file in the run directory and
8
+ * records the path in the harness state, so agents/ stays the single source of
9
+ * persona material and is never copied into config.
10
+ *
11
+ * This is a separate Pi entry from the /profile command because detached
12
+ * children need the persona without the command: they have no transition
13
+ * coordinator to run a switch through.
14
+ */
15
+ declare function personaExtension(pi: ExtensionAPI, telemetry?: ProfileTelemetry): void;
16
+ //#endregion
17
+ export { personaExtension as default, personaExtension };
18
+ //# sourceMappingURL=persona.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persona.d.mts","names":[],"sources":["../../../src/adapters/pi/persona.ts"],"mappings":";;;;;;;;;;;;;;iBAiBgB,iBAAiB,IAAI,cAAc,YAAW"}
@@ -0,0 +1,2 @@
1
+ import{createProfileTelemetry as e}from"../telemetry/logSinkTelemetry.mjs";import{PROFILE_EVENT as t}from"../../types/telemetry.mjs";import n from"node:fs";import{requireDoomConfigContext as r}from"@agimon-ai/doompi-config/piContext";function i(i,a=e()){i.on(`before_agent_start`,async(e,i)=>{let{personaFile:o}=r(i).harness;if(o)try{let t=(await n.promises.readFile(o,`utf8`)).trim();return t?{systemPrompt:`${e.systemPrompt}\n\n${t}`}:void 0}catch(e){let n=e instanceof Error?e.message:String(e);a.recordError(t.personaReadFailed,e),process.stderr.write(`[pi-persona] could not read ${o}: ${n}\n`);return}})}export{i as default,i as personaExtension};
2
+ //# sourceMappingURL=persona.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persona.mjs","names":[],"sources":["../../../src/adapters/pi/persona.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { PROFILE_EVENT, type ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\n/**\n * Appends the selected profile's persona to the system prompt.\n *\n * The harness writes the assembled persona to a file in the run directory and\n * records the path in the harness state, so agents/ stays the single source of\n * persona material and is never copied into config.\n *\n * This is a separate Pi entry from the /profile command because detached\n * children need the persona without the command: they have no transition\n * coordinator to run a switch through.\n */\nexport function personaExtension(pi: ExtensionAPI, telemetry: ProfileTelemetry = createProfileTelemetry()): void {\n pi.on('before_agent_start', async (event, ctx) => {\n const { personaFile } = requireDoomConfigContext(ctx).harness;\n if (!personaFile) return undefined;\n\n try {\n const content = (await fs.promises.readFile(personaFile, 'utf8')).trim();\n return content ? { systemPrompt: `${event.systemPrompt}\\n\\n${content}` } : undefined;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(PROFILE_EVENT.personaReadFailed, error);\n process.stderr.write(`[pi-persona] could not read ${personaFile}: ${reason}\\n`);\n return undefined;\n }\n });\n}\n\nexport default personaExtension;\n"],"mappings":"0OAiBA,SAAgB,EAAiB,EAAkB,EAA8B,EAAuB,EAAS,CAC/G,EAAG,GAAG,qBAAsB,MAAO,EAAO,IAAQ,CAChD,GAAM,CAAE,eAAgB,EAAyB,CAAG,CAAC,CAAC,QACjD,KAEL,GAAI,CACF,IAAM,GAAW,MAAM,EAAG,SAAS,SAAS,EAAa,MAAM,EAAA,CAAG,KAAK,EACvE,OAAO,EAAU,CAAE,aAAc,GAAG,EAAM,aAAa,MAAM,GAAU,EAAI,IAAA,EAC7E,OAAS,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACpE,EAAe,YAAY,EAAc,kBAAmB,CAAK,EACjE,QAAQ,OAAO,MAAM,+BAA+B,EAAY,IAAI,EAAO,GAAG,EAC9E,MACF,CACF,CAAC,CACH"}
@@ -0,0 +1,2 @@
1
+ let e=require("@agimon-ai/doompi-telemetry");function t(t={}){let n=(0,e.createDoomTelemetry)({serviceName:`doom-pi-profile`,packageName:`@agimon-ai/doompi-profile`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordEvent:(e,t)=>n.recordEvent(e,t)}}exports.createProfileTelemetry=t;
2
+ //# sourceMappingURL=logSinkTelemetry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSinkTelemetry.cjs","names":["createDoomTelemetry"],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\n\nconst SERVICE_NAME = 'doom-pi-profile';\nconst PACKAGE_NAME = '@agimon-ai/doompi-profile';\n\nexport interface ProfileTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createProfileTelemetry(options: ProfileTelemetryOptions = {}): ProfileTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordEvent: (event, attributes) => telemetry.recordEvent(event, attributes),\n };\n}\n"],"mappings":"6CAcA,SAAgB,EAAuB,EAAmC,CAAC,EAAqB,CAC9F,IAAM,GAAA,EAA2BA,EAAAA,oBAAAA,CAAoB,CACnD,YAAa,kBACb,YAAa,4BACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,CAAU,EACzF,aAAc,EAAO,IAAe,EAAU,YAAY,EAAO,CAAU,CAC7E,CACF"}
@@ -0,0 +1,14 @@
1
+ import { ProfileTelemetry } from "../../types/telemetry.cjs";
2
+ import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
3
+ //#region src/adapters/telemetry/logSinkTelemetry.d.ts
4
+ interface ProfileTelemetryOptions {
5
+ cwd?: string;
6
+ workspaceRoot?: string;
7
+ env?: NodeJS.ProcessEnv;
8
+ telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
9
+ warn?: (message: string) => void;
10
+ }
11
+ declare function createProfileTelemetry(options?: ProfileTelemetryOptions): ProfileTelemetry;
12
+ //#endregion
13
+ export { ProfileTelemetryOptions, createProfileTelemetry };
14
+ //# sourceMappingURL=logSinkTelemetry.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSinkTelemetry.d.cts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;UAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;iBAGM,uBAAuB,UAAS,0BAA+B"}
@@ -0,0 +1,14 @@
1
+ import { ProfileTelemetry } from "../../types/telemetry.mjs";
2
+ import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
3
+ //#region src/adapters/telemetry/logSinkTelemetry.d.ts
4
+ interface ProfileTelemetryOptions {
5
+ cwd?: string;
6
+ workspaceRoot?: string;
7
+ env?: NodeJS.ProcessEnv;
8
+ telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
9
+ warn?: (message: string) => void;
10
+ }
11
+ declare function createProfileTelemetry(options?: ProfileTelemetryOptions): ProfileTelemetry;
12
+ //#endregion
13
+ export { ProfileTelemetryOptions, createProfileTelemetry };
14
+ //# sourceMappingURL=logSinkTelemetry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSinkTelemetry.d.mts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;UAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;iBAGM,uBAAuB,UAAS,0BAA+B"}
@@ -0,0 +1,2 @@
1
+ import{createDoomTelemetry as e}from"@agimon-ai/doompi-telemetry";function t(t={}){let n=e({serviceName:`doom-pi-profile`,packageName:`@agimon-ai/doompi-profile`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordEvent:(e,t)=>n.recordEvent(e,t)}}export{t as createProfileTelemetry};
2
+ //# sourceMappingURL=logSinkTelemetry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logSinkTelemetry.mjs","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\n\nconst SERVICE_NAME = 'doom-pi-profile';\nconst PACKAGE_NAME = '@agimon-ai/doompi-profile';\n\nexport interface ProfileTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createProfileTelemetry(options: ProfileTelemetryOptions = {}): ProfileTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordEvent: (event, attributes) => telemetry.recordEvent(event, attributes),\n };\n}\n"],"mappings":"kEAcA,SAAgB,EAAuB,EAAmC,CAAC,EAAqB,CAC9F,IAAM,EAA2B,EAAoB,CACnD,YAAa,kBACb,YAAa,4BACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,CAAU,EACzF,aAAc,EAAO,IAAe,EAAU,YAAY,EAAO,CAAU,CAC7E,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("../types/telemetry.cjs"),t=require("../services/profileText.cjs");let n=require("@agimon-ai/doompi-config/piContext"),r=require("@agimon-ai/doompi-extension-contracts/transition");const i=`warning`,a=`info`,o=`.doom/profiles.yaml`;function s(){let e,t,n,r,i;return{harnessStore:()=>e??=import(`@agimon-ai/doompi-config/harnessStore`),journal:()=>t??=import(`@agimon-ai/doompi-config/piContext`),picker:()=>n??=import(`@agimon-ai/doompi-ui/components/matrixPicker`),profiles:()=>r??=import(`@agimon-ai/doompi-config/profiles`),selection:()=>i??=import(`@agimon-ai/doompi-config/selectionSwitch`)}}async function c(e,n,r,i){let a=t.profileTitle(r);if(e.mode!==`tui`)return e.ui.select(a,n.map(e=>e.name));let{MatrixPickerComponent:o}=await i();return(await e.ui.custom((e,i,s,c)=>new o({title:a,items:t.profileItems(n),selected:r?[r]:[],multi:!1},i,s,c)))?.[0]}function l(l,u){let d=s();l.registerCommand(`profile`,{description:`Show profiles and load a different persona and environment`,handler:async(s,f)=>{let p=(0,n.requireDoomConfigContext)(f).harness,[{requireHarnessRoot:m},{loadProfiles:h}]=await Promise.all([d.harnessStore(),d.profiles()]),g=m(p),_=p.profile,v;try{v=h(g)}catch(t){let n=t instanceof Error?t.message:String(t);u.recordError(e.PROFILE_EVENT.profileLoadFailed,t),f.ui.notify(`Could not load ${o}: ${n}`,i);return}if(v.length===0){f.ui.notify(`No profiles found in ${o}.`,i);return}let y=await c(f,v,_,d.picker),b=v.find(e=>e.name===y);if(!b)return;if(b.name===_){f.ui.notify(t.profileSummary(b),a);return}let x=(0,r.requireDoomTransitionCoordinator)(f),S,C=await x.execute({sessionId:f.sessionManager.getSessionId(),hostGeneration:x.hostGeneration,operationId:crypto.randomUUID(),source:f.mode===`tui`?`ui`:`command`,target:{axis:`profile`,profile:b.name}},async(t,n)=>{S=(0,r.prepareMinorModeReloadHandoff)(f,x.hostGeneration,n.operationId,n.previous.minorModes);try{let{applyProfile:t}=await d.selection();f.ui.notify(await t(b,p),a);let{persistHarnessSelection:r}=await d.journal();return r(l,{...p,profile:b.name}),u.recordEvent(e.PROFILE_EVENT.profileApplied,{"harness.profile":b.name,..._?{"harness.profile.previous":_}:{},"harness.transition.disposition":n.disposition,"harness.transition.operation_id":n.operationId}),`applied`}catch(e){throw S?.discard(),S=void 0,e}});if(C.outcome===`rejected`||C.outcome===`stale`){S?.discard(),f.ui.notify(`Profile transition was ${C.outcome}: ${C.diagnostics.join(`, `)}`,i);return}if(C.outcome!==`applied`){S?.discard();return}try{await f.waitForIdle(),await f.reload()}catch(e){throw S?.discard(),e}}})}exports.registerProfileCommand=l;
2
+ //# sourceMappingURL=profileCommand.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileCommand.cjs","names":["profileTitle","profileItems","requireDoomConfigContext","PROFILE_EVENT","profileSummary","requireDoomTransitionCoordinator","prepareMinorModeReloadHandoff"],"sources":["../../src/commands/profileCommand.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { AgentProfile } from '@agimon-ai/doompi-config/profiles';\nimport {\n type MinorModeReloadHandoffHandle,\n prepareMinorModeReloadHandoff,\n requireDoomTransitionCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { profileItems, profileSummary, profileTitle } from '../services/profileText.ts';\nimport { PROFILE_EVENT, type ProfileTelemetry } from '../types/telemetry.ts';\n\nconst WARNING = 'warning';\nconst INFO = 'info';\nconst PROFILE_CONFIG_PATH = '.doom/profiles.yaml';\n\n/**\n * The picker and everything behind it load on first use.\n *\n * Every session registers this command, but almost none of them run it, so the\n * profile catalogue, the TUI component and the switch stay off the startup path.\n */\nfunction lazyModules() {\n let harnessStore: Promise<typeof import('@agimon-ai/doompi-config/harnessStore')> | undefined;\n let journal: Promise<typeof import('@agimon-ai/doompi-config/piContext')> | undefined;\n let picker: Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')> | undefined;\n let profiles: Promise<typeof import('@agimon-ai/doompi-config/profiles')> | undefined;\n let selection: Promise<typeof import('@agimon-ai/doompi-config/selectionSwitch')> | undefined;\n return {\n harnessStore: () => (harnessStore ??= import('@agimon-ai/doompi-config/harnessStore')),\n journal: () => (journal ??= import('@agimon-ai/doompi-config/piContext')),\n picker: () => (picker ??= import('@agimon-ai/doompi-ui/components/matrixPicker')),\n profiles: () => (profiles ??= import('@agimon-ai/doompi-config/profiles')),\n selection: () => (selection ??= import('@agimon-ai/doompi-config/selectionSwitch')),\n };\n}\n\nasync function pickProfile(\n ctx: ExtensionContext,\n profiles: AgentProfile[],\n current: string | undefined,\n loadPicker: () => Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')>,\n): Promise<string | undefined> {\n const title = profileTitle(current);\n if (ctx.mode !== 'tui') {\n return ctx.ui.select(\n title,\n profiles.map((profile) => profile.name),\n );\n }\n const { MatrixPickerComponent } = await loadPicker();\n const chosen = await ctx.ui.custom<string[] | undefined>(\n (_tui, theme, keybindings, done) =>\n new MatrixPickerComponent(\n { title, items: profileItems(profiles), selected: current ? [current] : [], multi: false },\n theme,\n keybindings,\n done,\n ),\n );\n return chosen?.[0];\n}\n\nexport function registerProfileCommand(pi: ExtensionAPI, telemetry: ProfileTelemetry): void {\n const load = lazyModules();\n\n pi.registerCommand('profile', {\n description: 'Show profiles and load a different persona and environment',\n handler: async (_args, ctx) => {\n const state = requireDoomConfigContext(ctx).harness;\n const [{ requireHarnessRoot }, { loadProfiles }] = await Promise.all([load.harnessStore(), load.profiles()]);\n const root = requireHarnessRoot(state);\n const current = state.profile;\n let profiles: AgentProfile[];\n try {\n profiles = loadProfiles(root);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(PROFILE_EVENT.profileLoadFailed, error);\n ctx.ui.notify(`Could not load ${PROFILE_CONFIG_PATH}: ${reason}`, WARNING);\n return;\n }\n\n if (profiles.length === 0) {\n ctx.ui.notify(`No profiles found in ${PROFILE_CONFIG_PATH}.`, WARNING);\n return;\n }\n\n const picked = await pickProfile(ctx, profiles, current, load.picker);\n const profile = profiles.find((candidate) => candidate.name === picked);\n if (!profile) return;\n if (profile.name === current) {\n ctx.ui.notify(profileSummary(profile), INFO);\n return;\n }\n\n const coordinator = requireDoomTransitionCoordinator(ctx);\n let minorModeReloadHandoff: MinorModeReloadHandoffHandle | undefined;\n const result = await coordinator.execute(\n {\n sessionId: ctx.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: crypto.randomUUID(),\n source: ctx.mode === 'tui' ? 'ui' : 'command',\n target: { axis: 'profile', profile: profile.name },\n },\n async (_request, plan) => {\n minorModeReloadHandoff = prepareMinorModeReloadHandoff(\n ctx,\n coordinator.hostGeneration,\n plan.operationId,\n plan.previous.minorModes,\n );\n try {\n const { applyProfile } = await load.selection();\n ctx.ui.notify(await applyProfile(profile, state), INFO);\n const { persistHarnessSelection } = await load.journal();\n persistHarnessSelection(pi, { ...state, profile: profile.name });\n void telemetry.recordEvent(PROFILE_EVENT.profileApplied, {\n 'harness.profile': profile.name,\n ...(current ? { 'harness.profile.previous': current } : {}),\n 'harness.transition.disposition': plan.disposition,\n 'harness.transition.operation_id': plan.operationId,\n });\n return 'applied';\n } catch (error) {\n minorModeReloadHandoff?.discard();\n minorModeReloadHandoff = undefined;\n throw error;\n }\n },\n );\n if (result.outcome === 'rejected' || result.outcome === 'stale') {\n minorModeReloadHandoff?.discard();\n ctx.ui.notify(`Profile transition was ${result.outcome}: ${result.diagnostics.join(', ')}`, WARNING);\n return;\n }\n if (result.outcome !== 'applied') {\n minorModeReloadHandoff?.discard();\n return;\n }\n\n try {\n await ctx.waitForIdle();\n // Reload replaces the session and invalidates this command context.\n // Keep it as the handler's final action.\n await ctx.reload();\n } catch (error) {\n minorModeReloadHandoff?.discard();\n throw error;\n }\n },\n });\n}\n"],"mappings":"qMAWA,MAAM,EAAU,UACV,EAAO,OACP,EAAsB,sBAQ5B,SAAS,GAAc,CACrB,IAAI,EACA,EACA,EACA,EACA,EACJ,MAAO,CACL,iBAAqB,IAAiB,OAAO,yCAC7C,YAAgB,IAAY,OAAO,sCACnC,WAAe,IAAW,OAAO,gDACjC,aAAiB,IAAa,OAAO,qCACrC,cAAkB,IAAc,OAAO,2CACzC,CACF,CAEA,eAAe,EACb,EACA,EACA,EACA,EAC6B,CAC7B,IAAM,EAAQA,EAAAA,aAAa,CAAO,EAClC,GAAI,EAAI,OAAS,MACf,OAAO,EAAI,GAAG,OACZ,EACA,EAAS,IAAK,GAAY,EAAQ,IAAI,CACxC,EAEF,GAAM,CAAE,yBAA0B,MAAM,EAAW,EAUnD,OAAO,MATc,EAAI,GAAG,QACzB,EAAM,EAAO,EAAa,IACzB,IAAI,EACF,CAAE,QAAO,MAAOC,EAAAA,aAAa,CAAQ,EAAG,SAAU,EAAU,CAAC,CAAO,EAAI,CAAC,EAAG,MAAO,EAAM,EACzF,EACA,EACA,CACF,CACJ,EAAA,GACgB,EAClB,CAEA,SAAgB,EAAuB,EAAkB,EAAmC,CAC1F,IAAM,EAAO,EAAY,EAEzB,EAAG,gBAAgB,UAAW,CAC5B,YAAa,6DACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,IAAM,GAAA,EAAQC,EAAAA,yBAAAA,CAAyB,CAAG,CAAC,CAAC,QACtC,CAAC,CAAE,sBAAsB,CAAE,iBAAkB,MAAM,QAAQ,IAAI,CAAC,EAAK,aAAa,EAAG,EAAK,SAAS,CAAC,CAAC,EACrG,EAAO,EAAmB,CAAK,EAC/B,EAAU,EAAM,QAClB,EACJ,GAAI,CACF,EAAW,EAAa,CAAI,CAC9B,OAAS,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACpE,EAAe,YAAYC,EAAAA,cAAc,kBAAmB,CAAK,EACjE,EAAI,GAAG,OAAO,kBAAkB,EAAoB,IAAI,IAAU,CAAO,EACzE,MACF,CAEA,GAAI,EAAS,SAAW,EAAG,CACzB,EAAI,GAAG,OAAO,wBAAwB,EAAoB,GAAI,CAAO,EACrE,MACF,CAEA,IAAM,EAAS,MAAM,EAAY,EAAK,EAAU,EAAS,EAAK,MAAM,EAC9D,EAAU,EAAS,KAAM,GAAc,EAAU,OAAS,CAAM,EACtE,GAAI,CAAC,EAAS,OACd,GAAI,EAAQ,OAAS,EAAS,CAC5B,EAAI,GAAG,OAAOC,EAAAA,eAAe,CAAO,EAAG,CAAI,EAC3C,MACF,CAEA,IAAM,GAAA,EAAcC,EAAAA,iCAAAA,CAAiC,CAAG,EACpD,EACE,EAAS,MAAM,EAAY,QAC/B,CACE,UAAW,EAAI,eAAe,aAAa,EAC3C,eAAgB,EAAY,eAC5B,YAAa,OAAO,WAAW,EAC/B,OAAQ,EAAI,OAAS,MAAQ,KAAO,UACpC,OAAQ,CAAE,KAAM,UAAW,QAAS,EAAQ,IAAK,CACnD,EACA,MAAO,EAAU,IAAS,CACxB,GAAA,EAAyBC,EAAAA,8BAAAA,CACvB,EACA,EAAY,eACZ,EAAK,YACL,EAAK,SAAS,UAChB,EACA,GAAI,CACF,GAAM,CAAE,gBAAiB,MAAM,EAAK,UAAU,EAC9C,EAAI,GAAG,OAAO,MAAM,EAAa,EAAS,CAAK,EAAG,CAAI,EACtD,GAAM,CAAE,2BAA4B,MAAM,EAAK,QAAQ,EAQvD,OAPA,EAAwB,EAAI,CAAE,GAAG,EAAO,QAAS,EAAQ,IAAK,CAAC,EAC/D,EAAe,YAAYH,EAAAA,cAAc,eAAgB,CACvD,kBAAmB,EAAQ,KAC3B,GAAI,EAAU,CAAE,2BAA4B,CAAQ,EAAI,CAAC,EACzD,iCAAkC,EAAK,YACvC,kCAAmC,EAAK,WAC1C,CAAC,EACM,SACT,OAAS,EAAO,CAGd,MAFA,GAAwB,QAAQ,EAChC,EAAyB,IAAA,GACnB,CACR,CACF,CACF,EACA,GAAI,EAAO,UAAY,YAAc,EAAO,UAAY,QAAS,CAC/D,GAAwB,QAAQ,EAChC,EAAI,GAAG,OAAO,0BAA0B,EAAO,QAAQ,IAAI,EAAO,YAAY,KAAK,IAAI,IAAK,CAAO,EACnG,MACF,CACA,GAAI,EAAO,UAAY,UAAW,CAChC,GAAwB,QAAQ,EAChC,MACF,CAEA,GAAI,CACF,MAAM,EAAI,YAAY,EAGtB,MAAM,EAAI,OAAO,CACnB,OAAS,EAAO,CAEd,MADA,GAAwB,QAAQ,EAC1B,CACR,CACF,CACF,CAAC,CACH"}
@@ -0,0 +1,2 @@
1
+ import{PROFILE_EVENT as e}from"../types/telemetry.mjs";import{profileItems as t,profileSummary as n,profileTitle as r}from"../services/profileText.mjs";import{requireDoomConfigContext as i}from"@agimon-ai/doompi-config/piContext";import{prepareMinorModeReloadHandoff as a,requireDoomTransitionCoordinator as o}from"@agimon-ai/doompi-extension-contracts/transition";const s=`warning`,c=`info`,l=`.doom/profiles.yaml`;function u(){let e,t,n,r,i;return{harnessStore:()=>e??=import(`@agimon-ai/doompi-config/harnessStore`),journal:()=>t??=import(`@agimon-ai/doompi-config/piContext`),picker:()=>n??=import(`@agimon-ai/doompi-ui/components/matrixPicker`),profiles:()=>r??=import(`@agimon-ai/doompi-config/profiles`),selection:()=>i??=import(`@agimon-ai/doompi-config/selectionSwitch`)}}async function d(e,n,i,a){let o=r(i);if(e.mode!==`tui`)return e.ui.select(o,n.map(e=>e.name));let{MatrixPickerComponent:s}=await a();return(await e.ui.custom((e,r,a,c)=>new s({title:o,items:t(n),selected:i?[i]:[],multi:!1},r,a,c)))?.[0]}function f(t,r){let f=u();t.registerCommand(`profile`,{description:`Show profiles and load a different persona and environment`,handler:async(u,p)=>{let m=i(p).harness,[{requireHarnessRoot:h},{loadProfiles:g}]=await Promise.all([f.harnessStore(),f.profiles()]),_=h(m),v=m.profile,y;try{y=g(_)}catch(t){let n=t instanceof Error?t.message:String(t);r.recordError(e.profileLoadFailed,t),p.ui.notify(`Could not load ${l}: ${n}`,s);return}if(y.length===0){p.ui.notify(`No profiles found in ${l}.`,s);return}let b=await d(p,y,v,f.picker),x=y.find(e=>e.name===b);if(!x)return;if(x.name===v){p.ui.notify(n(x),c);return}let S=o(p),C,w=await S.execute({sessionId:p.sessionManager.getSessionId(),hostGeneration:S.hostGeneration,operationId:crypto.randomUUID(),source:p.mode===`tui`?`ui`:`command`,target:{axis:`profile`,profile:x.name}},async(n,i)=>{C=a(p,S.hostGeneration,i.operationId,i.previous.minorModes);try{let{applyProfile:n}=await f.selection();p.ui.notify(await n(x,m),c);let{persistHarnessSelection:a}=await f.journal();return a(t,{...m,profile:x.name}),r.recordEvent(e.profileApplied,{"harness.profile":x.name,...v?{"harness.profile.previous":v}:{},"harness.transition.disposition":i.disposition,"harness.transition.operation_id":i.operationId}),`applied`}catch(e){throw C?.discard(),C=void 0,e}});if(w.outcome===`rejected`||w.outcome===`stale`){C?.discard(),p.ui.notify(`Profile transition was ${w.outcome}: ${w.diagnostics.join(`, `)}`,s);return}if(w.outcome!==`applied`){C?.discard();return}try{await p.waitForIdle(),await p.reload()}catch(e){throw C?.discard(),e}}})}export{f as registerProfileCommand};
2
+ //# sourceMappingURL=profileCommand.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileCommand.mjs","names":[],"sources":["../../src/commands/profileCommand.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { AgentProfile } from '@agimon-ai/doompi-config/profiles';\nimport {\n type MinorModeReloadHandoffHandle,\n prepareMinorModeReloadHandoff,\n requireDoomTransitionCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { profileItems, profileSummary, profileTitle } from '../services/profileText.ts';\nimport { PROFILE_EVENT, type ProfileTelemetry } from '../types/telemetry.ts';\n\nconst WARNING = 'warning';\nconst INFO = 'info';\nconst PROFILE_CONFIG_PATH = '.doom/profiles.yaml';\n\n/**\n * The picker and everything behind it load on first use.\n *\n * Every session registers this command, but almost none of them run it, so the\n * profile catalogue, the TUI component and the switch stay off the startup path.\n */\nfunction lazyModules() {\n let harnessStore: Promise<typeof import('@agimon-ai/doompi-config/harnessStore')> | undefined;\n let journal: Promise<typeof import('@agimon-ai/doompi-config/piContext')> | undefined;\n let picker: Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')> | undefined;\n let profiles: Promise<typeof import('@agimon-ai/doompi-config/profiles')> | undefined;\n let selection: Promise<typeof import('@agimon-ai/doompi-config/selectionSwitch')> | undefined;\n return {\n harnessStore: () => (harnessStore ??= import('@agimon-ai/doompi-config/harnessStore')),\n journal: () => (journal ??= import('@agimon-ai/doompi-config/piContext')),\n picker: () => (picker ??= import('@agimon-ai/doompi-ui/components/matrixPicker')),\n profiles: () => (profiles ??= import('@agimon-ai/doompi-config/profiles')),\n selection: () => (selection ??= import('@agimon-ai/doompi-config/selectionSwitch')),\n };\n}\n\nasync function pickProfile(\n ctx: ExtensionContext,\n profiles: AgentProfile[],\n current: string | undefined,\n loadPicker: () => Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')>,\n): Promise<string | undefined> {\n const title = profileTitle(current);\n if (ctx.mode !== 'tui') {\n return ctx.ui.select(\n title,\n profiles.map((profile) => profile.name),\n );\n }\n const { MatrixPickerComponent } = await loadPicker();\n const chosen = await ctx.ui.custom<string[] | undefined>(\n (_tui, theme, keybindings, done) =>\n new MatrixPickerComponent(\n { title, items: profileItems(profiles), selected: current ? [current] : [], multi: false },\n theme,\n keybindings,\n done,\n ),\n );\n return chosen?.[0];\n}\n\nexport function registerProfileCommand(pi: ExtensionAPI, telemetry: ProfileTelemetry): void {\n const load = lazyModules();\n\n pi.registerCommand('profile', {\n description: 'Show profiles and load a different persona and environment',\n handler: async (_args, ctx) => {\n const state = requireDoomConfigContext(ctx).harness;\n const [{ requireHarnessRoot }, { loadProfiles }] = await Promise.all([load.harnessStore(), load.profiles()]);\n const root = requireHarnessRoot(state);\n const current = state.profile;\n let profiles: AgentProfile[];\n try {\n profiles = loadProfiles(root);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n void telemetry.recordError(PROFILE_EVENT.profileLoadFailed, error);\n ctx.ui.notify(`Could not load ${PROFILE_CONFIG_PATH}: ${reason}`, WARNING);\n return;\n }\n\n if (profiles.length === 0) {\n ctx.ui.notify(`No profiles found in ${PROFILE_CONFIG_PATH}.`, WARNING);\n return;\n }\n\n const picked = await pickProfile(ctx, profiles, current, load.picker);\n const profile = profiles.find((candidate) => candidate.name === picked);\n if (!profile) return;\n if (profile.name === current) {\n ctx.ui.notify(profileSummary(profile), INFO);\n return;\n }\n\n const coordinator = requireDoomTransitionCoordinator(ctx);\n let minorModeReloadHandoff: MinorModeReloadHandoffHandle | undefined;\n const result = await coordinator.execute(\n {\n sessionId: ctx.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: crypto.randomUUID(),\n source: ctx.mode === 'tui' ? 'ui' : 'command',\n target: { axis: 'profile', profile: profile.name },\n },\n async (_request, plan) => {\n minorModeReloadHandoff = prepareMinorModeReloadHandoff(\n ctx,\n coordinator.hostGeneration,\n plan.operationId,\n plan.previous.minorModes,\n );\n try {\n const { applyProfile } = await load.selection();\n ctx.ui.notify(await applyProfile(profile, state), INFO);\n const { persistHarnessSelection } = await load.journal();\n persistHarnessSelection(pi, { ...state, profile: profile.name });\n void telemetry.recordEvent(PROFILE_EVENT.profileApplied, {\n 'harness.profile': profile.name,\n ...(current ? { 'harness.profile.previous': current } : {}),\n 'harness.transition.disposition': plan.disposition,\n 'harness.transition.operation_id': plan.operationId,\n });\n return 'applied';\n } catch (error) {\n minorModeReloadHandoff?.discard();\n minorModeReloadHandoff = undefined;\n throw error;\n }\n },\n );\n if (result.outcome === 'rejected' || result.outcome === 'stale') {\n minorModeReloadHandoff?.discard();\n ctx.ui.notify(`Profile transition was ${result.outcome}: ${result.diagnostics.join(', ')}`, WARNING);\n return;\n }\n if (result.outcome !== 'applied') {\n minorModeReloadHandoff?.discard();\n return;\n }\n\n try {\n await ctx.waitForIdle();\n // Reload replaces the session and invalidates this command context.\n // Keep it as the handler's final action.\n await ctx.reload();\n } catch (error) {\n minorModeReloadHandoff?.discard();\n throw error;\n }\n },\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/pi/persona.cjs");exports.default=e.default,exports.personaExtension=e.default;
@@ -0,0 +1,2 @@
1
+ import personaExtension from "../adapters/pi/persona.cjs";
2
+ export { personaExtension as default, personaExtension };
@@ -0,0 +1,2 @@
1
+ import personaExtension from "../adapters/pi/persona.mjs";
2
+ export { personaExtension as default, personaExtension };
@@ -0,0 +1 @@
1
+ import e from"../adapters/pi/persona.mjs";export{e as default,e as personaExtension};
@@ -0,0 +1 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/pi/extension.cjs");exports.default=e.default,exports.profileExtension=e.default;
@@ -0,0 +1,2 @@
1
+ import profileExtension from "../adapters/pi/extension.cjs";
2
+ export { profileExtension as default, profileExtension };
@@ -0,0 +1,2 @@
1
+ import profileExtension from "../adapters/pi/extension.mjs";
2
+ export { profileExtension as default, profileExtension };
@@ -0,0 +1 @@
1
+ import e from"../adapters/pi/extension.mjs";export{e as default,e as profileExtension};
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/telemetry/logSinkTelemetry.cjs"),t=require("./types/telemetry.cjs"),n=require("./adapters/pi/persona.cjs"),r=require("./services/profileText.cjs"),i=require("./adapters/pi/extension.cjs");exports.PROFILE_EVENT=t.PROFILE_EVENT,exports.createProfileTelemetry=e.createProfileTelemetry,exports.personaExtension=n.default,exports.profileDescription=r.profileDescription,exports.profileExtension=i.default,exports.profileItems=r.profileItems,exports.profileSummary=r.profileSummary,exports.profileTitle=r.profileTitle;
@@ -0,0 +1,6 @@
1
+ import { PROFILE_EVENT, ProfileEventAttributes, ProfileEventName, ProfileTelemetry } from "./types/telemetry.cjs";
2
+ import personaExtension from "./adapters/pi/persona.cjs";
3
+ import profileExtension from "./adapters/pi/extension.cjs";
4
+ import { ProfileTelemetryOptions, createProfileTelemetry } from "./adapters/telemetry/logSinkTelemetry.cjs";
5
+ import { profileDescription, profileItems, profileSummary, profileTitle } from "./services/profileText.cjs";
6
+ export { PROFILE_EVENT, type ProfileEventAttributes, type ProfileEventName, type ProfileTelemetry, type ProfileTelemetryOptions, createProfileTelemetry, personaExtension, profileDescription, profileExtension, profileItems, profileSummary, profileTitle };
@@ -0,0 +1,6 @@
1
+ import { PROFILE_EVENT, ProfileEventAttributes, ProfileEventName, ProfileTelemetry } from "./types/telemetry.mjs";
2
+ import personaExtension from "./adapters/pi/persona.mjs";
3
+ import profileExtension from "./adapters/pi/extension.mjs";
4
+ import { ProfileTelemetryOptions, createProfileTelemetry } from "./adapters/telemetry/logSinkTelemetry.mjs";
5
+ import { profileDescription, profileItems, profileSummary, profileTitle } from "./services/profileText.mjs";
6
+ export { PROFILE_EVENT, type ProfileEventAttributes, type ProfileEventName, type ProfileTelemetry, type ProfileTelemetryOptions, createProfileTelemetry, personaExtension, profileDescription, profileExtension, profileItems, profileSummary, profileTitle };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{createProfileTelemetry as e}from"./adapters/telemetry/logSinkTelemetry.mjs";import{PROFILE_EVENT as t}from"./types/telemetry.mjs";import n from"./adapters/pi/persona.mjs";import{profileDescription as r,profileItems as i,profileSummary as a,profileTitle as o}from"./services/profileText.mjs";import s from"./adapters/pi/extension.mjs";export{t as PROFILE_EVENT,e as createProfileTelemetry,n as personaExtension,r as profileDescription,s as profileExtension,i as profileItems,a as profileSummary,o as profileTitle};
@@ -0,0 +1,3 @@
1
+ const e=`(none)`;function t(e){return e.map(e=>({value:e.name,label:e.name,description:n(e)}))}function n(e){let t=Object.keys(e.env).sort();return t.length>0?`${e.persona} (env: ${t.join(`, `)})`:e.persona}function r(t){let n=Object.keys(t.env).sort();return[`Profile ${t.name}`,`Persona: ${t.persona}`,`Env: ${n.join(`, `)||e}`,`Already loaded.`].join(`
2
+ `)}function i(t){return`Profile (current: ${t??e})`}exports.profileDescription=n,exports.profileItems=t,exports.profileSummary=r,exports.profileTitle=i;
3
+ //# sourceMappingURL=profileText.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileText.cjs","names":[],"sources":["../../src/services/profileText.ts"],"sourcesContent":["import type { AgentProfile } from '@agimon-ai/doompi-config/profiles';\nimport type { SelectItem } from '@earendil-works/pi-tui';\n\nconst NONE = '(none)';\n\n/** Rows for the single-select profile picker. */\nexport function profileItems(profiles: AgentProfile[]): SelectItem[] {\n return profiles.map((profile) => ({\n value: profile.name,\n label: profile.name,\n description: profileDescription(profile),\n }));\n}\n\nexport function profileDescription(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return environmentKeys.length > 0 ? `${profile.persona} (env: ${environmentKeys.join(', ')})` : profile.persona;\n}\n\n/** Shown when the picked profile is already active. */\nexport function profileSummary(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return [\n `Profile ${profile.name}`,\n `Persona: ${profile.persona}`,\n `Env: ${environmentKeys.join(', ') || NONE}`,\n 'Already loaded.',\n ].join('\\n');\n}\n\nexport function profileTitle(current?: string): string {\n return `Profile (current: ${current ?? NONE})`;\n}\n"],"mappings":"AAGA,MAAM,EAAO,SAGb,SAAgB,EAAa,EAAwC,CACnE,OAAO,EAAS,IAAK,IAAa,CAChC,MAAO,EAAQ,KACf,MAAO,EAAQ,KACf,YAAa,EAAmB,CAAO,CACzC,EAAE,CACJ,CAEA,SAAgB,EAAmB,EAA+B,CAChE,IAAM,EAAkB,OAAO,KAAK,EAAQ,GAAG,CAAC,CAAC,KAAK,EACtD,OAAO,EAAgB,OAAS,EAAI,GAAG,EAAQ,QAAQ,SAAS,EAAgB,KAAK,IAAI,EAAE,GAAK,EAAQ,OAC1G,CAGA,SAAgB,EAAe,EAA+B,CAC5D,IAAM,EAAkB,OAAO,KAAK,EAAQ,GAAG,CAAC,CAAC,KAAK,EACtD,MAAO,CACL,WAAW,EAAQ,OACnB,YAAY,EAAQ,UACpB,QAAQ,EAAgB,KAAK,IAAI,GAAK,IACtC,iBACF,CAAC,CAAC,KAAK;CAAI,CACb,CAEA,SAAgB,EAAa,EAA0B,CACrD,MAAO,qBAAqB,GAAW,EAAK,EAC9C"}
@@ -0,0 +1,12 @@
1
+ import { AgentProfile } from "@agimon-ai/doompi-config/profiles";
2
+ import { SelectItem } from "@earendil-works/pi-tui";
3
+ //#region src/services/profileText.d.ts
4
+ /** Rows for the single-select profile picker. */
5
+ declare function profileItems(profiles: AgentProfile[]): SelectItem[];
6
+ declare function profileDescription(profile: AgentProfile): string;
7
+ /** Shown when the picked profile is already active. */
8
+ declare function profileSummary(profile: AgentProfile): string;
9
+ declare function profileTitle(current?: string): string;
10
+ //#endregion
11
+ export { profileDescription, profileItems, profileSummary, profileTitle };
12
+ //# sourceMappingURL=profileText.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileText.d.cts","names":[],"sources":["../../src/services/profileText.ts"],"mappings":";;;;iBAMgB,aAAa,UAAU,iBAAiB;iBAQxC,mBAAmB,SAAS;;iBAM5B,eAAe,SAAS;iBAUxB,aAAa"}
@@ -0,0 +1,12 @@
1
+ import { AgentProfile } from "@agimon-ai/doompi-config/profiles";
2
+ import { SelectItem } from "@earendil-works/pi-tui";
3
+ //#region src/services/profileText.d.ts
4
+ /** Rows for the single-select profile picker. */
5
+ declare function profileItems(profiles: AgentProfile[]): SelectItem[];
6
+ declare function profileDescription(profile: AgentProfile): string;
7
+ /** Shown when the picked profile is already active. */
8
+ declare function profileSummary(profile: AgentProfile): string;
9
+ declare function profileTitle(current?: string): string;
10
+ //#endregion
11
+ export { profileDescription, profileItems, profileSummary, profileTitle };
12
+ //# sourceMappingURL=profileText.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileText.d.mts","names":[],"sources":["../../src/services/profileText.ts"],"mappings":";;;;iBAMgB,aAAa,UAAU,iBAAiB;iBAQxC,mBAAmB,SAAS;;iBAM5B,eAAe,SAAS;iBAUxB,aAAa"}
@@ -0,0 +1,3 @@
1
+ const e=`(none)`;function t(e){return e.map(e=>({value:e.name,label:e.name,description:n(e)}))}function n(e){let t=Object.keys(e.env).sort();return t.length>0?`${e.persona} (env: ${t.join(`, `)})`:e.persona}function r(t){let n=Object.keys(t.env).sort();return[`Profile ${t.name}`,`Persona: ${t.persona}`,`Env: ${n.join(`, `)||e}`,`Already loaded.`].join(`
2
+ `)}function i(t){return`Profile (current: ${t??e})`}export{n as profileDescription,t as profileItems,r as profileSummary,i as profileTitle};
3
+ //# sourceMappingURL=profileText.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileText.mjs","names":[],"sources":["../../src/services/profileText.ts"],"sourcesContent":["import type { AgentProfile } from '@agimon-ai/doompi-config/profiles';\nimport type { SelectItem } from '@earendil-works/pi-tui';\n\nconst NONE = '(none)';\n\n/** Rows for the single-select profile picker. */\nexport function profileItems(profiles: AgentProfile[]): SelectItem[] {\n return profiles.map((profile) => ({\n value: profile.name,\n label: profile.name,\n description: profileDescription(profile),\n }));\n}\n\nexport function profileDescription(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return environmentKeys.length > 0 ? `${profile.persona} (env: ${environmentKeys.join(', ')})` : profile.persona;\n}\n\n/** Shown when the picked profile is already active. */\nexport function profileSummary(profile: AgentProfile): string {\n const environmentKeys = Object.keys(profile.env).sort();\n return [\n `Profile ${profile.name}`,\n `Persona: ${profile.persona}`,\n `Env: ${environmentKeys.join(', ') || NONE}`,\n 'Already loaded.',\n ].join('\\n');\n}\n\nexport function profileTitle(current?: string): string {\n return `Profile (current: ${current ?? NONE})`;\n}\n"],"mappings":"AAGA,MAAM,EAAO,SAGb,SAAgB,EAAa,EAAwC,CACnE,OAAO,EAAS,IAAK,IAAa,CAChC,MAAO,EAAQ,KACf,MAAO,EAAQ,KACf,YAAa,EAAmB,CAAO,CACzC,EAAE,CACJ,CAEA,SAAgB,EAAmB,EAA+B,CAChE,IAAM,EAAkB,OAAO,KAAK,EAAQ,GAAG,CAAC,CAAC,KAAK,EACtD,OAAO,EAAgB,OAAS,EAAI,GAAG,EAAQ,QAAQ,SAAS,EAAgB,KAAK,IAAI,EAAE,GAAK,EAAQ,OAC1G,CAGA,SAAgB,EAAe,EAA+B,CAC5D,IAAM,EAAkB,OAAO,KAAK,EAAQ,GAAG,CAAC,CAAC,KAAK,EACtD,MAAO,CACL,WAAW,EAAQ,OACnB,YAAY,EAAQ,UACpB,QAAQ,EAAgB,KAAK,IAAI,GAAK,IACtC,iBACF,CAAC,CAAC,KAAK;CAAI,CACb,CAEA,SAAgB,EAAa,EAA0B,CACrD,MAAO,qBAAqB,GAAW,EAAK,EAC9C"}
@@ -0,0 +1,2 @@
1
+ const e={profileApplied:`doom_pi_profile.applied`,profileLoadFailed:`doom_pi_profile.load_failed`,personaReadFailed:`doom_pi_profile.persona_read_failed`};exports.PROFILE_EVENT=e;
2
+ //# sourceMappingURL=telemetry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.cjs","names":[],"sources":["../../src/types/telemetry.ts"],"sourcesContent":["/** Telemetry events this package reports, and the port that records them. */\nexport const PROFILE_EVENT = {\n profileApplied: 'doom_pi_profile.applied',\n profileLoadFailed: 'doom_pi_profile.load_failed',\n personaReadFailed: 'doom_pi_profile.persona_read_failed',\n} as const;\n\nexport type ProfileEventName = (typeof PROFILE_EVENT)[keyof typeof PROFILE_EVENT];\nexport type ProfileEventAttributes = Record<string, string | number | boolean>;\n\nexport interface ProfileTelemetry {\n recordError(event: ProfileEventName, error: unknown, attributes?: ProfileEventAttributes): Promise<void>;\n recordEvent(event: ProfileEventName, attributes?: ProfileEventAttributes): Promise<void>;\n}\n"],"mappings":"AACA,MAAa,EAAgB,CAC3B,eAAgB,0BAChB,kBAAmB,8BACnB,kBAAmB,qCACrB"}
@@ -0,0 +1,16 @@
1
+ //#region src/types/telemetry.d.ts
2
+ /** Telemetry events this package reports, and the port that records them. */
3
+ declare const PROFILE_EVENT: {
4
+ readonly profileApplied: "doom_pi_profile.applied";
5
+ readonly profileLoadFailed: "doom_pi_profile.load_failed";
6
+ readonly personaReadFailed: "doom_pi_profile.persona_read_failed";
7
+ };
8
+ type ProfileEventName = (typeof PROFILE_EVENT)[keyof typeof PROFILE_EVENT];
9
+ type ProfileEventAttributes = Record<string, string | number | boolean>;
10
+ interface ProfileTelemetry {
11
+ recordError(event: ProfileEventName, error: unknown, attributes?: ProfileEventAttributes): Promise<void>;
12
+ recordEvent(event: ProfileEventName, attributes?: ProfileEventAttributes): Promise<void>;
13
+ }
14
+ //#endregion
15
+ export { PROFILE_EVENT, ProfileEventAttributes, ProfileEventName, ProfileTelemetry };
16
+ //# sourceMappingURL=telemetry.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.cts","names":[],"sources":["../../src/types/telemetry.ts"],"mappings":";;cACa;;;;;KAMD,2BAA2B,4BAA4B;KACvD,yBAAyB;UAEpB;EACf,YAAY,OAAO,kBAAkB,gBAAgB,aAAa,yBAAyB;EAC3F,YAAY,OAAO,kBAAkB,aAAa,yBAAyB"}
@@ -0,0 +1,16 @@
1
+ //#region src/types/telemetry.d.ts
2
+ /** Telemetry events this package reports, and the port that records them. */
3
+ declare const PROFILE_EVENT: {
4
+ readonly profileApplied: "doom_pi_profile.applied";
5
+ readonly profileLoadFailed: "doom_pi_profile.load_failed";
6
+ readonly personaReadFailed: "doom_pi_profile.persona_read_failed";
7
+ };
8
+ type ProfileEventName = (typeof PROFILE_EVENT)[keyof typeof PROFILE_EVENT];
9
+ type ProfileEventAttributes = Record<string, string | number | boolean>;
10
+ interface ProfileTelemetry {
11
+ recordError(event: ProfileEventName, error: unknown, attributes?: ProfileEventAttributes): Promise<void>;
12
+ recordEvent(event: ProfileEventName, attributes?: ProfileEventAttributes): Promise<void>;
13
+ }
14
+ //#endregion
15
+ export { PROFILE_EVENT, ProfileEventAttributes, ProfileEventName, ProfileTelemetry };
16
+ //# sourceMappingURL=telemetry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.mts","names":[],"sources":["../../src/types/telemetry.ts"],"mappings":";;cACa;;;;;KAMD,2BAA2B,4BAA4B;KACvD,yBAAyB;UAEpB;EACf,YAAY,OAAO,kBAAkB,gBAAgB,aAAa,yBAAyB;EAC3F,YAAY,OAAO,kBAAkB,aAAa,yBAAyB"}
@@ -0,0 +1,2 @@
1
+ const e={profileApplied:`doom_pi_profile.applied`,profileLoadFailed:`doom_pi_profile.load_failed`,personaReadFailed:`doom_pi_profile.persona_read_failed`};export{e as PROFILE_EVENT};
2
+ //# sourceMappingURL=telemetry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.mjs","names":[],"sources":["../../src/types/telemetry.ts"],"sourcesContent":["/** Telemetry events this package reports, and the port that records them. */\nexport const PROFILE_EVENT = {\n profileApplied: 'doom_pi_profile.applied',\n profileLoadFailed: 'doom_pi_profile.load_failed',\n personaReadFailed: 'doom_pi_profile.persona_read_failed',\n} as const;\n\nexport type ProfileEventName = (typeof PROFILE_EVENT)[keyof typeof PROFILE_EVENT];\nexport type ProfileEventAttributes = Record<string, string | number | boolean>;\n\nexport interface ProfileTelemetry {\n recordError(event: ProfileEventName, error: unknown, attributes?: ProfileEventAttributes): Promise<void>;\n recordEvent(event: ProfileEventName, attributes?: ProfileEventAttributes): Promise<void>;\n}\n"],"mappings":"AACA,MAAa,EAAgB,CAC3B,eAAgB,0BAChB,kBAAmB,8BACnB,kBAAmB,qCACrB"}
package/llms.txt ADDED
@@ -0,0 +1,7 @@
1
+ # Doom Pi Profile
2
+
3
+ Persona and environment profile switching for Doom Pi sessions.
4
+
5
+ ## Resources
6
+
7
+ - [Package README](./README.md): the `/profile` command, the persona system-prompt entry, and how a profile resolves.
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "@agimon-ai/doompi-profile",
3
+ "version": "0.0.1-alpha.2",
4
+ "description": "Persona and environment profile switching for DoomPi sessions.",
5
+ "keywords": [
6
+ "agent-persona",
7
+ "ai",
8
+ "coding-agent",
9
+ "developer-tools",
10
+ "doompi",
11
+ "pi-coding-agent",
12
+ "pi-extension",
13
+ "pi-package",
14
+ "profile-switching",
15
+ "system-prompt"
16
+ ],
17
+ "homepage": "https://agimon.ai",
18
+ "license": "MIT",
19
+ "author": "Vuong Ngo",
20
+ "files": [
21
+ "dist",
22
+ "llms.txt",
23
+ "README.md",
24
+ "LICENSE",
25
+ "package.json"
26
+ ],
27
+ "type": "module",
28
+ "main": "./dist/index.cjs",
29
+ "types": "./dist/index.d.mts",
30
+ "jsnext:main": "./dist/index.mjs",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.mts",
34
+ "import": "./dist/index.mjs",
35
+ "require": "./dist/index.cjs"
36
+ },
37
+ "./extensions/persona": {
38
+ "types": "./dist/extensions/persona.d.mts",
39
+ "import": "./dist/extensions/persona.mjs",
40
+ "require": "./dist/extensions/persona.cjs"
41
+ },
42
+ "./extensions/pi": {
43
+ "types": "./dist/extensions/pi.d.mts",
44
+ "import": "./dist/extensions/pi.mjs",
45
+ "require": "./dist/extensions/pi.cjs"
46
+ },
47
+ "./package.json": "./package.json"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "dependencies": {
53
+ "@deepseek-ai/cordis": "4.0.1",
54
+ "@agimon-ai/doompi-config": "0.0.1-alpha.24",
55
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.24",
56
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.24",
57
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.24"
58
+ },
59
+ "devDependencies": {
60
+ "@deepseek-ai/cordis": "4.0.1",
61
+ "@earendil-works/pi-coding-agent": "0.84.2",
62
+ "@earendil-works/pi-tui": "0.84.2",
63
+ "@types/node": "26.1.1",
64
+ "@vitest/coverage-v8": "4.1.10",
65
+ "tsdown": "0.22.14",
66
+ "typescript": "6.0.3",
67
+ "vitest": "4.1.10",
68
+ "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.24"
69
+ },
70
+ "peerDependencies": {
71
+ "@earendil-works/pi-coding-agent": "0.84.2",
72
+ "@earendil-works/pi-tui": "0.84.2"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "@earendil-works/pi-coding-agent": {
76
+ "optional": true
77
+ },
78
+ "@earendil-works/pi-tui": {
79
+ "optional": true
80
+ }
81
+ },
82
+ "engines": {
83
+ "node": ">=22.19.0"
84
+ },
85
+ "pi": {
86
+ "extensions": [
87
+ "./dist/extensions/pi.mjs"
88
+ ]
89
+ },
90
+ "scripts": {
91
+ "build": "tsdown",
92
+ "test": "vitest --run",
93
+ "typecheck": "tsc --noEmit",
94
+ "lint": "oxlint . && oxfmt . --check",
95
+ "fixcode": "oxlint . --fix && oxfmt ."
96
+ }
97
+ }