@agimon-ai/po-prompt 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.
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,65 @@
1
+ # @agimon-ai/po-prompt
2
+
3
+ Staged recent prompts and saved prompt templates for Po.
4
+
5
+ This package is a composable [Po](https://www.npmjs.com/package/@agimon-ai/po) subsystem.
6
+
7
+ ## Requirements
8
+
9
+ - Node.js 24 or newer
10
+ - `@earendil-works/pi-coding-agent` 0.85.0
11
+
12
+ ## Install
13
+
14
+ Po users can
15
+ add `@agimon-ai/po-prompt` to `default.packages` or a selected layer's `packages` list in
16
+ `.po/modes.yaml`.
17
+
18
+ ## Cockpit
19
+
20
+ The package contributes a `Prompt template` entry to the composer's `+` menu, beside `File Upload`,
21
+ backed by a hub-scoped API at `/api/plugin/prompts`. The entry opens a list-first dialog over the
22
+ conversation, and picking one sends it immediately to the focused session. The same dialog creates
23
+ and edits entries, confirms replacements and removals, and refreshes the list after writes. Every
24
+ text-bearing user message also offers `save as prompt`, opening the editor with that message text
25
+ ready to name or edit. The dialog itself is a cockpit overlay rather than part of the menu, so the
26
+ message action reaches it without the menu being open.
27
+
28
+ | Route | Purpose |
29
+ | ----------------------- | ------------------------------------------------------------------- |
30
+ | `GET /prompts` | Every saved prompt, sorted by name |
31
+ | `PUT /prompts/:name` | Create or replace one, deriving its description from the first line |
32
+ | `DELETE /prompts/:name` | Remove one |
33
+
34
+ The API is hub-scoped because saved prompts belong to the agent directory rather than to a session.
35
+ Staged prompts are not exposed there: they live in the memory of the session that received them.
36
+
37
+ The cockpit hub mounts package APIs from the route table `po sync` generates. After installing
38
+ or changing this package, run a build and `po sync`, then restart the hub, or its routes answer 404.
39
+
40
+ ## Help
41
+
42
+ The published package includes `llms.txt` and the package-owned `src/prompts/po-use-prompt/SKILL.md`. When the Po Help minor mode is active, the extension contributes `po-use-prompt` to its live Help catalog. The contribution follows Help provider replacement and is withdrawn when the extension shuts down.
43
+
44
+ ## Public API
45
+
46
+ ```ts
47
+ import { createNodeSavedPromptStore, createRecentPrompts } from '@agimon-ai/po-prompt';
48
+ ```
49
+
50
+ ## Development
51
+
52
+ ```bash
53
+ pnpm build
54
+ pnpm typecheck
55
+ pnpm test
56
+ pnpm lint
57
+ pnpm exec vibe-lint check .
58
+ npm pack --dry-run
59
+ ```
60
+
61
+ Maintained by [Agimon](https://agimon.ai/about).
62
+
63
+ ## License
64
+
65
+ MIT
@@ -0,0 +1,74 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ let _agimon_ai_po_core_apiContracts = require("@agimon-ai/po-core/apiContracts");
6
+ let typebox = require("typebox");
7
+ //#region src/schemas/apiContracts.ts
8
+ const S = typebox.Type.String();
9
+ const B = typebox.Type.Boolean();
10
+ const Prompt = typebox.Type.Object({
11
+ name: S,
12
+ description: S,
13
+ text: S
14
+ });
15
+ const apiContracts = (0, _agimon_ai_po_core_apiContracts.defineApiContract)({
16
+ version: 1,
17
+ sockets: [],
18
+ dynamic: [],
19
+ http: [
20
+ "global",
21
+ "workspace",
22
+ "session"
23
+ ].flatMap((scope) => [
24
+ {
25
+ id: "prompts.list",
26
+ scope,
27
+ basePath: "prompts",
28
+ path: "/prompts",
29
+ method: "GET",
30
+ authentication: "owner",
31
+ description: "List prompts in this scope.",
32
+ responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(typebox.Type.Object({ prompts: typebox.Type.Array(Prompt) }))
33
+ },
34
+ {
35
+ id: "prompts.save",
36
+ scope,
37
+ basePath: "prompts",
38
+ path: "/prompts/{name}",
39
+ method: "PUT",
40
+ authentication: "owner",
41
+ description: "Save a prompt. Text is limited to 65536 UTF-8 bytes.",
42
+ body: {
43
+ required: true,
44
+ contentType: "application/json",
45
+ schema: typebox.Type.Object({ text: typebox.Type.String({ minLength: 1 }) })
46
+ },
47
+ responses: {
48
+ ...(0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(typebox.Type.Object({
49
+ prompt: Prompt,
50
+ replaced: B
51
+ })),
52
+ "413": {
53
+ description: "Prompt text exceeds the byte limit.",
54
+ schema: typebox.Type.Object({ error: S })
55
+ }
56
+ }
57
+ },
58
+ {
59
+ id: "prompts.delete",
60
+ scope,
61
+ basePath: "prompts",
62
+ path: "/prompts/{name}",
63
+ method: "DELETE",
64
+ authentication: "owner",
65
+ description: "Delete a prompt.",
66
+ responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(typebox.Type.Object({ name: S }))
67
+ }
68
+ ])
69
+ });
70
+ //#endregion
71
+ exports.apiContracts = apiContracts;
72
+ exports.default = apiContracts;
73
+
74
+ //# sourceMappingURL=apiContracts.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.cjs","names":["Type","defineApiContract","jsonApiResponses"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses } from '@agimon-ai/po-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst S = Type.String();\nconst B = Type.Boolean();\nconst Prompt = Type.Object({ name: S, description: S, text: S });\nexport const apiContracts = defineApiContract({\n version: 1,\n sockets: [],\n dynamic: [],\n http: (['global', 'workspace', 'session'] as const).flatMap((scope) => [\n {\n id: 'prompts.list',\n scope,\n basePath: 'prompts',\n path: '/prompts',\n method: 'GET',\n authentication: 'owner',\n description: 'List prompts in this scope.',\n responses: jsonApiResponses(Type.Object({ prompts: Type.Array(Prompt) })),\n },\n {\n id: 'prompts.save',\n scope,\n basePath: 'prompts',\n path: '/prompts/{name}',\n method: 'PUT',\n authentication: 'owner',\n description: 'Save a prompt. Text is limited to 65536 UTF-8 bytes.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({ text: Type.String({ minLength: 1 }) }),\n },\n responses: {\n ...jsonApiResponses(Type.Object({ prompt: Prompt, replaced: B })),\n '413': { description: 'Prompt text exceeds the byte limit.', schema: Type.Object({ error: S }) },\n },\n },\n {\n id: 'prompts.delete',\n scope,\n basePath: 'prompts',\n path: '/prompts/{name}',\n method: 'DELETE',\n authentication: 'owner',\n description: 'Delete a prompt.',\n responses: jsonApiResponses(Type.Object({ name: S })),\n },\n ]),\n});\nexport default apiContracts;\n"],"mappings":";;;;;;;AAGA,MAAM,IAAIA,QAAAA,KAAK,OAAO;AACtB,MAAM,IAAIA,QAAAA,KAAK,QAAQ;AACvB,MAAM,SAASA,QAAAA,KAAK,OAAO;CAAE,MAAM;CAAG,aAAa;CAAG,MAAM;AAAE,CAAC;AAC/D,MAAa,gBAAA,GAAeC,gCAAAA,kBAAAA,CAAkB;CAC5C,SAAS;CACT,SAAS,CAAC;CACV,SAAS,CAAC;CACV,MAAO;EAAC;EAAU;EAAa;CAAS,CAAC,CAAW,SAAS,UAAU;EACrE;GACE,IAAI;GACJ;GACA,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,YAAA,GAAWC,gCAAAA,iBAAAA,CAAiBF,QAAAA,KAAK,OAAO,EAAE,SAASA,QAAAA,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC;EAC1E;EACA;GACE,IAAI;GACJ;GACA,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQA,QAAAA,KAAK,OAAO,EAAE,MAAMA,QAAAA,KAAK,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;GAC7D;GACA,WAAW;IACT,IAAA,GAAGE,gCAAAA,iBAAAA,CAAiBF,QAAAA,KAAK,OAAO;KAAE,QAAQ;KAAQ,UAAU;IAAE,CAAC,CAAC;IAChE,OAAO;KAAE,aAAa;KAAuC,QAAQA,QAAAA,KAAK,OAAO,EAAE,OAAO,EAAE,CAAC;IAAE;GACjG;EACF;EACA;GACE,IAAI;GACJ;GACA,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,YAAA,GAAWE,gCAAAA,iBAAAA,CAAiBF,QAAAA,KAAK,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;EACtD;CACF,CAAC;AACH,CAAC"}
@@ -0,0 +1,52 @@
1
+ //#region src/schemas/apiContracts.d.ts
2
+ export declare const apiContracts: {
3
+ version: 1;
4
+ protocols?: Record<string, string> | undefined;
5
+ schemas?: Record<string, boolean | object> | undefined;
6
+ http: {
7
+ id: string;
8
+ scope: "global" | "session" | "workspace";
9
+ basePath?: string | undefined;
10
+ path: string;
11
+ method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
12
+ description: string;
13
+ availability?: string | undefined;
14
+ authentication: "device" | "none" | "owner";
15
+ parameters?: {
16
+ name: string;
17
+ in: "header" | "path" | "query";
18
+ required: boolean;
19
+ schema: boolean | object;
20
+ }[] | undefined;
21
+ body?: {
22
+ contentType: string;
23
+ contentTypes?: string[] | undefined;
24
+ required: boolean;
25
+ schema: boolean | object;
26
+ } | undefined;
27
+ responses: Record<string, {
28
+ description: string;
29
+ contentType?: string | undefined;
30
+ schema?: boolean | object | undefined;
31
+ events?: Record<string, boolean | object> | undefined;
32
+ }>;
33
+ }[];
34
+ sockets: {
35
+ id: string;
36
+ scope: "global" | "session" | "workspace";
37
+ description: string;
38
+ availability?: string | undefined;
39
+ service: string;
40
+ member: string;
41
+ direction: "client-to-server" | "server-to-client";
42
+ kind: "channel" | "method" | "state";
43
+ input: boolean | object;
44
+ output?: boolean | object | undefined;
45
+ errors?: boolean | object | undefined;
46
+ }[];
47
+ dynamic: string[];
48
+ gaps?: string[] | undefined;
49
+ };
50
+ //#endregion
51
+ export { apiContracts as default };
52
+ //# sourceMappingURL=apiContracts.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/apiContracts.ts"],"mappings":";qBAMa"}
@@ -0,0 +1,69 @@
1
+ import { defineApiContract, jsonApiResponses } from "@agimon-ai/po-core/apiContracts";
2
+ import { Type } from "typebox";
3
+ //#region src/schemas/apiContracts.ts
4
+ const S = Type.String();
5
+ const B = Type.Boolean();
6
+ const Prompt = Type.Object({
7
+ name: S,
8
+ description: S,
9
+ text: S
10
+ });
11
+ const apiContracts = defineApiContract({
12
+ version: 1,
13
+ sockets: [],
14
+ dynamic: [],
15
+ http: [
16
+ "global",
17
+ "workspace",
18
+ "session"
19
+ ].flatMap((scope) => [
20
+ {
21
+ id: "prompts.list",
22
+ scope,
23
+ basePath: "prompts",
24
+ path: "/prompts",
25
+ method: "GET",
26
+ authentication: "owner",
27
+ description: "List prompts in this scope.",
28
+ responses: jsonApiResponses(Type.Object({ prompts: Type.Array(Prompt) }))
29
+ },
30
+ {
31
+ id: "prompts.save",
32
+ scope,
33
+ basePath: "prompts",
34
+ path: "/prompts/{name}",
35
+ method: "PUT",
36
+ authentication: "owner",
37
+ description: "Save a prompt. Text is limited to 65536 UTF-8 bytes.",
38
+ body: {
39
+ required: true,
40
+ contentType: "application/json",
41
+ schema: Type.Object({ text: Type.String({ minLength: 1 }) })
42
+ },
43
+ responses: {
44
+ ...jsonApiResponses(Type.Object({
45
+ prompt: Prompt,
46
+ replaced: B
47
+ })),
48
+ "413": {
49
+ description: "Prompt text exceeds the byte limit.",
50
+ schema: Type.Object({ error: S })
51
+ }
52
+ }
53
+ },
54
+ {
55
+ id: "prompts.delete",
56
+ scope,
57
+ basePath: "prompts",
58
+ path: "/prompts/{name}",
59
+ method: "DELETE",
60
+ authentication: "owner",
61
+ description: "Delete a prompt.",
62
+ responses: jsonApiResponses(Type.Object({ name: S }))
63
+ }
64
+ ])
65
+ });
66
+ //#endregion
67
+ export { apiContracts, apiContracts as default };
68
+
69
+ //# sourceMappingURL=apiContracts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses } from '@agimon-ai/po-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst S = Type.String();\nconst B = Type.Boolean();\nconst Prompt = Type.Object({ name: S, description: S, text: S });\nexport const apiContracts = defineApiContract({\n version: 1,\n sockets: [],\n dynamic: [],\n http: (['global', 'workspace', 'session'] as const).flatMap((scope) => [\n {\n id: 'prompts.list',\n scope,\n basePath: 'prompts',\n path: '/prompts',\n method: 'GET',\n authentication: 'owner',\n description: 'List prompts in this scope.',\n responses: jsonApiResponses(Type.Object({ prompts: Type.Array(Prompt) })),\n },\n {\n id: 'prompts.save',\n scope,\n basePath: 'prompts',\n path: '/prompts/{name}',\n method: 'PUT',\n authentication: 'owner',\n description: 'Save a prompt. Text is limited to 65536 UTF-8 bytes.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({ text: Type.String({ minLength: 1 }) }),\n },\n responses: {\n ...jsonApiResponses(Type.Object({ prompt: Prompt, replaced: B })),\n '413': { description: 'Prompt text exceeds the byte limit.', schema: Type.Object({ error: S }) },\n },\n },\n {\n id: 'prompts.delete',\n scope,\n basePath: 'prompts',\n path: '/prompts/{name}',\n method: 'DELETE',\n authentication: 'owner',\n description: 'Delete a prompt.',\n responses: jsonApiResponses(Type.Object({ name: S })),\n },\n ]),\n});\nexport default apiContracts;\n"],"mappings":";;;AAGA,MAAM,IAAI,KAAK,OAAO;AACtB,MAAM,IAAI,KAAK,QAAQ;AACvB,MAAM,SAAS,KAAK,OAAO;CAAE,MAAM;CAAG,aAAa;CAAG,MAAM;AAAE,CAAC;AAC/D,MAAa,eAAe,kBAAkB;CAC5C,SAAS;CACT,SAAS,CAAC;CACV,SAAS,CAAC;CACV,MAAO;EAAC;EAAU;EAAa;CAAS,CAAC,CAAW,SAAS,UAAU;EACrE;GACE,IAAI;GACJ;GACA,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,WAAW,iBAAiB,KAAK,OAAO,EAAE,SAAS,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC;EAC1E;EACA;GACE,IAAI;GACJ;GACA,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQ,KAAK,OAAO,EAAE,MAAM,KAAK,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;GAC7D;GACA,WAAW;IACT,GAAG,iBAAiB,KAAK,OAAO;KAAE,QAAQ;KAAQ,UAAU;IAAE,CAAC,CAAC;IAChE,OAAO;KAAE,aAAa;KAAuC,QAAQ,KAAK,OAAO,EAAE,OAAO,EAAE,CAAC;IAAE;GACjG;EACF;EACA;GACE,IAAI;GACJ;GACA,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,WAAW,iBAAiB,KAAK,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;EACtD;CACF,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ let _agimon_ai_po_core_mcpFacet = require("@agimon-ai/po-core/mcpFacet");
6
+ let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
7
+ //#region src/extensions/workspaces/sessions/(backend)/skill/po-use-prompt.mcp.ts
8
+ var po_use_prompt_mcp_default = (0, _agimon_ai_po_core_mcpFacet.defineMcpSkill)({
9
+ name: "po-use-prompt",
10
+ description: "Use @agimon-ai/po-prompt: Staged recent prompts and saved prompt templates for Po",
11
+ read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-prompt/SKILL.md")
12
+ });
13
+ //#endregion
14
+ //#region generated/mcp.ts
15
+ const at = (value, context) => typeof value === "function" ? value(context) : value;
16
+ const mcp = (0, _agimon_ai_po_core_mcpFacet.defineMcpPlugin)({
17
+ name: "@agimon-ai/po-prompt",
18
+ session: (context) => ({ get skills() {
19
+ return [at(po_use_prompt_mcp_default, context)];
20
+ } })
21
+ });
22
+ //#endregion
23
+ exports.default = mcp;
24
+ exports.mcp = mcp;
25
+
26
+ //# sourceMappingURL=mcp.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.cjs","names":["defineMcpSkill","readPackageResource","defineMcpPlugin","skillPoUsePrompt"],"sources":["../../src/extensions/workspaces/sessions/(backend)/skill/po-use-prompt.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { defineMcpSkill } from '@agimon-ai/po-core/mcpFacet';\nimport { readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nexport default defineMcpSkill({\n name: 'po-use-prompt',\n description: 'Use @agimon-ai/po-prompt: Staged recent prompts and saved prompt templates for Po',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-prompt/SKILL.md'),\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport skillPoUsePrompt from '../src/extensions/workspaces/sessions/(backend)/skill/po-use-prompt.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-prompt',\n session: (context) => ({\n get skills(): DoomMcpSessionPlugin['skills'] { return [at(skillPoUsePrompt, context)]; },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;;;;;AAGA,IAAA,6BAAA,GAAeA,4BAAAA,eAAAA,CAAe;CAC5B,MAAM;CACN,aAAa;CACb,aAAA,GAAYC,+BAAAA,oBAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,MAAqC,oCAAoC;AACvF,CAAC;;;ACDD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAa,OAAA,GAAMC,4BAAAA,gBAAAA,CAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,SAAyC;EAAE,OAAO,CAAC,GAAGC,2BAAkB,OAAO,CAAC;CAAG,EACzF;AACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ //#region generated/mcp.d.ts
2
+ export declare const mcp: import("@agimon-ai/po-core/mcpFacet").DoomMcpPluginDefinition;
3
+ //#endregion
4
+ export { mcp as default };
5
+ //# sourceMappingURL=mcp.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.mts","names":[],"sources":["../../generated/mcp.ts"],"mappings":";qBASa,2CAAG"}
@@ -0,0 +1,21 @@
1
+ import { defineMcpPlugin, defineMcpSkill } from "@agimon-ai/po-core/mcpFacet";
2
+ import { readPackageResource } from "@agimon-ai/po-core/serverFacet";
3
+ //#region src/extensions/workspaces/sessions/(backend)/skill/po-use-prompt.mcp.ts
4
+ var po_use_prompt_mcp_default = defineMcpSkill({
5
+ name: "po-use-prompt",
6
+ description: "Use @agimon-ai/po-prompt: Staged recent prompts and saved prompt templates for Po",
7
+ read: () => readPackageResource(import.meta.url, "src/prompts/po-use-prompt/SKILL.md")
8
+ });
9
+ //#endregion
10
+ //#region generated/mcp.ts
11
+ const at = (value, context) => typeof value === "function" ? value(context) : value;
12
+ const mcp = defineMcpPlugin({
13
+ name: "@agimon-ai/po-prompt",
14
+ session: (context) => ({ get skills() {
15
+ return [at(po_use_prompt_mcp_default, context)];
16
+ } })
17
+ });
18
+ //#endregion
19
+ export { mcp as default, mcp };
20
+
21
+ //# sourceMappingURL=mcp.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.mjs","names":["skillPoUsePrompt"],"sources":["../../src/extensions/workspaces/sessions/(backend)/skill/po-use-prompt.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { defineMcpSkill } from '@agimon-ai/po-core/mcpFacet';\nimport { readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nexport default defineMcpSkill({\n name: 'po-use-prompt',\n description: 'Use @agimon-ai/po-prompt: Staged recent prompts and saved prompt templates for Po',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-prompt/SKILL.md'),\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport skillPoUsePrompt from '../src/extensions/workspaces/sessions/(backend)/skill/po-use-prompt.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-prompt',\n session: (context) => ({\n get skills(): DoomMcpSessionPlugin['skills'] { return [at(skillPoUsePrompt, context)]; },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;AAGA,IAAA,4BAAe,eAAe;CAC5B,MAAM;CACN,aAAa;CACb,YAAY,oBAAoB,YAAY,KAAK,oCAAoC;AACvF,CAAC;;;ACDD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAa,MAAM,gBAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,SAAyC;EAAE,OAAO,CAAC,GAAGA,2BAAkB,OAAO,CAAC;CAAG,EACzF;AACF,CAAC"}
@@ -0,0 +1,249 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ const require_promptStore = require("../promptStore-Cu4KqaXU.cjs");
6
+ let node_fs_promises = require("node:fs/promises");
7
+ let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
8
+ let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
9
+ let hono = require("hono");
10
+ let _agimon_ai_po_core_web = require("@agimon-ai/po-core/web");
11
+ let _agimon_ai_po_core_help = require("@agimon-ai/po-core/help");
12
+ //#region src/constants/promptsApi.ts
13
+ const NAME_PARAM = "name";
14
+ const STATUS = {
15
+ badRequest: 400,
16
+ notFound: 404,
17
+ tooLarge: 413,
18
+ failed: 500
19
+ };
20
+ //#endregion
21
+ //#region src/constants/webPrompts.ts
22
+ const API_BASE_PATH = "prompts";
23
+ const PROMPTS_PATH = "/prompts";
24
+ //#endregion
25
+ //#region src/types/apiRoutes.ts
26
+ /**
27
+ * This package's routes, as data.
28
+ *
29
+ * No scope and no base path. The build reads both off
30
+ * `src/extensions/(backend)/api/prompts/`, so the mount is stated once, by the
31
+ * folder that creates it. This package stated it three times before: a
32
+ * constant, and the literal `prompts` twice more inside a URL builder that also
33
+ * decided, on its own, whether a call was global or session scoped.
34
+ *
35
+ * The Hono app registers these paths and the browser addresses them, so a path
36
+ * cannot move on one side alone.
37
+ *
38
+ * `:name` is Hono's own parameter syntax, because the app registers `path`
39
+ * verbatim, and the client fills it from `params` on the call.
40
+ */
41
+ var apiRoutes_default = (0, _agimon_ai_po_core_web.defineApiRoutes)({
42
+ list: {
43
+ method: "GET",
44
+ path: PROMPTS_PATH,
45
+ response: (0, _agimon_ai_po_core_web.apiResponse)()
46
+ },
47
+ save: {
48
+ method: "PUT",
49
+ path: `${PROMPTS_PATH}/:${NAME_PARAM}`,
50
+ response: (0, _agimon_ai_po_core_web.apiResponse)()
51
+ },
52
+ /** The same path as `save`; the method is the whole of the difference. */
53
+ remove: {
54
+ method: "DELETE",
55
+ path: `${PROMPTS_PATH}/:${NAME_PARAM}`
56
+ }
57
+ });
58
+ //#endregion
59
+ //#region src/services/promptsApi/index.ts
60
+ function toView(prompt) {
61
+ return {
62
+ name: prompt.name,
63
+ description: prompt.description,
64
+ text: prompt.text
65
+ };
66
+ }
67
+ function failureMessage(error) {
68
+ return error instanceof Error ? error.message : "The prompt library could not complete that request.";
69
+ }
70
+ /** Reads `{ text }` out of a request body, or the reason it is unusable. */
71
+ async function readText(request) {
72
+ let payload;
73
+ try {
74
+ payload = await request.json();
75
+ } catch {
76
+ return { error: "The request body must be JSON." };
77
+ }
78
+ const text = payload?.text;
79
+ if (typeof text !== "string" || text.trim().length === 0) return { error: "A non-empty text is required." };
80
+ if (Buffer.byteLength(text, "utf8") > 65536) return { error: "That prompt is too large to save." };
81
+ return { text };
82
+ }
83
+ function createPromptHubApi(options = {}) {
84
+ const store = options.store ?? require_promptStore.createNodeSavedPromptStore();
85
+ const app = new hono.Hono();
86
+ app.get(apiRoutes_default.list.path, async (context) => {
87
+ try {
88
+ const prompts = await store.list();
89
+ return context.json({ prompts: prompts.map(toView) });
90
+ } catch (error) {
91
+ return context.json({ error: failureMessage(error) }, STATUS.failed);
92
+ }
93
+ });
94
+ app.put(apiRoutes_default.save.path, async (context) => {
95
+ const name = context.req.param(NAME_PARAM);
96
+ if (!require_promptStore.isValidPromptName(name)) return context.json({ error: `"${name}" is not a usable prompt name. Use ${require_promptStore.PROMPT_NAME_RULE}.` }, STATUS.badRequest);
97
+ const body = await readText(context.req.raw);
98
+ if ("error" in body) {
99
+ const status = body.error.includes("too large") ? STATUS.tooLarge : STATUS.badRequest;
100
+ return context.json({ error: body.error }, status);
101
+ }
102
+ try {
103
+ const replaced = await store.has(name);
104
+ const prompt = {
105
+ name,
106
+ description: require_promptStore.describePrompt(body.text),
107
+ text: body.text
108
+ };
109
+ await store.save(prompt);
110
+ return context.json({
111
+ prompt: toView(prompt),
112
+ replaced
113
+ });
114
+ } catch (error) {
115
+ return context.json({ error: failureMessage(error) }, STATUS.failed);
116
+ }
117
+ });
118
+ app.delete(apiRoutes_default.remove.path, async (context) => {
119
+ const name = context.req.param(NAME_PARAM);
120
+ if (!require_promptStore.isValidPromptName(name)) return context.json({ error: `"${name}" is not a usable prompt name.` }, STATUS.badRequest);
121
+ try {
122
+ if (!await store.remove(name)) return context.json({ error: `No saved prompt is named "${name}".` }, STATUS.notFound);
123
+ return context.json({ name });
124
+ } catch (error) {
125
+ return context.json({ error: failureMessage(error) }, STATUS.failed);
126
+ }
127
+ });
128
+ return app;
129
+ }
130
+ /** The named export a host imports from this package's built entry. */
131
+ const api = {
132
+ basePath: API_BASE_PATH,
133
+ start(_context) {
134
+ const app = createPromptHubApi();
135
+ return {
136
+ fetch: (request) => app.fetch(request),
137
+ close: () => void 0
138
+ };
139
+ }
140
+ };
141
+ //#endregion
142
+ //#region src/extensions/(backend)/api/prompts/route.server.ts
143
+ /**
144
+ * Mounts this package's HTTP API at `prompts`, which the folder names.
145
+ *
146
+ * The folder is the declaration: the build reads the base path off it and hands
147
+ * the browser a client bound to the same segment, so the mount is stated once
148
+ * rather than in a constant, a URL builder and a story stub that were each free
149
+ * to drift.
150
+ */
151
+ var route_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoute)(api);
152
+ //#endregion
153
+ //#region src/constants/prompts.ts
154
+ const COMMAND_NAME = "prompts";
155
+ const SERVER_COMMAND_DESCRIPTION = "List saved prompts or run one by name.";
156
+ //#endregion
157
+ //#region src/services/savedPrompts/index.ts
158
+ async function savedPrompts() {
159
+ const directory = require_promptStore.resolvePromptsDirectory();
160
+ try {
161
+ const { readdir } = await import("node:fs/promises");
162
+ const entries = await readdir(directory, { withFileTypes: true });
163
+ const prompts = [];
164
+ for (const entry of entries.filter((candidate) => candidate.isFile() && candidate.name.endsWith(".md")).sort((a, b) => a.name.localeCompare(b.name))) {
165
+ const name = entry.name.slice(0, -3);
166
+ prompts.push(require_promptStore.parsePromptDocument(name, await (0, node_fs_promises.readFile)(`${directory}/${entry.name}`, "utf8")));
167
+ }
168
+ return prompts;
169
+ } catch {
170
+ return [];
171
+ }
172
+ }
173
+ //#endregion
174
+ //#region src/services/serverPrompts/index.ts
175
+ const serverPromptCommand = {
176
+ name: COMMAND_NAME,
177
+ description: SERVER_COMMAND_DESCRIPTION,
178
+ async execute(args, execution) {
179
+ const prompts = await savedPrompts();
180
+ const requested = args.trim();
181
+ if (!requested) {
182
+ await execution.client.notify({
183
+ title: "Po prompts",
184
+ body: prompts.map((prompt) => `/${prompt.name}: ${prompt.description}`).join("\n") || "(no saved prompts)",
185
+ level: "info"
186
+ });
187
+ return;
188
+ }
189
+ const prompt = prompts.find((candidate) => candidate.name === requested);
190
+ if (!prompt) {
191
+ await execution.client.notify({
192
+ body: `Saved prompt not found: ${requested}`,
193
+ level: "warning"
194
+ });
195
+ return;
196
+ }
197
+ await execution.session.prompt(prompt.text);
198
+ }
199
+ };
200
+ //#endregion
201
+ //#region src/extensions/workspaces/sessions/(backend)/command/prompts.server.ts
202
+ var prompts_server_default$1 = (0, _agimon_ai_po_core_extensionFile.defineServerCommand)(serverPromptCommand);
203
+ //#endregion
204
+ //#region src/extensions/workspaces/sessions/(backend)/resource/po-use-prompt.server.ts
205
+ var po_use_prompt_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
206
+ name: "po-use-prompt",
207
+ when: _agimon_ai_po_core_help.DOOM_HELP_WHEN,
208
+ kind: "skill",
209
+ read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-prompt/SKILL.md")
210
+ });
211
+ //#endregion
212
+ //#region src/extensions/workspaces/sessions/(backend)/resource/prompts.server.ts
213
+ var prompts_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
214
+ name: "po/prompts",
215
+ kind: "prompt",
216
+ read: async () => JSON.stringify(await savedPrompts(), null, 2)
217
+ });
218
+ //#endregion
219
+ //#region generated/server.ts
220
+ const at = (value, context) => typeof value === "function" ? value(context) : value;
221
+ const via = (identity, value) => value === void 0 ? void 0 : {
222
+ ...identity,
223
+ ...value
224
+ };
225
+ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
226
+ name: "@agimon-ai/po-prompt",
227
+ global: (context) => ({ get api() {
228
+ return [at(route_server_default, context)];
229
+ } }),
230
+ workspace: (context) => ({ get api() {
231
+ return [at(route_server_default, context)];
232
+ } }),
233
+ session: (context) => ({
234
+ get api() {
235
+ return [at(route_server_default, context)];
236
+ },
237
+ get commands() {
238
+ return [via({ name: "prompts" }, at(prompts_server_default$1, context))];
239
+ },
240
+ get resources() {
241
+ return [at(po_use_prompt_server_default, context), at(prompts_server_default, context)];
242
+ }
243
+ })
244
+ });
245
+ //#endregion
246
+ exports.default = facet;
247
+ exports.facet = facet;
248
+
249
+ //# sourceMappingURL=server.cjs.map