@agimon-ai/po-profile 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.
@@ -0,0 +1,292 @@
1
+ let _agimon_ai_po_config_profiles = require("@agimon-ai/po-config/profiles");
2
+ //#region src/constants/profileRuntime.ts
3
+ const PROFILE_RUNTIME_SERVICE = "po/profile-runtime";
4
+ //#endregion
5
+ //#region src/services/profileRuntime/index.ts
6
+ const UNAVAILABLE = "Profile integration provider is unavailable";
7
+ const INVALIDATED = "Profile operation was invalidated";
8
+ /** A single selected profile and provider, owned by one session, not a provider registry. */
9
+ var SessionProfileRuntime = class {
10
+ options;
11
+ controller = new AbortController();
12
+ snapshot;
13
+ provider;
14
+ connection;
15
+ transition = Promise.resolve();
16
+ retirement = Promise.resolve();
17
+ pending = /* @__PURE__ */ new Set();
18
+ initializing = false;
19
+ disposed = false;
20
+ disposal;
21
+ constructor(options) {
22
+ this.options = options;
23
+ this.snapshot = this.capture(options.profileName, 1);
24
+ }
25
+ capture(profileName, generation) {
26
+ const binding = profileName === void 0 ? void 0 : this.options.readBinding(profileName);
27
+ return Object.freeze({
28
+ ...profileName === void 0 ? {} : { profileName },
29
+ ...binding === void 0 ? {} : { integration: (0, _agimon_ai_po_config_profiles.parseProfileBinding)(binding) },
30
+ generation,
31
+ signal: this.controller.signal
32
+ });
33
+ }
34
+ readSelection() {
35
+ return this.snapshot;
36
+ }
37
+ invalidate() {
38
+ this.controller.abort();
39
+ const connection = this.connection;
40
+ this.connection = void 0;
41
+ if (connection) {
42
+ this.retirement = this.retirement.then(async () => {
43
+ try {
44
+ await connection.dispose();
45
+ } catch {
46
+ throw new Error("Profile provider disposal failed");
47
+ }
48
+ });
49
+ this.track(this.retirement);
50
+ }
51
+ }
52
+ track(work) {
53
+ this.pending.add(work);
54
+ work.then(() => this.pending.delete(work), () => this.pending.delete(work));
55
+ return work;
56
+ }
57
+ initialize() {
58
+ const snapshot = this.snapshot;
59
+ const provider = this.provider;
60
+ this.initializing = Boolean(snapshot.integration && provider);
61
+ const work = (async () => {
62
+ await this.retirement;
63
+ if (snapshot.signal.aborted) return;
64
+ if (!snapshot.integration || !provider) return;
65
+ if (snapshot.integration.provider !== provider.name) throw new Error(UNAVAILABLE);
66
+ let connection;
67
+ try {
68
+ connection = await provider.factory(snapshot.integration, {
69
+ profileName: snapshot.profileName,
70
+ generation: snapshot.generation,
71
+ signal: snapshot.signal
72
+ });
73
+ } catch {
74
+ if (snapshot.signal.aborted) return;
75
+ throw new Error("Profile provider initialization failed");
76
+ }
77
+ if (snapshot.signal.aborted || this.snapshot !== snapshot || this.disposed) {
78
+ try {
79
+ await connection.dispose();
80
+ } catch {
81
+ throw new Error("Profile provider disposal failed");
82
+ }
83
+ return;
84
+ }
85
+ this.connection = connection;
86
+ })();
87
+ this.transition = this.track(work.finally(() => {
88
+ if (this.snapshot === snapshot) this.initializing = false;
89
+ }));
90
+ return this.transition;
91
+ }
92
+ async select(profileName) {
93
+ if (this.disposed) throw new Error(INVALIDATED);
94
+ if (this.snapshot.profileName === profileName && !this.snapshot.signal.aborted && (!this.snapshot.integration || !this.provider || this.connection || this.initializing)) return;
95
+ this.invalidate();
96
+ this.controller = new AbortController();
97
+ this.snapshot = this.capture(profileName, this.snapshot.generation + 1);
98
+ await this.initialize();
99
+ }
100
+ async ready() {
101
+ const snapshot = this.snapshot;
102
+ await this.transition;
103
+ if (this.disposed || snapshot.signal.aborted || this.snapshot !== snapshot) throw new Error(INVALIDATED);
104
+ if (snapshot.integration && !this.connection) throw new Error(UNAVAILABLE);
105
+ }
106
+ async attachProvider(providerName, factory) {
107
+ if (this.disposed || this.snapshot.signal.aborted) throw new Error(INVALIDATED);
108
+ if (this.provider) throw new Error("Profile provider is already attached");
109
+ if (this.snapshot.integration && this.snapshot.integration.provider !== providerName) throw new Error(UNAVAILABLE);
110
+ const provider = {
111
+ name: providerName,
112
+ factory
113
+ };
114
+ this.provider = provider;
115
+ try {
116
+ await this.initialize();
117
+ await this.ready();
118
+ if (this.disposed || this.provider !== provider) throw new Error(INVALIDATED);
119
+ } catch {
120
+ if (this.provider === provider) this.provider = void 0;
121
+ this.invalidate();
122
+ throw new Error("Profile provider initialization failed");
123
+ }
124
+ let detached = false;
125
+ return async () => {
126
+ if (detached || this.provider !== provider) return;
127
+ detached = true;
128
+ this.invalidate();
129
+ this.provider = void 0;
130
+ this.controller = new AbortController();
131
+ this.snapshot = Object.freeze({
132
+ ...this.snapshot,
133
+ generation: this.snapshot.generation + 1,
134
+ signal: this.controller.signal
135
+ });
136
+ await this.retirement;
137
+ };
138
+ }
139
+ async resolveSecret(name, request) {
140
+ if (this.initializing) throw new Error("Profile secrets are unavailable during provider initialization");
141
+ await this.ready();
142
+ const snapshot = this.snapshot;
143
+ const connection = this.connection;
144
+ const reference = snapshot.integration?.secrets[name];
145
+ if (!connection || !reference || !Object.hasOwn(snapshot.integration.secrets, name)) throw new Error("Profile secret alias is unavailable");
146
+ if (!reference.allowedOrigins.includes(request.origin)) throw new Error("Profile secret origin is not allowed");
147
+ const signal = request.signal ? AbortSignal.any([snapshot.signal, request.signal]) : snapshot.signal;
148
+ if (signal.aborted) throw new Error(INVALIDATED);
149
+ let value;
150
+ try {
151
+ value = await connection.resolveSecret(reference, signal);
152
+ } catch {
153
+ throw new Error("Profile secret resolution failed");
154
+ }
155
+ if (signal.aborted || this.snapshot !== snapshot || this.connection !== connection) throw new Error(INVALIDATED);
156
+ if (typeof value !== "string" || value.length === 0) throw new Error("Profile secret field is unavailable");
157
+ return value;
158
+ }
159
+ dispose() {
160
+ if (this.disposal) return this.disposal;
161
+ this.disposed = true;
162
+ this.invalidate();
163
+ this.provider = void 0;
164
+ this.disposal = (async () => {
165
+ if ((await Promise.allSettled([...this.pending, this.retirement])).some((result) => result.status === "rejected")) throw new Error("Profile runtime disposal failed");
166
+ })();
167
+ return this.disposal;
168
+ }
169
+ };
170
+ function createProfileRuntime(options) {
171
+ return new SessionProfileRuntime(options);
172
+ }
173
+ /** Mounted in the scoped root services array, before dependent integration tools. */
174
+ function createProfileRuntimePlugin(runtime) {
175
+ return (context) => {
176
+ context.provide(PROFILE_RUNTIME_SERVICE, runtime);
177
+ };
178
+ }
179
+ function requireProfileRuntime(context) {
180
+ const service = context.get(PROFILE_RUNTIME_SERVICE);
181
+ if (!service) throw new Error("Profile runtime service is unavailable");
182
+ return service;
183
+ }
184
+ //#endregion
185
+ //#region src/services/profileText/index.ts
186
+ const NONE = "(none)";
187
+ const PROFILE_STATUS_KEY = "doom-profile";
188
+ /** The command a queued voice switch invokes, and the reload handoff kind it parks. */
189
+ const PROFILE_COMMAND = "profile";
190
+ /**
191
+ * The published axis content: the active profile's name, empty while
192
+ * profiles exist with none active, and undefined to withhold the status so
193
+ * the cockpit keeps the axis off the bar entirely.
194
+ */
195
+ function profileStatus(current, hasProfiles) {
196
+ if (current) return current;
197
+ return hasProfiles ? "" : void 0;
198
+ }
199
+ /** Rows for the single-select profile picker. */
200
+ function profileItems(profiles) {
201
+ return profiles.map((profile) => ({
202
+ value: profile.name,
203
+ label: profile.name,
204
+ description: profileDescription(profile)
205
+ }));
206
+ }
207
+ function profileDescription(profile) {
208
+ const environmentKeys = Object.keys(profile.env).sort();
209
+ return environmentKeys.length > 0 ? `${profile.persona} (env: ${environmentKeys.join(", ")})` : profile.persona;
210
+ }
211
+ /** Shown when the picked profile is already active. */
212
+ function profileSummary(profile) {
213
+ const environmentKeys = Object.keys(profile.env).sort();
214
+ return [
215
+ `Profile ${profile.name}`,
216
+ `Persona: ${profile.persona}`,
217
+ `Env: ${environmentKeys.join(", ") || NONE}`,
218
+ "Already loaded."
219
+ ].join("\n");
220
+ }
221
+ function profileTitle(current) {
222
+ return `Profile (current: ${current ?? NONE})`;
223
+ }
224
+ //#endregion
225
+ Object.defineProperty(exports, "PROFILE_COMMAND", {
226
+ enumerable: true,
227
+ get: function() {
228
+ return PROFILE_COMMAND;
229
+ }
230
+ });
231
+ Object.defineProperty(exports, "PROFILE_RUNTIME_SERVICE", {
232
+ enumerable: true,
233
+ get: function() {
234
+ return PROFILE_RUNTIME_SERVICE;
235
+ }
236
+ });
237
+ Object.defineProperty(exports, "PROFILE_STATUS_KEY", {
238
+ enumerable: true,
239
+ get: function() {
240
+ return PROFILE_STATUS_KEY;
241
+ }
242
+ });
243
+ Object.defineProperty(exports, "createProfileRuntime", {
244
+ enumerable: true,
245
+ get: function() {
246
+ return createProfileRuntime;
247
+ }
248
+ });
249
+ Object.defineProperty(exports, "createProfileRuntimePlugin", {
250
+ enumerable: true,
251
+ get: function() {
252
+ return createProfileRuntimePlugin;
253
+ }
254
+ });
255
+ Object.defineProperty(exports, "profileDescription", {
256
+ enumerable: true,
257
+ get: function() {
258
+ return profileDescription;
259
+ }
260
+ });
261
+ Object.defineProperty(exports, "profileItems", {
262
+ enumerable: true,
263
+ get: function() {
264
+ return profileItems;
265
+ }
266
+ });
267
+ Object.defineProperty(exports, "profileStatus", {
268
+ enumerable: true,
269
+ get: function() {
270
+ return profileStatus;
271
+ }
272
+ });
273
+ Object.defineProperty(exports, "profileSummary", {
274
+ enumerable: true,
275
+ get: function() {
276
+ return profileSummary;
277
+ }
278
+ });
279
+ Object.defineProperty(exports, "profileTitle", {
280
+ enumerable: true,
281
+ get: function() {
282
+ return profileTitle;
283
+ }
284
+ });
285
+ Object.defineProperty(exports, "requireProfileRuntime", {
286
+ enumerable: true,
287
+ get: function() {
288
+ return requireProfileRuntime;
289
+ }
290
+ });
291
+
292
+ //# sourceMappingURL=profileText-BkeG0Ulo.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileText-BkeG0Ulo.cjs","names":["parseProfileBinding"],"sources":["../src/constants/profileRuntime.ts","../src/services/profileRuntime/index.ts","../src/services/profileText/index.ts"],"sourcesContent":["export const PROFILE_RUNTIME_SERVICE = 'po/profile-runtime';\n","import { parseProfileBinding } from '@agimon-ai/po-config/profiles';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { PROFILE_RUNTIME_SERVICE } from '../../constants/profileRuntime';\nimport type {\n ProfileProviderFactory,\n ProfileRuntime,\n ProfileRuntimeOptions,\n ProfileRuntimeSnapshot,\n ProfileSecretRequest,\n ProfileSecretResolver,\n} from './type';\n\nconst UNAVAILABLE = 'Profile integration provider is unavailable';\nconst INVALIDATED = 'Profile operation was invalidated';\n\n/** A single selected profile and provider, owned by one session, not a provider registry. */\nclass SessionProfileRuntime implements ProfileRuntime {\n private controller = new AbortController();\n private snapshot: ProfileRuntimeSnapshot;\n private provider?: { name: string; factory: ProfileProviderFactory };\n private connection?: ProfileSecretResolver;\n private transition: Promise<void> = Promise.resolve();\n private retirement: Promise<void> = Promise.resolve();\n private readonly pending = new Set<Promise<void>>();\n private initializing = false;\n private disposed = false;\n private disposal?: Promise<void>;\n\n constructor(private readonly options: ProfileRuntimeOptions) {\n this.snapshot = this.capture(options.profileName, 1);\n }\n\n private capture(profileName: string | undefined, generation: number): ProfileRuntimeSnapshot {\n const binding = profileName === undefined ? undefined : this.options.readBinding(profileName);\n return Object.freeze({\n ...(profileName === undefined ? {} : { profileName }),\n ...(binding === undefined ? {} : { integration: parseProfileBinding(binding) }),\n generation,\n signal: this.controller.signal,\n });\n }\n\n readSelection(): ProfileRuntimeSnapshot {\n return this.snapshot;\n }\n\n invalidate(): void {\n this.controller.abort();\n const connection = this.connection;\n this.connection = undefined;\n if (connection) {\n this.retirement = this.retirement.then(async () => {\n try {\n await connection.dispose();\n } catch {\n throw new Error('Profile provider disposal failed');\n }\n });\n void this.track(this.retirement);\n }\n }\n\n private track(work: Promise<void>): Promise<void> {\n this.pending.add(work);\n // Keep rejection observable through ready/dispose while preventing an unhandled\n // rejection when selection invalidates an initialization before its owner awaits it.\n void work.then(\n () => this.pending.delete(work),\n () => this.pending.delete(work),\n );\n return work;\n }\n\n private initialize(): Promise<void> {\n const snapshot = this.snapshot;\n const provider = this.provider;\n this.initializing = Boolean(snapshot.integration && provider);\n const work = (async () => {\n await this.retirement;\n if (snapshot.signal.aborted) return;\n if (!snapshot.integration || !provider) return;\n if (snapshot.integration.provider !== provider.name) throw new Error(UNAVAILABLE);\n let connection: ProfileSecretResolver;\n try {\n connection = await provider.factory(snapshot.integration, {\n profileName: snapshot.profileName!,\n generation: snapshot.generation,\n signal: snapshot.signal,\n });\n } catch {\n // A retired factory commonly rejects on abort. That cannot remove the\n // provider attachment or poison the replacement generation.\n if (snapshot.signal.aborted) return;\n throw new Error('Profile provider initialization failed');\n }\n if (snapshot.signal.aborted || this.snapshot !== snapshot || this.disposed) {\n try {\n await connection.dispose();\n } catch {\n throw new Error('Profile provider disposal failed');\n }\n return;\n }\n this.connection = connection;\n })();\n this.transition = this.track(\n work.finally(() => {\n if (this.snapshot === snapshot) this.initializing = false;\n }),\n );\n return this.transition;\n }\n\n async select(profileName?: string): Promise<void> {\n if (this.disposed) throw new Error(INVALIDATED);\n if (\n this.snapshot.profileName === profileName &&\n !this.snapshot.signal.aborted &&\n (!this.snapshot.integration || !this.provider || this.connection || this.initializing)\n )\n return;\n this.invalidate();\n this.controller = new AbortController();\n // If reading/validation fails, leave the old generation aborted, never usable.\n this.snapshot = this.capture(profileName, this.snapshot.generation + 1);\n await this.initialize();\n }\n\n async ready(): Promise<void> {\n const snapshot = this.snapshot;\n await this.transition;\n if (this.disposed || snapshot.signal.aborted || this.snapshot !== snapshot) throw new Error(INVALIDATED);\n if (snapshot.integration && !this.connection) throw new Error(UNAVAILABLE);\n }\n\n async attachProvider(providerName: string, factory: ProfileProviderFactory): Promise<() => Promise<void>> {\n if (this.disposed || this.snapshot.signal.aborted) throw new Error(INVALIDATED);\n if (this.provider) throw new Error('Profile provider is already attached');\n if (this.snapshot.integration && this.snapshot.integration.provider !== providerName) throw new Error(UNAVAILABLE);\n const provider = { name: providerName, factory };\n this.provider = provider;\n try {\n await this.initialize();\n await this.ready();\n if (this.disposed || this.provider !== provider) throw new Error(INVALIDATED);\n } catch {\n if (this.provider === provider) this.provider = undefined;\n this.invalidate();\n throw new Error('Profile provider initialization failed');\n }\n let detached = false;\n return async () => {\n if (detached || this.provider !== provider) return;\n detached = true;\n this.invalidate();\n this.provider = undefined;\n this.controller = new AbortController();\n this.snapshot = Object.freeze({\n ...this.snapshot,\n generation: this.snapshot.generation + 1,\n signal: this.controller.signal,\n });\n await this.retirement;\n };\n }\n\n async resolveSecret(name: string, request: ProfileSecretRequest): Promise<string> {\n // Do not await ready here: a provider factory invoking this callback would\n // otherwise wait for itself. Browser creation may retain, but not invoke it.\n if (this.initializing) throw new Error('Profile secrets are unavailable during provider initialization');\n await this.ready();\n const snapshot = this.snapshot;\n const connection = this.connection;\n const reference = snapshot.integration?.secrets[name];\n if (!connection || !reference || !Object.hasOwn(snapshot.integration!.secrets, name)) {\n throw new Error('Profile secret alias is unavailable');\n }\n if (!reference.allowedOrigins.includes(request.origin)) throw new Error('Profile secret origin is not allowed');\n const signal = request.signal ? AbortSignal.any([snapshot.signal, request.signal]) : snapshot.signal;\n if (signal.aborted) throw new Error(INVALIDATED);\n let value: string;\n try {\n value = await connection.resolveSecret(reference, signal);\n } catch {\n // Provider failures must not leak API responses, credential fields or secrets.\n throw new Error('Profile secret resolution failed');\n }\n if (signal.aborted || this.snapshot !== snapshot || this.connection !== connection) throw new Error(INVALIDATED);\n if (typeof value !== 'string' || value.length === 0) throw new Error('Profile secret field is unavailable');\n return value;\n }\n\n dispose(): Promise<void> {\n if (this.disposal) return this.disposal;\n this.disposed = true;\n this.invalidate();\n this.provider = undefined;\n this.disposal = (async () => {\n const results = await Promise.allSettled([...this.pending, this.retirement]);\n if (results.some((result) => result.status === 'rejected')) throw new Error('Profile runtime disposal failed');\n })();\n return this.disposal;\n }\n}\n\nexport function createProfileRuntime(options: ProfileRuntimeOptions): ProfileRuntime {\n return new SessionProfileRuntime(options);\n}\n\n/** Mounted in the scoped root services array, before dependent integration tools. */\nexport function createProfileRuntimePlugin(runtime: ProfileRuntime): (context: Context) => void {\n return (context) => {\n context.provide(PROFILE_RUNTIME_SERVICE, runtime);\n };\n}\n\nexport function requireProfileRuntime(context: Context): ProfileRuntime {\n const service = context.get(PROFILE_RUNTIME_SERVICE);\n if (!service) throw new Error('Profile runtime service is unavailable');\n return service;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'po/profile-runtime': ProfileRuntime;\n }\n}\n","import type { AgentProfile } from '@agimon-ai/po-config/profiles';\n\nconst NONE = '(none)';\n\n/** Footer status key the cockpit's profile axis reads. */\ninterface SelectItem {\n value: string;\n label: string;\n description?: string;\n}\n\nexport const PROFILE_STATUS_KEY = 'doom-profile';\n\n/** Identity this package registers voice capabilities under. */\nexport const PROFILE_SOURCE = '@agimon-ai/po-profile';\n\n/** The command a queued voice switch invokes, and the reload handoff kind it parks. */\nexport const PROFILE_COMMAND = 'profile';\n\n/**\n * The published axis content: the active profile's name, empty while\n * profiles exist with none active, and undefined to withhold the status so\n * the cockpit keeps the axis off the bar entirely.\n */\nexport function profileStatus(current: string | undefined, hasProfiles: boolean): string | undefined {\n if (current) return current;\n return hasProfiles ? '' : undefined;\n}\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":"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"}
package/llms.txt ADDED
@@ -0,0 +1,12 @@
1
+ # Doom Pi Profile
2
+
3
+ Package-owned guidance for Po profile discovery, personas, environment defaults, and precedence.
4
+
5
+ ## How to author
6
+
7
+ - [Author Po profiles](./src/prompts/po-author-profile/SKILL.md): Configure personal and repository profiles.
8
+ - [Profiles authoring contract](./src/prompts/po-author-profile/references/profiles-contract.md): File locations, discovery, precedence, path safety, environment defaults, and verification.
9
+
10
+ ## Package reference
11
+
12
+ - [Package README](./README.md): Profile behavior, activation, and public package entries.
package/package.json ADDED
@@ -0,0 +1,135 @@
1
+ {
2
+ "name": "@agimon-ai/po-profile",
3
+ "version": "0.0.0-alpha.0",
4
+ "description": "Persona and environment profile switching for Po sessions.",
5
+ "keywords": [
6
+ "agent-persona",
7
+ "ai",
8
+ "coding-agent",
9
+ "developer-tools",
10
+ "pi-coding-agent",
11
+ "pi-extension",
12
+ "pi-package",
13
+ "po",
14
+ "profile-switching",
15
+ "system-prompt"
16
+ ],
17
+ "homepage": "https://agimon.ai",
18
+ "bugs": {
19
+ "url": "https://github.com/AgiFlow/po/issues"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Vuong Ngo",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/AgiFlow/po.git",
26
+ "directory": "packages/foundations/po-profile"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "llms.txt",
31
+ "README.md",
32
+ "src/prompts",
33
+ "LICENSE",
34
+ "package.json"
35
+ ],
36
+ "type": "module",
37
+ "main": "./dist/index.cjs",
38
+ "module": "./dist/index.mjs",
39
+ "types": "./dist/index.d.mts",
40
+ "jsnext:main": "./dist/index.mjs",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./dist/index.d.mts",
44
+ "import": "./dist/index.mjs",
45
+ "require": "./dist/index.cjs"
46
+ },
47
+ "./apiContracts": {
48
+ "types": "./dist/apiContracts.d.mts",
49
+ "import": "./dist/apiContracts.mjs",
50
+ "require": "./dist/apiContracts.cjs"
51
+ },
52
+ "./extensions/server": {
53
+ "types": "./dist/extensions/server.d.mts",
54
+ "import": "./dist/extensions/server.mjs",
55
+ "require": "./dist/extensions/server.cjs"
56
+ },
57
+ "./extensions/web": {
58
+ "import": "./dist/extensions/web.mjs"
59
+ },
60
+ "./package.json": "./package.json"
61
+ },
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "dependencies": {
66
+ "@agimon-ai/po-config": "0.0.0-alpha.0",
67
+ "@agimon-ai/po-core": "0.0.0-alpha.0",
68
+ "@agimon-ai/po-minor-mode": "0.0.0-alpha.0",
69
+ "@agimon-ai/po-telemetry": "0.0.0-alpha.0",
70
+ "@deepseek-ai/cordis": "4.0.4",
71
+ "typebox": "1.3.34"
72
+ },
73
+ "devDependencies": {
74
+ "@agimon-ai/po-build": "0.0.0-alpha.0",
75
+ "@agimon-ai/po-core": "0.0.0-alpha.0",
76
+ "@agimon-ai/po-voice": "0.0.0-alpha.0",
77
+ "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.0-alpha.0",
78
+ "@deepseek-ai/cordis": "4.0.4",
79
+ "@earendil-works/pi-coding-agent": "1.0.2",
80
+ "@types/node": "26.6.4",
81
+ "@vitest/coverage-v8": "5.0.3",
82
+ "tsdown": "0.23.0",
83
+ "typescript": "7.0.2",
84
+ "vitest": "5.0.3"
85
+ },
86
+ "peerDependencies": {
87
+ "@agimon-ai/po-core": "0.0.0-alpha.0",
88
+ "@earendil-works/pi-coding-agent": "1.0.2"
89
+ },
90
+ "peerDependenciesMeta": {
91
+ "@earendil-works/pi-coding-agent": {
92
+ "optional": true
93
+ },
94
+ "@agimon-ai/po-core": {
95
+ "optional": true
96
+ }
97
+ },
98
+ "engines": {
99
+ "node": ">=24"
100
+ },
101
+ "poMcp": {
102
+ "entry": "./generated/mcp.ts",
103
+ "dist": "./dist/extensions/mcp.mjs",
104
+ "scopes": [
105
+ "session"
106
+ ]
107
+ },
108
+ "poServer": {
109
+ "entry": "./generated/server.ts",
110
+ "dist": "./dist/extensions/server.mjs",
111
+ "scopes": [
112
+ "session"
113
+ ],
114
+ "contracts": {
115
+ "entry": "./src/exports/apiContracts.ts",
116
+ "dist": "./dist/apiContracts.mjs"
117
+ }
118
+ },
119
+ "poWeb": {
120
+ "pluginId": "profile",
121
+ "channels": [],
122
+ "client": "./dist/extensions/web.mjs",
123
+ "scopes": [
124
+ "session"
125
+ ]
126
+ },
127
+ "scripts": {
128
+ "build": "tsdown && pnpm build:mcp",
129
+ "build:mcp": "tsdown --config tsdown.mcp.config.ts",
130
+ "test": "vitest --run",
131
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json",
132
+ "lint": "oxlint . && oxfmt . --check",
133
+ "fixcode": "oxlint . --fix && oxfmt ."
134
+ }
135
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: po-author-profile
3
+ description: Configure Po profile discovery, personas, environment defaults, and precedence in profiles.yaml. Use when creating or changing personal or repository profiles. Do not use for config.yaml runtime settings, modes.yaml, or domains.yaml.
4
+ ---
5
+
6
+ # Author Po profiles
7
+
8
+ Configure a profile as one persona plus optional environment defaults.
9
+
10
+ ## Workflow
11
+
12
+ 1. Read both `~/.po/profiles.yaml` and the repository's `.po/profiles.yaml` when they exist.
13
+ 2. Use `profiles.roots` for one-level persona discovery. Use `profiles.entries` when a profile needs an explicit persona path or environment defaults.
14
+ 3. Resolve relative roots and persona paths against the file that declares them. Keep an explicit persona inside that file's `agents/` directory or one of its configured roots.
15
+ 4. Put instructions in `profile.md`, `SOUL.md`, or `AGENTS.md`. Po concatenates non-empty files in that order.
16
+ 5. Keep every `env` value a string. Treat it as a default because an already exported value wins.
17
+ 6. Preserve the precedence rules. Explicit entries override discoveries, and repository entries override personal entries at the same precedence level.
18
+ 7. Verify the selection with `po --profile <name> --explain`, then smoke-test `/profile` when changing live switching behavior.
19
+
20
+ Read [references/profiles-contract.md](references/profiles-contract.md) before changing discovery, precedence, path handling, or profile application.