my-pi 0.1.48 → 0.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/dist/api.d.ts +30 -0
- package/dist/api.js +1 -1
- package/dist/{builtin-registry-DpLtHlYK.js → builtin-registry-CTncHotU.js} +47 -5
- package/dist/builtin-registry-CTncHotU.js.map +1 -0
- package/dist/footer-DI_dqrz-.js +2 -0
- package/dist/{hooks-resolution-DNTz2NXs.js → hooks-resolution-C1fO4fuc.js} +1 -1
- package/dist/{hooks-resolution-DNTz2NXs.js.map → hooks-resolution-C1fO4fuc.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/{prompt-presets-BhlErXaD.js → prompt-presets-DRi6CwoJ.js} +3 -144
- package/dist/prompt-presets-DRi6CwoJ.js.map +1 -0
- package/dist/{session-name-8BLMnCqq.js → session-name-De4KoM5r.js} +1 -1
- package/dist/{session-name-8BLMnCqq.js.map → session-name-De4KoM5r.js.map} +1 -1
- package/dist/{startup-screen-ofHxGDsk.js → startup-screen-DIbhKCsP.js} +1 -1
- package/dist/{startup-screen-ofHxGDsk.js.map → startup-screen-DIbhKCsP.js.map} +1 -1
- package/package.json +26 -24
- package/dist/builtin-registry-DpLtHlYK.js.map +0 -1
- package/dist/prompt-presets-BhlErXaD.js.map +0 -1
package/README.md
CHANGED
|
@@ -563,17 +563,20 @@ In interactive mode:
|
|
|
563
563
|
interactive toggle list
|
|
564
564
|
- `/extensions enable <key>` / `/extensions disable <key>` — toggle a
|
|
565
565
|
built-in extension
|
|
566
|
-
- `/skills` — open the interactive skills manager
|
|
567
|
-
managed and importable sections, checkbox batch-import)
|
|
566
|
+
- `/skills` — open the interactive Pi/GitHub skills manager
|
|
568
567
|
- `/skills add <owner/repo> <skill[@ref]>` — install a GitHub-hosted
|
|
569
568
|
skill through `gh skill` when GitHub CLI support is available
|
|
570
|
-
- `/skills import <key|name>` — import an external skill from the
|
|
571
|
-
command line
|
|
572
|
-
- `/skills import <owner/repo> <skill[@ref]>` — alias GitHub-hosted
|
|
573
|
-
skill installs through `gh skill`
|
|
574
|
-
- `/skills sync <key|name>` — sync an imported skill to its upstream
|
|
575
569
|
- `/skills update --dry-run|--all` — check or apply GitHub skill
|
|
576
570
|
updates through `gh skill update`
|
|
571
|
+
- `/skill-importer` — open the external Claude/plugin skill importer
|
|
572
|
+
- `/skill-importer list` — show importable external skills and
|
|
573
|
+
imported copies with sync status
|
|
574
|
+
- `/skill-importer import <key|name>` — copy an external skill into
|
|
575
|
+
Pi-native storage
|
|
576
|
+
- `/skill-importer sync <key|name>` — sync an imported copy to
|
|
577
|
+
upstream
|
|
578
|
+
- `/skill-importer delete <key|name>` — delete only an imported copy
|
|
579
|
+
with importer metadata
|
|
577
580
|
- `/skills refresh` — rescan skill directories
|
|
578
581
|
- `/skills defaults <all-enabled|all-disabled>` — set default policy
|
|
579
582
|
- `/prompt-preset` — open the prompt preset manager (base presets +
|
package/dist/api.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Api, Model } from "@earendil-works/pi-ai";
|
|
2
2
|
import * as _$_earendil_works_pi_coding_agent0 from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { AgentSessionRuntime, CreateAgentSessionFromServicesOptions, ExtensionAPI, ExtensionFactory, ExtensionFactory as ExtensionFactory$1, InteractiveMode, InteractiveModeOptions, PrintModeOptions, runPrintMode, runRpcMode } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import * as _$_spences10_pi_footer0 from "@spences10/pi-footer";
|
|
4
5
|
import * as _$_spences10_pi_context0 from "@spences10/pi-context";
|
|
5
6
|
import * as _$_spences10_pi_mcp0 from "@spences10/pi-mcp";
|
|
6
7
|
import * as _$_spences10_pi_skills0 from "@spences10/pi-skills";
|
|
8
|
+
import * as _$_spences10_pi_skill_importer0 from "@spences10/pi-skill-importer";
|
|
7
9
|
import * as _$_spences10_pi_redact0 from "@spences10/pi-redact";
|
|
8
10
|
import * as _$_spences10_pi_recall0 from "@spences10/pi-recall";
|
|
9
11
|
import * as _$_spences10_pi_nopeek0 from "@spences10/pi-nopeek";
|
|
@@ -49,6 +51,22 @@ declare const BUILTIN_EXTENSION_REGISTRY: readonly [{
|
|
|
49
51
|
readonly cli_description: "Disable built-in MCP extension";
|
|
50
52
|
readonly aliases: readonly ["mcp"];
|
|
51
53
|
readonly load: () => Promise<typeof _$_spences10_pi_mcp0.default>;
|
|
54
|
+
}, {
|
|
55
|
+
readonly key: "footer";
|
|
56
|
+
readonly label: "Footer";
|
|
57
|
+
readonly docs_label: "Footer";
|
|
58
|
+
readonly description: "Configurable interactive footer/statusline";
|
|
59
|
+
readonly default_enabled: true;
|
|
60
|
+
readonly option_name: "footer";
|
|
61
|
+
readonly cli_arg: "no-footer";
|
|
62
|
+
readonly cli_flag: "--no-footer";
|
|
63
|
+
readonly cli_description: "Disable custom footer/statusline";
|
|
64
|
+
readonly aliases: readonly ["footer", "statusline", "status-line"];
|
|
65
|
+
readonly mode_constraints: {
|
|
66
|
+
readonly disabled_in: readonly ["print", "json", "rpc"];
|
|
67
|
+
readonly reason: "Footer only renders in the interactive TUI";
|
|
68
|
+
};
|
|
69
|
+
readonly load: () => Promise<typeof _$_spences10_pi_footer0.default>;
|
|
52
70
|
}, {
|
|
53
71
|
readonly key: "skills";
|
|
54
72
|
readonly label: "Skills";
|
|
@@ -61,6 +79,18 @@ declare const BUILTIN_EXTENSION_REGISTRY: readonly [{
|
|
|
61
79
|
readonly cli_description: "Disable built-in skills extension";
|
|
62
80
|
readonly aliases: readonly ["skills", "skill"];
|
|
63
81
|
readonly load: () => Promise<typeof _$_spences10_pi_skills0.default>;
|
|
82
|
+
}, {
|
|
83
|
+
readonly key: "skill-importer";
|
|
84
|
+
readonly label: "Skill importer";
|
|
85
|
+
readonly docs_label: "Skill importer";
|
|
86
|
+
readonly description: "Import external Claude/plugin skills into Pi-native storage";
|
|
87
|
+
readonly default_enabled: true;
|
|
88
|
+
readonly option_name: "skill_importer";
|
|
89
|
+
readonly cli_arg: "no-skill-importer";
|
|
90
|
+
readonly cli_flag: "--no-skill-importer";
|
|
91
|
+
readonly cli_description: "Disable external skill importer extension";
|
|
92
|
+
readonly aliases: readonly ["skill-importer", "import-skills", "skill-import"];
|
|
93
|
+
readonly load: () => Promise<typeof _$_spences10_pi_skill_importer0.default>;
|
|
64
94
|
}, {
|
|
65
95
|
readonly key: "filter-output";
|
|
66
96
|
readonly label: "Secret redaction";
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as BUILTIN_EXTENSION_REGISTRY, t as BUILTIN_EXTENSIONS } from "./builtin-registry-
|
|
1
|
+
import { n as BUILTIN_EXTENSION_REGISTRY, t as BUILTIN_EXTENSIONS } from "./builtin-registry-CTncHotU.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -30,6 +30,31 @@ const BUILTIN_EXTENSION_REGISTRY = [
|
|
|
30
30
|
aliases: ["mcp"],
|
|
31
31
|
load: async () => (await import("@spences10/pi-mcp")).default
|
|
32
32
|
},
|
|
33
|
+
{
|
|
34
|
+
key: "footer",
|
|
35
|
+
label: "Footer",
|
|
36
|
+
docs_label: "Footer",
|
|
37
|
+
description: "Configurable interactive footer/statusline",
|
|
38
|
+
default_enabled: true,
|
|
39
|
+
option_name: "footer",
|
|
40
|
+
cli_arg: "no-footer",
|
|
41
|
+
cli_flag: "--no-footer",
|
|
42
|
+
cli_description: "Disable custom footer/statusline",
|
|
43
|
+
aliases: [
|
|
44
|
+
"footer",
|
|
45
|
+
"statusline",
|
|
46
|
+
"status-line"
|
|
47
|
+
],
|
|
48
|
+
mode_constraints: {
|
|
49
|
+
disabled_in: [
|
|
50
|
+
"print",
|
|
51
|
+
"json",
|
|
52
|
+
"rpc"
|
|
53
|
+
],
|
|
54
|
+
reason: "Footer only renders in the interactive TUI"
|
|
55
|
+
},
|
|
56
|
+
load: async () => (await import("./footer-DI_dqrz-.js")).default
|
|
57
|
+
},
|
|
33
58
|
{
|
|
34
59
|
key: "skills",
|
|
35
60
|
label: "Skills",
|
|
@@ -43,6 +68,23 @@ const BUILTIN_EXTENSION_REGISTRY = [
|
|
|
43
68
|
aliases: ["skills", "skill"],
|
|
44
69
|
load: async () => (await import("@spences10/pi-skills")).default
|
|
45
70
|
},
|
|
71
|
+
{
|
|
72
|
+
key: "skill-importer",
|
|
73
|
+
label: "Skill importer",
|
|
74
|
+
docs_label: "Skill importer",
|
|
75
|
+
description: "Import external Claude/plugin skills into Pi-native storage",
|
|
76
|
+
default_enabled: true,
|
|
77
|
+
option_name: "skill_importer",
|
|
78
|
+
cli_arg: "no-skill-importer",
|
|
79
|
+
cli_flag: "--no-skill-importer",
|
|
80
|
+
cli_description: "Disable external skill importer extension",
|
|
81
|
+
aliases: [
|
|
82
|
+
"skill-importer",
|
|
83
|
+
"import-skills",
|
|
84
|
+
"skill-import"
|
|
85
|
+
],
|
|
86
|
+
load: async () => (await import("@spences10/pi-skill-importer")).default
|
|
87
|
+
},
|
|
46
88
|
{
|
|
47
89
|
key: "filter-output",
|
|
48
90
|
label: "Secret redaction",
|
|
@@ -152,7 +194,7 @@ const BUILTIN_EXTENSION_REGISTRY = [
|
|
|
152
194
|
],
|
|
153
195
|
reason: "Startup screen only renders in the interactive TUI"
|
|
154
196
|
},
|
|
155
|
-
load: async () => (await import("./startup-screen-
|
|
197
|
+
load: async () => (await import("./startup-screen-DIbhKCsP.js")).default
|
|
156
198
|
},
|
|
157
199
|
{
|
|
158
200
|
key: "prompt-presets",
|
|
@@ -169,7 +211,7 @@ const BUILTIN_EXTENSION_REGISTRY = [
|
|
|
169
211
|
"preset",
|
|
170
212
|
"presets"
|
|
171
213
|
],
|
|
172
|
-
load: async () => (await import("./prompt-presets-
|
|
214
|
+
load: async () => (await import("./prompt-presets-DRi6CwoJ.js")).default
|
|
173
215
|
},
|
|
174
216
|
{
|
|
175
217
|
key: "git-ui",
|
|
@@ -233,7 +275,7 @@ const BUILTIN_EXTENSION_REGISTRY = [
|
|
|
233
275
|
],
|
|
234
276
|
reason: "UI-only session naming is only useful in interactive mode"
|
|
235
277
|
},
|
|
236
|
-
load: async () => (await import("./session-name-
|
|
278
|
+
load: async () => (await import("./session-name-De4KoM5r.js")).default
|
|
237
279
|
},
|
|
238
280
|
{
|
|
239
281
|
key: "confirm-destructive",
|
|
@@ -259,7 +301,7 @@ const BUILTIN_EXTENSION_REGISTRY = [
|
|
|
259
301
|
cli_flag: "--no-hooks",
|
|
260
302
|
cli_description: "Disable Claude-style hook execution",
|
|
261
303
|
aliases: ["hooks-resolution", "hooks"],
|
|
262
|
-
load: async () => (await import("./hooks-resolution-
|
|
304
|
+
load: async () => (await import("./hooks-resolution-C1fO4fuc.js")).default
|
|
263
305
|
},
|
|
264
306
|
{
|
|
265
307
|
key: "svelte-guardrails",
|
|
@@ -313,4 +355,4 @@ const BUILTIN_EXTENSIONS = BUILTIN_EXTENSION_REGISTRY.map(({ load: _load, ...ext
|
|
|
313
355
|
//#endregion
|
|
314
356
|
export { BUILTIN_EXTENSION_REGISTRY as n, BUILTIN_EXTENSIONS as t };
|
|
315
357
|
|
|
316
|
-
//# sourceMappingURL=builtin-registry-
|
|
358
|
+
//# sourceMappingURL=builtin-registry-CTncHotU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtin-registry-CTncHotU.js","names":[],"sources":["../src/extensions/builtin-registry.ts"],"sourcesContent":["import type { ExtensionFactory } from '@earendil-works/pi-coding-agent';\n\nexport type BuiltinExtensionRuntimeMode =\n\t| 'interactive'\n\t| 'print'\n\t| 'json'\n\t| 'rpc';\n\ntype BuiltinExtensionLoader = () => Promise<ExtensionFactory>;\n\nexport interface BuiltinExtensionManifestEntry {\n\tkey: string;\n\tlabel: string;\n\tdocs_label: string;\n\tdescription: string;\n\tdefault_enabled: boolean;\n\toption_name: string;\n\tcli_arg: string;\n\tcli_flag: `--${string}`;\n\tcli_description: string;\n\taliases: readonly string[];\n\tmode_constraints?: {\n\t\tdisabled_in: readonly BuiltinExtensionRuntimeMode[];\n\t\treason: string;\n\t};\n\tload: BuiltinExtensionLoader;\n}\n\nexport const BUILTIN_EXTENSION_REGISTRY = [\n\t{\n\t\tkey: 'context-sidecar',\n\t\tlabel: 'Context sidecar',\n\t\tdocs_label: 'SQLite context sidecar',\n\t\tdescription: 'Local SQLite FTS sidecar for oversized tool output',\n\t\tdefault_enabled: true,\n\t\toption_name: 'context_sidecar',\n\t\tcli_arg: 'no-context-sidecar',\n\t\tcli_flag: '--no-context-sidecar',\n\t\tcli_description:\n\t\t\t'Disable SQLite context sidecar for large tool output',\n\t\taliases: ['context-sidecar', 'context', 'sidecar'],\n\t\tload: async () => (await import('@spences10/pi-context')).default,\n\t},\n\t{\n\t\tkey: 'mcp',\n\t\tlabel: 'MCP',\n\t\tdocs_label: 'MCP',\n\t\tdescription: 'MCP server integration and /mcp command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'mcp',\n\t\tcli_arg: 'no-mcp',\n\t\tcli_flag: '--no-mcp',\n\t\tcli_description: 'Disable built-in MCP extension',\n\t\taliases: ['mcp'],\n\t\tload: async () => (await import('@spences10/pi-mcp')).default,\n\t},\n\t{\n\t\tkey: 'footer',\n\t\tlabel: 'Footer',\n\t\tdocs_label: 'Footer',\n\t\tdescription: 'Configurable interactive footer/statusline',\n\t\tdefault_enabled: true,\n\t\toption_name: 'footer',\n\t\tcli_arg: 'no-footer',\n\t\tcli_flag: '--no-footer',\n\t\tcli_description: 'Disable custom footer/statusline',\n\t\taliases: ['footer', 'statusline', 'status-line'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason: 'Footer only renders in the interactive TUI',\n\t\t},\n\t\tload: async () => (await import('./footer/index.js')).default,\n\t},\n\t{\n\t\tkey: 'skills',\n\t\tlabel: 'Skills',\n\t\tdocs_label: 'Skills',\n\t\tdescription: 'Managed pi-native skills and /skills command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'skills',\n\t\tcli_arg: 'no-skills',\n\t\tcli_flag: '--no-skills',\n\t\tcli_description: 'Disable built-in skills extension',\n\t\taliases: ['skills', 'skill'],\n\t\tload: async () => (await import('@spences10/pi-skills')).default,\n\t},\n\t{\n\t\tkey: 'skill-importer',\n\t\tlabel: 'Skill importer',\n\t\tdocs_label: 'Skill importer',\n\t\tdescription:\n\t\t\t'Import external Claude/plugin skills into Pi-native storage',\n\t\tdefault_enabled: true,\n\t\toption_name: 'skill_importer',\n\t\tcli_arg: 'no-skill-importer',\n\t\tcli_flag: '--no-skill-importer',\n\t\tcli_description: 'Disable external skill importer extension',\n\t\taliases: ['skill-importer', 'import-skills', 'skill-import'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-skill-importer')).default,\n\t},\n\t{\n\t\tkey: 'filter-output',\n\t\tlabel: 'Secret redaction',\n\t\tdocs_label: 'Secret redaction',\n\t\tdescription:\n\t\t\t'Redacts secrets from tool output before the model sees them',\n\t\tdefault_enabled: true,\n\t\toption_name: 'filter_output',\n\t\tcli_arg: 'no-filter',\n\t\tcli_flag: '--no-filter',\n\t\tcli_description: 'Disable secret redaction in tool output',\n\t\taliases: [\n\t\t\t'filter-output',\n\t\t\t'filter_output',\n\t\t\t'filter',\n\t\t\t'redaction',\n\t\t\t'secret-redaction',\n\t\t\t'output-redaction',\n\t\t],\n\t\tload: async () => (await import('@spences10/pi-redact')).default,\n\t},\n\t{\n\t\tkey: 'recall',\n\t\tlabel: 'Recall',\n\t\tdocs_label: 'Recall',\n\t\tdescription: 'pirecall reminder and background session sync',\n\t\tdefault_enabled: true,\n\t\toption_name: 'recall',\n\t\tcli_arg: 'no-recall',\n\t\tcli_flag: '--no-recall',\n\t\tcli_description: 'Disable recall extension',\n\t\taliases: ['recall', 'pirecall'],\n\t\tload: async () => (await import('@spences10/pi-recall')).default,\n\t},\n\t{\n\t\tkey: 'nopeek',\n\t\tlabel: 'Nopeek',\n\t\tdocs_label: 'Nopeek',\n\t\tdescription:\n\t\t\t'nopeek reminder for secret-safe environment loading',\n\t\tdefault_enabled: true,\n\t\toption_name: 'nopeek',\n\t\tcli_arg: 'no-nopeek',\n\t\tcli_flag: '--no-nopeek',\n\t\tcli_description: 'Disable nopeek reminder extension',\n\t\taliases: ['nopeek', 'secrets', 'secret-loading'],\n\t\tload: async () => (await import('@spences10/pi-nopeek')).default,\n\t},\n\t{\n\t\tkey: 'omnisearch',\n\t\tlabel: 'Omnisearch',\n\t\tdocs_label: 'Omnisearch',\n\t\tdescription: 'mcp-omnisearch reminder for verified web research',\n\t\tdefault_enabled: true,\n\t\toption_name: 'omnisearch',\n\t\tcli_arg: 'no-omnisearch',\n\t\tcli_flag: '--no-omnisearch',\n\t\tcli_description: 'Disable mcp-omnisearch reminder extension',\n\t\taliases: ['omnisearch', 'search', 'web-search', 'research'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-omnisearch')).default,\n\t},\n\t{\n\t\tkey: 'sqlite-tools',\n\t\tlabel: 'SQLite tools',\n\t\tdocs_label: 'SQLite tools',\n\t\tdescription:\n\t\t\t'mcp-sqlite-tools reminder for safer SQLite database work',\n\t\tdefault_enabled: true,\n\t\toption_name: 'sqlite_tools',\n\t\tcli_arg: 'no-sqlite-tools',\n\t\tcli_flag: '--no-sqlite-tools',\n\t\tcli_description: 'Disable mcp-sqlite-tools reminder extension',\n\t\taliases: ['sqlite-tools', 'sqlite', 'mcp-sqlite-tools'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-sqlite-tools')).default,\n\t},\n\t{\n\t\tkey: 'startup-screen',\n\t\tlabel: 'Startup screen',\n\t\tdocs_label: 'Startup screen',\n\t\tdescription:\n\t\t\t'Pixel-art gradient startup header for interactive sessions',\n\t\tdefault_enabled: true,\n\t\toption_name: 'startup_screen',\n\t\tcli_arg: 'no-startup-screen',\n\t\tcli_flag: '--no-startup-screen',\n\t\tcli_description: 'Disable the custom startup screen',\n\t\taliases: ['startup-screen', 'startup', 'header', 'splash'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason: 'Startup screen only renders in the interactive TUI',\n\t\t},\n\t\tload: async () =>\n\t\t\t(await import('./startup-screen/index.js')).default,\n\t},\n\t{\n\t\tkey: 'prompt-presets',\n\t\tlabel: 'Prompt presets',\n\t\tdocs_label: 'Prompt presets',\n\t\tdescription:\n\t\t\t'Runtime prompt preset selection and /prompt-preset command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'prompt_presets',\n\t\tcli_arg: 'no-prompt-presets',\n\t\tcli_flag: '--no-prompt-presets',\n\t\tcli_description: 'Disable prompt presets extension',\n\t\taliases: ['prompt-preset', 'preset', 'presets'],\n\t\tload: async () =>\n\t\t\t(await import('./prompt-presets/index.js')).default,\n\t},\n\t{\n\t\tkey: 'git-ui',\n\t\tlabel: 'Git UI',\n\t\tdocs_label: 'Git staging UI',\n\t\tdescription: 'Interactive source control staging panel',\n\t\tdefault_enabled: true,\n\t\toption_name: 'git_ui',\n\t\tcli_arg: 'no-git-ui',\n\t\tcli_flag: '--no-git-ui',\n\t\tcli_description: 'Disable built-in Git staging UI',\n\t\taliases: ['git-ui', 'git', 'source-control', 'scm'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason: 'Git UI is only useful in interactive mode',\n\t\t},\n\t\tload: async () => (await import('@spences10/pi-git-ui')).default,\n\t},\n\t{\n\t\tkey: 'lsp',\n\t\tlabel: 'LSP',\n\t\tdocs_label: 'LSP',\n\t\tdescription:\n\t\t\t'Language Server Protocol tools (diagnostics, hover, definition, references)',\n\t\tdefault_enabled: true,\n\t\toption_name: 'lsp',\n\t\tcli_arg: 'no-lsp',\n\t\tcli_flag: '--no-lsp',\n\t\tcli_description: 'Disable LSP extension',\n\t\taliases: ['lsp', 'language-server'],\n\t\tload: async () => (await import('@spences10/pi-lsp')).default,\n\t},\n\t{\n\t\tkey: 'session-name',\n\t\tlabel: 'Session name',\n\t\tdocs_label: 'Session auto-naming',\n\t\tdescription:\n\t\t\t'AI-powered session auto-naming and /session-name command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'session_name',\n\t\tcli_arg: 'no-session-name',\n\t\tcli_flag: '--no-session-name',\n\t\tcli_description: 'Disable session name extension',\n\t\taliases: ['session-name', 'session', 'auto-name'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason:\n\t\t\t\t'UI-only session naming is only useful in interactive mode',\n\t\t},\n\t\tload: async () =>\n\t\t\t(await import('./session-name/index.js')).default,\n\t},\n\t{\n\t\tkey: 'confirm-destructive',\n\t\tlabel: 'Confirm destructive',\n\t\tdocs_label: 'Destructive action confirmation',\n\t\tdescription:\n\t\t\t'Prompt before destructive tool calls like file deletes, overwrites, and hard resets',\n\t\tdefault_enabled: true,\n\t\toption_name: 'confirm_destructive',\n\t\tcli_arg: 'no-confirm-destructive',\n\t\tcli_flag: '--no-confirm-destructive',\n\t\tcli_description: 'Disable destructive action confirmations',\n\t\taliases: ['confirm-destructive', 'confirm'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-confirm-destructive')).default,\n\t},\n\t{\n\t\tkey: 'hooks-resolution',\n\t\tlabel: 'Hooks resolution',\n\t\tdocs_label: 'Hooks resolution',\n\t\tdescription:\n\t\t\t'Claude Code style PreToolUse and PostToolUse hook compatibility from .claude, .rulesync, and .pi configs',\n\t\tdefault_enabled: true,\n\t\toption_name: 'hooks_resolution',\n\t\tcli_arg: 'no-hooks',\n\t\tcli_flag: '--no-hooks',\n\t\tcli_description: 'Disable Claude-style hook execution',\n\t\taliases: ['hooks-resolution', 'hooks'],\n\t\tload: async () =>\n\t\t\t(await import('./hooks-resolution/index.js')).default,\n\t},\n\t{\n\t\tkey: 'svelte-guardrails',\n\t\tlabel: 'Svelte guardrails',\n\t\tdocs_label: 'Svelte guardrails',\n\t\tdescription:\n\t\t\t'Blocks discouraged Svelte patterns like $effect before agents write them',\n\t\tdefault_enabled: true,\n\t\toption_name: 'svelte_guardrails',\n\t\tcli_arg: 'no-svelte-guardrails',\n\t\tcli_flag: '--no-svelte-guardrails',\n\t\tcli_description: 'Disable Svelte guardrails',\n\t\taliases: ['svelte-guardrails', 'svelte'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-svelte-guardrails')).default,\n\t},\n\t{\n\t\tkey: 'coding-preferences',\n\t\tlabel: 'Coding preferences',\n\t\tdocs_label: 'Coding preferences',\n\t\tdescription:\n\t\t\t'Blocks configured coding workflow anti-patterns from JSON preferences',\n\t\tdefault_enabled: true,\n\t\toption_name: 'coding_preferences',\n\t\tcli_arg: 'no-coding-preferences',\n\t\tcli_flag: '--no-coding-preferences',\n\t\tcli_description: 'Disable coding preferences guardrails',\n\t\taliases: ['coding-preferences', 'preferences', 'prefs'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-coding-preferences')).default,\n\t},\n\t{\n\t\tkey: 'team-mode',\n\t\tlabel: 'Team mode',\n\t\tdocs_label: 'Team mode',\n\t\tdescription:\n\t\t\t'Experimental orchestrator/team mode with RPC teammates, tasks, and mailboxes',\n\t\tdefault_enabled: true,\n\t\toption_name: 'team_mode',\n\t\tcli_arg: 'no-team-mode',\n\t\tcli_flag: '--no-team-mode',\n\t\tcli_description: 'Disable experimental team mode extension',\n\t\taliases: ['team-mode', 'team', 'teammates'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-team-mode')).default,\n\t},\n] as const satisfies readonly BuiltinExtensionManifestEntry[];\n\nexport type BuiltinExtensionKey =\n\t(typeof BUILTIN_EXTENSION_REGISTRY)[number]['key'];\n\nexport type BuiltinExtensionOptionName =\n\t(typeof BUILTIN_EXTENSION_REGISTRY)[number]['option_name'];\n\nexport type BuiltinExtensionInfo = Omit<\n\tBuiltinExtensionManifestEntry,\n\t'load'\n> & {\n\tkey: BuiltinExtensionKey;\n\toption_name: BuiltinExtensionOptionName;\n};\n\nexport const BUILTIN_EXTENSIONS: BuiltinExtensionInfo[] =\n\tBUILTIN_EXTENSION_REGISTRY.map(\n\t\t({ load: _load, ...extension }) => extension,\n\t);\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-resolution-DNTz2NXs.js","names":["create_child_process_env","create_shared_child_process_env","create_child_process_env","HOOKS_CONFIG_ENV"],"sources":["../src/extensions/hooks-resolution/config.ts","../src/extensions/hooks-resolution/payload.ts","../src/extensions/hooks-resolution/env.ts","../src/extensions/hooks-resolution/runner.ts","../src/extensions/hooks-resolution/trust.ts","../src/extensions/hooks-resolution/trust-gate.ts","../src/extensions/hooks-resolution/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport type {\n\tHookEventName,\n\tHooksConfigInfo,\n\tHookState,\n\tJsonValue,\n\tResolvedCommandHook,\n} from './types.js';\n\nexport function is_file(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function as_record(\n\tvalue: unknown,\n): Record<string, unknown> | undefined {\n\tif (typeof value !== 'object' || value === null) return undefined;\n\treturn value as Record<string, unknown>;\n}\n\nexport function walk_up_directories(\n\tstart_dir: string,\n\tstop_dir?: string,\n): string[] {\n\tconst directories: string[] = [];\n\tconst has_stop_dir = stop_dir !== undefined;\n\tlet current = resolve(start_dir);\n\tlet parent = dirname(current);\n\tlet reached_stop_dir = has_stop_dir && current === stop_dir;\n\tlet reached_filesystem_root = parent === current;\n\n\tdirectories.push(current);\n\twhile (!reached_stop_dir && !reached_filesystem_root) {\n\t\tcurrent = parent;\n\t\tparent = dirname(current);\n\t\treached_stop_dir = has_stop_dir && current === stop_dir;\n\t\treached_filesystem_root = parent === current;\n\t\tdirectories.push(current);\n\t}\n\n\treturn directories;\n}\n\nexport function find_nearest_git_root(\n\tstart_dir: string,\n): string | undefined {\n\tfor (const directory of walk_up_directories(start_dir)) {\n\t\tif (existsSync(join(directory, '.git'))) {\n\t\t\treturn directory;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function has_hooks_config(directory: string): boolean {\n\treturn (\n\t\tis_file(join(directory, '.claude', 'settings.json')) ||\n\t\tis_file(join(directory, '.rulesync', 'hooks.json')) ||\n\t\tis_file(join(directory, '.pi', 'hooks.json'))\n\t);\n}\n\nexport function find_project_dir(cwd: string): string {\n\tconst git_root = find_nearest_git_root(cwd);\n\tfor (const directory of walk_up_directories(cwd, git_root)) {\n\t\tif (has_hooks_config(directory)) {\n\t\t\treturn directory;\n\t\t}\n\t}\n\treturn git_root ?? resolve(cwd);\n}\n\nexport function read_json_file(path: string): JsonValue | undefined {\n\tif (!is_file(path)) return undefined;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, 'utf8')) as JsonValue;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function resolve_hook_command(\n\tcommand: string,\n\tproject_dir: string,\n): string {\n\treturn command.replace(/\\$CLAUDE_PROJECT_DIR\\b/g, project_dir);\n}\n\nexport function compile_matcher(\n\tmatcher_text: string | undefined,\n): RegExp | undefined {\n\tif (matcher_text === undefined) return undefined;\n\ttry {\n\t\treturn new RegExp(matcher_text);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function create_hook(\n\tevent_name: HookEventName,\n\tmatcher_text: string | undefined,\n\tcommand: string,\n\tsource: string,\n\tproject_dir: string,\n): ResolvedCommandHook | undefined {\n\tconst matcher = compile_matcher(matcher_text);\n\tif (matcher_text !== undefined && matcher === undefined)\n\t\treturn undefined;\n\treturn {\n\t\tevent_name,\n\t\tmatcher,\n\t\tmatcher_text,\n\t\tcommand: resolve_hook_command(command, project_dir),\n\t\tsource,\n\t};\n}\n\nexport function get_hook_entries(\n\thooks_record: Record<string, unknown>,\n\tevent_name: HookEventName,\n): unknown[] {\n\tconst keys =\n\t\tevent_name === 'PreToolUse'\n\t\t\t? ['PreToolUse', 'preToolUse']\n\t\t\t: event_name === 'PostToolUse'\n\t\t\t\t? ['PostToolUse', 'postToolUse']\n\t\t\t\t: ['PostToolUseFailure', 'postToolUseFailure'];\n\n\tfor (const key of keys) {\n\t\tconst value = hooks_record[key];\n\t\tif (Array.isArray(value)) return value;\n\t}\n\treturn [];\n}\n\nexport function parse_claude_settings_hooks(\n\tconfig: unknown,\n\tsource: string,\n\tproject_dir: string,\n): ResolvedCommandHook[] {\n\tconst root = as_record(config);\n\tconst hooks_root = root ? as_record(root.hooks) : undefined;\n\tif (!hooks_root) return [];\n\n\tconst hooks: ResolvedCommandHook[] = [];\n\tconst events: HookEventName[] = [\n\t\t'PreToolUse',\n\t\t'PostToolUse',\n\t\t'PostToolUseFailure',\n\t];\n\n\tfor (const event_name of events) {\n\t\tconst entries = get_hook_entries(hooks_root, event_name);\n\t\tfor (const entry of entries) {\n\t\t\tconst entry_record = as_record(entry);\n\t\t\tif (!entry_record || !Array.isArray(entry_record.hooks))\n\t\t\t\tcontinue;\n\n\t\t\tconst matcher_text =\n\t\t\t\ttypeof entry_record.matcher === 'string'\n\t\t\t\t\t? entry_record.matcher\n\t\t\t\t\t: undefined;\n\t\t\tfor (const nested_hook of entry_record.hooks) {\n\t\t\t\tconst nested_record = as_record(nested_hook);\n\t\t\t\tif (!nested_record) continue;\n\t\t\t\tif (nested_record.type !== 'command') continue;\n\t\t\t\tif (typeof nested_record.command !== 'string') continue;\n\n\t\t\t\tconst hook = create_hook(\n\t\t\t\t\tevent_name,\n\t\t\t\t\tmatcher_text,\n\t\t\t\t\tnested_record.command,\n\t\t\t\t\tsource,\n\t\t\t\t\tproject_dir,\n\t\t\t\t);\n\t\t\t\tif (hook) hooks.push(hook);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn hooks;\n}\n\nexport function parse_simple_hooks_file(\n\tconfig: unknown,\n\tsource: string,\n\tproject_dir: string,\n): ResolvedCommandHook[] {\n\tconst root = as_record(config);\n\tconst hooks_root = root ? as_record(root.hooks) : undefined;\n\tif (!hooks_root) return [];\n\n\tconst hooks: ResolvedCommandHook[] = [];\n\tconst events: HookEventName[] = [\n\t\t'PreToolUse',\n\t\t'PostToolUse',\n\t\t'PostToolUseFailure',\n\t];\n\n\tfor (const event_name of events) {\n\t\tconst entries = get_hook_entries(hooks_root, event_name);\n\t\tfor (const entry of entries) {\n\t\t\tconst entry_record = as_record(entry);\n\t\t\tif (!entry_record || typeof entry_record.command !== 'string') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst matcher_text =\n\t\t\t\ttypeof entry_record.matcher === 'string'\n\t\t\t\t\t? entry_record.matcher\n\t\t\t\t\t: undefined;\n\t\t\tconst hook = create_hook(\n\t\t\t\tevent_name,\n\t\t\t\tmatcher_text,\n\t\t\t\tentry_record.command,\n\t\t\t\tsource,\n\t\t\t\tproject_dir,\n\t\t\t);\n\t\t\tif (hook) hooks.push(hook);\n\t\t}\n\t}\n\n\treturn hooks;\n}\n\nfunction hook_config_paths(project_dir: string): string[] {\n\treturn [\n\t\tjoin(project_dir, '.claude', 'settings.json'),\n\t\tjoin(project_dir, '.rulesync', 'hooks.json'),\n\t\tjoin(project_dir, '.pi', 'hooks.json'),\n\t];\n}\n\nfunction parse_hooks_config_file(\n\tpath: string,\n\tproject_dir: string,\n): ResolvedCommandHook[] {\n\tconst config = read_json_file(path);\n\tif (config === undefined) return [];\n\tif (path.endsWith(join('.claude', 'settings.json'))) {\n\t\treturn parse_claude_settings_hooks(config, path, project_dir);\n\t}\n\treturn parse_simple_hooks_file(config, path, project_dir);\n}\n\nexport function load_hooks(cwd: string): HookState {\n\tconst project_dir = find_project_dir(cwd);\n\tconst hooks = hook_config_paths(project_dir).flatMap((path) =>\n\t\tparse_hooks_config_file(path, project_dir),\n\t);\n\n\treturn { project_dir, hooks };\n}\n\nexport function get_hooks_config_info(\n\tcwd: string,\n): HooksConfigInfo | undefined {\n\tconst project_dir = find_project_dir(cwd);\n\tconst sources = hook_config_paths(project_dir).filter(is_file);\n\tif (sources.length === 0) return undefined;\n\n\tconst hash = createHash('sha256');\n\tfor (const source of sources) {\n\t\thash.update(source);\n\t\thash.update('\\0');\n\t\thash.update(readFileSync(source, 'utf8'));\n\t\thash.update('\\0');\n\t}\n\n\tconst hooks = sources\n\t\t.flatMap((source) => parse_hooks_config_file(source, project_dir))\n\t\t.map((hook) => ({\n\t\t\tevent_name: hook.event_name,\n\t\t\tmatcher_text: hook.matcher_text,\n\t\t\tcommand: hook.command,\n\t\t\tsource: hook.source,\n\t\t}));\n\n\treturn {\n\t\tproject_dir,\n\t\thash: hash.digest('hex'),\n\t\tsources,\n\t\thooks,\n\t};\n}\n","import type {\n\tExtensionContext,\n\tToolCallEvent,\n\tToolResultEvent,\n} from '@earendil-works/pi-coding-agent';\nimport type { HookEventName, ResolvedCommandHook } from './types.js';\n\nexport function to_claude_tool_name(tool_name: string): string {\n\tif (tool_name === 'ls') return 'LS';\n\tif (tool_name.length === 0) return tool_name;\n\treturn tool_name[0].toUpperCase() + tool_name.slice(1);\n}\n\nexport function matches_hook(\n\thook: ResolvedCommandHook,\n\ttool_name: string,\n): boolean {\n\tif (!hook.matcher) return true;\n\n\tconst claude_tool_name = to_claude_tool_name(tool_name);\n\thook.matcher.lastIndex = 0;\n\tif (hook.matcher.test(tool_name)) return true;\n\n\thook.matcher.lastIndex = 0;\n\treturn hook.matcher.test(claude_tool_name);\n}\n\nexport function extract_text_content(content: unknown): string {\n\tif (!Array.isArray(content)) return '';\n\n\tconst parts: string[] = [];\n\tfor (const item of content) {\n\t\tif (!item || typeof item !== 'object') continue;\n\t\tconst item_record = item as Record<string, unknown>;\n\t\tif (\n\t\t\titem_record.type === 'text' &&\n\t\t\ttypeof item_record.text === 'string'\n\t\t) {\n\t\t\tparts.push(item_record.text);\n\t\t}\n\t}\n\n\treturn parts.join('\\n');\n}\n\nexport function normalize_tool_input(\n\tinput: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst normalized: Record<string, unknown> = { ...input };\n\tconst path_value =\n\t\ttypeof input.path === 'string' ? input.path : undefined;\n\tif (path_value !== undefined) {\n\t\tnormalized.file_path = path_value;\n\t\tnormalized.filePath = path_value;\n\t}\n\treturn normalized;\n}\n\nexport function build_tool_response(\n\tevent: ToolResultEvent,\n\tnormalized_input: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst response: Record<string, unknown> = {\n\t\tis_error: event.isError,\n\t\tisError: event.isError,\n\t\tcontent: event.content,\n\t\ttext: extract_text_content(event.content),\n\t\tdetails: event.details ?? null,\n\t};\n\n\tconst file_path =\n\t\ttypeof normalized_input.file_path === 'string'\n\t\t\t? normalized_input.file_path\n\t\t\t: undefined;\n\tif (file_path !== undefined) {\n\t\tresponse.file_path = file_path;\n\t\tresponse.filePath = file_path;\n\t}\n\n\treturn response;\n}\n\nexport function build_hook_payload(\n\tevent: ToolCallEvent | ToolResultEvent,\n\tevent_name: HookEventName,\n\tctx: ExtensionContext,\n\tproject_dir: string,\n): Record<string, unknown> {\n\tconst normalized_input = normalize_tool_input(\n\t\tevent.input as Record<string, unknown>,\n\t);\n\tconst session_id =\n\t\tctx.sessionManager.getSessionFile() ?? 'ephemeral';\n\tconst payload: Record<string, unknown> = {\n\t\tsession_id,\n\t\tcwd: ctx.cwd,\n\t\tclaude_project_dir: project_dir,\n\t\thook_event_name: event_name,\n\t\ttool_name: to_claude_tool_name(event.toolName),\n\t\ttool_call_id: event.toolCallId,\n\t\ttool_input: normalized_input,\n\t};\n\n\tif ('content' in event) {\n\t\tpayload.tool_response = build_tool_response(\n\t\t\tevent,\n\t\t\tnormalized_input,\n\t\t);\n\t}\n\n\treturn payload;\n}\n","import { create_child_process_env as create_shared_child_process_env } from '@spences10/pi-child-env';\n\nexport function create_child_process_env(\n\texplicit_env: Record<string, string> = {},\n\tsource_env: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n\treturn create_shared_child_process_env({\n\t\tprofile: 'hooks',\n\t\texplicit_env,\n\t\tsource_env,\n\t});\n}\n","import type { ToolResultEvent } from '@earendil-works/pi-coding-agent';\nimport { spawn } from 'node:child_process';\nimport { basename } from 'node:path';\nimport { as_record } from './config.js';\nimport { create_child_process_env } from './env.js';\nimport type { CommandRunResult, HookEventName } from './types.js';\n\nconst HOOK_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport async function run_command_hook(\n\tcommand: string,\n\tcwd: string,\n\tpayload: Record<string, unknown>,\n): Promise<CommandRunResult> {\n\treturn await new Promise((resolve) => {\n\t\tconst started_at = Date.now();\n\t\tconst child = spawn('bash', ['-lc', command], {\n\t\t\tcwd,\n\t\t\tenv: create_child_process_env({ CLAUDE_PROJECT_DIR: cwd }),\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\t\tlet timed_out = false;\n\t\tlet resolved = false;\n\n\t\tconst finish = (code: number) => {\n\t\t\tif (resolved) return;\n\t\t\tresolved = true;\n\t\t\tresolve({\n\t\t\t\tcode,\n\t\t\t\tstdout,\n\t\t\t\tstderr,\n\t\t\t\telapsed_ms: Date.now() - started_at,\n\t\t\t\ttimed_out,\n\t\t\t});\n\t\t};\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\ttimed_out = true;\n\t\t\tchild.kill('SIGTERM');\n\t\t\tconst kill_timer = setTimeout(() => {\n\t\t\t\tchild.kill('SIGKILL');\n\t\t\t}, 1000);\n\t\t\t(\n\t\t\t\tkill_timer as NodeJS.Timeout & { unref?: () => void }\n\t\t\t).unref?.();\n\t\t}, HOOK_TIMEOUT_MS);\n\t\t(timeout as NodeJS.Timeout & { unref?: () => void }).unref?.();\n\n\t\tchild.stdout.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString('utf8');\n\t\t});\n\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString('utf8');\n\t\t});\n\n\t\tchild.on('error', (error) => {\n\t\t\tclearTimeout(timeout);\n\t\t\tstderr += `${error.message}\\n`;\n\t\t\tfinish(-1);\n\t\t});\n\n\t\tchild.on('close', (code) => {\n\t\t\tclearTimeout(timeout);\n\t\t\tfinish(code ?? -1);\n\t\t});\n\n\t\ttry {\n\t\t\tchild.stdin.write(JSON.stringify(payload));\n\t\t\tchild.stdin.end();\n\t\t} catch (error) {\n\t\t\tstderr += `${error instanceof Error ? error.message : String(error)}\\n`;\n\t\t}\n\t});\n}\n\nexport function hook_event_name_for_result(\n\tevent: ToolResultEvent,\n): HookEventName {\n\treturn event.isError ? 'PostToolUseFailure' : 'PostToolUse';\n}\n\nexport function hook_block_reason(\n\tresult: CommandRunResult,\n): string | undefined {\n\tconst parse_json = (\n\t\ttext: string,\n\t): Record<string, unknown> | undefined => {\n\t\tconst trimmed = text.trim();\n\t\tif (!trimmed) return undefined;\n\t\ttry {\n\t\t\treturn as_record(JSON.parse(trimmed));\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t};\n\n\tconst json = parse_json(result.stdout) ?? parse_json(result.stderr);\n\tif (json?.decision === 'block') {\n\t\treturn typeof json.reason === 'string'\n\t\t\t? json.reason\n\t\t\t: 'Blocked by hook';\n\t}\n\tif (result.code === 2) {\n\t\treturn (\n\t\t\tresult.stderr.trim() ||\n\t\t\tresult.stdout.trim() ||\n\t\t\t'Blocked by hook'\n\t\t);\n\t}\n\treturn undefined;\n}\n\nexport function format_duration(elapsed_ms: number): string {\n\tif (elapsed_ms < 1000) return `${elapsed_ms}ms`;\n\treturn `${(elapsed_ms / 1000).toFixed(1)}s`;\n}\n\nexport function hook_name(command: string): string {\n\tconst sh_path_match = command.match(/[^\\s|;&]+\\.sh\\b/);\n\tif (sh_path_match) return basename(sh_path_match[0]);\n\tconst first_token = command.trim().split(/\\s+/)[0] ?? 'hook';\n\treturn basename(first_token);\n}\n","import { getAgentDir } from '@earendil-works/pi-coding-agent';\nimport {\n\tis_project_subject_trusted,\n\tread_project_trust_store,\n\ttrust_project_subject,\n\ttype ProjectTrustSubject,\n} from '@spences10/pi-project-trust';\nimport { join } from 'node:path';\n\nconst HOOKS_CONFIG_ENV = 'MY_PI_HOOKS_CONFIG';\n\nexport function default_hooks_trust_store_path(): string {\n\treturn join(getAgentDir(), 'trusted-hooks.json');\n}\n\nexport function create_hooks_config_trust_subject(\n\tproject_dir: string,\n\thash: string,\n): ProjectTrustSubject {\n\treturn {\n\t\tkind: 'hooks-config',\n\t\tid: project_dir,\n\t\tstore_key: project_dir,\n\t\thash,\n\t\tenv_key: HOOKS_CONFIG_ENV,\n\t\tprompt_title:\n\t\t\t'Project hook config can execute shell commands after tool use. Trust these hooks?',\n\t};\n}\n\nexport function is_hooks_config_trusted(\n\tproject_dir: string,\n\thash: string,\n\ttrust_store_path = default_hooks_trust_store_path(),\n): boolean {\n\tconst subject = create_hooks_config_trust_subject(\n\t\tproject_dir,\n\t\thash,\n\t);\n\tif (is_project_subject_trusted(subject, trust_store_path))\n\t\treturn true;\n\n\tconst legacy_entry = read_project_trust_store(trust_store_path)[\n\t\tproject_dir\n\t] as { project_dir?: unknown; hash?: unknown } | undefined;\n\treturn (\n\t\tlegacy_entry?.project_dir === project_dir &&\n\t\tlegacy_entry.hash === hash\n\t);\n}\n\nexport function trust_hooks_config(\n\tproject_dir: string,\n\thash: string,\n\ttrust_store_path = default_hooks_trust_store_path(),\n): void {\n\ttrust_project_subject(\n\t\tcreate_hooks_config_trust_subject(project_dir, hash),\n\t\ttrust_store_path,\n\t);\n}\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n\tresolve_project_trust,\n\ttype ProjectTrustSubject,\n} from '@spences10/pi-project-trust';\nimport { get_hooks_config_info } from './config.js';\nimport {\n\tdefault_hooks_trust_store_path,\n\tis_hooks_config_trusted,\n} from './trust.js';\nimport type { HooksConfigInfo } from './types.js';\n\nconst HOOKS_CONFIG_ENV = 'MY_PI_HOOKS_CONFIG';\n\nexport function create_hooks_trust_subject(\n\tinfo: HooksConfigInfo,\n): ProjectTrustSubject {\n\tconst source_lines = info.sources.map((source) => `- ${source}`);\n\tconst hook_lines =\n\t\tinfo.hooks.length === 0\n\t\t\t? ['- no valid command hooks detected']\n\t\t\t: info.hooks.map((hook) => {\n\t\t\t\t\tconst matcher = hook.matcher_text\n\t\t\t\t\t\t? ` matcher=${hook.matcher_text}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `- ${hook.event_name}${matcher}: ${hook.command}`;\n\t\t\t\t});\n\treturn {\n\t\tkind: 'hooks-config',\n\t\tid: info.project_dir,\n\t\tstore_key: info.project_dir,\n\t\thash: info.hash,\n\t\tenv_key: HOOKS_CONFIG_ENV,\n\t\tprompt_title:\n\t\t\t'Project hook config can execute shell commands after tool use. Trust these hooks?',\n\t\tsummary_lines: [\n\t\t\t'Sources:',\n\t\t\t...source_lines,\n\t\t\t'Commands:',\n\t\t\t...hook_lines,\n\t\t],\n\t\tchoices: {\n\t\t\tallow_once: 'Allow once for this session',\n\t\t\ttrust: 'Trust this repo until hook config changes',\n\t\t\tskip: 'Skip project hooks',\n\t\t},\n\t\theadless_warning: `Skipping untrusted hook config in ${info.project_dir}. Set ${HOOKS_CONFIG_ENV}=allow to enable hooks for this run.`,\n\t};\n}\n\nexport async function should_load_hooks_config(\n\tcwd: string,\n\tctx?: ExtensionContext,\n): Promise<boolean> {\n\tconst info = get_hooks_config_info(cwd);\n\tif (!info) return true;\n\tif (is_hooks_config_trusted(info.project_dir, info.hash))\n\t\treturn true;\n\n\tconst decision = await resolve_project_trust(\n\t\tcreate_hooks_trust_subject(info),\n\t\t{\n\t\t\thas_ui: ctx?.hasUI,\n\t\t\tselect: ctx?.hasUI\n\t\t\t\t? async (\n\t\t\t\t\t\tmessage: string,\n\t\t\t\t\t\tchoices: string[],\n\t\t\t\t\t): Promise<string> => {\n\t\t\t\t\t\tconst selected = await ctx.ui.select(message, choices);\n\t\t\t\t\t\treturn selected ?? '';\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tenv: process.env,\n\t\t\ttrust_store_path: default_hooks_trust_store_path(),\n\t\t},\n\t);\n\treturn (\n\t\tdecision.action === 'allow-once' ||\n\t\tdecision.action === 'trust-persisted'\n\t);\n}\n","// Hooks resolution — Claude Code style hook compatibility\n\nimport type {\n\tExtensionAPI,\n\tExtensionContext,\n\tExtensionFactory,\n\tToolCallEventResult,\n} from '@earendil-works/pi-coding-agent';\nimport { load_hooks } from './config.js';\nimport { build_hook_payload, matches_hook } from './payload.js';\nimport {\n\tformat_duration,\n\thook_block_reason,\n\thook_event_name_for_result,\n\thook_name,\n\trun_command_hook,\n} from './runner.js';\nimport { should_load_hooks_config } from './trust-gate.js';\nimport type { CommandRunResult, HookState } from './types.js';\n\nexport {\n\tas_record,\n\tcompile_matcher,\n\tcreate_hook,\n\tfind_nearest_git_root,\n\tfind_project_dir,\n\tget_hook_entries,\n\tget_hooks_config_info,\n\thas_hooks_config,\n\tis_file,\n\tload_hooks,\n\tparse_claude_settings_hooks,\n\tparse_simple_hooks_file,\n\tread_json_file,\n\tresolve_hook_command,\n\twalk_up_directories,\n} from './config.js';\nexport {\n\tbuild_hook_payload,\n\tbuild_tool_response,\n\textract_text_content,\n\tmatches_hook,\n\tnormalize_tool_input,\n\tto_claude_tool_name,\n} from './payload.js';\nexport {\n\tformat_duration,\n\thook_block_reason,\n\thook_event_name_for_result,\n\thook_name,\n\trun_command_hook,\n} from './runner.js';\nexport type {\n\tCommandRunResult,\n\tHookEventName,\n\tHooksConfigInfo,\n\tHookState,\n\tResolvedCommandHook,\n} from './types.js';\nexport interface HooksResolutionOptions {\n\tload_hooks?: (cwd: string) => HookState;\n\trun_command_hook?: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\tpayload: Record<string, unknown>,\n\t) => Promise<CommandRunResult>;\n}\n\nexport function create_hooks_resolution_extension(\n\toptions: HooksResolutionOptions = {},\n): ExtensionFactory {\n\tconst load_hooks_impl = options.load_hooks ?? load_hooks;\n\tconst run_command_hook_impl =\n\t\toptions.run_command_hook ?? run_command_hook;\n\n\treturn async function hooks_resolution(pi: ExtensionAPI) {\n\t\tlet state: HookState = {\n\t\t\tproject_dir: process.cwd(),\n\t\t\thooks: [],\n\t\t};\n\n\t\tconst refresh_hooks = async (\n\t\t\tcwd: string,\n\t\t\tctx?: ExtensionContext,\n\t\t) => {\n\t\t\tif (!(await should_load_hooks_config(cwd, ctx))) {\n\t\t\t\tstate = { project_dir: cwd, hooks: [] };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate = load_hooks_impl(cwd);\n\t\t};\n\n\t\tpi.on('session_start', async (_event, ctx) => {\n\t\t\tawait refresh_hooks(ctx.cwd, ctx);\n\t\t});\n\n\t\tpi.on(\n\t\t\t'tool_call',\n\t\t\tasync (\n\t\t\t\tevent,\n\t\t\t\tctx,\n\t\t\t): Promise<ToolCallEventResult | undefined> => {\n\t\t\t\tif (state.hooks.length === 0) return;\n\n\t\t\t\tconst matching_hooks = state.hooks.filter(\n\t\t\t\t\t(hook) =>\n\t\t\t\t\t\thook.event_name === 'PreToolUse' &&\n\t\t\t\t\t\tmatches_hook(hook, event.toolName),\n\t\t\t\t);\n\t\t\t\tif (matching_hooks.length === 0) return;\n\n\t\t\t\tconst payload = build_hook_payload(\n\t\t\t\t\tevent,\n\t\t\t\t\t'PreToolUse',\n\t\t\t\t\tctx,\n\t\t\t\t\tstate.project_dir,\n\t\t\t\t);\n\t\t\t\tconst executed_commands = new Set<string>();\n\n\t\t\t\tfor (const hook of matching_hooks) {\n\t\t\t\t\tif (executed_commands.has(hook.command)) continue;\n\t\t\t\t\texecuted_commands.add(hook.command);\n\n\t\t\t\t\tconst result = await run_command_hook_impl(\n\t\t\t\t\t\thook.command,\n\t\t\t\t\t\tstate.project_dir,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t);\n\t\t\t\t\tconst reason = hook_block_reason(result);\n\t\t\t\t\tif (reason) return { block: true, reason };\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tpi.on('tool_result', async (event, ctx) => {\n\t\t\tif (state.hooks.length === 0) return;\n\n\t\t\tconst event_name = hook_event_name_for_result(event);\n\t\t\tconst matching_hooks = state.hooks.filter(\n\t\t\t\t(hook) =>\n\t\t\t\t\thook.event_name === event_name &&\n\t\t\t\t\tmatches_hook(hook, event.toolName),\n\t\t\t);\n\t\t\tif (matching_hooks.length === 0) return;\n\n\t\t\tconst payload = build_hook_payload(\n\t\t\t\tevent,\n\t\t\t\tevent_name,\n\t\t\t\tctx,\n\t\t\t\tstate.project_dir,\n\t\t\t);\n\t\t\tconst executed_commands = new Set<string>();\n\n\t\t\tfor (const hook of matching_hooks) {\n\t\t\t\tif (executed_commands.has(hook.command)) continue;\n\t\t\t\texecuted_commands.add(hook.command);\n\n\t\t\t\tconst result = await run_command_hook_impl(\n\t\t\t\t\thook.command,\n\t\t\t\t\tstate.project_dir,\n\t\t\t\t\tpayload,\n\t\t\t\t);\n\t\t\t\tconst name = hook_name(hook.command);\n\t\t\t\tconst duration = format_duration(result.elapsed_ms);\n\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tif (result.code === 0) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t`Hook \\`${name}\\` ran (${duration})`,\n\t\t\t\t\t\t\t'info',\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst error_line =\n\t\t\t\t\t\t\tresult.stderr.trim() ||\n\t\t\t\t\t\t\tresult.stdout.trim() ||\n\t\t\t\t\t\t\t`exit code ${result.code}`;\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t`Hook \\`${name}\\` failed (${duration}): ${error_line}`,\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t};\n}\n\nexport default create_hooks_resolution_extension();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hooks-resolution-C1fO4fuc.js","names":["create_child_process_env","create_shared_child_process_env","create_child_process_env","HOOKS_CONFIG_ENV"],"sources":["../src/extensions/hooks-resolution/config.ts","../src/extensions/hooks-resolution/payload.ts","../src/extensions/hooks-resolution/env.ts","../src/extensions/hooks-resolution/runner.ts","../src/extensions/hooks-resolution/trust.ts","../src/extensions/hooks-resolution/trust-gate.ts","../src/extensions/hooks-resolution/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport type {\n\tHookEventName,\n\tHooksConfigInfo,\n\tHookState,\n\tJsonValue,\n\tResolvedCommandHook,\n} from './types.js';\n\nexport function is_file(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function as_record(\n\tvalue: unknown,\n): Record<string, unknown> | undefined {\n\tif (typeof value !== 'object' || value === null) return undefined;\n\treturn value as Record<string, unknown>;\n}\n\nexport function walk_up_directories(\n\tstart_dir: string,\n\tstop_dir?: string,\n): string[] {\n\tconst directories: string[] = [];\n\tconst has_stop_dir = stop_dir !== undefined;\n\tlet current = resolve(start_dir);\n\tlet parent = dirname(current);\n\tlet reached_stop_dir = has_stop_dir && current === stop_dir;\n\tlet reached_filesystem_root = parent === current;\n\n\tdirectories.push(current);\n\twhile (!reached_stop_dir && !reached_filesystem_root) {\n\t\tcurrent = parent;\n\t\tparent = dirname(current);\n\t\treached_stop_dir = has_stop_dir && current === stop_dir;\n\t\treached_filesystem_root = parent === current;\n\t\tdirectories.push(current);\n\t}\n\n\treturn directories;\n}\n\nexport function find_nearest_git_root(\n\tstart_dir: string,\n): string | undefined {\n\tfor (const directory of walk_up_directories(start_dir)) {\n\t\tif (existsSync(join(directory, '.git'))) {\n\t\t\treturn directory;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function has_hooks_config(directory: string): boolean {\n\treturn (\n\t\tis_file(join(directory, '.claude', 'settings.json')) ||\n\t\tis_file(join(directory, '.rulesync', 'hooks.json')) ||\n\t\tis_file(join(directory, '.pi', 'hooks.json'))\n\t);\n}\n\nexport function find_project_dir(cwd: string): string {\n\tconst git_root = find_nearest_git_root(cwd);\n\tfor (const directory of walk_up_directories(cwd, git_root)) {\n\t\tif (has_hooks_config(directory)) {\n\t\t\treturn directory;\n\t\t}\n\t}\n\treturn git_root ?? resolve(cwd);\n}\n\nexport function read_json_file(path: string): JsonValue | undefined {\n\tif (!is_file(path)) return undefined;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, 'utf8')) as JsonValue;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function resolve_hook_command(\n\tcommand: string,\n\tproject_dir: string,\n): string {\n\treturn command.replace(/\\$CLAUDE_PROJECT_DIR\\b/g, project_dir);\n}\n\nexport function compile_matcher(\n\tmatcher_text: string | undefined,\n): RegExp | undefined {\n\tif (matcher_text === undefined) return undefined;\n\ttry {\n\t\treturn new RegExp(matcher_text);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function create_hook(\n\tevent_name: HookEventName,\n\tmatcher_text: string | undefined,\n\tcommand: string,\n\tsource: string,\n\tproject_dir: string,\n): ResolvedCommandHook | undefined {\n\tconst matcher = compile_matcher(matcher_text);\n\tif (matcher_text !== undefined && matcher === undefined)\n\t\treturn undefined;\n\treturn {\n\t\tevent_name,\n\t\tmatcher,\n\t\tmatcher_text,\n\t\tcommand: resolve_hook_command(command, project_dir),\n\t\tsource,\n\t};\n}\n\nexport function get_hook_entries(\n\thooks_record: Record<string, unknown>,\n\tevent_name: HookEventName,\n): unknown[] {\n\tconst keys =\n\t\tevent_name === 'PreToolUse'\n\t\t\t? ['PreToolUse', 'preToolUse']\n\t\t\t: event_name === 'PostToolUse'\n\t\t\t\t? ['PostToolUse', 'postToolUse']\n\t\t\t\t: ['PostToolUseFailure', 'postToolUseFailure'];\n\n\tfor (const key of keys) {\n\t\tconst value = hooks_record[key];\n\t\tif (Array.isArray(value)) return value;\n\t}\n\treturn [];\n}\n\nexport function parse_claude_settings_hooks(\n\tconfig: unknown,\n\tsource: string,\n\tproject_dir: string,\n): ResolvedCommandHook[] {\n\tconst root = as_record(config);\n\tconst hooks_root = root ? as_record(root.hooks) : undefined;\n\tif (!hooks_root) return [];\n\n\tconst hooks: ResolvedCommandHook[] = [];\n\tconst events: HookEventName[] = [\n\t\t'PreToolUse',\n\t\t'PostToolUse',\n\t\t'PostToolUseFailure',\n\t];\n\n\tfor (const event_name of events) {\n\t\tconst entries = get_hook_entries(hooks_root, event_name);\n\t\tfor (const entry of entries) {\n\t\t\tconst entry_record = as_record(entry);\n\t\t\tif (!entry_record || !Array.isArray(entry_record.hooks))\n\t\t\t\tcontinue;\n\n\t\t\tconst matcher_text =\n\t\t\t\ttypeof entry_record.matcher === 'string'\n\t\t\t\t\t? entry_record.matcher\n\t\t\t\t\t: undefined;\n\t\t\tfor (const nested_hook of entry_record.hooks) {\n\t\t\t\tconst nested_record = as_record(nested_hook);\n\t\t\t\tif (!nested_record) continue;\n\t\t\t\tif (nested_record.type !== 'command') continue;\n\t\t\t\tif (typeof nested_record.command !== 'string') continue;\n\n\t\t\t\tconst hook = create_hook(\n\t\t\t\t\tevent_name,\n\t\t\t\t\tmatcher_text,\n\t\t\t\t\tnested_record.command,\n\t\t\t\t\tsource,\n\t\t\t\t\tproject_dir,\n\t\t\t\t);\n\t\t\t\tif (hook) hooks.push(hook);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn hooks;\n}\n\nexport function parse_simple_hooks_file(\n\tconfig: unknown,\n\tsource: string,\n\tproject_dir: string,\n): ResolvedCommandHook[] {\n\tconst root = as_record(config);\n\tconst hooks_root = root ? as_record(root.hooks) : undefined;\n\tif (!hooks_root) return [];\n\n\tconst hooks: ResolvedCommandHook[] = [];\n\tconst events: HookEventName[] = [\n\t\t'PreToolUse',\n\t\t'PostToolUse',\n\t\t'PostToolUseFailure',\n\t];\n\n\tfor (const event_name of events) {\n\t\tconst entries = get_hook_entries(hooks_root, event_name);\n\t\tfor (const entry of entries) {\n\t\t\tconst entry_record = as_record(entry);\n\t\t\tif (!entry_record || typeof entry_record.command !== 'string') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst matcher_text =\n\t\t\t\ttypeof entry_record.matcher === 'string'\n\t\t\t\t\t? entry_record.matcher\n\t\t\t\t\t: undefined;\n\t\t\tconst hook = create_hook(\n\t\t\t\tevent_name,\n\t\t\t\tmatcher_text,\n\t\t\t\tentry_record.command,\n\t\t\t\tsource,\n\t\t\t\tproject_dir,\n\t\t\t);\n\t\t\tif (hook) hooks.push(hook);\n\t\t}\n\t}\n\n\treturn hooks;\n}\n\nfunction hook_config_paths(project_dir: string): string[] {\n\treturn [\n\t\tjoin(project_dir, '.claude', 'settings.json'),\n\t\tjoin(project_dir, '.rulesync', 'hooks.json'),\n\t\tjoin(project_dir, '.pi', 'hooks.json'),\n\t];\n}\n\nfunction parse_hooks_config_file(\n\tpath: string,\n\tproject_dir: string,\n): ResolvedCommandHook[] {\n\tconst config = read_json_file(path);\n\tif (config === undefined) return [];\n\tif (path.endsWith(join('.claude', 'settings.json'))) {\n\t\treturn parse_claude_settings_hooks(config, path, project_dir);\n\t}\n\treturn parse_simple_hooks_file(config, path, project_dir);\n}\n\nexport function load_hooks(cwd: string): HookState {\n\tconst project_dir = find_project_dir(cwd);\n\tconst hooks = hook_config_paths(project_dir).flatMap((path) =>\n\t\tparse_hooks_config_file(path, project_dir),\n\t);\n\n\treturn { project_dir, hooks };\n}\n\nexport function get_hooks_config_info(\n\tcwd: string,\n): HooksConfigInfo | undefined {\n\tconst project_dir = find_project_dir(cwd);\n\tconst sources = hook_config_paths(project_dir).filter(is_file);\n\tif (sources.length === 0) return undefined;\n\n\tconst hash = createHash('sha256');\n\tfor (const source of sources) {\n\t\thash.update(source);\n\t\thash.update('\\0');\n\t\thash.update(readFileSync(source, 'utf8'));\n\t\thash.update('\\0');\n\t}\n\n\tconst hooks = sources\n\t\t.flatMap((source) => parse_hooks_config_file(source, project_dir))\n\t\t.map((hook) => ({\n\t\t\tevent_name: hook.event_name,\n\t\t\tmatcher_text: hook.matcher_text,\n\t\t\tcommand: hook.command,\n\t\t\tsource: hook.source,\n\t\t}));\n\n\treturn {\n\t\tproject_dir,\n\t\thash: hash.digest('hex'),\n\t\tsources,\n\t\thooks,\n\t};\n}\n","import type {\n\tExtensionContext,\n\tToolCallEvent,\n\tToolResultEvent,\n} from '@earendil-works/pi-coding-agent';\nimport type { HookEventName, ResolvedCommandHook } from './types.js';\n\nexport function to_claude_tool_name(tool_name: string): string {\n\tif (tool_name === 'ls') return 'LS';\n\tif (tool_name.length === 0) return tool_name;\n\treturn tool_name[0].toUpperCase() + tool_name.slice(1);\n}\n\nexport function matches_hook(\n\thook: ResolvedCommandHook,\n\ttool_name: string,\n): boolean {\n\tif (!hook.matcher) return true;\n\n\tconst claude_tool_name = to_claude_tool_name(tool_name);\n\thook.matcher.lastIndex = 0;\n\tif (hook.matcher.test(tool_name)) return true;\n\n\thook.matcher.lastIndex = 0;\n\treturn hook.matcher.test(claude_tool_name);\n}\n\nexport function extract_text_content(content: unknown): string {\n\tif (!Array.isArray(content)) return '';\n\n\tconst parts: string[] = [];\n\tfor (const item of content) {\n\t\tif (!item || typeof item !== 'object') continue;\n\t\tconst item_record = item as Record<string, unknown>;\n\t\tif (\n\t\t\titem_record.type === 'text' &&\n\t\t\ttypeof item_record.text === 'string'\n\t\t) {\n\t\t\tparts.push(item_record.text);\n\t\t}\n\t}\n\n\treturn parts.join('\\n');\n}\n\nexport function normalize_tool_input(\n\tinput: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst normalized: Record<string, unknown> = { ...input };\n\tconst path_value =\n\t\ttypeof input.path === 'string' ? input.path : undefined;\n\tif (path_value !== undefined) {\n\t\tnormalized.file_path = path_value;\n\t\tnormalized.filePath = path_value;\n\t}\n\treturn normalized;\n}\n\nexport function build_tool_response(\n\tevent: ToolResultEvent,\n\tnormalized_input: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst response: Record<string, unknown> = {\n\t\tis_error: event.isError,\n\t\tisError: event.isError,\n\t\tcontent: event.content,\n\t\ttext: extract_text_content(event.content),\n\t\tdetails: event.details ?? null,\n\t};\n\n\tconst file_path =\n\t\ttypeof normalized_input.file_path === 'string'\n\t\t\t? normalized_input.file_path\n\t\t\t: undefined;\n\tif (file_path !== undefined) {\n\t\tresponse.file_path = file_path;\n\t\tresponse.filePath = file_path;\n\t}\n\n\treturn response;\n}\n\nexport function build_hook_payload(\n\tevent: ToolCallEvent | ToolResultEvent,\n\tevent_name: HookEventName,\n\tctx: ExtensionContext,\n\tproject_dir: string,\n): Record<string, unknown> {\n\tconst normalized_input = normalize_tool_input(\n\t\tevent.input as Record<string, unknown>,\n\t);\n\tconst session_id =\n\t\tctx.sessionManager.getSessionFile() ?? 'ephemeral';\n\tconst payload: Record<string, unknown> = {\n\t\tsession_id,\n\t\tcwd: ctx.cwd,\n\t\tclaude_project_dir: project_dir,\n\t\thook_event_name: event_name,\n\t\ttool_name: to_claude_tool_name(event.toolName),\n\t\ttool_call_id: event.toolCallId,\n\t\ttool_input: normalized_input,\n\t};\n\n\tif ('content' in event) {\n\t\tpayload.tool_response = build_tool_response(\n\t\t\tevent,\n\t\t\tnormalized_input,\n\t\t);\n\t}\n\n\treturn payload;\n}\n","import { create_child_process_env as create_shared_child_process_env } from '@spences10/pi-child-env';\n\nexport function create_child_process_env(\n\texplicit_env: Record<string, string> = {},\n\tsource_env: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n\treturn create_shared_child_process_env({\n\t\tprofile: 'hooks',\n\t\texplicit_env,\n\t\tsource_env,\n\t});\n}\n","import type { ToolResultEvent } from '@earendil-works/pi-coding-agent';\nimport { spawn } from 'node:child_process';\nimport { basename } from 'node:path';\nimport { as_record } from './config.js';\nimport { create_child_process_env } from './env.js';\nimport type { CommandRunResult, HookEventName } from './types.js';\n\nconst HOOK_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport async function run_command_hook(\n\tcommand: string,\n\tcwd: string,\n\tpayload: Record<string, unknown>,\n): Promise<CommandRunResult> {\n\treturn await new Promise((resolve) => {\n\t\tconst started_at = Date.now();\n\t\tconst child = spawn('bash', ['-lc', command], {\n\t\t\tcwd,\n\t\t\tenv: create_child_process_env({ CLAUDE_PROJECT_DIR: cwd }),\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\t\tlet timed_out = false;\n\t\tlet resolved = false;\n\n\t\tconst finish = (code: number) => {\n\t\t\tif (resolved) return;\n\t\t\tresolved = true;\n\t\t\tresolve({\n\t\t\t\tcode,\n\t\t\t\tstdout,\n\t\t\t\tstderr,\n\t\t\t\telapsed_ms: Date.now() - started_at,\n\t\t\t\ttimed_out,\n\t\t\t});\n\t\t};\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\ttimed_out = true;\n\t\t\tchild.kill('SIGTERM');\n\t\t\tconst kill_timer = setTimeout(() => {\n\t\t\t\tchild.kill('SIGKILL');\n\t\t\t}, 1000);\n\t\t\t(\n\t\t\t\tkill_timer as NodeJS.Timeout & { unref?: () => void }\n\t\t\t).unref?.();\n\t\t}, HOOK_TIMEOUT_MS);\n\t\t(timeout as NodeJS.Timeout & { unref?: () => void }).unref?.();\n\n\t\tchild.stdout.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString('utf8');\n\t\t});\n\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString('utf8');\n\t\t});\n\n\t\tchild.on('error', (error) => {\n\t\t\tclearTimeout(timeout);\n\t\t\tstderr += `${error.message}\\n`;\n\t\t\tfinish(-1);\n\t\t});\n\n\t\tchild.on('close', (code) => {\n\t\t\tclearTimeout(timeout);\n\t\t\tfinish(code ?? -1);\n\t\t});\n\n\t\ttry {\n\t\t\tchild.stdin.write(JSON.stringify(payload));\n\t\t\tchild.stdin.end();\n\t\t} catch (error) {\n\t\t\tstderr += `${error instanceof Error ? error.message : String(error)}\\n`;\n\t\t}\n\t});\n}\n\nexport function hook_event_name_for_result(\n\tevent: ToolResultEvent,\n): HookEventName {\n\treturn event.isError ? 'PostToolUseFailure' : 'PostToolUse';\n}\n\nexport function hook_block_reason(\n\tresult: CommandRunResult,\n): string | undefined {\n\tconst parse_json = (\n\t\ttext: string,\n\t): Record<string, unknown> | undefined => {\n\t\tconst trimmed = text.trim();\n\t\tif (!trimmed) return undefined;\n\t\ttry {\n\t\t\treturn as_record(JSON.parse(trimmed));\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t};\n\n\tconst json = parse_json(result.stdout) ?? parse_json(result.stderr);\n\tif (json?.decision === 'block') {\n\t\treturn typeof json.reason === 'string'\n\t\t\t? json.reason\n\t\t\t: 'Blocked by hook';\n\t}\n\tif (result.code === 2) {\n\t\treturn (\n\t\t\tresult.stderr.trim() ||\n\t\t\tresult.stdout.trim() ||\n\t\t\t'Blocked by hook'\n\t\t);\n\t}\n\treturn undefined;\n}\n\nexport function format_duration(elapsed_ms: number): string {\n\tif (elapsed_ms < 1000) return `${elapsed_ms}ms`;\n\treturn `${(elapsed_ms / 1000).toFixed(1)}s`;\n}\n\nexport function hook_name(command: string): string {\n\tconst sh_path_match = command.match(/[^\\s|;&]+\\.sh\\b/);\n\tif (sh_path_match) return basename(sh_path_match[0]);\n\tconst first_token = command.trim().split(/\\s+/)[0] ?? 'hook';\n\treturn basename(first_token);\n}\n","import { getAgentDir } from '@earendil-works/pi-coding-agent';\nimport {\n\tis_project_subject_trusted,\n\tread_project_trust_store,\n\ttrust_project_subject,\n\ttype ProjectTrustSubject,\n} from '@spences10/pi-project-trust';\nimport { join } from 'node:path';\n\nconst HOOKS_CONFIG_ENV = 'MY_PI_HOOKS_CONFIG';\n\nexport function default_hooks_trust_store_path(): string {\n\treturn join(getAgentDir(), 'trusted-hooks.json');\n}\n\nexport function create_hooks_config_trust_subject(\n\tproject_dir: string,\n\thash: string,\n): ProjectTrustSubject {\n\treturn {\n\t\tkind: 'hooks-config',\n\t\tid: project_dir,\n\t\tstore_key: project_dir,\n\t\thash,\n\t\tenv_key: HOOKS_CONFIG_ENV,\n\t\tprompt_title:\n\t\t\t'Project hook config can execute shell commands after tool use. Trust these hooks?',\n\t};\n}\n\nexport function is_hooks_config_trusted(\n\tproject_dir: string,\n\thash: string,\n\ttrust_store_path = default_hooks_trust_store_path(),\n): boolean {\n\tconst subject = create_hooks_config_trust_subject(\n\t\tproject_dir,\n\t\thash,\n\t);\n\tif (is_project_subject_trusted(subject, trust_store_path))\n\t\treturn true;\n\n\tconst legacy_entry = read_project_trust_store(trust_store_path)[\n\t\tproject_dir\n\t] as { project_dir?: unknown; hash?: unknown } | undefined;\n\treturn (\n\t\tlegacy_entry?.project_dir === project_dir &&\n\t\tlegacy_entry.hash === hash\n\t);\n}\n\nexport function trust_hooks_config(\n\tproject_dir: string,\n\thash: string,\n\ttrust_store_path = default_hooks_trust_store_path(),\n): void {\n\ttrust_project_subject(\n\t\tcreate_hooks_config_trust_subject(project_dir, hash),\n\t\ttrust_store_path,\n\t);\n}\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n\tresolve_project_trust,\n\ttype ProjectTrustSubject,\n} from '@spences10/pi-project-trust';\nimport { get_hooks_config_info } from './config.js';\nimport {\n\tdefault_hooks_trust_store_path,\n\tis_hooks_config_trusted,\n} from './trust.js';\nimport type { HooksConfigInfo } from './types.js';\n\nconst HOOKS_CONFIG_ENV = 'MY_PI_HOOKS_CONFIG';\n\nexport function create_hooks_trust_subject(\n\tinfo: HooksConfigInfo,\n): ProjectTrustSubject {\n\tconst source_lines = info.sources.map((source) => `- ${source}`);\n\tconst hook_lines =\n\t\tinfo.hooks.length === 0\n\t\t\t? ['- no valid command hooks detected']\n\t\t\t: info.hooks.map((hook) => {\n\t\t\t\t\tconst matcher = hook.matcher_text\n\t\t\t\t\t\t? ` matcher=${hook.matcher_text}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `- ${hook.event_name}${matcher}: ${hook.command}`;\n\t\t\t\t});\n\treturn {\n\t\tkind: 'hooks-config',\n\t\tid: info.project_dir,\n\t\tstore_key: info.project_dir,\n\t\thash: info.hash,\n\t\tenv_key: HOOKS_CONFIG_ENV,\n\t\tprompt_title:\n\t\t\t'Project hook config can execute shell commands after tool use. Trust these hooks?',\n\t\tsummary_lines: [\n\t\t\t'Sources:',\n\t\t\t...source_lines,\n\t\t\t'Commands:',\n\t\t\t...hook_lines,\n\t\t],\n\t\tchoices: {\n\t\t\tallow_once: 'Allow once for this session',\n\t\t\ttrust: 'Trust this repo until hook config changes',\n\t\t\tskip: 'Skip project hooks',\n\t\t},\n\t\theadless_warning: `Skipping untrusted hook config in ${info.project_dir}. Set ${HOOKS_CONFIG_ENV}=allow to enable hooks for this run.`,\n\t};\n}\n\nexport async function should_load_hooks_config(\n\tcwd: string,\n\tctx?: ExtensionContext,\n): Promise<boolean> {\n\tconst info = get_hooks_config_info(cwd);\n\tif (!info) return true;\n\tif (is_hooks_config_trusted(info.project_dir, info.hash))\n\t\treturn true;\n\n\tconst decision = await resolve_project_trust(\n\t\tcreate_hooks_trust_subject(info),\n\t\t{\n\t\t\thas_ui: ctx?.hasUI,\n\t\t\tselect: ctx?.hasUI\n\t\t\t\t? async (\n\t\t\t\t\t\tmessage: string,\n\t\t\t\t\t\tchoices: string[],\n\t\t\t\t\t): Promise<string> => {\n\t\t\t\t\t\tconst selected = await ctx.ui.select(message, choices);\n\t\t\t\t\t\treturn selected ?? '';\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tenv: process.env,\n\t\t\ttrust_store_path: default_hooks_trust_store_path(),\n\t\t},\n\t);\n\treturn (\n\t\tdecision.action === 'allow-once' ||\n\t\tdecision.action === 'trust-persisted'\n\t);\n}\n","// Hooks resolution — Claude Code style hook compatibility\n\nimport type {\n\tExtensionAPI,\n\tExtensionContext,\n\tExtensionFactory,\n\tToolCallEventResult,\n} from '@earendil-works/pi-coding-agent';\nimport { load_hooks } from './config.js';\nimport { build_hook_payload, matches_hook } from './payload.js';\nimport {\n\tformat_duration,\n\thook_block_reason,\n\thook_event_name_for_result,\n\thook_name,\n\trun_command_hook,\n} from './runner.js';\nimport { should_load_hooks_config } from './trust-gate.js';\nimport type { CommandRunResult, HookState } from './types.js';\n\nexport {\n\tas_record,\n\tcompile_matcher,\n\tcreate_hook,\n\tfind_nearest_git_root,\n\tfind_project_dir,\n\tget_hook_entries,\n\tget_hooks_config_info,\n\thas_hooks_config,\n\tis_file,\n\tload_hooks,\n\tparse_claude_settings_hooks,\n\tparse_simple_hooks_file,\n\tread_json_file,\n\tresolve_hook_command,\n\twalk_up_directories,\n} from './config.js';\nexport {\n\tbuild_hook_payload,\n\tbuild_tool_response,\n\textract_text_content,\n\tmatches_hook,\n\tnormalize_tool_input,\n\tto_claude_tool_name,\n} from './payload.js';\nexport {\n\tformat_duration,\n\thook_block_reason,\n\thook_event_name_for_result,\n\thook_name,\n\trun_command_hook,\n} from './runner.js';\nexport type {\n\tCommandRunResult,\n\tHookEventName,\n\tHooksConfigInfo,\n\tHookState,\n\tResolvedCommandHook,\n} from './types.js';\nexport interface HooksResolutionOptions {\n\tload_hooks?: (cwd: string) => HookState;\n\trun_command_hook?: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\tpayload: Record<string, unknown>,\n\t) => Promise<CommandRunResult>;\n}\n\nexport function create_hooks_resolution_extension(\n\toptions: HooksResolutionOptions = {},\n): ExtensionFactory {\n\tconst load_hooks_impl = options.load_hooks ?? load_hooks;\n\tconst run_command_hook_impl =\n\t\toptions.run_command_hook ?? run_command_hook;\n\n\treturn async function hooks_resolution(pi: ExtensionAPI) {\n\t\tlet state: HookState = {\n\t\t\tproject_dir: process.cwd(),\n\t\t\thooks: [],\n\t\t};\n\n\t\tconst refresh_hooks = async (\n\t\t\tcwd: string,\n\t\t\tctx?: ExtensionContext,\n\t\t) => {\n\t\t\tif (!(await should_load_hooks_config(cwd, ctx))) {\n\t\t\t\tstate = { project_dir: cwd, hooks: [] };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate = load_hooks_impl(cwd);\n\t\t};\n\n\t\tpi.on('session_start', async (_event, ctx) => {\n\t\t\tawait refresh_hooks(ctx.cwd, ctx);\n\t\t});\n\n\t\tpi.on(\n\t\t\t'tool_call',\n\t\t\tasync (\n\t\t\t\tevent,\n\t\t\t\tctx,\n\t\t\t): Promise<ToolCallEventResult | undefined> => {\n\t\t\t\tif (state.hooks.length === 0) return;\n\n\t\t\t\tconst matching_hooks = state.hooks.filter(\n\t\t\t\t\t(hook) =>\n\t\t\t\t\t\thook.event_name === 'PreToolUse' &&\n\t\t\t\t\t\tmatches_hook(hook, event.toolName),\n\t\t\t\t);\n\t\t\t\tif (matching_hooks.length === 0) return;\n\n\t\t\t\tconst payload = build_hook_payload(\n\t\t\t\t\tevent,\n\t\t\t\t\t'PreToolUse',\n\t\t\t\t\tctx,\n\t\t\t\t\tstate.project_dir,\n\t\t\t\t);\n\t\t\t\tconst executed_commands = new Set<string>();\n\n\t\t\t\tfor (const hook of matching_hooks) {\n\t\t\t\t\tif (executed_commands.has(hook.command)) continue;\n\t\t\t\t\texecuted_commands.add(hook.command);\n\n\t\t\t\t\tconst result = await run_command_hook_impl(\n\t\t\t\t\t\thook.command,\n\t\t\t\t\t\tstate.project_dir,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t);\n\t\t\t\t\tconst reason = hook_block_reason(result);\n\t\t\t\t\tif (reason) return { block: true, reason };\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tpi.on('tool_result', async (event, ctx) => {\n\t\t\tif (state.hooks.length === 0) return;\n\n\t\t\tconst event_name = hook_event_name_for_result(event);\n\t\t\tconst matching_hooks = state.hooks.filter(\n\t\t\t\t(hook) =>\n\t\t\t\t\thook.event_name === event_name &&\n\t\t\t\t\tmatches_hook(hook, event.toolName),\n\t\t\t);\n\t\t\tif (matching_hooks.length === 0) return;\n\n\t\t\tconst payload = build_hook_payload(\n\t\t\t\tevent,\n\t\t\t\tevent_name,\n\t\t\t\tctx,\n\t\t\t\tstate.project_dir,\n\t\t\t);\n\t\t\tconst executed_commands = new Set<string>();\n\n\t\t\tfor (const hook of matching_hooks) {\n\t\t\t\tif (executed_commands.has(hook.command)) continue;\n\t\t\t\texecuted_commands.add(hook.command);\n\n\t\t\t\tconst result = await run_command_hook_impl(\n\t\t\t\t\thook.command,\n\t\t\t\t\tstate.project_dir,\n\t\t\t\t\tpayload,\n\t\t\t\t);\n\t\t\t\tconst name = hook_name(hook.command);\n\t\t\t\tconst duration = format_duration(result.elapsed_ms);\n\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tif (result.code === 0) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t`Hook \\`${name}\\` ran (${duration})`,\n\t\t\t\t\t\t\t'info',\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst error_line =\n\t\t\t\t\t\t\tresult.stderr.trim() ||\n\t\t\t\t\t\t\tresult.stdout.trim() ||\n\t\t\t\t\t\t\t`exit code ${result.code}`;\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t`Hook \\`${name}\\` failed (${duration}): ${error_line}`,\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t};\n}\n\nexport default create_hooks_resolution_extension();\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as BUILTIN_EXTENSIONS } from "./builtin-registry-
|
|
2
|
+
import { t as BUILTIN_EXTENSIONS } from "./builtin-registry-CTncHotU.js";
|
|
3
3
|
import { defineCommand, renderUsage, runMain } from "citty";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import { clampThinkingLevel, getSupportedThinkingLevels } from "@earendil-works/pi-ai";
|
|
4
3
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
5
4
|
import { show_settings_modal } from "@spences10/pi-tui-modal";
|
|
6
|
-
import
|
|
5
|
+
import "@spences10/pi-footer";
|
|
7
6
|
//#region src/extensions/prompt-presets/catalog.ts
|
|
8
7
|
function get_prompt_source_label(source) {
|
|
9
8
|
switch (source) {
|
|
@@ -99,147 +98,8 @@ function get_footer_prompt_status(active_base_name, active_layers) {
|
|
|
99
98
|
if (!active_base_name && active_layers.size === 0) return;
|
|
100
99
|
return `prompt:${active_base_name ?? "none"}${active_layers.size > 0 ? ` +${active_layers.size}` : ""}`;
|
|
101
100
|
}
|
|
102
|
-
function sanitize_status_text(text) {
|
|
103
|
-
return text.replace(/[\r\n\t]/g, " ").replace(/ +/g, " ").trim();
|
|
104
|
-
}
|
|
105
|
-
function format_token_count(count) {
|
|
106
|
-
if (count < 1e3) return count.toString();
|
|
107
|
-
if (count < 1e4) return `${(count / 1e3).toFixed(1)}k`;
|
|
108
|
-
if (count < 1e6) return `${Math.round(count / 1e3)}k`;
|
|
109
|
-
if (count < 1e7) return `${(count / 1e6).toFixed(1)}M`;
|
|
110
|
-
return `${Math.round(count / 1e6)}M`;
|
|
111
|
-
}
|
|
112
|
-
function render_footer_status_line(theme, width, left_items, right_item) {
|
|
113
|
-
const left = sanitize_status_text(left_items.join(" "));
|
|
114
|
-
const right = right_item ? sanitize_status_text(right_item) : "";
|
|
115
|
-
if (!left && !right) return void 0;
|
|
116
|
-
if (!right) return truncateToWidth(theme.fg("dim", left), width, theme.fg("dim", "..."));
|
|
117
|
-
if (!left) {
|
|
118
|
-
const themed_right = theme.fg("dim", right);
|
|
119
|
-
const right_width = visibleWidth(themed_right);
|
|
120
|
-
return right_width >= width ? truncateToWidth(themed_right, width, theme.fg("dim", "...")) : `${" ".repeat(width - right_width)}${themed_right}`;
|
|
121
|
-
}
|
|
122
|
-
const right_width = visibleWidth(right);
|
|
123
|
-
if (right_width >= width) return truncateToWidth(theme.fg("dim", right), width, theme.fg("dim", "..."));
|
|
124
|
-
const min_gap = 1;
|
|
125
|
-
const truncated_left = truncateToWidth(left, Math.max(0, width - right_width - min_gap), "...");
|
|
126
|
-
const left_width = visibleWidth(truncated_left);
|
|
127
|
-
const gap = Math.max(min_gap, width - left_width - right_width);
|
|
128
|
-
return theme.fg("dim", truncated_left) + " ".repeat(gap) + theme.fg("dim", right);
|
|
129
|
-
}
|
|
130
|
-
const VALID_THINKING_LEVELS = new Set([
|
|
131
|
-
"off",
|
|
132
|
-
"minimal",
|
|
133
|
-
"low",
|
|
134
|
-
"medium",
|
|
135
|
-
"high",
|
|
136
|
-
"xhigh"
|
|
137
|
-
]);
|
|
138
|
-
function is_model_thinking_level(level) {
|
|
139
|
-
return VALID_THINKING_LEVELS.has(level);
|
|
140
|
-
}
|
|
141
|
-
function get_default_footer_thinking_level(model) {
|
|
142
|
-
if (!model?.reasoning) return "off";
|
|
143
|
-
return clampThinkingLevel(model, "medium");
|
|
144
|
-
}
|
|
145
|
-
function get_current_thinking_level(ctx) {
|
|
146
|
-
const entries = ctx.sessionManager.getEntries();
|
|
147
|
-
for (let i = entries.length - 1; i >= 0; i--) {
|
|
148
|
-
const entry = entries[i];
|
|
149
|
-
if (entry.type === "thinking_level_change" && typeof entry.thinkingLevel === "string" && is_model_thinking_level(entry.thinkingLevel)) {
|
|
150
|
-
if (!ctx.model?.reasoning) return "off";
|
|
151
|
-
return getSupportedThinkingLevels(ctx.model).includes(entry.thinkingLevel) ? entry.thinkingLevel : clampThinkingLevel(ctx.model, entry.thinkingLevel);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return get_default_footer_thinking_level(ctx.model);
|
|
155
|
-
}
|
|
156
|
-
function render_footer_lines(ctx, theme, footer_data, width, active_base_name, active_layers) {
|
|
157
|
-
let total_input = 0;
|
|
158
|
-
let total_output = 0;
|
|
159
|
-
let total_cache_read = 0;
|
|
160
|
-
let total_cache_write = 0;
|
|
161
|
-
let total_cost = 0;
|
|
162
|
-
for (const entry of ctx.sessionManager.getEntries()) if (entry.type === "message" && entry.message.role === "assistant") {
|
|
163
|
-
total_input += entry.message.usage.input;
|
|
164
|
-
total_output += entry.message.usage.output;
|
|
165
|
-
total_cache_read += entry.message.usage.cacheRead;
|
|
166
|
-
total_cache_write += entry.message.usage.cacheWrite;
|
|
167
|
-
total_cost += entry.message.usage.cost.total;
|
|
168
|
-
}
|
|
169
|
-
const context_usage = ctx.getContextUsage();
|
|
170
|
-
const context_window = context_usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;
|
|
171
|
-
const context_percent_value = context_usage?.percent ?? 0;
|
|
172
|
-
const context_percent = context_usage?.percent !== null ? context_percent_value.toFixed(1) : "?";
|
|
173
|
-
let pwd = ctx.cwd;
|
|
174
|
-
const home = process.env.HOME || process.env.USERPROFILE;
|
|
175
|
-
if (home && pwd.startsWith(home)) pwd = `~${pwd.slice(home.length)}`;
|
|
176
|
-
const branch = footer_data.getGitBranch();
|
|
177
|
-
if (branch) pwd = `${pwd} (${branch})`;
|
|
178
|
-
const session_name = ctx.sessionManager.getSessionName();
|
|
179
|
-
if (session_name) pwd = `${pwd} • ${session_name}`;
|
|
180
|
-
const stats_parts = [];
|
|
181
|
-
if (total_input) stats_parts.push(`↑${format_token_count(total_input)}`);
|
|
182
|
-
if (total_output) stats_parts.push(`↓${format_token_count(total_output)}`);
|
|
183
|
-
if (total_cache_read) stats_parts.push(`R${format_token_count(total_cache_read)}`);
|
|
184
|
-
if (total_cache_write) stats_parts.push(`W${format_token_count(total_cache_write)}`);
|
|
185
|
-
const using_subscription = ctx.model ? ctx.modelRegistry.isUsingOAuth(ctx.model) : false;
|
|
186
|
-
if (total_cost || using_subscription) stats_parts.push(`$${total_cost.toFixed(3)}${using_subscription ? " (sub)" : ""}`);
|
|
187
|
-
const context_percent_display = context_percent === "?" ? `?/${format_token_count(context_window)}` : `${context_percent}%/${format_token_count(context_window)}`;
|
|
188
|
-
let context_percent_str = context_percent_display;
|
|
189
|
-
if (context_percent_value > 90) context_percent_str = theme.fg("error", context_percent_display);
|
|
190
|
-
else if (context_percent_value > 70) context_percent_str = theme.fg("warning", context_percent_display);
|
|
191
|
-
stats_parts.push(context_percent_str);
|
|
192
|
-
let stats_left = stats_parts.join(" ");
|
|
193
|
-
let stats_left_width = visibleWidth(stats_left);
|
|
194
|
-
if (stats_left_width > width) {
|
|
195
|
-
stats_left = truncateToWidth(stats_left, width, "...");
|
|
196
|
-
stats_left_width = visibleWidth(stats_left);
|
|
197
|
-
}
|
|
198
|
-
const model_name = ctx.model?.id || "no-model";
|
|
199
|
-
const thinking_level = get_current_thinking_level(ctx);
|
|
200
|
-
let right_side_without_provider = model_name;
|
|
201
|
-
if (ctx.model?.reasoning) right_side_without_provider = thinking_level === "off" ? `${model_name} • thinking off` : `${model_name} • ${thinking_level}`;
|
|
202
|
-
let right_side = right_side_without_provider;
|
|
203
|
-
if (footer_data.getAvailableProviderCount() > 1 && ctx.model) {
|
|
204
|
-
right_side = `(${ctx.model.provider}) ${right_side_without_provider}`;
|
|
205
|
-
if (stats_left_width + 2 + visibleWidth(right_side) > width) right_side = right_side_without_provider;
|
|
206
|
-
}
|
|
207
|
-
const right_side_width = visibleWidth(right_side);
|
|
208
|
-
const total_needed = stats_left_width + 2 + right_side_width;
|
|
209
|
-
let stats_line;
|
|
210
|
-
if (total_needed <= width) {
|
|
211
|
-
const padding = " ".repeat(width - stats_left_width - right_side_width);
|
|
212
|
-
stats_line = stats_left + padding + right_side;
|
|
213
|
-
} else {
|
|
214
|
-
const available_for_right = width - stats_left_width - 2;
|
|
215
|
-
if (available_for_right > 0) {
|
|
216
|
-
const truncated_right = truncateToWidth(right_side, available_for_right, "");
|
|
217
|
-
const truncated_right_width = visibleWidth(truncated_right);
|
|
218
|
-
const padding = " ".repeat(Math.max(0, width - stats_left_width - truncated_right_width));
|
|
219
|
-
stats_line = stats_left + padding + truncated_right;
|
|
220
|
-
} else stats_line = stats_left;
|
|
221
|
-
}
|
|
222
|
-
const dim_stats_left = theme.fg("dim", stats_left);
|
|
223
|
-
const remainder = stats_line.slice(stats_left.length);
|
|
224
|
-
const dim_remainder = theme.fg("dim", remainder);
|
|
225
|
-
const lines = [truncateToWidth(theme.fg("dim", pwd), width, theme.fg("dim", "...")), dim_stats_left + dim_remainder];
|
|
226
|
-
const prompt_status = get_footer_prompt_status(active_base_name, active_layers);
|
|
227
|
-
const combined_status_line = render_footer_status_line(theme, width, Array.from(footer_data.getExtensionStatuses().entries()).filter(([key]) => key !== "preset").sort(([a], [b]) => a.localeCompare(b)).map(([, text]) => sanitize_status_text(text)), prompt_status);
|
|
228
|
-
if (combined_status_line) lines.push(combined_status_line);
|
|
229
|
-
return lines;
|
|
230
|
-
}
|
|
231
101
|
function set_status(ctx, active_base_name, active_layers) {
|
|
232
|
-
ctx.ui.setStatus("preset",
|
|
233
|
-
if (!ctx.hasUI) return;
|
|
234
|
-
ctx.ui.setFooter((tui, theme, footer_data) => {
|
|
235
|
-
return {
|
|
236
|
-
dispose: footer_data.onBranchChange(() => tui.requestRender()),
|
|
237
|
-
invalidate() {},
|
|
238
|
-
render(width) {
|
|
239
|
-
return render_footer_lines(ctx, theme, footer_data, width, active_base_name, active_layers);
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
});
|
|
102
|
+
ctx.ui.setStatus("preset", get_footer_prompt_status(active_base_name, active_layers));
|
|
243
103
|
}
|
|
244
104
|
//#endregion
|
|
245
105
|
//#region src/extensions/prompt-presets/help.ts
|
|
@@ -1001,10 +861,9 @@ async function prompt_presets(pi) {
|
|
|
1001
861
|
});
|
|
1002
862
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
1003
863
|
ctx.ui.setStatus("preset", void 0);
|
|
1004
|
-
ctx.ui.setFooter(void 0);
|
|
1005
864
|
});
|
|
1006
865
|
}
|
|
1007
866
|
//#endregion
|
|
1008
867
|
export { prompt_presets as default };
|
|
1009
868
|
|
|
1010
|
-
//# sourceMappingURL=prompt-presets-
|
|
869
|
+
//# sourceMappingURL=prompt-presets-DRi6CwoJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-presets-DRi6CwoJ.js","names":[],"sources":["../src/extensions/prompt-presets/catalog.ts","../src/extensions/prompt-presets/defaults.ts","../src/extensions/prompt-presets/footer.ts","../src/extensions/prompt-presets/help.ts","../src/extensions/prompt-presets/storage.ts","../src/extensions/prompt-presets/state.ts","../src/extensions/prompt-presets/index.ts"],"sourcesContent":["import type {\n\tLoadedPromptPreset,\n\tPromptPresetSource,\n} from './types.js';\n\nexport function get_prompt_source_label(\n\tsource: PromptPresetSource,\n): string {\n\tswitch (source) {\n\t\tcase 'builtin':\n\t\t\treturn 'built-in';\n\t\tcase 'user':\n\t\t\treturn 'user';\n\t\tcase 'project':\n\t\t\treturn 'project';\n\t}\n}\n\nexport function list_base_presets(\n\tpresets: Record<string, LoadedPromptPreset>,\n): LoadedPromptPreset[] {\n\treturn Object.values(presets)\n\t\t.filter((preset) => preset.kind === 'base')\n\t\t.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport function list_layer_presets(\n\tpresets: Record<string, LoadedPromptPreset>,\n): LoadedPromptPreset[] {\n\treturn Object.values(presets)\n\t\t.filter((preset) => preset.kind === 'layer')\n\t\t.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport function format_summary(\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n\tpresets: Record<string, LoadedPromptPreset>,\n): string {\n\tconst lines = [`Base: ${active_base_name ?? '(none)'}`];\n\n\tconst layer_names = [...active_layers].sort();\n\tif (layer_names.length === 0) {\n\t\tlines.push('Layers: (none)');\n\t} else {\n\t\tlines.push('Layers:');\n\t\tfor (const name of layer_names) {\n\t\t\tconst preset = presets[name];\n\t\t\tconst description = preset?.description\n\t\t\t\t? ` — ${preset.description}`\n\t\t\t\t: '';\n\t\t\tlines.push(`- ${name}${description}`);\n\t\t}\n\t}\n\n\treturn lines.join('\\n');\n}\n\nexport function format_active_details(\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n\tpresets: Record<string, LoadedPromptPreset>,\n): string {\n\tconst parts: string[] = [];\n\n\tif (active_base_name) {\n\t\tconst base = presets[active_base_name];\n\t\tif (base) {\n\t\t\tparts.push(`Base: ${base.name}`);\n\t\t\tif (base.description)\n\t\t\t\tparts.push(`Description: ${base.description}`);\n\t\t\tparts.push(`Source: ${get_prompt_source_label(base.source)}`);\n\t\t\tparts.push('', base.instructions.trim());\n\t\t}\n\t}\n\n\tconst layer_names = [...active_layers].sort();\n\tif (layer_names.length > 0) {\n\t\tif (parts.length > 0) parts.push('', '---', '');\n\t\tparts.push('Layers:');\n\t\tfor (const name of layer_names) {\n\t\t\tconst layer = presets[name];\n\t\t\tif (!layer) continue;\n\t\t\tparts.push(\n\t\t\t\t`- ${layer.name} (${get_prompt_source_label(layer.source)})`,\n\t\t\t);\n\t\t\tif (layer.description) parts.push(` ${layer.description}`);\n\t\t}\n\t}\n\n\treturn parts.join('\\n') || 'No preset or layers active';\n}\n","import type { PromptPresetMap } from './types.js';\n\nexport const DEFAULT_BASE_PROMPT_PRESET_NAME = 'terse';\n\nexport const DEFAULT_PROMPT_PRESETS: PromptPresetMap = {\n\tterse: {\n\t\tkind: 'base',\n\t\tdescription: 'Short, direct, no fluff',\n\t\tinstructions:\n\t\t\t\"Be concise and direct. Default to the shortest response that fully solves the user's request. Use at most one short paragraph or 3 bullets unless the user explicitly asks for detail. For implementation reports, include only what changed, validation, and the next step if relevant. No purple prose, no filler, no repetitive caveats.\",\n\t},\n\tstandard: {\n\t\tkind: 'base',\n\t\tdescription: 'Clear and concise with key context',\n\t\tinstructions:\n\t\t\t'Be clear, direct, and concise. Include only the reasoning and implementation details that matter. Avoid filler, grandstanding, and ornamental language. Use bullets when they improve scanability.',\n\t},\n\tdetailed: {\n\t\tkind: 'base',\n\t\tdescription: 'More explanation when nuance matters',\n\t\tinstructions:\n\t\t\t'Be thorough when the task is complex or tradeoffs matter, but stay practical. Explain only the details that help the user decide, verify, or implement. Avoid purple prose and unnecessary scene-setting.',\n\t},\n\t'no-purple-prose': {\n\t\tkind: 'layer',\n\t\tdescription: 'Strip out ornamental language',\n\t\tinstructions:\n\t\t\t'Do not use purple prose, flourish, motivational filler, or theatrical transitions. Prefer plain language and concrete statements.',\n\t},\n\tbullets: {\n\t\tkind: 'layer',\n\t\tdescription: 'Prefer short bullets when useful',\n\t\tinstructions:\n\t\t\t'When presenting options, findings, or steps, prefer short bullet lists over long paragraphs.',\n\t},\n\t'clarify-first': {\n\t\tkind: 'layer',\n\t\tdescription:\n\t\t\t'Ask brief clarifying questions when requirements are ambiguous',\n\t\tinstructions:\n\t\t\t'If the request is materially ambiguous, ask the minimum clarifying question(s) needed before proceeding. Do not ask unnecessary questions.',\n\t},\n\t'include-risks': {\n\t\tkind: 'layer',\n\t\tdescription: 'Call out notable risks or tradeoffs',\n\t\tinstructions:\n\t\t\t'When making a recommendation or implementation plan, briefly mention the key risk, tradeoff, or caveat if one materially matters.',\n\t},\n};\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nfunction get_footer_prompt_status(\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): string | undefined {\n\tif (!active_base_name && active_layers.size === 0) {\n\t\treturn undefined;\n\t}\n\n\tconst label = active_base_name ?? 'none';\n\tconst layer_suffix =\n\t\tactive_layers.size > 0 ? ` +${active_layers.size}` : '';\n\treturn `prompt:${label}${layer_suffix}`;\n}\n\nexport function set_status(\n\tctx: ExtensionContext,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): void {\n\tctx.ui.setStatus(\n\t\t'preset',\n\t\tget_footer_prompt_status(active_base_name, active_layers),\n\t);\n}\n","export function is_subcommand(command: string): boolean {\n\treturn [\n\t\t'help',\n\t\t'list',\n\t\t'show',\n\t\t'clear',\n\t\t'edit',\n\t\t'edit-global',\n\t\t'export-defaults',\n\t\t'delete',\n\t\t'reset',\n\t\t'reload',\n\t\t'base',\n\t\t'enable',\n\t\t'disable',\n\t\t'toggle',\n\t].includes(command);\n}\n\nexport function format_prompt_preset_help(): string {\n\treturn `Prompt presets append instructions to the system prompt.\n\nCommands:\n- /prompt-preset Open the preset picker\n- /prompt-preset show Show the active base and layers\n- /prompt-preset <name> Activate a base preset or toggle a layer\n- /prompt-preset base <name> Activate a base preset\n- /prompt-preset enable <layer> Enable a layer\n- /prompt-preset disable <layer> Disable a layer\n- /prompt-preset edit <name> Edit/create .pi/presets/<name>.md\n- /prompt-preset edit-global <name> Edit/create ~/.pi/agent/presets/<name>.md\n- /prompt-preset export-defaults Export built-ins to ~/.pi/agent/presets/*.md\n- /prompt-preset export-defaults project Export built-ins to .pi/presets/*.md\n- /prompt-preset reload Reload presets after manual file edits\n- /prompt-preset clear Clear active base and layers\n\nExamples:\n- /prompt-preset export-defaults\n- /prompt-preset edit-global terse\n- /prompt-preset base detailed\n- /prompt-preset enable bullets\n- /prompt-preset show\n\nAlias: /preset`;\n}\n","import { getAgentDir } from '@earendil-works/pi-coding-agent';\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { DEFAULT_PROMPT_PRESETS } from './defaults.js';\nimport type {\n\tLoadedPromptPreset,\n\tPromptPreset,\n\tPromptPresetMap,\n\tPromptPresetSource,\n\tPromptPresetState,\n} from './types.js';\n\nconst PROJECT_PROMPT_PRESETS_ENV = 'MY_PI_PROMPT_PRESETS_PROJECT';\n\ninterface PersistedPromptPresetStates {\n\tversion: number;\n\tprojects: Record<string, PromptPresetState>;\n}\n\nexport function normalize_prompt_presets(\n\tinput: unknown,\n): PromptPresetMap {\n\tif (!input || typeof input !== 'object') return {};\n\n\tconst normalized: PromptPresetMap = {};\n\tfor (const [raw_name, raw_value] of Object.entries(input)) {\n\t\tconst name = raw_name.trim();\n\t\tif (!name) continue;\n\n\t\tif (typeof raw_value === 'string') {\n\t\t\tnormalized[name] = {\n\t\t\t\tkind: 'base',\n\t\t\t\tinstructions: raw_value,\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!raw_value || typeof raw_value !== 'object') continue;\n\t\tconst candidate = raw_value as {\n\t\t\tkind?: unknown;\n\t\t\tdescription?: unknown;\n\t\t\tinstructions?: unknown;\n\t\t};\n\t\tif (typeof candidate.instructions !== 'string') continue;\n\n\t\tnormalized[name] = {\n\t\t\tinstructions: candidate.instructions,\n\t\t\t...(candidate.kind === 'layer'\n\t\t\t\t? { kind: 'layer' as const }\n\t\t\t\t: {}),\n\t\t\t...(typeof candidate.description === 'string'\n\t\t\t\t? { description: candidate.description }\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\treturn normalized;\n}\n\nexport function merge_prompt_presets(\n\t...sources: PromptPresetMap[]\n): PromptPresetMap {\n\treturn Object.assign({}, ...sources);\n}\n\nfunction to_loaded_prompt_presets(\n\tpresets: PromptPresetMap,\n\tsource: PromptPresetSource,\n): Record<string, LoadedPromptPreset> {\n\treturn Object.fromEntries(\n\t\tObject.entries(presets).map(([name, preset]) => [\n\t\t\tname,\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tkind: preset.kind === 'layer' ? 'layer' : 'base',\n\t\t\t\tsource,\n\t\t\t\t...preset,\n\t\t\t},\n\t\t]),\n\t);\n}\n\nfunction get_global_presets_path(): string {\n\treturn join(getAgentDir(), 'presets.json');\n}\n\nfunction get_project_presets_path(cwd: string): string {\n\treturn join(cwd, '.pi', 'presets.json');\n}\n\nexport function get_global_presets_dir(): string {\n\treturn join(getAgentDir(), 'presets');\n}\n\nexport function get_project_presets_dir(cwd: string): string {\n\treturn join(cwd, '.pi', 'presets');\n}\n\nfunction sanitize_prompt_preset_file_name(name: string): string {\n\tconst sanitized = name\n\t\t.trim()\n\t\t.replace(/[\\\\/:*?\"<>|]/g, '-')\n\t\t.replace(/^\\.+$/, '')\n\t\t.replace(/^\\.+/, '')\n\t\t.replace(/\\.+$/, '');\n\tif (!sanitized) {\n\t\tthrow new Error(\n\t\t\t'Prompt preset name must contain a file-safe character',\n\t\t);\n\t}\n\treturn sanitized;\n}\n\nexport function get_prompt_preset_file_path(\n\tdir: string,\n\tname: string,\n): string {\n\treturn join(dir, `${sanitize_prompt_preset_file_name(name)}.md`);\n}\n\nfunction get_persisted_prompt_state_path(): string {\n\treturn join(getAgentDir(), 'prompt-preset-state.json');\n}\n\nfunction read_prompt_presets_file(path: string): PromptPresetMap {\n\tif (!existsSync(path)) return {};\n\n\ttry {\n\t\treturn normalize_prompt_presets(\n\t\t\tJSON.parse(readFileSync(path, 'utf-8')),\n\t\t);\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction unquote_frontmatter_value(value: string): string {\n\tconst trimmed = value.trim();\n\tif (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n\t\ttry {\n\t\t\treturn JSON.parse(trimmed) as string;\n\t\t} catch {\n\t\t\treturn trimmed.slice(1, -1);\n\t\t}\n\t}\n\tif (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n\t\treturn trimmed.slice(1, -1);\n\t}\n\treturn trimmed;\n}\n\nfunction parse_prompt_preset_markdown(content: string): {\n\tmetadata: Record<string, string>;\n\tbody: string;\n} {\n\tconst normalized = content.replace(/\\r\\n/g, '\\n');\n\tif (!normalized.startsWith('---\\n')) {\n\t\treturn { metadata: {}, body: normalized.trim() };\n\t}\n\n\tconst lines = normalized.split('\\n');\n\tconst end = lines.findIndex(\n\t\t(line, index) => index > 0 && line.trim() === '---',\n\t);\n\tif (end === -1) {\n\t\treturn { metadata: {}, body: normalized.trim() };\n\t}\n\n\tconst metadata: Record<string, string> = {};\n\tfor (const line of lines.slice(1, end)) {\n\t\tconst separator = line.indexOf(':');\n\t\tif (separator === -1) continue;\n\t\tconst key = line.slice(0, separator).trim().toLowerCase();\n\t\tconst value = line.slice(separator + 1).trim();\n\t\tif (!key) continue;\n\t\tmetadata[key] = unquote_frontmatter_value(value);\n\t}\n\n\treturn {\n\t\tmetadata,\n\t\tbody: lines\n\t\t\t.slice(end + 1)\n\t\t\t.join('\\n')\n\t\t\t.trim(),\n\t};\n}\n\nexport function read_prompt_presets_dir(\n\tpath: string,\n): PromptPresetMap {\n\tif (!existsSync(path)) return {};\n\n\ttry {\n\t\tconst presets: PromptPresetMap = {};\n\t\tfor (const entry of readdirSync(path, { withFileTypes: true })\n\t\t\t.filter((item) => item.isFile() && item.name.endsWith('.md'))\n\t\t\t.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\t\tconst name = entry.name.slice(0, -3).trim();\n\t\t\tif (!name) continue;\n\t\t\tconst { metadata, body } = parse_prompt_preset_markdown(\n\t\t\t\treadFileSync(join(path, entry.name), 'utf-8'),\n\t\t\t);\n\t\t\tif (!body) continue;\n\t\t\tpresets[name] = {\n\t\t\t\tkind: metadata.kind === 'layer' ? 'layer' : 'base',\n\t\t\t\tinstructions: body,\n\t\t\t\t...(metadata.description\n\t\t\t\t\t? { description: metadata.description }\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\t}\n\t\treturn presets;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction format_prompt_preset_markdown(preset: PromptPreset): string {\n\tconst lines = [\n\t\t'---',\n\t\t`kind: ${preset.kind === 'layer' ? 'layer' : 'base'}`,\n\t];\n\tif (preset.description?.trim()) {\n\t\tlines.push(\n\t\t\t`description: ${JSON.stringify(preset.description.trim())}`,\n\t\t);\n\t}\n\tlines.push('---', '', preset.instructions.trim(), '');\n\treturn lines.join('\\n');\n}\n\nexport function save_prompt_preset_file(\n\tdir: string,\n\tname: string,\n\tpreset: PromptPreset,\n): string {\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst path = get_prompt_preset_file_path(dir, name);\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(tmp, format_prompt_preset_markdown(preset), {\n\t\tmode: 0o600,\n\t});\n\trenameSync(tmp, path);\n\treturn path;\n}\n\nexport function save_project_prompt_preset_file(\n\tcwd: string,\n\tname: string,\n\tpreset: PromptPreset,\n): string {\n\treturn save_prompt_preset_file(\n\t\tget_project_presets_dir(cwd),\n\t\tname,\n\t\tpreset,\n\t);\n}\n\nexport function save_global_prompt_preset_file(\n\tname: string,\n\tpreset: PromptPreset,\n): string {\n\treturn save_prompt_preset_file(\n\t\tget_global_presets_dir(),\n\t\tname,\n\t\tpreset,\n\t);\n}\n\nfunction should_load_project_prompt_presets(): boolean {\n\tconst normalized = process.env[PROJECT_PROMPT_PRESETS_ENV]\n\t\t?.trim()\n\t\t.toLowerCase();\n\treturn !['0', 'false', 'no', 'skip', 'disable'].includes(\n\t\tnormalized ?? '',\n\t);\n}\n\nexport function load_prompt_presets(\n\tcwd: string,\n): Record<string, LoadedPromptPreset> {\n\treturn Object.assign(\n\t\t{},\n\t\tto_loaded_prompt_presets(DEFAULT_PROMPT_PRESETS, 'builtin'),\n\t\tto_loaded_prompt_presets(\n\t\t\tread_prompt_presets_file(get_global_presets_path()),\n\t\t\t'user',\n\t\t),\n\t\tto_loaded_prompt_presets(\n\t\t\tread_prompt_presets_dir(get_global_presets_dir()),\n\t\t\t'user',\n\t\t),\n\t\t...(should_load_project_prompt_presets()\n\t\t\t? [\n\t\t\t\t\tto_loaded_prompt_presets(\n\t\t\t\t\t\tread_prompt_presets_file(get_project_presets_path(cwd)),\n\t\t\t\t\t\t'project',\n\t\t\t\t\t),\n\t\t\t\t\tto_loaded_prompt_presets(\n\t\t\t\t\t\tread_prompt_presets_dir(get_project_presets_dir(cwd)),\n\t\t\t\t\t\t'project',\n\t\t\t\t\t),\n\t\t\t\t]\n\t\t\t: []),\n\t);\n}\n\nfunction sort_prompt_presets(\n\tpresets: PromptPresetMap,\n): PromptPresetMap {\n\treturn Object.fromEntries(\n\t\tObject.entries(presets).sort(([a], [b]) => a.localeCompare(b)),\n\t);\n}\n\nexport function save_project_prompt_presets(\n\tcwd: string,\n\tpresets: PromptPresetMap,\n): string {\n\tconst path = get_project_presets_path(cwd);\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(\n\t\ttmp,\n\t\tJSON.stringify(sort_prompt_presets(presets), null, '\\t') + '\\n',\n\t\t{ mode: 0o600 },\n\t);\n\trenameSync(tmp, path);\n\treturn path;\n}\n\nexport function remove_project_prompt_preset(\n\tcwd: string,\n\tname: string,\n): {\n\tremoved: boolean;\n\tpath: string;\n\tremaining: number;\n} {\n\tconst json_path = get_project_presets_path(cwd);\n\tconst project_presets = read_prompt_presets_file(json_path);\n\tlet removed = false;\n\tlet removed_path = json_path;\n\n\tif (name in project_presets) {\n\t\tdelete project_presets[name];\n\t\tremoved = true;\n\t\tremoved_path = json_path;\n\t\tif (Object.keys(project_presets).length === 0) {\n\t\t\tif (existsSync(json_path)) {\n\t\t\t\tunlinkSync(json_path);\n\t\t\t}\n\t\t} else {\n\t\t\tsave_project_prompt_presets(cwd, project_presets);\n\t\t}\n\t}\n\n\tconst file_path = get_prompt_preset_file_path(\n\t\tget_project_presets_dir(cwd),\n\t\tname,\n\t);\n\tif (existsSync(file_path)) {\n\t\tunlinkSync(file_path);\n\t\tremoved = true;\n\t\tremoved_path = file_path;\n\t}\n\n\tconst remaining =\n\t\tObject.keys(read_prompt_presets_file(json_path)).length +\n\t\tObject.keys(read_prompt_presets_dir(get_project_presets_dir(cwd)))\n\t\t\t.length;\n\n\treturn { removed, path: removed_path, remaining };\n}\n\nfunction normalize_prompt_preset_state(\n\tinput: unknown,\n): PromptPresetState | undefined {\n\tif (!input || typeof input !== 'object') return undefined;\n\n\tconst candidate = input as {\n\t\tbase_name?: unknown;\n\t\tlayer_names?: unknown;\n\t};\n\tconst base_name =\n\t\ttypeof candidate.base_name === 'string' &&\n\t\tcandidate.base_name.trim()\n\t\t\t? candidate.base_name.trim()\n\t\t\t: null;\n\tconst layer_names = Array.isArray(candidate.layer_names)\n\t\t? [\n\t\t\t\t...new Set(\n\t\t\t\t\tcandidate.layer_names\n\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t(value): value is string =>\n\t\t\t\t\t\t\t\ttypeof value === 'string' && value.trim().length > 0,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.map((value) => value.trim()),\n\t\t\t\t),\n\t\t\t].sort()\n\t\t: [];\n\n\treturn {\n\t\tbase_name,\n\t\tlayer_names,\n\t};\n}\n\nfunction read_persisted_prompt_states(\n\tpath = get_persisted_prompt_state_path(),\n): PersistedPromptPresetStates {\n\tif (!existsSync(path)) {\n\t\treturn { version: 1, projects: {} };\n\t}\n\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, 'utf-8')) as {\n\t\t\tversion?: unknown;\n\t\t\tprojects?: unknown;\n\t\t};\n\t\tconst raw_projects =\n\t\t\tparsed.projects && typeof parsed.projects === 'object'\n\t\t\t\t? parsed.projects\n\t\t\t\t: {};\n\t\tconst projects: Record<string, PromptPresetState> = {};\n\t\tfor (const [cwd, value] of Object.entries(raw_projects)) {\n\t\t\tconst normalized = normalize_prompt_preset_state(value);\n\t\t\tif (!normalized) continue;\n\t\t\tprojects[cwd] = normalized;\n\t\t}\n\t\treturn {\n\t\t\tversion:\n\t\t\t\ttypeof parsed.version === 'number' ? parsed.version : 1,\n\t\t\tprojects,\n\t\t};\n\t} catch {\n\t\treturn { version: 1, projects: {} };\n\t}\n}\n\nexport function load_persisted_prompt_state(\n\tcwd: string,\n\tpath = get_persisted_prompt_state_path(),\n): PromptPresetState | undefined {\n\treturn read_persisted_prompt_states(path).projects[cwd];\n}\n\nexport function save_persisted_prompt_state(\n\tcwd: string,\n\tstate: PromptPresetState,\n\tpath = get_persisted_prompt_state_path(),\n): string {\n\tconst persisted = read_persisted_prompt_states(path);\n\tpersisted.projects[cwd] = normalize_prompt_preset_state(state) ?? {\n\t\tbase_name: null,\n\t\tlayer_names: [],\n\t};\n\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(\n\t\ttmp,\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tversion: 1,\n\t\t\t\tprojects: Object.fromEntries(\n\t\t\t\t\tObject.entries(persisted.projects).sort(([a], [b]) =>\n\t\t\t\t\t\ta.localeCompare(b),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t},\n\t\t\tnull,\n\t\t\t'\\t',\n\t\t) + '\\n',\n\t\t{ mode: 0o600 },\n\t);\n\trenameSync(tmp, path);\n\treturn path;\n}\n","import type {\n\tExtensionAPI,\n\tExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport { save_persisted_prompt_state } from './storage.js';\nimport type {\n\tLoadedPromptPreset,\n\tPromptPresetState,\n} from './types.js';\n\nexport const PRESET_STATE_TYPE = 'prompt-preset-state';\nexport const ENABLED = '● enabled';\nexport const DISABLED = '○ disabled';\nexport const SELECTED = '● selected';\nexport const UNSELECTED = '○';\nexport const NONE_BASE_ID = '__base_none__';\n\nexport function get_last_preset_state(\n\tctx: ExtensionContext,\n): PromptPresetState | undefined {\n\tconst entries = ctx.sessionManager.getEntries();\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i] as {\n\t\t\ttype?: string;\n\t\t\tcustomType?: string;\n\t\t\tdata?: PromptPresetState;\n\t\t};\n\t\tif (\n\t\t\tentry.type === 'custom' &&\n\t\t\tentry.customType === PRESET_STATE_TYPE &&\n\t\t\tentry.data\n\t\t) {\n\t\t\treturn entry.data;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function sets_equal(\n\ta: ReadonlySet<string>,\n\tb: ReadonlySet<string>,\n): boolean {\n\tif (a.size !== b.size) return false;\n\tfor (const value of a) {\n\t\tif (!b.has(value)) return false;\n\t}\n\treturn true;\n}\n\nexport function persist_state(\n\tpi: ExtensionAPI,\n\tctx: ExtensionContext,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): void {\n\tconst state = {\n\t\tbase_name: active_base_name ?? null,\n\t\tlayer_names: [...active_layers].sort(),\n\t};\n\tpi.appendEntry(PRESET_STATE_TYPE, state);\n\tsave_persisted_prompt_state(ctx.cwd, state);\n}\n\nexport function normalize_active_state(\n\tpresets: Record<string, LoadedPromptPreset>,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): {\n\tactive_base_name: string | undefined;\n\tactive_layers: Set<string>;\n} {\n\tconst next_base_name =\n\t\tactive_base_name && presets[active_base_name]?.kind === 'base'\n\t\t\t? active_base_name\n\t\t\t: undefined;\n\tconst next_layers = new Set(\n\t\t[...active_layers].filter(\n\t\t\t(name) => presets[name]?.kind === 'layer',\n\t\t),\n\t);\n\treturn {\n\t\tactive_base_name: next_base_name,\n\t\tactive_layers: next_layers,\n\t};\n}\n\nexport function parse_preset_flag(flag: string): string[] {\n\treturn flag\n\t\t.split(',')\n\t\t.map((item) => item.trim())\n\t\t.filter(Boolean);\n}\n","import {\n\ttype ExtensionAPI,\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport type { SettingItem } from '@earendil-works/pi-tui';\nimport { show_settings_modal } from '@spences10/pi-tui-modal';\nimport { existsSync } from 'node:fs';\nimport {\n\tformat_active_details,\n\tformat_summary,\n\tget_prompt_source_label,\n\tlist_base_presets,\n\tlist_layer_presets,\n} from './catalog.js';\nimport {\n\tDEFAULT_BASE_PROMPT_PRESET_NAME,\n\tDEFAULT_PROMPT_PRESETS,\n} from './defaults.js';\nimport { set_status } from './footer.js';\nimport { format_prompt_preset_help, is_subcommand } from './help.js';\nimport {\n\tDISABLED,\n\tENABLED,\n\tget_last_preset_state,\n\tNONE_BASE_ID,\n\tnormalize_active_state,\n\tparse_preset_flag,\n\tpersist_state,\n\tSELECTED,\n\tsets_equal,\n\tUNSELECTED,\n} from './state.js';\nimport {\n\tget_global_presets_dir,\n\tget_project_presets_dir,\n\tget_prompt_preset_file_path,\n\tload_persisted_prompt_state,\n\tload_prompt_presets,\n\tremove_project_prompt_preset,\n\tsave_global_prompt_preset_file,\n\tsave_project_prompt_preset_file,\n\tsave_prompt_preset_file,\n} from './storage.js';\nimport type {\n\tLoadedPromptPreset,\n\tPromptPresetKind,\n} from './types.js';\n\nexport {\n\tDEFAULT_BASE_PROMPT_PRESET_NAME,\n\tDEFAULT_PROMPT_PRESETS,\n} from './defaults.js';\nexport {\n\tget_current_thinking_level,\n\tget_default_footer_thinking_level,\n\trender_footer_status_line,\n} from '@spences10/pi-footer';\nexport {\n\tload_persisted_prompt_state,\n\tload_prompt_presets,\n\tmerge_prompt_presets,\n\tnormalize_prompt_presets,\n\tread_prompt_presets_dir,\n\tremove_project_prompt_preset,\n\tsave_persisted_prompt_state,\n\tsave_project_prompt_presets,\n\tsave_prompt_preset_file,\n} from './storage.js';\nexport type {\n\tLoadedPromptPreset,\n\tPromptPreset,\n\tPromptPresetKind,\n\tPromptPresetMap,\n\tPromptPresetSource,\n\tPromptPresetState,\n} from './types.js';\n\nexport default async function prompt_presets(pi: ExtensionAPI) {\n\tlet presets: Record<string, LoadedPromptPreset> = {};\n\tlet active_base_name: string | undefined;\n\tlet active_layers = new Set<string>();\n\n\tfunction get_base(\n\t\tname: string | undefined,\n\t): LoadedPromptPreset | undefined {\n\t\treturn name ? presets[name] : undefined;\n\t}\n\n\tfunction get_layer(name: string): LoadedPromptPreset | undefined {\n\t\tconst preset = presets[name];\n\t\treturn preset?.kind === 'layer' ? preset : undefined;\n\t}\n\n\tfunction commit_state(\n\t\tctx: ExtensionContext,\n\t\tnext_base_name: string | undefined,\n\t\tnext_layers: ReadonlySet<string>,\n\t\toptions?: { persist?: boolean; notify?: string },\n\t): void {\n\t\tactive_base_name = next_base_name;\n\t\tactive_layers = new Set(next_layers);\n\t\tset_status(ctx, active_base_name, active_layers);\n\t\tif (options?.persist !== false) {\n\t\t\tpersist_state(pi, ctx, active_base_name, active_layers);\n\t\t}\n\t\tif (options?.notify) {\n\t\t\tctx.ui.notify(options.notify, 'info');\n\t\t}\n\t}\n\n\tfunction activate_base(\n\t\tname: string | undefined,\n\t\tctx: ExtensionContext,\n\t\toptions?: { persist?: boolean },\n\t): boolean {\n\t\tif (!name) {\n\t\t\tcommit_state(ctx, undefined, active_layers, {\n\t\t\t\tpersist: options?.persist,\n\t\t\t\tnotify: 'Base preset cleared',\n\t\t\t});\n\t\t\treturn true;\n\t\t}\n\n\t\tconst preset = get_base(name);\n\t\tif (!preset) {\n\t\t\tctx.ui.notify(`Unknown base preset: ${name}`, 'warning');\n\t\t\treturn false;\n\t\t}\n\n\t\tcommit_state(ctx, preset.name, active_layers, {\n\t\t\tpersist: options?.persist,\n\t\t\tnotify: `Base preset \"${preset.name}\" activated`,\n\t\t});\n\t\treturn true;\n\t}\n\n\tfunction set_layer_enabled(\n\t\tname: string,\n\t\tenabled: boolean,\n\t\tctx: ExtensionContext,\n\t\toptions?: { persist?: boolean },\n\t): boolean {\n\t\tconst preset = get_layer(name);\n\t\tif (!preset) {\n\t\t\tctx.ui.notify(`Unknown prompt layer: ${name}`, 'warning');\n\t\t\treturn false;\n\t\t}\n\n\t\tconst next_layers = new Set(active_layers);\n\t\tif (enabled) {\n\t\t\tnext_layers.add(preset.name);\n\t\t} else {\n\t\t\tnext_layers.delete(preset.name);\n\t\t}\n\n\t\tcommit_state(ctx, active_base_name, next_layers, {\n\t\t\tpersist: options?.persist,\n\t\t\tnotify: enabled\n\t\t\t\t? `Layer \"${preset.name}\" enabled`\n\t\t\t\t: `Layer \"${preset.name}\" disabled`,\n\t\t});\n\t\treturn true;\n\t}\n\n\tfunction toggle_layer(\n\t\tname: string,\n\t\tctx: ExtensionContext,\n\t\toptions?: { persist?: boolean },\n\t): boolean {\n\t\treturn set_layer_enabled(\n\t\t\tname,\n\t\t\t!active_layers.has(name),\n\t\t\tctx,\n\t\t\toptions,\n\t\t);\n\t}\n\n\tasync function edit_preset(\n\t\tname: string,\n\t\tctx: ExtensionCommandContext,\n\t\tscope: 'project' | 'global' = 'project',\n\t): Promise<void> {\n\t\tconst existing = presets[name];\n\t\tconst kind_choice = await ctx.ui.select('Preset kind', [\n\t\t\texisting?.kind === 'layer'\n\t\t\t\t? 'layer (current)'\n\t\t\t\t: 'base (current)',\n\t\t\texisting?.kind === 'layer' ? 'base' : 'layer',\n\t\t]);\n\t\tif (!kind_choice) return;\n\t\tconst kind: PromptPresetKind = kind_choice.startsWith('layer')\n\t\t\t? 'layer'\n\t\t\t: 'base';\n\n\t\tconst description = await ctx.ui.input(\n\t\t\t`Description for ${name}`,\n\t\t\texisting?.description ?? '',\n\t\t);\n\t\tif (description === undefined) return;\n\n\t\tconst instructions = await ctx.ui.editor(\n\t\t\t`Edit ${kind} preset: ${name}`,\n\t\t\texisting?.instructions ?? '',\n\t\t);\n\t\tif (instructions === undefined) return;\n\n\t\tconst saved_path =\n\t\t\tscope === 'global'\n\t\t\t\t? save_global_prompt_preset_file(name, {\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tinstructions,\n\t\t\t\t\t\t...(description.trim()\n\t\t\t\t\t\t\t? { description: description.trim() }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})\n\t\t\t\t: save_project_prompt_preset_file(ctx.cwd, name, {\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tinstructions,\n\t\t\t\t\t\t...(description.trim()\n\t\t\t\t\t\t\t? { description: description.trim() }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t});\n\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\n\t\tif (kind === 'base') {\n\t\t\tactivate_base(name, ctx);\n\t\t} else {\n\t\t\tset_layer_enabled(name, true, ctx);\n\t\t}\n\t\tctx.ui.notify(`Saved preset \"${name}\" to ${saved_path}`, 'info');\n\t}\n\n\tfunction export_default_presets(\n\t\tctx: ExtensionCommandContext,\n\t\tscope: 'project' | 'global',\n\t): void {\n\t\tconst dir =\n\t\t\tscope === 'global'\n\t\t\t\t? get_global_presets_dir()\n\t\t\t\t: get_project_presets_dir(ctx.cwd);\n\t\tlet written = 0;\n\t\tlet skipped = 0;\n\t\tfor (const [name, preset] of Object.entries(\n\t\t\tDEFAULT_PROMPT_PRESETS,\n\t\t)) {\n\t\t\tconst path = get_prompt_preset_file_path(dir, name);\n\t\t\tif (existsSync(path)) {\n\t\t\t\tskipped += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsave_prompt_preset_file(dir, name, preset);\n\t\t\twritten += 1;\n\t\t}\n\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\t\tset_status(ctx, active_base_name, active_layers);\n\n\t\tctx.ui.notify(\n\t\t\t`Exported ${written} built-in preset file(s) to ${dir}${skipped ? ` (${skipped} already existed)` : ''}`,\n\t\t\t'info',\n\t\t);\n\t}\n\n\tfunction remove_custom_preset(\n\t\tname: string,\n\t\tctx: ExtensionCommandContext,\n\t\tmode: 'delete' | 'reset',\n\t): void {\n\t\tconst result = remove_project_prompt_preset(ctx.cwd, name);\n\t\tif (!result.removed) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`No project-local preset named \"${name}\" to ${mode}`,\n\t\t\t\t'warning',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\t\tset_status(ctx, active_base_name, active_layers);\n\t\tpersist_state(pi, ctx, active_base_name, active_layers);\n\n\t\tconst fallback = presets[name];\n\t\tif (mode === 'reset' && fallback) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Reset \"${name}\" to ${get_prompt_source_label(fallback.source)} preset`,\n\t\t\t\t'info',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tctx.ui.notify(\n\t\t\tresult.remaining === 0\n\t\t\t\t? `Removed \"${name}\" and deleted ${result.path}`\n\t\t\t\t: `Removed \"${name}\" from ${result.path}`,\n\t\t\t'info',\n\t\t);\n\t}\n\n\tasync function show_manager(\n\t\tctx: ExtensionCommandContext,\n\t): Promise<void> {\n\t\tconst base_presets = list_base_presets(presets);\n\t\tconst layer_presets = list_layer_presets(presets);\n\t\tif (base_presets.length === 0 && layer_presets.length === 0) {\n\t\t\tctx.ui.notify('No prompt presets available', 'warning');\n\t\t\treturn;\n\t\t}\n\n\t\tconst initial_base = active_base_name;\n\t\tconst initial_layers = new Set(active_layers);\n\t\tlet selected_base = active_base_name;\n\t\tconst enabled_layers = new Set(active_layers);\n\n\t\tconst items: SettingItem[] = [];\n\t\tconst base_ids = new Set<string>();\n\t\tconst layer_ids = new Set<string>();\n\n\t\titems.push({\n\t\t\tid: '__header_base__',\n\t\t\tlabel: `── Base presets (${base_presets.length + 1}) ──`,\n\t\t\tdescription: '',\n\t\t\tcurrentValue: '',\n\t\t});\n\t\titems.push({\n\t\t\tid: NONE_BASE_ID,\n\t\t\tlabel: '(none)',\n\t\t\tdescription: 'No active base preset',\n\t\t\tcurrentValue: UNSELECTED,\n\t\t\tvalues: [SELECTED, UNSELECTED],\n\t\t});\n\t\tbase_ids.add(NONE_BASE_ID);\n\n\t\tfor (const preset of base_presets) {\n\t\t\titems.push({\n\t\t\t\tid: preset.name,\n\t\t\t\tlabel: preset.name,\n\t\t\t\tdescription: [\n\t\t\t\t\t`${get_prompt_source_label(preset.source)} • ${preset.description ?? 'base preset'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t\tcurrentValue: UNSELECTED,\n\t\t\t\tvalues: [SELECTED, UNSELECTED],\n\t\t\t});\n\t\t\tbase_ids.add(preset.name);\n\t\t}\n\n\t\titems.push({\n\t\t\tid: '__header_layers__',\n\t\t\tlabel: `── Prompt layers (${layer_presets.length}) ──`,\n\t\t\tdescription: '',\n\t\t\tcurrentValue: '',\n\t\t});\n\t\tfor (const preset of layer_presets) {\n\t\t\titems.push({\n\t\t\t\tid: preset.name,\n\t\t\t\tlabel: preset.name,\n\t\t\t\tdescription: [\n\t\t\t\t\t`${get_prompt_source_label(preset.source)} • ${preset.description ?? 'layer'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t\tcurrentValue: DISABLED,\n\t\t\t\tvalues: [ENABLED, DISABLED],\n\t\t\t});\n\t\t\tlayer_ids.add(preset.name);\n\t\t}\n\n\t\tfunction sync_values() {\n\t\t\tfor (const item of items) {\n\t\t\t\tif (base_ids.has(item.id)) {\n\t\t\t\t\tconst is_selected =\n\t\t\t\t\t\t(item.id === NONE_BASE_ID && !selected_base) ||\n\t\t\t\t\t\titem.id === selected_base;\n\t\t\t\t\titem.currentValue = is_selected ? SELECTED : UNSELECTED;\n\t\t\t\t} else if (layer_ids.has(item.id)) {\n\t\t\t\t\titem.currentValue = enabled_layers.has(item.id)\n\t\t\t\t\t\t? ENABLED\n\t\t\t\t\t\t: DISABLED;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsync_values();\n\n\t\tawait show_settings_modal(ctx, {\n\t\t\ttitle: 'Prompt presets',\n\t\t\tsubtitle: () =>\n\t\t\t\t`base: ${selected_base ?? '(none)'} • ${enabled_layers.size} layer(s) enabled`,\n\t\t\titems,\n\t\t\tmax_visible: Math.min(Math.max(items.length + 4, 8), 24),\n\t\t\tenable_search: true,\n\t\t\ton_change: (id, new_value) => {\n\t\t\t\tif (id.startsWith('__header_')) return;\n\n\t\t\t\tif (base_ids.has(id)) {\n\t\t\t\t\tselected_base =\n\t\t\t\t\t\tnew_value === SELECTED && id !== NONE_BASE_ID\n\t\t\t\t\t\t\t? id\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\tsync_values();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (layer_ids.has(id)) {\n\t\t\t\t\tif (new_value === ENABLED) {\n\t\t\t\t\t\tenabled_layers.add(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tenabled_layers.delete(id);\n\t\t\t\t\t}\n\t\t\t\t\tsync_values();\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\tif (\n\t\t\tselected_base !== initial_base ||\n\t\t\t!sets_equal(initial_layers, enabled_layers)\n\t\t) {\n\t\t\tcommit_state(ctx, selected_base, enabled_layers, {\n\t\t\t\tnotify: 'Updated prompt preset selection',\n\t\t\t});\n\t\t}\n\t}\n\n\tpi.registerFlag('preset', {\n\t\tdescription:\n\t\t\t'Activate prompt config on startup. Accepts a base preset or comma-separated preset/layer names.',\n\t\ttype: 'string',\n\t});\n\n\tconst prompt_preset_command: Parameters<\n\t\tExtensionAPI['registerCommand']\n\t>[1] = {\n\t\tdescription:\n\t\t\t'Manage prompt presets and layers. Try: /prompt-preset help, /prompt-preset export-defaults, /prompt-preset edit-global terse',\n\t\tgetArgumentCompletions: (prefix) => {\n\t\t\tconst trimmed = prefix.trim();\n\t\t\tconst parts = trimmed ? trimmed.split(/\\s+/) : [];\n\t\t\tconst base_names = list_base_presets(presets).map(\n\t\t\t\t(preset) => preset.name,\n\t\t\t);\n\t\t\tconst layer_names = list_layer_presets(presets).map(\n\t\t\t\t(preset) => preset.name,\n\t\t\t);\n\t\t\tconst all_names = [...base_names, ...layer_names];\n\n\t\t\tif (parts.length <= 1) {\n\t\t\t\tconst query = parts[0] ?? '';\n\t\t\t\tconst subcommands = [\n\t\t\t\t\t'help',\n\t\t\t\t\t'list',\n\t\t\t\t\t'show',\n\t\t\t\t\t'clear',\n\t\t\t\t\t'edit',\n\t\t\t\t\t'edit-global',\n\t\t\t\t\t'export-defaults',\n\t\t\t\t\t'delete',\n\t\t\t\t\t'reset',\n\t\t\t\t\t'reload',\n\t\t\t\t\t'base',\n\t\t\t\t\t'enable',\n\t\t\t\t\t'disable',\n\t\t\t\t\t'toggle',\n\t\t\t\t];\n\t\t\t\treturn [\n\t\t\t\t\t...subcommands\n\t\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t\t.map((item) => ({ value: item, label: item })),\n\t\t\t\t\t...all_names\n\t\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t\t.map((item) => ({ value: item, label: item })),\n\t\t\t\t];\n\t\t\t}\n\n\t\t\tconst command = parts[0];\n\t\t\tconst query = parts.slice(1).join(' ');\n\t\t\tif (command === 'base') {\n\t\t\t\treturn base_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({ value: `base ${item}`, label: item }));\n\t\t\t}\n\t\t\tif (['enable', 'disable', 'toggle'].includes(command)) {\n\t\t\t\treturn layer_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tvalue: `${command} ${item}`,\n\t\t\t\t\t\tlabel: item,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\tif (command === 'edit' || command === 'edit-global') {\n\t\t\t\treturn all_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tvalue: `${command} ${item}`,\n\t\t\t\t\t\tlabel: item,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\tif (['delete', 'reset'].includes(command)) {\n\t\t\t\treturn all_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tvalue: `${command} ${item}`,\n\t\t\t\t\t\tlabel: item,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tconst trimmed = args.trim();\n\t\t\tif (!trimmed) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tawait show_manager(ctx);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\tformat_summary(active_base_name, active_layers, presets),\n\t\t\t\t\t'info',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst [first, ...rest] = trimmed.split(/\\s+/);\n\t\t\tconst arg = rest.join(' ').trim();\n\n\t\t\tswitch (first) {\n\t\t\t\tcase 'help':\n\t\t\t\t\tctx.ui.notify(format_prompt_preset_help(), 'info');\n\t\t\t\t\treturn;\n\t\t\t\tcase 'list':\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\tformat_summary(active_base_name, active_layers, presets),\n\t\t\t\t\t\t'info',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'show':\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\tformat_active_details(\n\t\t\t\t\t\t\tactive_base_name,\n\t\t\t\t\t\t\tactive_layers,\n\t\t\t\t\t\t\tpresets,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t'info',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'clear':\n\t\t\t\t\tcommit_state(ctx, undefined, new Set(), {\n\t\t\t\t\t\tnotify: 'Cleared base preset and prompt layers',\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\tcase 'reload': {\n\t\t\t\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\t\t\t\tconst normalized = normalize_active_state(\n\t\t\t\t\t\tpresets,\n\t\t\t\t\t\tactive_base_name,\n\t\t\t\t\t\tactive_layers,\n\t\t\t\t\t);\n\t\t\t\t\tactive_base_name = normalized.active_base_name;\n\t\t\t\t\tactive_layers = normalized.active_layers;\n\t\t\t\t\tset_status(ctx, active_base_name, active_layers);\n\t\t\t\t\tctx.ui.notify('Reloaded prompt presets', 'info');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase 'base':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset base <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tactivate_base(arg, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'enable':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset enable <layer> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tset_layer_enabled(arg, true, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'disable':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset disable <layer> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tset_layer_enabled(arg, false, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'toggle':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset toggle <layer> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttoggle_layer(arg, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'edit': {\n\t\t\t\t\tlet scope: 'project' | 'global' = 'project';\n\t\t\t\t\tlet name = arg;\n\t\t\t\t\tif (arg.startsWith('--global ')) {\n\t\t\t\t\t\tscope = 'global';\n\t\t\t\t\t\tname = arg.slice('--global '.length).trim();\n\t\t\t\t\t} else if (arg.startsWith('--project ')) {\n\t\t\t\t\t\tname = arg.slice('--project '.length).trim();\n\t\t\t\t\t}\n\t\t\t\t\tif (!name) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset edit [--global|--project] <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait edit_preset(name, ctx, scope);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase 'edit-global':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset edit-global <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait edit_preset(arg, ctx, 'global');\n\t\t\t\t\treturn;\n\t\t\t\tcase 'export-defaults': {\n\t\t\t\t\tconst scope = arg || 'global';\n\t\t\t\t\tif (scope !== 'global' && scope !== 'project') {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset export-defaults [global|project] (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\texport_default_presets(ctx, scope);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase 'delete':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset delete <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tremove_custom_preset(arg, ctx, 'delete');\n\t\t\t\t\treturn;\n\t\t\t\tcase 'reset':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset reset <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tremove_custom_preset(arg, ctx, 'reset');\n\t\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (is_subcommand(first)) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`Unsupported preset command: ${first}`,\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst preset = presets[trimmed];\n\t\t\tif (!preset) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`Unknown preset or layer: ${trimmed}. Try /prompt-preset help.`,\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (preset.kind === 'base') {\n\t\t\t\tactivate_base(preset.name, ctx);\n\t\t\t} else {\n\t\t\t\ttoggle_layer(preset.name, ctx);\n\t\t\t}\n\t\t},\n\t};\n\n\tfor (const command_name of ['prompt-preset', 'preset']) {\n\t\tpi.registerCommand(command_name, prompt_preset_command);\n\t}\n\n\tpi.on('session_start', async (_event, ctx) => {\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tactive_base_name = undefined;\n\t\tactive_layers = new Set();\n\n\t\tconst preset_flag = pi.getFlag('preset');\n\t\tif (typeof preset_flag === 'string' && preset_flag.trim()) {\n\t\t\tfor (const name of parse_preset_flag(preset_flag)) {\n\t\t\t\tconst preset = presets[name];\n\t\t\t\tif (!preset) continue;\n\t\t\t\tif (preset.kind === 'base') {\n\t\t\t\t\tactive_base_name = name;\n\t\t\t\t} else {\n\t\t\t\t\tactive_layers.add(name);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst normalized = normalize_active_state(\n\t\t\t\tpresets,\n\t\t\t\tactive_base_name,\n\t\t\t\tactive_layers,\n\t\t\t);\n\t\t\tactive_base_name = normalized.active_base_name;\n\t\t\tactive_layers = normalized.active_layers;\n\t\t\tset_status(ctx, active_base_name, active_layers);\n\t\t\treturn;\n\t\t}\n\n\t\tconst restored = get_last_preset_state(ctx) ??\n\t\t\tload_persisted_prompt_state(ctx.cwd) ?? {\n\t\t\t\tbase_name: DEFAULT_BASE_PROMPT_PRESET_NAME,\n\t\t\t\tlayer_names: [],\n\t\t\t};\n\t\tactive_base_name = restored.base_name ?? undefined;\n\t\tactive_layers = new Set(restored.layer_names ?? []);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\t\tset_status(ctx, active_base_name, active_layers);\n\t});\n\n\tpi.on('before_agent_start', async (event) => {\n\t\tconst blocks: string[] = [];\n\t\tconst base = get_base(active_base_name);\n\t\tif (base?.instructions.trim()) {\n\t\t\tblocks.push(\n\t\t\t\t`## Active Base Prompt: ${base.name}\\n${base.instructions.trim()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst layer_blocks = [...active_layers]\n\t\t\t.sort()\n\t\t\t.map((name) => presets[name])\n\t\t\t.filter((preset): preset is LoadedPromptPreset =>\n\t\t\t\tBoolean(preset?.instructions.trim()),\n\t\t\t)\n\t\t\t.map(\n\t\t\t\t(preset) =>\n\t\t\t\t\t`### ${preset.name}\\n${preset.instructions.trim()}`,\n\t\t\t);\n\t\tif (layer_blocks.length > 0) {\n\t\t\tblocks.push(\n\t\t\t\t`## Active Prompt Layers\\n\\n${layer_blocks.join('\\n\\n')}`,\n\t\t\t);\n\t\t}\n\n\t\tif (blocks.length === 0) return;\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n\\n${blocks.join('\\n\\n')}`,\n\t\t};\n\t});\n\n\tpi.on('session_shutdown', async (_event, ctx) => {\n\t\tctx.ui.setStatus('preset', undefined);\n\t});\n}\n"],"mappings":";;;;;;AAKA,SAAgB,wBACf,QACS;CACT,QAAQ,QAAR;EACC,KAAK,WACJ,OAAO;EACR,KAAK,QACJ,OAAO;EACR,KAAK,WACJ,OAAO;;;AAIV,SAAgB,kBACf,SACuB;CACvB,OAAO,OAAO,OAAO,QAAQ,CAC3B,QAAQ,WAAW,OAAO,SAAS,OAAO,CAC1C,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,CAAC;;AAG/C,SAAgB,mBACf,SACuB;CACvB,OAAO,OAAO,OAAO,QAAQ,CAC3B,QAAQ,WAAW,OAAO,SAAS,QAAQ,CAC3C,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,CAAC;;AAG/C,SAAgB,eACf,kBACA,eACA,SACS;CACT,MAAM,QAAQ,CAAC,SAAS,oBAAoB,WAAW;CAEvD,MAAM,cAAc,CAAC,GAAG,cAAc,CAAC,MAAM;CAC7C,IAAI,YAAY,WAAW,GAC1B,MAAM,KAAK,iBAAiB;MACtB;EACN,MAAM,KAAK,UAAU;EACrB,KAAK,MAAM,QAAQ,aAAa;GAC/B,MAAM,SAAS,QAAQ;GACvB,MAAM,cAAc,QAAQ,cACzB,MAAM,OAAO,gBACb;GACH,MAAM,KAAK,KAAK,OAAO,cAAc;;;CAIvC,OAAO,MAAM,KAAK,KAAK;;AAGxB,SAAgB,sBACf,kBACA,eACA,SACS;CACT,MAAM,QAAkB,EAAE;CAE1B,IAAI,kBAAkB;EACrB,MAAM,OAAO,QAAQ;EACrB,IAAI,MAAM;GACT,MAAM,KAAK,SAAS,KAAK,OAAO;GAChC,IAAI,KAAK,aACR,MAAM,KAAK,gBAAgB,KAAK,cAAc;GAC/C,MAAM,KAAK,WAAW,wBAAwB,KAAK,OAAO,GAAG;GAC7D,MAAM,KAAK,IAAI,KAAK,aAAa,MAAM,CAAC;;;CAI1C,MAAM,cAAc,CAAC,GAAG,cAAc,CAAC,MAAM;CAC7C,IAAI,YAAY,SAAS,GAAG;EAC3B,IAAI,MAAM,SAAS,GAAG,MAAM,KAAK,IAAI,OAAO,GAAG;EAC/C,MAAM,KAAK,UAAU;EACrB,KAAK,MAAM,QAAQ,aAAa;GAC/B,MAAM,QAAQ,QAAQ;GACtB,IAAI,CAAC,OAAO;GACZ,MAAM,KACL,KAAK,MAAM,KAAK,IAAI,wBAAwB,MAAM,OAAO,CAAC,GAC1D;GACD,IAAI,MAAM,aAAa,MAAM,KAAK,KAAK,MAAM,cAAc;;;CAI7D,OAAO,MAAM,KAAK,KAAK,IAAI;;ACtF5B,MAAa,yBAA0C;CACtD,OAAO;EACN,MAAM;EACN,aAAa;EACb,cACC;EACD;CACD,UAAU;EACT,MAAM;EACN,aAAa;EACb,cACC;EACD;CACD,UAAU;EACT,MAAM;EACN,aAAa;EACb,cACC;EACD;CACD,mBAAmB;EAClB,MAAM;EACN,aAAa;EACb,cACC;EACD;CACD,SAAS;EACR,MAAM;EACN,aAAa;EACb,cACC;EACD;CACD,iBAAiB;EAChB,MAAM;EACN,aACC;EACD,cACC;EACD;CACD,iBAAiB;EAChB,MAAM;EACN,aAAa;EACb,cACC;EACD;CACD;;;AC9CD,SAAS,yBACR,kBACA,eACqB;CACrB,IAAI,CAAC,oBAAoB,cAAc,SAAS,GAC/C;CAMD,OAAO,UAHO,oBAAoB,SAEjC,cAAc,OAAO,IAAI,KAAK,cAAc,SAAS;;AAIvD,SAAgB,WACf,KACA,kBACA,eACO;CACP,IAAI,GAAG,UACN,UACA,yBAAyB,kBAAkB,cAAc,CACzD;;;;ACxBF,SAAgB,cAAc,SAA0B;CACvD,OAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,CAAC,SAAS,QAAQ;;AAGpB,SAAgB,4BAAoC;CACnD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAR,MAAM,6BAA6B;AAOnC,SAAgB,yBACf,OACkB;CAClB,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO,EAAE;CAElD,MAAM,aAA8B,EAAE;CACtC,KAAK,MAAM,CAAC,UAAU,cAAc,OAAO,QAAQ,MAAM,EAAE;EAC1D,MAAM,OAAO,SAAS,MAAM;EAC5B,IAAI,CAAC,MAAM;EAEX,IAAI,OAAO,cAAc,UAAU;GAClC,WAAW,QAAQ;IAClB,MAAM;IACN,cAAc;IACd;GACD;;EAGD,IAAI,CAAC,aAAa,OAAO,cAAc,UAAU;EACjD,MAAM,YAAY;EAKlB,IAAI,OAAO,UAAU,iBAAiB,UAAU;EAEhD,WAAW,QAAQ;GAClB,cAAc,UAAU;GACxB,GAAI,UAAU,SAAS,UACpB,EAAE,MAAM,SAAkB,GAC1B,EAAE;GACL,GAAI,OAAO,UAAU,gBAAgB,WAClC,EAAE,aAAa,UAAU,aAAa,GACtC,EAAE;GACL;;CAGF,OAAO;;AASR,SAAS,yBACR,SACA,QACqC;CACrC,OAAO,OAAO,YACb,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,MAAM,YAAY,CAC/C,MACA;EACC;EACA,MAAM,OAAO,SAAS,UAAU,UAAU;EAC1C;EACA,GAAG;EACH,CACD,CAAC,CACF;;AAGF,SAAS,0BAAkC;CAC1C,OAAO,KAAK,aAAa,EAAE,eAAe;;AAG3C,SAAS,yBAAyB,KAAqB;CACtD,OAAO,KAAK,KAAK,OAAO,eAAe;;AAGxC,SAAgB,yBAAiC;CAChD,OAAO,KAAK,aAAa,EAAE,UAAU;;AAGtC,SAAgB,wBAAwB,KAAqB;CAC5D,OAAO,KAAK,KAAK,OAAO,UAAU;;AAGnC,SAAS,iCAAiC,MAAsB;CAC/D,MAAM,YAAY,KAChB,MAAM,CACN,QAAQ,iBAAiB,IAAI,CAC7B,QAAQ,SAAS,GAAG,CACpB,QAAQ,QAAQ,GAAG,CACnB,QAAQ,QAAQ,GAAG;CACrB,IAAI,CAAC,WACJ,MAAM,IAAI,MACT,wDACA;CAEF,OAAO;;AAGR,SAAgB,4BACf,KACA,MACS;CACT,OAAO,KAAK,KAAK,GAAG,iCAAiC,KAAK,CAAC,KAAK;;AAGjE,SAAS,kCAA0C;CAClD,OAAO,KAAK,aAAa,EAAE,2BAA2B;;AAGvD,SAAS,yBAAyB,MAA+B;CAChE,IAAI,CAAC,WAAW,KAAK,EAAE,OAAO,EAAE;CAEhC,IAAI;EACH,OAAO,yBACN,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAC,CACvC;SACM;EACP,OAAO,EAAE;;;AAIX,SAAS,0BAA0B,OAAuB;CACzD,MAAM,UAAU,MAAM,MAAM;CAC5B,IAAI,QAAQ,WAAW,KAAI,IAAI,QAAQ,SAAS,KAAI,EACnD,IAAI;EACH,OAAO,KAAK,MAAM,QAAQ;SACnB;EACP,OAAO,QAAQ,MAAM,GAAG,GAAG;;CAG7B,IAAI,QAAQ,WAAW,IAAI,IAAI,QAAQ,SAAS,IAAI,EACnD,OAAO,QAAQ,MAAM,GAAG,GAAG;CAE5B,OAAO;;AAGR,SAAS,6BAA6B,SAGpC;CACD,MAAM,aAAa,QAAQ,QAAQ,SAAS,KAAK;CACjD,IAAI,CAAC,WAAW,WAAW,QAAQ,EAClC,OAAO;EAAE,UAAU,EAAE;EAAE,MAAM,WAAW,MAAM;EAAE;CAGjD,MAAM,QAAQ,WAAW,MAAM,KAAK;CACpC,MAAM,MAAM,MAAM,WAChB,MAAM,UAAU,QAAQ,KAAK,KAAK,MAAM,KAAK,MAC9C;CACD,IAAI,QAAQ,IACX,OAAO;EAAE,UAAU,EAAE;EAAE,MAAM,WAAW,MAAM;EAAE;CAGjD,MAAM,WAAmC,EAAE;CAC3C,KAAK,MAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,EAAE;EACvC,MAAM,YAAY,KAAK,QAAQ,IAAI;EACnC,IAAI,cAAc,IAAI;EACtB,MAAM,MAAM,KAAK,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,aAAa;EACzD,MAAM,QAAQ,KAAK,MAAM,YAAY,EAAE,CAAC,MAAM;EAC9C,IAAI,CAAC,KAAK;EACV,SAAS,OAAO,0BAA0B,MAAM;;CAGjD,OAAO;EACN;EACA,MAAM,MACJ,MAAM,MAAM,EAAE,CACd,KAAK,KAAK,CACV,MAAM;EACR;;AAGF,SAAgB,wBACf,MACkB;CAClB,IAAI,CAAC,WAAW,KAAK,EAAE,OAAO,EAAE;CAEhC,IAAI;EACH,MAAM,UAA2B,EAAE;EACnC,KAAK,MAAM,SAAS,YAAY,MAAM,EAAE,eAAe,MAAM,CAAC,CAC5D,QAAQ,SAAS,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS,MAAM,CAAC,CAC5D,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,CAAC,EAAE;GAC/C,MAAM,OAAO,MAAM,KAAK,MAAM,GAAG,GAAG,CAAC,MAAM;GAC3C,IAAI,CAAC,MAAM;GACX,MAAM,EAAE,UAAU,SAAS,6BAC1B,aAAa,KAAK,MAAM,MAAM,KAAK,EAAE,QAAQ,CAC7C;GACD,IAAI,CAAC,MAAM;GACX,QAAQ,QAAQ;IACf,MAAM,SAAS,SAAS,UAAU,UAAU;IAC5C,cAAc;IACd,GAAI,SAAS,cACV,EAAE,aAAa,SAAS,aAAa,GACrC,EAAE;IACL;;EAEF,OAAO;SACA;EACP,OAAO,EAAE;;;AAIX,SAAS,8BAA8B,QAA8B;CACpE,MAAM,QAAQ,CACb,OACA,SAAS,OAAO,SAAS,UAAU,UAAU,SAC7C;CACD,IAAI,OAAO,aAAa,MAAM,EAC7B,MAAM,KACL,gBAAgB,KAAK,UAAU,OAAO,YAAY,MAAM,CAAC,GACzD;CAEF,MAAM,KAAK,OAAO,IAAI,OAAO,aAAa,MAAM,EAAE,GAAG;CACrD,OAAO,MAAM,KAAK,KAAK;;AAGxB,SAAgB,wBACf,KACA,MACA,QACS;CACT,IAAI,CAAC,WAAW,IAAI,EACnB,UAAU,KAAK;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CAGjD,MAAM,OAAO,4BAA4B,KAAK,KAAK;CACnD,MAAM,MAAM,GAAG,KAAK,OAAO,KAAK,KAAK;CACrC,cAAc,KAAK,8BAA8B,OAAO,EAAE,EACzD,MAAM,KACN,CAAC;CACF,WAAW,KAAK,KAAK;CACrB,OAAO;;AAGR,SAAgB,gCACf,KACA,MACA,QACS;CACT,OAAO,wBACN,wBAAwB,IAAI,EAC5B,MACA,OACA;;AAGF,SAAgB,+BACf,MACA,QACS;CACT,OAAO,wBACN,wBAAwB,EACxB,MACA,OACA;;AAGF,SAAS,qCAA8C;CACtD,MAAM,aAAa,QAAQ,IAAI,6BAC5B,MAAM,CACP,aAAa;CACf,OAAO,CAAC;EAAC;EAAK;EAAS;EAAM;EAAQ;EAAU,CAAC,SAC/C,cAAc,GACd;;AAGF,SAAgB,oBACf,KACqC;CACrC,OAAO,OAAO,OACb,EAAE,EACF,yBAAyB,wBAAwB,UAAU,EAC3D,yBACC,yBAAyB,yBAAyB,CAAC,EACnD,OACA,EACD,yBACC,wBAAwB,wBAAwB,CAAC,EACjD,OACA,EACD,GAAI,oCAAoC,GACrC,CACA,yBACC,yBAAyB,yBAAyB,IAAI,CAAC,EACvD,UACA,EACD,yBACC,wBAAwB,wBAAwB,IAAI,CAAC,EACrD,UACA,CACD,GACA,EAAE,CACL;;AAGF,SAAS,oBACR,SACkB;CAClB,OAAO,OAAO,YACb,OAAO,QAAQ,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CAC9D;;AAGF,SAAgB,4BACf,KACA,SACS;CACT,MAAM,OAAO,yBAAyB,IAAI;CAC1C,MAAM,MAAM,QAAQ,KAAK;CACzB,IAAI,CAAC,WAAW,IAAI,EACnB,UAAU,KAAK;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CAGjD,MAAM,MAAM,GAAG,KAAK,OAAO,KAAK,KAAK;CACrC,cACC,KACA,KAAK,UAAU,oBAAoB,QAAQ,EAAE,MAAM,IAAK,GAAG,MAC3D,EAAE,MAAM,KAAO,CACf;CACD,WAAW,KAAK,KAAK;CACrB,OAAO;;AAGR,SAAgB,6BACf,KACA,MAKC;CACD,MAAM,YAAY,yBAAyB,IAAI;CAC/C,MAAM,kBAAkB,yBAAyB,UAAU;CAC3D,IAAI,UAAU;CACd,IAAI,eAAe;CAEnB,IAAI,QAAQ,iBAAiB;EAC5B,OAAO,gBAAgB;EACvB,UAAU;EACV,eAAe;EACf,IAAI,OAAO,KAAK,gBAAgB,CAAC,WAAW;OACvC,WAAW,UAAU,EACxB,WAAW,UAAU;SAGtB,4BAA4B,KAAK,gBAAgB;;CAInD,MAAM,YAAY,4BACjB,wBAAwB,IAAI,EAC5B,KACA;CACD,IAAI,WAAW,UAAU,EAAE;EAC1B,WAAW,UAAU;EACrB,UAAU;EACV,eAAe;;CAGhB,MAAM,YACL,OAAO,KAAK,yBAAyB,UAAU,CAAC,CAAC,SACjD,OAAO,KAAK,wBAAwB,wBAAwB,IAAI,CAAC,CAAC,CAChE;CAEH,OAAO;EAAE;EAAS,MAAM;EAAc;EAAW;;AAGlD,SAAS,8BACR,OACgC;CAChC,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO,KAAA;CAEhD,MAAM,YAAY;CAsBlB,OAAO;EACN,WAlBA,OAAO,UAAU,cAAc,YAC/B,UAAU,UAAU,MAAM,GACvB,UAAU,UAAU,MAAM,GAC1B;EAgBH,aAfmB,MAAM,QAAQ,UAAU,YAAY,GACrD,CACA,GAAG,IAAI,IACN,UAAU,YACR,QACC,UACA,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACpD,CACA,KAAK,UAAU,MAAM,MAAM,CAAC,CAC9B,CACD,CAAC,MAAM,GACP,EAAE;EAKJ;;AAGF,SAAS,6BACR,OAAO,iCAAiC,EACV;CAC9B,IAAI,CAAC,WAAW,KAAK,EACpB,OAAO;EAAE,SAAS;EAAG,UAAU,EAAE;EAAE;CAGpC,IAAI;EACH,MAAM,SAAS,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAC;EAItD,MAAM,eACL,OAAO,YAAY,OAAO,OAAO,aAAa,WAC3C,OAAO,WACP,EAAE;EACN,MAAM,WAA8C,EAAE;EACtD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa,EAAE;GACxD,MAAM,aAAa,8BAA8B,MAAM;GACvD,IAAI,CAAC,YAAY;GACjB,SAAS,OAAO;;EAEjB,OAAO;GACN,SACC,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;GACvD;GACA;SACM;EACP,OAAO;GAAE,SAAS;GAAG,UAAU,EAAE;GAAE;;;AAIrC,SAAgB,4BACf,KACA,OAAO,iCAAiC,EACR;CAChC,OAAO,6BAA6B,KAAK,CAAC,SAAS;;AAGpD,SAAgB,4BACf,KACA,OACA,OAAO,iCAAiC,EAC/B;CACT,MAAM,YAAY,6BAA6B,KAAK;CACpD,UAAU,SAAS,OAAO,8BAA8B,MAAM,IAAI;EACjE,WAAW;EACX,aAAa,EAAE;EACf;CAED,MAAM,MAAM,QAAQ,KAAK;CACzB,IAAI,CAAC,WAAW,IAAI,EACnB,UAAU,KAAK;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CAGjD,MAAM,MAAM,GAAG,KAAK,OAAO,KAAK,KAAK;CACrC,cACC,KACA,KAAK,UACJ;EACC,SAAS;EACT,UAAU,OAAO,YAChB,OAAO,QAAQ,UAAU,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,OAC9C,EAAE,cAAc,EAAE,CAClB,CACD;EACD,EACD,MACA,IACA,GAAG,MACJ,EAAE,MAAM,KAAO,CACf;CACD,WAAW,KAAK,KAAK;CACrB,OAAO;;;;ACteR,MAAa,oBAAoB;AACjC,MAAa,UAAU;AACvB,MAAa,WAAW;AACxB,MAAa,WAAW;AAExB,MAAa,eAAe;AAE5B,SAAgB,sBACf,KACgC;CAChC,MAAM,UAAU,IAAI,eAAe,YAAY;CAC/C,KAAK,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,MAAM,QAAQ,QAAQ;EAKtB,IACC,MAAM,SAAS,YACf,MAAM,eAAA,yBACN,MAAM,MAEN,OAAO,MAAM;;;AAMhB,SAAgB,WACf,GACA,GACU;CACV,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;CAC9B,KAAK,MAAM,SAAS,GACnB,IAAI,CAAC,EAAE,IAAI,MAAM,EAAE,OAAO;CAE3B,OAAO;;AAGR,SAAgB,cACf,IACA,KACA,kBACA,eACO;CACP,MAAM,QAAQ;EACb,WAAW,oBAAoB;EAC/B,aAAa,CAAC,GAAG,cAAc,CAAC,MAAM;EACtC;CACD,GAAG,YAAY,mBAAmB,MAAM;CACxC,4BAA4B,IAAI,KAAK,MAAM;;AAG5C,SAAgB,uBACf,SACA,kBACA,eAIC;CAUD,OAAO;EACN,kBATA,oBAAoB,QAAQ,mBAAmB,SAAS,SACrD,mBACA,KAAA;EAQH,eAAe,IAPQ,IACvB,CAAC,GAAG,cAAc,CAAC,QACjB,SAAS,QAAQ,OAAO,SAAS,QAClC,CAIyB;EAC1B;;AAGF,SAAgB,kBAAkB,MAAwB;CACzD,OAAO,KACL,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ;;;;ACZlB,eAA8B,eAAe,IAAkB;CAC9D,IAAI,UAA8C,EAAE;CACpD,IAAI;CACJ,IAAI,gCAAgB,IAAI,KAAa;CAErC,SAAS,SACR,MACiC;EACjC,OAAO,OAAO,QAAQ,QAAQ,KAAA;;CAG/B,SAAS,UAAU,MAA8C;EAChE,MAAM,SAAS,QAAQ;EACvB,OAAO,QAAQ,SAAS,UAAU,SAAS,KAAA;;CAG5C,SAAS,aACR,KACA,gBACA,aACA,SACO;EACP,mBAAmB;EACnB,gBAAgB,IAAI,IAAI,YAAY;EACpC,WAAW,KAAK,kBAAkB,cAAc;EAChD,IAAI,SAAS,YAAY,OACxB,cAAc,IAAI,KAAK,kBAAkB,cAAc;EAExD,IAAI,SAAS,QACZ,IAAI,GAAG,OAAO,QAAQ,QAAQ,OAAO;;CAIvC,SAAS,cACR,MACA,KACA,SACU;EACV,IAAI,CAAC,MAAM;GACV,aAAa,KAAK,KAAA,GAAW,eAAe;IAC3C,SAAS,SAAS;IAClB,QAAQ;IACR,CAAC;GACF,OAAO;;EAGR,MAAM,SAAS,SAAS,KAAK;EAC7B,IAAI,CAAC,QAAQ;GACZ,IAAI,GAAG,OAAO,wBAAwB,QAAQ,UAAU;GACxD,OAAO;;EAGR,aAAa,KAAK,OAAO,MAAM,eAAe;GAC7C,SAAS,SAAS;GAClB,QAAQ,gBAAgB,OAAO,KAAK;GACpC,CAAC;EACF,OAAO;;CAGR,SAAS,kBACR,MACA,SACA,KACA,SACU;EACV,MAAM,SAAS,UAAU,KAAK;EAC9B,IAAI,CAAC,QAAQ;GACZ,IAAI,GAAG,OAAO,yBAAyB,QAAQ,UAAU;GACzD,OAAO;;EAGR,MAAM,cAAc,IAAI,IAAI,cAAc;EAC1C,IAAI,SACH,YAAY,IAAI,OAAO,KAAK;OAE5B,YAAY,OAAO,OAAO,KAAK;EAGhC,aAAa,KAAK,kBAAkB,aAAa;GAChD,SAAS,SAAS;GAClB,QAAQ,UACL,UAAU,OAAO,KAAK,aACtB,UAAU,OAAO,KAAK;GACzB,CAAC;EACF,OAAO;;CAGR,SAAS,aACR,MACA,KACA,SACU;EACV,OAAO,kBACN,MACA,CAAC,cAAc,IAAI,KAAK,EACxB,KACA,QACA;;CAGF,eAAe,YACd,MACA,KACA,QAA8B,WACd;EAChB,MAAM,WAAW,QAAQ;EACzB,MAAM,cAAc,MAAM,IAAI,GAAG,OAAO,eAAe,CACtD,UAAU,SAAS,UAChB,oBACA,kBACH,UAAU,SAAS,UAAU,SAAS,QACtC,CAAC;EACF,IAAI,CAAC,aAAa;EAClB,MAAM,OAAyB,YAAY,WAAW,QAAQ,GAC3D,UACA;EAEH,MAAM,cAAc,MAAM,IAAI,GAAG,MAChC,mBAAmB,QACnB,UAAU,eAAe,GACzB;EACD,IAAI,gBAAgB,KAAA,GAAW;EAE/B,MAAM,eAAe,MAAM,IAAI,GAAG,OACjC,QAAQ,KAAK,WAAW,QACxB,UAAU,gBAAgB,GAC1B;EACD,IAAI,iBAAiB,KAAA,GAAW;EAEhC,MAAM,aACL,UAAU,WACP,+BAA+B,MAAM;GACrC;GACA;GACA,GAAI,YAAY,MAAM,GACnB,EAAE,aAAa,YAAY,MAAM,EAAE,GACnC,EAAE;GACL,CAAC,GACD,gCAAgC,IAAI,KAAK,MAAM;GAC/C;GACA;GACA,GAAI,YAAY,MAAM,GACnB,EAAE,aAAa,YAAY,MAAM,EAAE,GACnC,EAAE;GACL,CAAC;EAEL,UAAU,oBAAoB,IAAI,IAAI;EACtC,MAAM,aAAa,uBAClB,SACA,kBACA,cACA;EACD,mBAAmB,WAAW;EAC9B,gBAAgB,WAAW;EAE3B,IAAI,SAAS,QACZ,cAAc,MAAM,IAAI;OAExB,kBAAkB,MAAM,MAAM,IAAI;EAEnC,IAAI,GAAG,OAAO,iBAAiB,KAAK,OAAO,cAAc,OAAO;;CAGjE,SAAS,uBACR,KACA,OACO;EACP,MAAM,MACL,UAAU,WACP,wBAAwB,GACxB,wBAAwB,IAAI,IAAI;EACpC,IAAI,UAAU;EACd,IAAI,UAAU;EACd,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QACnC,uBACA,EAAE;GAEF,IAAI,WADS,4BAA4B,KAAK,KAC3B,CAAC,EAAE;IACrB,WAAW;IACX;;GAED,wBAAwB,KAAK,MAAM,OAAO;GAC1C,WAAW;;EAGZ,UAAU,oBAAoB,IAAI,IAAI;EACtC,MAAM,aAAa,uBAClB,SACA,kBACA,cACA;EACD,mBAAmB,WAAW;EAC9B,gBAAgB,WAAW;EAC3B,WAAW,KAAK,kBAAkB,cAAc;EAEhD,IAAI,GAAG,OACN,YAAY,QAAQ,8BAA8B,MAAM,UAAU,KAAK,QAAQ,qBAAqB,MACpG,OACA;;CAGF,SAAS,qBACR,MACA,KACA,MACO;EACP,MAAM,SAAS,6BAA6B,IAAI,KAAK,KAAK;EAC1D,IAAI,CAAC,OAAO,SAAS;GACpB,IAAI,GAAG,OACN,kCAAkC,KAAK,OAAO,QAC9C,UACA;GACD;;EAGD,UAAU,oBAAoB,IAAI,IAAI;EACtC,MAAM,aAAa,uBAClB,SACA,kBACA,cACA;EACD,mBAAmB,WAAW;EAC9B,gBAAgB,WAAW;EAC3B,WAAW,KAAK,kBAAkB,cAAc;EAChD,cAAc,IAAI,KAAK,kBAAkB,cAAc;EAEvD,MAAM,WAAW,QAAQ;EACzB,IAAI,SAAS,WAAW,UAAU;GACjC,IAAI,GAAG,OACN,UAAU,KAAK,OAAO,wBAAwB,SAAS,OAAO,CAAC,UAC/D,OACA;GACD;;EAGD,IAAI,GAAG,OACN,OAAO,cAAc,IAClB,YAAY,KAAK,gBAAgB,OAAO,SACxC,YAAY,KAAK,SAAS,OAAO,QACpC,OACA;;CAGF,eAAe,aACd,KACgB;EAChB,MAAM,eAAe,kBAAkB,QAAQ;EAC/C,MAAM,gBAAgB,mBAAmB,QAAQ;EACjD,IAAI,aAAa,WAAW,KAAK,cAAc,WAAW,GAAG;GAC5D,IAAI,GAAG,OAAO,+BAA+B,UAAU;GACvD;;EAGD,MAAM,eAAe;EACrB,MAAM,iBAAiB,IAAI,IAAI,cAAc;EAC7C,IAAI,gBAAgB;EACpB,MAAM,iBAAiB,IAAI,IAAI,cAAc;EAE7C,MAAM,QAAuB,EAAE;EAC/B,MAAM,2BAAW,IAAI,KAAa;EAClC,MAAM,4BAAY,IAAI,KAAa;EAEnC,MAAM,KAAK;GACV,IAAI;GACJ,OAAO,oBAAoB,aAAa,SAAS,EAAE;GACnD,aAAa;GACb,cAAc;GACd,CAAC;EACF,MAAM,KAAK;GACV,IAAI;GACJ,OAAO;GACP,aAAa;GACb,cAAA;GACA,QAAQ,CAAC,UAAA,IAAqB;GAC9B,CAAC;EACF,SAAS,IAAI,aAAa;EAE1B,KAAK,MAAM,UAAU,cAAc;GAClC,MAAM,KAAK;IACV,IAAI,OAAO;IACX,OAAO,OAAO;IACd,aAAa,CACZ,GAAG,wBAAwB,OAAO,OAAO,CAAC,KAAK,OAAO,eAAe,gBACrE,CAAC,KAAK,KAAK;IACZ,cAAA;IACA,QAAQ,CAAC,UAAA,IAAqB;IAC9B,CAAC;GACF,SAAS,IAAI,OAAO,KAAK;;EAG1B,MAAM,KAAK;GACV,IAAI;GACJ,OAAO,qBAAqB,cAAc,OAAO;GACjD,aAAa;GACb,cAAc;GACd,CAAC;EACF,KAAK,MAAM,UAAU,eAAe;GACnC,MAAM,KAAK;IACV,IAAI,OAAO;IACX,OAAO,OAAO;IACd,aAAa,CACZ,GAAG,wBAAwB,OAAO,OAAO,CAAC,KAAK,OAAO,eAAe,UACrE,CAAC,KAAK,KAAK;IACZ,cAAc;IACd,QAAQ,CAAC,SAAS,SAAS;IAC3B,CAAC;GACF,UAAU,IAAI,OAAO,KAAK;;EAG3B,SAAS,cAAc;GACtB,KAAK,MAAM,QAAQ,OAClB,IAAI,SAAS,IAAI,KAAK,GAAG,EAIxB,KAAK,eAFH,KAAK,OAAA,mBAAuB,CAAC,iBAC9B,KAAK,OAAO,gBACqB,WAAA;QAC5B,IAAI,UAAU,IAAI,KAAK,GAAG,EAChC,KAAK,eAAe,eAAe,IAAI,KAAK,GAAG,GAC5C,UACA;;EAKN,aAAa;EAEb,MAAM,oBAAoB,KAAK;GAC9B,OAAO;GACP,gBACC,SAAS,iBAAiB,SAAS,KAAK,eAAe,KAAK;GAC7D;GACA,aAAa,KAAK,IAAI,KAAK,IAAI,MAAM,SAAS,GAAG,EAAE,EAAE,GAAG;GACxD,eAAe;GACf,YAAY,IAAI,cAAc;IAC7B,IAAI,GAAG,WAAW,YAAY,EAAE;IAEhC,IAAI,SAAS,IAAI,GAAG,EAAE;KACrB,gBACC,cAAA,gBAA0B,OAAA,kBACvB,KACA,KAAA;KACJ,aAAa;KACb;;IAGD,IAAI,UAAU,IAAI,GAAG,EAAE;KACtB,IAAI,cAAA,aACH,eAAe,IAAI,GAAG;UAEtB,eAAe,OAAO,GAAG;KAE1B,aAAa;;;GAGf,CAAC;EAEF,IACC,kBAAkB,gBAClB,CAAC,WAAW,gBAAgB,eAAe,EAE3C,aAAa,KAAK,eAAe,gBAAgB,EAChD,QAAQ,mCACR,CAAC;;CAIJ,GAAG,aAAa,UAAU;EACzB,aACC;EACD,MAAM;EACN,CAAC;CAEF,MAAM,wBAEC;EACN,aACC;EACD,yBAAyB,WAAW;GACnC,MAAM,UAAU,OAAO,MAAM;GAC7B,MAAM,QAAQ,UAAU,QAAQ,MAAM,MAAM,GAAG,EAAE;GACjD,MAAM,aAAa,kBAAkB,QAAQ,CAAC,KAC5C,WAAW,OAAO,KACnB;GACD,MAAM,cAAc,mBAAmB,QAAQ,CAAC,KAC9C,WAAW,OAAO,KACnB;GACD,MAAM,YAAY,CAAC,GAAG,YAAY,GAAG,YAAY;GAEjD,IAAI,MAAM,UAAU,GAAG;IACtB,MAAM,QAAQ,MAAM,MAAM;IAiB1B,OAAO,CACN,GAAG;KAhBH;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KAGc,CACZ,QAAQ,SAAS,KAAK,WAAW,MAAM,CAAC,CACxC,KAAK,UAAU;KAAE,OAAO;KAAM,OAAO;KAAM,EAAE,EAC/C,GAAG,UACD,QAAQ,SAAS,KAAK,WAAW,MAAM,CAAC,CACxC,KAAK,UAAU;KAAE,OAAO;KAAM,OAAO;KAAM,EAAE,CAC/C;;GAGF,MAAM,UAAU,MAAM;GACtB,MAAM,QAAQ,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI;GACtC,IAAI,YAAY,QACf,OAAO,WACL,QAAQ,SAAS,KAAK,WAAW,MAAM,CAAC,CACxC,KAAK,UAAU;IAAE,OAAO,QAAQ;IAAQ,OAAO;IAAM,EAAE;GAE1D,IAAI;IAAC;IAAU;IAAW;IAAS,CAAC,SAAS,QAAQ,EACpD,OAAO,YACL,QAAQ,SAAS,KAAK,WAAW,MAAM,CAAC,CACxC,KAAK,UAAU;IACf,OAAO,GAAG,QAAQ,GAAG;IACrB,OAAO;IACP,EAAE;GAEL,IAAI,YAAY,UAAU,YAAY,eACrC,OAAO,UACL,QAAQ,SAAS,KAAK,WAAW,MAAM,CAAC,CACxC,KAAK,UAAU;IACf,OAAO,GAAG,QAAQ,GAAG;IACrB,OAAO;IACP,EAAE;GAEL,IAAI,CAAC,UAAU,QAAQ,CAAC,SAAS,QAAQ,EACxC,OAAO,UACL,QAAQ,SAAS,KAAK,WAAW,MAAM,CAAC,CACxC,KAAK,UAAU;IACf,OAAO,GAAG,QAAQ,GAAG;IACrB,OAAO;IACP,EAAE;GAEL,OAAO;;EAER,SAAS,OAAO,MAAM,QAAQ;GAC7B,MAAM,UAAU,KAAK,MAAM;GAC3B,IAAI,CAAC,SAAS;IACb,IAAI,IAAI,OAAO;KACd,MAAM,aAAa,IAAI;KACvB;;IAED,IAAI,GAAG,OACN,eAAe,kBAAkB,eAAe,QAAQ,EACxD,OACA;IACD;;GAGD,MAAM,CAAC,OAAO,GAAG,QAAQ,QAAQ,MAAM,MAAM;GAC7C,MAAM,MAAM,KAAK,KAAK,IAAI,CAAC,MAAM;GAEjC,QAAQ,OAAR;IACC,KAAK;KACJ,IAAI,GAAG,OAAO,2BAA2B,EAAE,OAAO;KAClD;IACD,KAAK;KACJ,IAAI,GAAG,OACN,eAAe,kBAAkB,eAAe,QAAQ,EACxD,OACA;KACD;IACD,KAAK;KACJ,IAAI,GAAG,OACN,sBACC,kBACA,eACA,QACA,EACD,OACA;KACD;IACD,KAAK;KACJ,aAAa,KAAK,KAAA,mBAAW,IAAI,KAAK,EAAE,EACvC,QAAQ,yCACR,CAAC;KACF;IACD,KAAK,UAAU;KACd,UAAU,oBAAoB,IAAI,IAAI;KACtC,MAAM,aAAa,uBAClB,SACA,kBACA,cACA;KACD,mBAAmB,WAAW;KAC9B,gBAAgB,WAAW;KAC3B,WAAW,KAAK,kBAAkB,cAAc;KAChD,IAAI,GAAG,OAAO,2BAA2B,OAAO;KAChD;;IAED,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,sDACA,UACA;MACD;;KAED,cAAc,KAAK,IAAI;KACvB;IACD,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,yDACA,UACA;MACD;;KAED,kBAAkB,KAAK,MAAM,IAAI;KACjC;IACD,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,0DACA,UACA;MACD;;KAED,kBAAkB,KAAK,OAAO,IAAI;KAClC;IACD,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,yDACA,UACA;MACD;;KAED,aAAa,KAAK,IAAI;KACtB;IACD,KAAK,QAAQ;KACZ,IAAI,QAA8B;KAClC,IAAI,OAAO;KACX,IAAI,IAAI,WAAW,YAAY,EAAE;MAChC,QAAQ;MACR,OAAO,IAAI,MAAM,EAAmB,CAAC,MAAM;YACrC,IAAI,IAAI,WAAW,aAAa,EACtC,OAAO,IAAI,MAAM,GAAoB,CAAC,MAAM;KAE7C,IAAI,CAAC,MAAM;MACV,IAAI,GAAG,OACN,2EACA,UACA;MACD;;KAED,MAAM,YAAY,MAAM,KAAK,MAAM;KACnC;;IAED,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,6DACA,UACA;MACD;;KAED,MAAM,YAAY,KAAK,KAAK,SAAS;KACrC;IACD,KAAK,mBAAmB;KACvB,MAAM,QAAQ,OAAO;KACrB,IAAI,UAAU,YAAY,UAAU,WAAW;MAC9C,IAAI,GAAG,OACN,2EACA,UACA;MACD;;KAED,uBAAuB,KAAK,MAAM;KAClC;;IAED,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,wDACA,UACA;MACD;;KAED,qBAAqB,KAAK,KAAK,SAAS;KACxC;IACD,KAAK;KACJ,IAAI,CAAC,KAAK;MACT,IAAI,GAAG,OACN,uDACA,UACA;MACD;;KAED,qBAAqB,KAAK,KAAK,QAAQ;KACvC;;GAGF,IAAI,cAAc,MAAM,EAAE;IACzB,IAAI,GAAG,OACN,+BAA+B,SAC/B,UACA;IACD;;GAGD,MAAM,SAAS,QAAQ;GACvB,IAAI,CAAC,QAAQ;IACZ,IAAI,GAAG,OACN,4BAA4B,QAAQ,6BACpC,UACA;IACD;;GAED,IAAI,OAAO,SAAS,QACnB,cAAc,OAAO,MAAM,IAAI;QAE/B,aAAa,OAAO,MAAM,IAAI;;EAGhC;CAED,KAAK,MAAM,gBAAgB,CAAC,iBAAiB,SAAS,EACrD,GAAG,gBAAgB,cAAc,sBAAsB;CAGxD,GAAG,GAAG,iBAAiB,OAAO,QAAQ,QAAQ;EAC7C,UAAU,oBAAoB,IAAI,IAAI;EACtC,mBAAmB,KAAA;EACnB,gCAAgB,IAAI,KAAK;EAEzB,MAAM,cAAc,GAAG,QAAQ,SAAS;EACxC,IAAI,OAAO,gBAAgB,YAAY,YAAY,MAAM,EAAE;GAC1D,KAAK,MAAM,QAAQ,kBAAkB,YAAY,EAAE;IAClD,MAAM,SAAS,QAAQ;IACvB,IAAI,CAAC,QAAQ;IACb,IAAI,OAAO,SAAS,QACnB,mBAAmB;SAEnB,cAAc,IAAI,KAAK;;GAGzB,MAAM,aAAa,uBAClB,SACA,kBACA,cACA;GACD,mBAAmB,WAAW;GAC9B,gBAAgB,WAAW;GAC3B,WAAW,KAAK,kBAAkB,cAAc;GAChD;;EAGD,MAAM,WAAW,sBAAsB,IAAI,IAC1C,4BAA4B,IAAI,IAAI,IAAI;GACvC,WAAA;GACA,aAAa,EAAE;GACf;EACF,mBAAmB,SAAS,aAAa,KAAA;EACzC,gBAAgB,IAAI,IAAI,SAAS,eAAe,EAAE,CAAC;EACnD,MAAM,aAAa,uBAClB,SACA,kBACA,cACA;EACD,mBAAmB,WAAW;EAC9B,gBAAgB,WAAW;EAC3B,WAAW,KAAK,kBAAkB,cAAc;GAC/C;CAEF,GAAG,GAAG,sBAAsB,OAAO,UAAU;EAC5C,MAAM,SAAmB,EAAE;EAC3B,MAAM,OAAO,SAAS,iBAAiB;EACvC,IAAI,MAAM,aAAa,MAAM,EAC5B,OAAO,KACN,0BAA0B,KAAK,KAAK,IAAI,KAAK,aAAa,MAAM,GAChE;EAGF,MAAM,eAAe,CAAC,GAAG,cAAc,CACrC,MAAM,CACN,KAAK,SAAS,QAAQ,MAAM,CAC5B,QAAQ,WACR,QAAQ,QAAQ,aAAa,MAAM,CAAC,CACpC,CACA,KACC,WACA,OAAO,OAAO,KAAK,IAAI,OAAO,aAAa,MAAM,GAClD;EACF,IAAI,aAAa,SAAS,GACzB,OAAO,KACN,8BAA8B,aAAa,KAAK,OAAO,GACvD;EAGF,IAAI,OAAO,WAAW,GAAG;EACzB,OAAO,EACN,cAAc,GAAG,MAAM,aAAa,MAAM,OAAO,KAAK,OAAO,IAC7D;GACA;CAEF,GAAG,GAAG,oBAAoB,OAAO,QAAQ,QAAQ;EAChD,IAAI,GAAG,UAAU,UAAU,KAAA,EAAU;GACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-name-
|
|
1
|
+
{"version":3,"file":"session-name-De4KoM5r.js","names":[],"sources":["../src/extensions/session-name/index.ts"],"sourcesContent":["// Session name — AI-powered session naming\n// Adapted from Thomas Lopes' pi dotfiles\n\nimport { complete, type Message } from '@earendil-works/pi-ai';\nimport type {\n\tExtensionAPI,\n\tSessionEntry,\n} from '@earendil-works/pi-coding-agent';\nimport {\n\tBorderedLoader,\n\tconvertToLlm,\n\tserializeConversation,\n} from '@earendil-works/pi-coding-agent';\n\nconst SYSTEM_PROMPT = `You are a session naming assistant. Given a conversation history, generate a short, descriptive session name (2-5 words) that captures the main topic or task.\n\nGuidelines:\n- Be concise but specific\n- Use kebab-case or natural language\n- Focus on the core task/question\n- Avoid generic names like \"discussion\" or \"conversation\"\n- No quotes, no punctuation at the end\n\nExamples:\n- \"fix auth bug\" -> \"fix-auth-bug\" or \"authentication fix\"\n- \"how do I deploy to vercel\" -> \"vercel deployment\"\n- \"explain react hooks\" -> \"react hooks explanation\"\n- \"optimize database queries\" -> \"db query optimization\"\n\nOutput ONLY the session name, nothing else.`;\n\nconst AUTO_NAME_THRESHOLD = 1;\nconst MAX_CHARS = 4000;\nconst MAX_NAME_LEN = 50;\n\nfunction clean_name(value: string): string {\n\treturn value\n\t\t.replace(/^[\"']|[\"']$/g, '')\n\t\t.replace(/\\n/g, ' ')\n\t\t.replace(/\\s+/g, ' ')\n\t\t.trim()\n\t\t.slice(0, MAX_NAME_LEN);\n}\n\nfunction truncate_conversation(value: string): string {\n\treturn value.length > MAX_CHARS\n\t\t? value.slice(0, MAX_CHARS) + '\\n...'\n\t\t: value;\n}\n\nasync function generate_session_name(\n\tctx: {\n\t\tmodelRegistry: {\n\t\t\tgetApiKeyAndHeaders: (\n\t\t\t\tmodel: NonNullable<\n\t\t\t\t\tParameters<\n\t\t\t\t\t\tParameters<ExtensionAPI['registerCommand']>[1]['handler']\n\t\t\t\t\t>[1]['model']\n\t\t\t\t>,\n\t\t\t) => Promise<any>;\n\t\t};\n\t},\n\tmodel: NonNullable<\n\t\tParameters<\n\t\t\tParameters<ExtensionAPI['registerCommand']>[1]['handler']\n\t\t>[1]['model']\n\t>,\n\tconversation_text: string,\n\tsignal?: AbortSignal,\n): Promise<string | null> {\n\tconst auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n\tif (!auth.ok || !auth.apiKey) {\n\t\tthrow new Error(\n\t\t\tauth.ok ? `No API key for ${model.provider}` : auth.error,\n\t\t);\n\t}\n\n\tconst user_message: Message = {\n\t\trole: 'user',\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: 'text',\n\t\t\t\ttext: `## Conversation History\\n\\n${truncate_conversation(conversation_text)}\\n\\nGenerate a concise session name for this conversation.`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.now(),\n\t};\n\n\tconst response = await complete(\n\t\tmodel,\n\t\t{ systemPrompt: SYSTEM_PROMPT, messages: [user_message] },\n\t\t{ apiKey: auth.apiKey, headers: auth.headers, signal },\n\t);\n\n\tif (response.stopReason === 'aborted') {\n\t\treturn null;\n\t}\n\n\treturn clean_name(\n\t\tresponse.content\n\t\t\t.filter(\n\t\t\t\t(c): c is { type: 'text'; text: string } => c.type === 'text',\n\t\t\t)\n\t\t\t.map((c) => c.text.trim())\n\t\t\t.join(' '),\n\t);\n}\n\nexport default async function session_name(pi: ExtensionAPI) {\n\tlet auto_named_attempted = false;\n\n\tpi.on('agent_end', async (_event, ctx) => {\n\t\tif (!ctx.hasUI || !ctx.model) return;\n\t\tif (pi.getSessionName() || auto_named_attempted) return;\n\n\t\tconst branch = ctx.sessionManager.getBranch();\n\t\tconst user_messages = branch.filter(\n\t\t\t(entry): entry is SessionEntry & { type: 'message' } =>\n\t\t\t\tentry.type === 'message' && entry.message.role === 'user',\n\t\t);\n\t\tif (user_messages.length < AUTO_NAME_THRESHOLD) return;\n\n\t\tauto_named_attempted = true;\n\t\tconst messages = branch\n\t\t\t.filter(\n\t\t\t\t(entry): entry is SessionEntry & { type: 'message' } =>\n\t\t\t\t\tentry.type === 'message',\n\t\t\t)\n\t\t\t.map((entry) => entry.message);\n\t\tif (messages.length === 0) return;\n\n\t\tconst conversation_text = serializeConversation(\n\t\t\tconvertToLlm(messages),\n\t\t);\n\n\t\tgenerate_session_name(ctx, ctx.model, conversation_text)\n\t\t\t.then((name) => {\n\t\t\t\tif (!name) return;\n\t\t\t\tpi.setSessionName(name);\n\t\t\t\tctx.ui.notify(`Auto-named: ${name}`, 'info');\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\tconsole.error('Auto-naming failed:', err);\n\t\t\t});\n\t});\n\n\tpi.on('session_start', async () => {\n\t\tauto_named_attempted = false;\n\t});\n\n\tpi.registerCommand('session-name', {\n\t\tdescription:\n\t\t\t'Set, show, or auto-generate the current session name',\n\t\thandler: async (args, ctx) => {\n\t\t\tconst trimmed = args.trim();\n\n\t\t\tif (!trimmed) {\n\t\t\t\tconst current = pi.getSessionName();\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\tcurrent ? `Session: ${current}` : 'No session name set',\n\t\t\t\t\t'info',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (trimmed === '--auto' || trimmed === '-a') {\n\t\t\t\tif (!ctx.hasUI || !ctx.model) {\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t'Auto-naming requires interactive mode and a selected model',\n\t\t\t\t\t\t'error',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst branch = ctx.sessionManager.getBranch();\n\t\t\t\tconst messages = branch\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(entry): entry is SessionEntry & { type: 'message' } =>\n\t\t\t\t\t\t\tentry.type === 'message',\n\t\t\t\t\t)\n\t\t\t\t\t.map((entry) => entry.message);\n\t\t\t\tif (messages.length === 0) {\n\t\t\t\t\tctx.ui.notify('No conversation to analyze', 'error');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst conversation_text = serializeConversation(\n\t\t\t\t\tconvertToLlm(messages),\n\t\t\t\t);\n\n\t\t\t\tconst result = await ctx.ui.custom<string | null>(\n\t\t\t\t\t(tui, theme, _kb, done) => {\n\t\t\t\t\t\tconst loader = new BorderedLoader(\n\t\t\t\t\t\t\ttui,\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\t'Generating session name...',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tloader.onAbort = () => done(null);\n\n\t\t\t\t\t\tgenerate_session_name(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\tctx.model!,\n\t\t\t\t\t\t\tconversation_text,\n\t\t\t\t\t\t\tloader.signal,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.then(done)\n\t\t\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\t\t\tconsole.error('Auto-naming failed:', err);\n\t\t\t\t\t\t\t\tdone(null);\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn loader;\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tif (result === null) {\n\t\t\t\t\tctx.ui.notify('Auto-naming cancelled', 'info');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!result) {\n\t\t\t\t\tctx.ui.notify('Failed to generate name', 'error');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tpi.setSessionName(result);\n\t\t\t\tctx.ui.notify(`Session named: ${result}`, 'info');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpi.setSessionName(clean_name(trimmed));\n\t\t\tctx.ui.notify(`Session named: ${clean_name(trimmed)}`, 'info');\n\t\t},\n\t});\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-screen-ofHxGDsk.js","names":[],"sources":["../src/extensions/startup-screen/index.ts"],"sourcesContent":["import type {\n\tExtensionAPI,\n\tExtensionContext,\n\tTheme,\n\tThemeColor,\n} from '@earendil-works/pi-coding-agent';\nimport {\n\ttruncateToWidth,\n\tvisibleWidth,\n} from '@earendil-works/pi-tui';\nimport { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\n\ntype Rgb = [number, number, number];\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst TRUECOLOR_FG_PREFIX = '\\x1b[38;2;';\nconst XTERM_FG_PREFIX = '\\x1b[38;5;';\n\nconst FALLBACK_PALETTE: Rgb[] = [\n\t[22, 83, 189],\n\t[48, 129, 247],\n\t[93, 171, 255],\n\t[151, 205, 255],\n\t[93, 171, 255],\n\t[48, 129, 247],\n];\n\nconst THEME_GRADIENT_TOKENS: ThemeColor[] = [\n\t'accent',\n\t'borderAccent',\n\t'mdHeading',\n\t'syntaxFunction',\n\t'thinkingHigh',\n\t'mdCode',\n];\n\nconst XTERM_CUBE_VALUES = [0, 95, 135, 175, 215, 255] as const;\nconst XTERM_GRAY_START = 232;\n\nconst TITLE_LINES = [\n\t'███╗ ███╗ ██████╗ ██╗',\n\t'████╗ ████║ ██╗ ██╗ ██╔══██╗ ',\n\t'██╔████╔██║ ╚██╗ ██╔╝ ████╗ ██████╔╝██╗',\n\t'██║╚██╔╝██║ ╚████╔╝ ╚═══╝ ██╔═══╝ ██║',\n\t'██║ ╚═╝ ██║ ╚██╔╝ ██║ ██║',\n\t'╚═╝ ╚═╝ ██╔╝ ╚═╝ ╚═╝',\n] as const;\n\nconst TITLE_WIDTH = Math.max(\n\t...TITLE_LINES.map((line) => line.length),\n);\n\nfunction read_my_pi_version(): string {\n\tconst candidates = [\n\t\tnew URL('../../../package.json', import.meta.url),\n\t\tnew URL('../package.json', import.meta.url),\n\t];\n\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(\n\t\t\t\treadFileSync(candidate, 'utf-8'),\n\t\t\t);\n\t\t\tconst version = (parsed as { version?: unknown } | null)\n\t\t\t\t?.version;\n\t\t\tif (typeof version === 'string') return version;\n\t\t} catch {\n\t\t\t// Try the next source/distro-relative location.\n\t\t}\n\t}\n\n\treturn 'dev';\n}\n\nconst MY_PI_VERSION = read_my_pi_version();\n\nfunction mix(a: number, b: number, t: number): number {\n\treturn Math.round(a + (b - a) * t);\n}\n\nfunction sample_gradient(position: number, palette: Rgb[]): Rgb {\n\tconst wrapped = ((position % 1) + 1) % 1;\n\tconst scaled = wrapped * palette.length;\n\tconst index = Math.floor(scaled);\n\tconst next_index = (index + 1) % palette.length;\n\tconst t = scaled - index;\n\tconst a = palette[index]!;\n\tconst b = palette[next_index]!;\n\treturn [mix(a[0], b[0], t), mix(a[1], b[1], t), mix(a[2], b[2], t)];\n}\n\nfunction ansi_fg([r, g, b]: Rgb, text: string): string {\n\treturn `\\x1b[38;2;${r};${g};${b}m${text}${RESET}`;\n}\n\nfunction rgb_from_xterm(index: number): Rgb | undefined {\n\tif (index < 0 || index > 255) return undefined;\n\tif (index < 16) return undefined;\n\tif (index >= XTERM_GRAY_START) {\n\t\tconst gray = 8 + (index - XTERM_GRAY_START) * 10;\n\t\treturn [gray, gray, gray];\n\t}\n\n\tconst cube = index - 16;\n\tconst r = XTERM_CUBE_VALUES[Math.floor(cube / 36)]!;\n\tconst g = XTERM_CUBE_VALUES[Math.floor((cube % 36) / 6)]!;\n\tconst b = XTERM_CUBE_VALUES[cube % 6]!;\n\treturn [r, g, b];\n}\n\nfunction ansi_params(\n\tansi: string,\n\tprefix: string,\n): string[] | undefined {\n\tif (!ansi.startsWith(prefix)) return undefined;\n\tconst end = ansi.indexOf('m', prefix.length);\n\tif (end === -1) return undefined;\n\treturn ansi.slice(prefix.length, end).split(';');\n}\n\nfunction rgb_from_ansi(ansi: string): Rgb | undefined {\n\tconst truecolor = ansi_params(ansi, TRUECOLOR_FG_PREFIX);\n\tif (truecolor?.length === 3) {\n\t\treturn [\n\t\t\tNumber(truecolor[0]),\n\t\t\tNumber(truecolor[1]),\n\t\t\tNumber(truecolor[2]),\n\t\t];\n\t}\n\n\tconst xterm = ansi_params(ansi, XTERM_FG_PREFIX);\n\treturn xterm?.length === 1\n\t\t? rgb_from_xterm(Number(xterm[0]))\n\t\t: undefined;\n}\n\nfunction theme_gradient_palette(theme: Theme): Rgb[] {\n\tconst palette: Rgb[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const token of THEME_GRADIENT_TOKENS) {\n\t\tconst rgb = rgb_from_ansi(theme.getFgAnsi(token));\n\t\tif (!rgb) continue;\n\t\tconst key = rgb.join(',');\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tpalette.push(rgb);\n\t}\n\n\treturn palette.length >= 2 ? palette : FALLBACK_PALETTE;\n}\n\nfunction gradient_text(\n\ttext: string,\n\tphase: number,\n\tpalette: Rgb[],\n): string {\n\tconst chars = text.split('');\n\tconst span = Math.max(chars.length - 1, 1);\n\treturn chars\n\t\t.map((char, index) => {\n\t\t\tif (char === ' ') return char;\n\t\t\treturn ansi_fg(\n\t\t\t\tsample_gradient(index / span + phase, palette),\n\t\t\t\tchar,\n\t\t\t);\n\t\t})\n\t\t.join('');\n}\n\nfunction center_line(line: string, width: number): string {\n\tconst clipped =\n\t\tvisibleWidth(line) > width\n\t\t\t? truncateToWidth(line, width, '')\n\t\t\t: line;\n\tconst padding = Math.max(\n\t\t0,\n\t\tMath.floor((width - visibleWidth(clipped)) / 2),\n\t);\n\treturn `${' '.repeat(padding)}${clipped}`;\n}\n\nfunction color_line(\n\ttheme: Theme,\n\tpalette: Rgb[],\n\tline: string,\n\tphase: number,\n): string {\n\treturn theme.getColorMode() === 'truecolor'\n\t\t? gradient_text(line, phase, palette)\n\t\t: theme.fg('accent', line);\n}\n\nfunction gradient_or_theme(\n\ttheme: Theme,\n\tpalette: Rgb[],\n\tline: string,\n\tphase: number,\n): string {\n\treturn theme.getColorMode() === 'truecolor'\n\t\t? `${BOLD}${gradient_text(line, phase, palette)}${RESET}`\n\t\t: theme.bold(theme.fg('accent', line));\n}\n\nfunction render_brand(\n\ttheme: Theme,\n\tpalette: Rgb[],\n\twidth: number,\n): string {\n\treturn gradient_or_theme(\n\t\ttheme,\n\t\tpalette,\n\t\tcenter_line(`My-Pi v${MY_PI_VERSION}`, width),\n\t\t0.12,\n\t);\n}\n\nfunction render_subtitle(\n\tctx: ExtensionContext,\n\ttheme: Theme,\n\tpalette: Rgb[],\n\tmodel_id: string,\n\twidth: number,\n): string {\n\tconst project = basename(ctx.cwd) || ctx.cwd;\n\tconst subtitle = center_line(`${model_id} · ${project}`, width);\n\treturn gradient_or_theme(theme, palette, subtitle, 0.18);\n}\n\nexport function render_startup_header(\n\tctx: ExtensionContext,\n\ttheme: Theme,\n\twidth: number,\n\tmodel_id = ctx.model?.id ?? 'no model selected',\n): string[] {\n\tif (width < 24) {\n\t\treturn [\n\t\t\tcenter_line(\n\t\t\t\ttheme.bold(theme.fg('accent', `My-Pi v${MY_PI_VERSION}`)),\n\t\t\t\twidth,\n\t\t\t),\n\t\t\tcenter_line(\n\t\t\t\t`${model_id} · ${basename(ctx.cwd) || ctx.cwd}`,\n\t\t\t\twidth,\n\t\t\t),\n\t\t];\n\t}\n\n\tconst palette = theme_gradient_palette(theme);\n\tconst logo = TITLE_LINES.map((line, row) =>\n\t\tcolor_line(\n\t\t\ttheme,\n\t\t\tpalette,\n\t\t\tcenter_line(line.padEnd(TITLE_WIDTH), width),\n\t\t\trow * 0.045,\n\t\t),\n\t);\n\n\treturn [\n\t\t'',\n\t\trender_brand(theme, palette, width),\n\t\t...logo,\n\t\trender_subtitle(ctx, theme, palette, model_id, width),\n\t\t'',\n\t];\n}\n\nexport default function startup_screen_extension(\n\tpi: ExtensionAPI,\n): void {\n\tlet request_render: (() => void) | undefined;\n\tlet current_model_id = 'no model selected';\n\n\tfunction install_header(ctx: ExtensionContext): void {\n\t\tctx.ui.setHeader((tui, theme) => {\n\t\t\trequest_render = () => tui.requestRender();\n\t\t\treturn {\n\t\t\t\tinvalidate() {\n\t\t\t\t\ttui.requestRender();\n\t\t\t\t},\n\t\t\t\trender(width: number) {\n\t\t\t\t\treturn render_startup_header(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\tcurrent_model_id,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tpi.on('session_start', async (_event, ctx) => {\n\t\tcurrent_model_id = ctx.model?.id ?? 'no model selected';\n\t\tif (!ctx.hasUI) return;\n\t\tinstall_header(ctx);\n\t});\n\n\tpi.on('model_select', (event) => {\n\t\tcurrent_model_id = event.model.id;\n\t\trequest_render?.();\n\t});\n\n\tpi.on('session_shutdown', (_event, ctx) => {\n\t\tif (ctx.hasUI) ctx.ui.setHeader(undefined);\n\t});\n\n\tpi.registerCommand('builtin-header', {\n\t\tdescription: 'Restore the built-in pi startup header',\n\t\thandler: async (_args, ctx) => {\n\t\t\tctx.ui.setHeader(undefined);\n\t\t\tctx.ui.notify('Built-in startup header restored', 'info');\n\t\t},\n\t});\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"startup-screen-DIbhKCsP.js","names":[],"sources":["../src/extensions/startup-screen/index.ts"],"sourcesContent":["import type {\n\tExtensionAPI,\n\tExtensionContext,\n\tTheme,\n\tThemeColor,\n} from '@earendil-works/pi-coding-agent';\nimport {\n\ttruncateToWidth,\n\tvisibleWidth,\n} from '@earendil-works/pi-tui';\nimport { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\n\ntype Rgb = [number, number, number];\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst TRUECOLOR_FG_PREFIX = '\\x1b[38;2;';\nconst XTERM_FG_PREFIX = '\\x1b[38;5;';\n\nconst FALLBACK_PALETTE: Rgb[] = [\n\t[22, 83, 189],\n\t[48, 129, 247],\n\t[93, 171, 255],\n\t[151, 205, 255],\n\t[93, 171, 255],\n\t[48, 129, 247],\n];\n\nconst THEME_GRADIENT_TOKENS: ThemeColor[] = [\n\t'accent',\n\t'borderAccent',\n\t'mdHeading',\n\t'syntaxFunction',\n\t'thinkingHigh',\n\t'mdCode',\n];\n\nconst XTERM_CUBE_VALUES = [0, 95, 135, 175, 215, 255] as const;\nconst XTERM_GRAY_START = 232;\n\nconst TITLE_LINES = [\n\t'███╗ ███╗ ██████╗ ██╗',\n\t'████╗ ████║ ██╗ ██╗ ██╔══██╗ ',\n\t'██╔████╔██║ ╚██╗ ██╔╝ ████╗ ██████╔╝██╗',\n\t'██║╚██╔╝██║ ╚████╔╝ ╚═══╝ ██╔═══╝ ██║',\n\t'██║ ╚═╝ ██║ ╚██╔╝ ██║ ██║',\n\t'╚═╝ ╚═╝ ██╔╝ ╚═╝ ╚═╝',\n] as const;\n\nconst TITLE_WIDTH = Math.max(\n\t...TITLE_LINES.map((line) => line.length),\n);\n\nfunction read_my_pi_version(): string {\n\tconst candidates = [\n\t\tnew URL('../../../package.json', import.meta.url),\n\t\tnew URL('../package.json', import.meta.url),\n\t];\n\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(\n\t\t\t\treadFileSync(candidate, 'utf-8'),\n\t\t\t);\n\t\t\tconst version = (parsed as { version?: unknown } | null)\n\t\t\t\t?.version;\n\t\t\tif (typeof version === 'string') return version;\n\t\t} catch {\n\t\t\t// Try the next source/distro-relative location.\n\t\t}\n\t}\n\n\treturn 'dev';\n}\n\nconst MY_PI_VERSION = read_my_pi_version();\n\nfunction mix(a: number, b: number, t: number): number {\n\treturn Math.round(a + (b - a) * t);\n}\n\nfunction sample_gradient(position: number, palette: Rgb[]): Rgb {\n\tconst wrapped = ((position % 1) + 1) % 1;\n\tconst scaled = wrapped * palette.length;\n\tconst index = Math.floor(scaled);\n\tconst next_index = (index + 1) % palette.length;\n\tconst t = scaled - index;\n\tconst a = palette[index]!;\n\tconst b = palette[next_index]!;\n\treturn [mix(a[0], b[0], t), mix(a[1], b[1], t), mix(a[2], b[2], t)];\n}\n\nfunction ansi_fg([r, g, b]: Rgb, text: string): string {\n\treturn `\\x1b[38;2;${r};${g};${b}m${text}${RESET}`;\n}\n\nfunction rgb_from_xterm(index: number): Rgb | undefined {\n\tif (index < 0 || index > 255) return undefined;\n\tif (index < 16) return undefined;\n\tif (index >= XTERM_GRAY_START) {\n\t\tconst gray = 8 + (index - XTERM_GRAY_START) * 10;\n\t\treturn [gray, gray, gray];\n\t}\n\n\tconst cube = index - 16;\n\tconst r = XTERM_CUBE_VALUES[Math.floor(cube / 36)]!;\n\tconst g = XTERM_CUBE_VALUES[Math.floor((cube % 36) / 6)]!;\n\tconst b = XTERM_CUBE_VALUES[cube % 6]!;\n\treturn [r, g, b];\n}\n\nfunction ansi_params(\n\tansi: string,\n\tprefix: string,\n): string[] | undefined {\n\tif (!ansi.startsWith(prefix)) return undefined;\n\tconst end = ansi.indexOf('m', prefix.length);\n\tif (end === -1) return undefined;\n\treturn ansi.slice(prefix.length, end).split(';');\n}\n\nfunction rgb_from_ansi(ansi: string): Rgb | undefined {\n\tconst truecolor = ansi_params(ansi, TRUECOLOR_FG_PREFIX);\n\tif (truecolor?.length === 3) {\n\t\treturn [\n\t\t\tNumber(truecolor[0]),\n\t\t\tNumber(truecolor[1]),\n\t\t\tNumber(truecolor[2]),\n\t\t];\n\t}\n\n\tconst xterm = ansi_params(ansi, XTERM_FG_PREFIX);\n\treturn xterm?.length === 1\n\t\t? rgb_from_xterm(Number(xterm[0]))\n\t\t: undefined;\n}\n\nfunction theme_gradient_palette(theme: Theme): Rgb[] {\n\tconst palette: Rgb[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const token of THEME_GRADIENT_TOKENS) {\n\t\tconst rgb = rgb_from_ansi(theme.getFgAnsi(token));\n\t\tif (!rgb) continue;\n\t\tconst key = rgb.join(',');\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tpalette.push(rgb);\n\t}\n\n\treturn palette.length >= 2 ? palette : FALLBACK_PALETTE;\n}\n\nfunction gradient_text(\n\ttext: string,\n\tphase: number,\n\tpalette: Rgb[],\n): string {\n\tconst chars = text.split('');\n\tconst span = Math.max(chars.length - 1, 1);\n\treturn chars\n\t\t.map((char, index) => {\n\t\t\tif (char === ' ') return char;\n\t\t\treturn ansi_fg(\n\t\t\t\tsample_gradient(index / span + phase, palette),\n\t\t\t\tchar,\n\t\t\t);\n\t\t})\n\t\t.join('');\n}\n\nfunction center_line(line: string, width: number): string {\n\tconst clipped =\n\t\tvisibleWidth(line) > width\n\t\t\t? truncateToWidth(line, width, '')\n\t\t\t: line;\n\tconst padding = Math.max(\n\t\t0,\n\t\tMath.floor((width - visibleWidth(clipped)) / 2),\n\t);\n\treturn `${' '.repeat(padding)}${clipped}`;\n}\n\nfunction color_line(\n\ttheme: Theme,\n\tpalette: Rgb[],\n\tline: string,\n\tphase: number,\n): string {\n\treturn theme.getColorMode() === 'truecolor'\n\t\t? gradient_text(line, phase, palette)\n\t\t: theme.fg('accent', line);\n}\n\nfunction gradient_or_theme(\n\ttheme: Theme,\n\tpalette: Rgb[],\n\tline: string,\n\tphase: number,\n): string {\n\treturn theme.getColorMode() === 'truecolor'\n\t\t? `${BOLD}${gradient_text(line, phase, palette)}${RESET}`\n\t\t: theme.bold(theme.fg('accent', line));\n}\n\nfunction render_brand(\n\ttheme: Theme,\n\tpalette: Rgb[],\n\twidth: number,\n): string {\n\treturn gradient_or_theme(\n\t\ttheme,\n\t\tpalette,\n\t\tcenter_line(`My-Pi v${MY_PI_VERSION}`, width),\n\t\t0.12,\n\t);\n}\n\nfunction render_subtitle(\n\tctx: ExtensionContext,\n\ttheme: Theme,\n\tpalette: Rgb[],\n\tmodel_id: string,\n\twidth: number,\n): string {\n\tconst project = basename(ctx.cwd) || ctx.cwd;\n\tconst subtitle = center_line(`${model_id} · ${project}`, width);\n\treturn gradient_or_theme(theme, palette, subtitle, 0.18);\n}\n\nexport function render_startup_header(\n\tctx: ExtensionContext,\n\ttheme: Theme,\n\twidth: number,\n\tmodel_id = ctx.model?.id ?? 'no model selected',\n): string[] {\n\tif (width < 24) {\n\t\treturn [\n\t\t\tcenter_line(\n\t\t\t\ttheme.bold(theme.fg('accent', `My-Pi v${MY_PI_VERSION}`)),\n\t\t\t\twidth,\n\t\t\t),\n\t\t\tcenter_line(\n\t\t\t\t`${model_id} · ${basename(ctx.cwd) || ctx.cwd}`,\n\t\t\t\twidth,\n\t\t\t),\n\t\t];\n\t}\n\n\tconst palette = theme_gradient_palette(theme);\n\tconst logo = TITLE_LINES.map((line, row) =>\n\t\tcolor_line(\n\t\t\ttheme,\n\t\t\tpalette,\n\t\t\tcenter_line(line.padEnd(TITLE_WIDTH), width),\n\t\t\trow * 0.045,\n\t\t),\n\t);\n\n\treturn [\n\t\t'',\n\t\trender_brand(theme, palette, width),\n\t\t...logo,\n\t\trender_subtitle(ctx, theme, palette, model_id, width),\n\t\t'',\n\t];\n}\n\nexport default function startup_screen_extension(\n\tpi: ExtensionAPI,\n): void {\n\tlet request_render: (() => void) | undefined;\n\tlet current_model_id = 'no model selected';\n\n\tfunction install_header(ctx: ExtensionContext): void {\n\t\tctx.ui.setHeader((tui, theme) => {\n\t\t\trequest_render = () => tui.requestRender();\n\t\t\treturn {\n\t\t\t\tinvalidate() {\n\t\t\t\t\ttui.requestRender();\n\t\t\t\t},\n\t\t\t\trender(width: number) {\n\t\t\t\t\treturn render_startup_header(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\tcurrent_model_id,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tpi.on('session_start', async (_event, ctx) => {\n\t\tcurrent_model_id = ctx.model?.id ?? 'no model selected';\n\t\tif (!ctx.hasUI) return;\n\t\tinstall_header(ctx);\n\t});\n\n\tpi.on('model_select', (event) => {\n\t\tcurrent_model_id = event.model.id;\n\t\trequest_render?.();\n\t});\n\n\tpi.on('session_shutdown', (_event, ctx) => {\n\t\tif (ctx.hasUI) ctx.ui.setHeader(undefined);\n\t});\n\n\tpi.registerCommand('builtin-header', {\n\t\tdescription: 'Restore the built-in pi startup header',\n\t\thandler: async (_args, ctx) => {\n\t\t\tctx.ui.setHeader(undefined);\n\t\t\tctx.ui.notify('Built-in startup header restored', 'info');\n\t\t},\n\t});\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"description": "Composable pi coding agent with MCP, LSP, prompt presets, and local eval telemetry",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -43,39 +43,41 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@earendil-works/pi-ai": "^0.74.
|
|
47
|
-
"@earendil-works/pi-coding-agent": "^0.74.
|
|
48
|
-
"@earendil-works/pi-tui": "^0.74.
|
|
46
|
+
"@earendil-works/pi-ai": "^0.74.1",
|
|
47
|
+
"@earendil-works/pi-coding-agent": "^0.74.1",
|
|
48
|
+
"@earendil-works/pi-tui": "^0.74.1",
|
|
49
49
|
"citty": "^0.2.2",
|
|
50
50
|
"typebox": "^1.1.38",
|
|
51
|
-
"@spences10/pi-project-trust": "0.0.6",
|
|
52
51
|
"@spences10/pi-themes": "0.0.5",
|
|
53
|
-
"@spences10/pi-tui-modal": "0.0.
|
|
52
|
+
"@spences10/pi-tui-modal": "0.0.16",
|
|
53
|
+
"@spences10/pi-project-trust": "0.0.7"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@changesets/cli": "^2.31.0",
|
|
57
57
|
"@types/node": "^25.8.0",
|
|
58
|
-
"@vitest/coverage-v8": "
|
|
58
|
+
"@vitest/coverage-v8": "4.1.5",
|
|
59
59
|
"vite-plus": "^0.1.21",
|
|
60
|
-
"vitest": "
|
|
60
|
+
"vitest": "4.1.5"
|
|
61
61
|
},
|
|
62
62
|
"optionalDependencies": {
|
|
63
|
-
"@spences10/pi-child-env": "0.1.
|
|
64
|
-
"@spences10/pi-coding-preferences": "0.0.
|
|
65
|
-
"@spences10/pi-confirm-destructive": "0.0.
|
|
66
|
-
"@spences10/pi-context": "0.0.
|
|
67
|
-
"@spences10/pi-
|
|
68
|
-
"@spences10/pi-
|
|
69
|
-
"@spences10/pi-
|
|
70
|
-
"@spences10/pi-
|
|
71
|
-
"@spences10/pi-
|
|
72
|
-
"@spences10/pi-
|
|
73
|
-
"@spences10/pi-
|
|
74
|
-
"@spences10/pi-redact": "0.0.
|
|
75
|
-
"@spences10/pi-
|
|
76
|
-
"@spences10/pi-
|
|
77
|
-
"@spences10/pi-
|
|
78
|
-
"@spences10/pi-
|
|
63
|
+
"@spences10/pi-child-env": "0.1.5",
|
|
64
|
+
"@spences10/pi-coding-preferences": "0.0.6",
|
|
65
|
+
"@spences10/pi-confirm-destructive": "0.0.12",
|
|
66
|
+
"@spences10/pi-context": "0.0.18",
|
|
67
|
+
"@spences10/pi-footer": "0.0.1",
|
|
68
|
+
"@spences10/pi-git-ui": "0.0.7",
|
|
69
|
+
"@spences10/pi-lsp": "0.0.25",
|
|
70
|
+
"@spences10/pi-mcp": "0.0.28",
|
|
71
|
+
"@spences10/pi-nopeek": "0.0.10",
|
|
72
|
+
"@spences10/pi-omnisearch": "0.0.10",
|
|
73
|
+
"@spences10/pi-recall": "0.0.10",
|
|
74
|
+
"@spences10/pi-redact": "0.0.9",
|
|
75
|
+
"@spences10/pi-skill-importer": "0.0.3",
|
|
76
|
+
"@spences10/pi-skills": "0.0.22",
|
|
77
|
+
"@spences10/pi-sqlite-tools": "0.0.9",
|
|
78
|
+
"@spences10/pi-svelte-guardrails": "0.0.7",
|
|
79
|
+
"@spences10/pi-team-mode": "0.0.24",
|
|
80
|
+
"@spences10/pi-telemetry": "0.0.17"
|
|
79
81
|
},
|
|
80
82
|
"engines": {
|
|
81
83
|
"node": ">=24.15.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-registry-DpLtHlYK.js","names":[],"sources":["../src/extensions/builtin-registry.ts"],"sourcesContent":["import type { ExtensionFactory } from '@earendil-works/pi-coding-agent';\n\nexport type BuiltinExtensionRuntimeMode =\n\t| 'interactive'\n\t| 'print'\n\t| 'json'\n\t| 'rpc';\n\ntype BuiltinExtensionLoader = () => Promise<ExtensionFactory>;\n\nexport interface BuiltinExtensionManifestEntry {\n\tkey: string;\n\tlabel: string;\n\tdocs_label: string;\n\tdescription: string;\n\tdefault_enabled: boolean;\n\toption_name: string;\n\tcli_arg: string;\n\tcli_flag: `--${string}`;\n\tcli_description: string;\n\taliases: readonly string[];\n\tmode_constraints?: {\n\t\tdisabled_in: readonly BuiltinExtensionRuntimeMode[];\n\t\treason: string;\n\t};\n\tload: BuiltinExtensionLoader;\n}\n\nexport const BUILTIN_EXTENSION_REGISTRY = [\n\t{\n\t\tkey: 'context-sidecar',\n\t\tlabel: 'Context sidecar',\n\t\tdocs_label: 'SQLite context sidecar',\n\t\tdescription: 'Local SQLite FTS sidecar for oversized tool output',\n\t\tdefault_enabled: true,\n\t\toption_name: 'context_sidecar',\n\t\tcli_arg: 'no-context-sidecar',\n\t\tcli_flag: '--no-context-sidecar',\n\t\tcli_description:\n\t\t\t'Disable SQLite context sidecar for large tool output',\n\t\taliases: ['context-sidecar', 'context', 'sidecar'],\n\t\tload: async () => (await import('@spences10/pi-context')).default,\n\t},\n\t{\n\t\tkey: 'mcp',\n\t\tlabel: 'MCP',\n\t\tdocs_label: 'MCP',\n\t\tdescription: 'MCP server integration and /mcp command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'mcp',\n\t\tcli_arg: 'no-mcp',\n\t\tcli_flag: '--no-mcp',\n\t\tcli_description: 'Disable built-in MCP extension',\n\t\taliases: ['mcp'],\n\t\tload: async () => (await import('@spences10/pi-mcp')).default,\n\t},\n\t{\n\t\tkey: 'skills',\n\t\tlabel: 'Skills',\n\t\tdocs_label: 'Skills',\n\t\tdescription: 'Managed pi-native skills and /skills command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'skills',\n\t\tcli_arg: 'no-skills',\n\t\tcli_flag: '--no-skills',\n\t\tcli_description: 'Disable built-in skills extension',\n\t\taliases: ['skills', 'skill'],\n\t\tload: async () => (await import('@spences10/pi-skills')).default,\n\t},\n\t{\n\t\tkey: 'filter-output',\n\t\tlabel: 'Secret redaction',\n\t\tdocs_label: 'Secret redaction',\n\t\tdescription:\n\t\t\t'Redacts secrets from tool output before the model sees them',\n\t\tdefault_enabled: true,\n\t\toption_name: 'filter_output',\n\t\tcli_arg: 'no-filter',\n\t\tcli_flag: '--no-filter',\n\t\tcli_description: 'Disable secret redaction in tool output',\n\t\taliases: [\n\t\t\t'filter-output',\n\t\t\t'filter_output',\n\t\t\t'filter',\n\t\t\t'redaction',\n\t\t\t'secret-redaction',\n\t\t\t'output-redaction',\n\t\t],\n\t\tload: async () => (await import('@spences10/pi-redact')).default,\n\t},\n\t{\n\t\tkey: 'recall',\n\t\tlabel: 'Recall',\n\t\tdocs_label: 'Recall',\n\t\tdescription: 'pirecall reminder and background session sync',\n\t\tdefault_enabled: true,\n\t\toption_name: 'recall',\n\t\tcli_arg: 'no-recall',\n\t\tcli_flag: '--no-recall',\n\t\tcli_description: 'Disable recall extension',\n\t\taliases: ['recall', 'pirecall'],\n\t\tload: async () => (await import('@spences10/pi-recall')).default,\n\t},\n\t{\n\t\tkey: 'nopeek',\n\t\tlabel: 'Nopeek',\n\t\tdocs_label: 'Nopeek',\n\t\tdescription:\n\t\t\t'nopeek reminder for secret-safe environment loading',\n\t\tdefault_enabled: true,\n\t\toption_name: 'nopeek',\n\t\tcli_arg: 'no-nopeek',\n\t\tcli_flag: '--no-nopeek',\n\t\tcli_description: 'Disable nopeek reminder extension',\n\t\taliases: ['nopeek', 'secrets', 'secret-loading'],\n\t\tload: async () => (await import('@spences10/pi-nopeek')).default,\n\t},\n\t{\n\t\tkey: 'omnisearch',\n\t\tlabel: 'Omnisearch',\n\t\tdocs_label: 'Omnisearch',\n\t\tdescription: 'mcp-omnisearch reminder for verified web research',\n\t\tdefault_enabled: true,\n\t\toption_name: 'omnisearch',\n\t\tcli_arg: 'no-omnisearch',\n\t\tcli_flag: '--no-omnisearch',\n\t\tcli_description: 'Disable mcp-omnisearch reminder extension',\n\t\taliases: ['omnisearch', 'search', 'web-search', 'research'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-omnisearch')).default,\n\t},\n\t{\n\t\tkey: 'sqlite-tools',\n\t\tlabel: 'SQLite tools',\n\t\tdocs_label: 'SQLite tools',\n\t\tdescription:\n\t\t\t'mcp-sqlite-tools reminder for safer SQLite database work',\n\t\tdefault_enabled: true,\n\t\toption_name: 'sqlite_tools',\n\t\tcli_arg: 'no-sqlite-tools',\n\t\tcli_flag: '--no-sqlite-tools',\n\t\tcli_description: 'Disable mcp-sqlite-tools reminder extension',\n\t\taliases: ['sqlite-tools', 'sqlite', 'mcp-sqlite-tools'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-sqlite-tools')).default,\n\t},\n\t{\n\t\tkey: 'startup-screen',\n\t\tlabel: 'Startup screen',\n\t\tdocs_label: 'Startup screen',\n\t\tdescription:\n\t\t\t'Pixel-art gradient startup header for interactive sessions',\n\t\tdefault_enabled: true,\n\t\toption_name: 'startup_screen',\n\t\tcli_arg: 'no-startup-screen',\n\t\tcli_flag: '--no-startup-screen',\n\t\tcli_description: 'Disable the custom startup screen',\n\t\taliases: ['startup-screen', 'startup', 'header', 'splash'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason: 'Startup screen only renders in the interactive TUI',\n\t\t},\n\t\tload: async () =>\n\t\t\t(await import('./startup-screen/index.js')).default,\n\t},\n\t{\n\t\tkey: 'prompt-presets',\n\t\tlabel: 'Prompt presets',\n\t\tdocs_label: 'Prompt presets',\n\t\tdescription:\n\t\t\t'Runtime prompt preset selection and /prompt-preset command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'prompt_presets',\n\t\tcli_arg: 'no-prompt-presets',\n\t\tcli_flag: '--no-prompt-presets',\n\t\tcli_description: 'Disable prompt presets extension',\n\t\taliases: ['prompt-preset', 'preset', 'presets'],\n\t\tload: async () =>\n\t\t\t(await import('./prompt-presets/index.js')).default,\n\t},\n\t{\n\t\tkey: 'git-ui',\n\t\tlabel: 'Git UI',\n\t\tdocs_label: 'Git staging UI',\n\t\tdescription: 'Interactive source control staging panel',\n\t\tdefault_enabled: true,\n\t\toption_name: 'git_ui',\n\t\tcli_arg: 'no-git-ui',\n\t\tcli_flag: '--no-git-ui',\n\t\tcli_description: 'Disable built-in Git staging UI',\n\t\taliases: ['git-ui', 'git', 'source-control', 'scm'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason: 'Git UI is only useful in interactive mode',\n\t\t},\n\t\tload: async () => (await import('@spences10/pi-git-ui')).default,\n\t},\n\t{\n\t\tkey: 'lsp',\n\t\tlabel: 'LSP',\n\t\tdocs_label: 'LSP',\n\t\tdescription:\n\t\t\t'Language Server Protocol tools (diagnostics, hover, definition, references)',\n\t\tdefault_enabled: true,\n\t\toption_name: 'lsp',\n\t\tcli_arg: 'no-lsp',\n\t\tcli_flag: '--no-lsp',\n\t\tcli_description: 'Disable LSP extension',\n\t\taliases: ['lsp', 'language-server'],\n\t\tload: async () => (await import('@spences10/pi-lsp')).default,\n\t},\n\t{\n\t\tkey: 'session-name',\n\t\tlabel: 'Session name',\n\t\tdocs_label: 'Session auto-naming',\n\t\tdescription:\n\t\t\t'AI-powered session auto-naming and /session-name command',\n\t\tdefault_enabled: true,\n\t\toption_name: 'session_name',\n\t\tcli_arg: 'no-session-name',\n\t\tcli_flag: '--no-session-name',\n\t\tcli_description: 'Disable session name extension',\n\t\taliases: ['session-name', 'session', 'auto-name'],\n\t\tmode_constraints: {\n\t\t\tdisabled_in: ['print', 'json', 'rpc'],\n\t\t\treason:\n\t\t\t\t'UI-only session naming is only useful in interactive mode',\n\t\t},\n\t\tload: async () =>\n\t\t\t(await import('./session-name/index.js')).default,\n\t},\n\t{\n\t\tkey: 'confirm-destructive',\n\t\tlabel: 'Confirm destructive',\n\t\tdocs_label: 'Destructive action confirmation',\n\t\tdescription:\n\t\t\t'Prompt before destructive tool calls like file deletes, overwrites, and hard resets',\n\t\tdefault_enabled: true,\n\t\toption_name: 'confirm_destructive',\n\t\tcli_arg: 'no-confirm-destructive',\n\t\tcli_flag: '--no-confirm-destructive',\n\t\tcli_description: 'Disable destructive action confirmations',\n\t\taliases: ['confirm-destructive', 'confirm'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-confirm-destructive')).default,\n\t},\n\t{\n\t\tkey: 'hooks-resolution',\n\t\tlabel: 'Hooks resolution',\n\t\tdocs_label: 'Hooks resolution',\n\t\tdescription:\n\t\t\t'Claude Code style PreToolUse and PostToolUse hook compatibility from .claude, .rulesync, and .pi configs',\n\t\tdefault_enabled: true,\n\t\toption_name: 'hooks_resolution',\n\t\tcli_arg: 'no-hooks',\n\t\tcli_flag: '--no-hooks',\n\t\tcli_description: 'Disable Claude-style hook execution',\n\t\taliases: ['hooks-resolution', 'hooks'],\n\t\tload: async () =>\n\t\t\t(await import('./hooks-resolution/index.js')).default,\n\t},\n\t{\n\t\tkey: 'svelte-guardrails',\n\t\tlabel: 'Svelte guardrails',\n\t\tdocs_label: 'Svelte guardrails',\n\t\tdescription:\n\t\t\t'Blocks discouraged Svelte patterns like $effect before agents write them',\n\t\tdefault_enabled: true,\n\t\toption_name: 'svelte_guardrails',\n\t\tcli_arg: 'no-svelte-guardrails',\n\t\tcli_flag: '--no-svelte-guardrails',\n\t\tcli_description: 'Disable Svelte guardrails',\n\t\taliases: ['svelte-guardrails', 'svelte'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-svelte-guardrails')).default,\n\t},\n\t{\n\t\tkey: 'coding-preferences',\n\t\tlabel: 'Coding preferences',\n\t\tdocs_label: 'Coding preferences',\n\t\tdescription:\n\t\t\t'Blocks configured coding workflow anti-patterns from JSON preferences',\n\t\tdefault_enabled: true,\n\t\toption_name: 'coding_preferences',\n\t\tcli_arg: 'no-coding-preferences',\n\t\tcli_flag: '--no-coding-preferences',\n\t\tcli_description: 'Disable coding preferences guardrails',\n\t\taliases: ['coding-preferences', 'preferences', 'prefs'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-coding-preferences')).default,\n\t},\n\t{\n\t\tkey: 'team-mode',\n\t\tlabel: 'Team mode',\n\t\tdocs_label: 'Team mode',\n\t\tdescription:\n\t\t\t'Experimental orchestrator/team mode with RPC teammates, tasks, and mailboxes',\n\t\tdefault_enabled: true,\n\t\toption_name: 'team_mode',\n\t\tcli_arg: 'no-team-mode',\n\t\tcli_flag: '--no-team-mode',\n\t\tcli_description: 'Disable experimental team mode extension',\n\t\taliases: ['team-mode', 'team', 'teammates'],\n\t\tload: async () =>\n\t\t\t(await import('@spences10/pi-team-mode')).default,\n\t},\n] as const satisfies readonly BuiltinExtensionManifestEntry[];\n\nexport type BuiltinExtensionKey =\n\t(typeof BUILTIN_EXTENSION_REGISTRY)[number]['key'];\n\nexport type BuiltinExtensionOptionName =\n\t(typeof BUILTIN_EXTENSION_REGISTRY)[number]['option_name'];\n\nexport type BuiltinExtensionInfo = Omit<\n\tBuiltinExtensionManifestEntry,\n\t'load'\n> & {\n\tkey: BuiltinExtensionKey;\n\toption_name: BuiltinExtensionOptionName;\n};\n\nexport const BUILTIN_EXTENSIONS: BuiltinExtensionInfo[] =\n\tBUILTIN_EXTENSION_REGISTRY.map(\n\t\t({ load: _load, ...extension }) => extension,\n\t);\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-presets-BhlErXaD.js","names":[],"sources":["../src/extensions/prompt-presets/catalog.ts","../src/extensions/prompt-presets/defaults.ts","../src/extensions/prompt-presets/footer.ts","../src/extensions/prompt-presets/help.ts","../src/extensions/prompt-presets/storage.ts","../src/extensions/prompt-presets/state.ts","../src/extensions/prompt-presets/index.ts"],"sourcesContent":["import type {\n\tLoadedPromptPreset,\n\tPromptPresetSource,\n} from './types.js';\n\nexport function get_prompt_source_label(\n\tsource: PromptPresetSource,\n): string {\n\tswitch (source) {\n\t\tcase 'builtin':\n\t\t\treturn 'built-in';\n\t\tcase 'user':\n\t\t\treturn 'user';\n\t\tcase 'project':\n\t\t\treturn 'project';\n\t}\n}\n\nexport function list_base_presets(\n\tpresets: Record<string, LoadedPromptPreset>,\n): LoadedPromptPreset[] {\n\treturn Object.values(presets)\n\t\t.filter((preset) => preset.kind === 'base')\n\t\t.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport function list_layer_presets(\n\tpresets: Record<string, LoadedPromptPreset>,\n): LoadedPromptPreset[] {\n\treturn Object.values(presets)\n\t\t.filter((preset) => preset.kind === 'layer')\n\t\t.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport function format_summary(\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n\tpresets: Record<string, LoadedPromptPreset>,\n): string {\n\tconst lines = [`Base: ${active_base_name ?? '(none)'}`];\n\n\tconst layer_names = [...active_layers].sort();\n\tif (layer_names.length === 0) {\n\t\tlines.push('Layers: (none)');\n\t} else {\n\t\tlines.push('Layers:');\n\t\tfor (const name of layer_names) {\n\t\t\tconst preset = presets[name];\n\t\t\tconst description = preset?.description\n\t\t\t\t? ` — ${preset.description}`\n\t\t\t\t: '';\n\t\t\tlines.push(`- ${name}${description}`);\n\t\t}\n\t}\n\n\treturn lines.join('\\n');\n}\n\nexport function format_active_details(\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n\tpresets: Record<string, LoadedPromptPreset>,\n): string {\n\tconst parts: string[] = [];\n\n\tif (active_base_name) {\n\t\tconst base = presets[active_base_name];\n\t\tif (base) {\n\t\t\tparts.push(`Base: ${base.name}`);\n\t\t\tif (base.description)\n\t\t\t\tparts.push(`Description: ${base.description}`);\n\t\t\tparts.push(`Source: ${get_prompt_source_label(base.source)}`);\n\t\t\tparts.push('', base.instructions.trim());\n\t\t}\n\t}\n\n\tconst layer_names = [...active_layers].sort();\n\tif (layer_names.length > 0) {\n\t\tif (parts.length > 0) parts.push('', '---', '');\n\t\tparts.push('Layers:');\n\t\tfor (const name of layer_names) {\n\t\t\tconst layer = presets[name];\n\t\t\tif (!layer) continue;\n\t\t\tparts.push(\n\t\t\t\t`- ${layer.name} (${get_prompt_source_label(layer.source)})`,\n\t\t\t);\n\t\t\tif (layer.description) parts.push(` ${layer.description}`);\n\t\t}\n\t}\n\n\treturn parts.join('\\n') || 'No preset or layers active';\n}\n","import type { PromptPresetMap } from './types.js';\n\nexport const DEFAULT_BASE_PROMPT_PRESET_NAME = 'terse';\n\nexport const DEFAULT_PROMPT_PRESETS: PromptPresetMap = {\n\tterse: {\n\t\tkind: 'base',\n\t\tdescription: 'Short, direct, no fluff',\n\t\tinstructions:\n\t\t\t\"Be concise and direct. Default to the shortest response that fully solves the user's request. Use at most one short paragraph or 3 bullets unless the user explicitly asks for detail. For implementation reports, include only what changed, validation, and the next step if relevant. No purple prose, no filler, no repetitive caveats.\",\n\t},\n\tstandard: {\n\t\tkind: 'base',\n\t\tdescription: 'Clear and concise with key context',\n\t\tinstructions:\n\t\t\t'Be clear, direct, and concise. Include only the reasoning and implementation details that matter. Avoid filler, grandstanding, and ornamental language. Use bullets when they improve scanability.',\n\t},\n\tdetailed: {\n\t\tkind: 'base',\n\t\tdescription: 'More explanation when nuance matters',\n\t\tinstructions:\n\t\t\t'Be thorough when the task is complex or tradeoffs matter, but stay practical. Explain only the details that help the user decide, verify, or implement. Avoid purple prose and unnecessary scene-setting.',\n\t},\n\t'no-purple-prose': {\n\t\tkind: 'layer',\n\t\tdescription: 'Strip out ornamental language',\n\t\tinstructions:\n\t\t\t'Do not use purple prose, flourish, motivational filler, or theatrical transitions. Prefer plain language and concrete statements.',\n\t},\n\tbullets: {\n\t\tkind: 'layer',\n\t\tdescription: 'Prefer short bullets when useful',\n\t\tinstructions:\n\t\t\t'When presenting options, findings, or steps, prefer short bullet lists over long paragraphs.',\n\t},\n\t'clarify-first': {\n\t\tkind: 'layer',\n\t\tdescription:\n\t\t\t'Ask brief clarifying questions when requirements are ambiguous',\n\t\tinstructions:\n\t\t\t'If the request is materially ambiguous, ask the minimum clarifying question(s) needed before proceeding. Do not ask unnecessary questions.',\n\t},\n\t'include-risks': {\n\t\tkind: 'layer',\n\t\tdescription: 'Call out notable risks or tradeoffs',\n\t\tinstructions:\n\t\t\t'When making a recommendation or implementation plan, briefly mention the key risk, tradeoff, or caveat if one materially matters.',\n\t},\n};\n","import {\n\tclampThinkingLevel,\n\tgetSupportedThinkingLevels,\n\ttype ModelThinkingLevel,\n} from '@earendil-works/pi-ai';\nimport type {\n\tExtensionContext,\n\tReadonlyFooterDataProvider,\n} from '@earendil-works/pi-coding-agent';\nimport {\n\ttruncateToWidth,\n\tvisibleWidth,\n} from '@earendil-works/pi-tui';\n\nfunction get_footer_prompt_status(\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): string | undefined {\n\tif (!active_base_name && active_layers.size === 0) {\n\t\treturn undefined;\n\t}\n\n\tconst label = active_base_name ?? 'none';\n\tconst layer_suffix =\n\t\tactive_layers.size > 0 ? ` +${active_layers.size}` : '';\n\treturn `prompt:${label}${layer_suffix}`;\n}\n\nfunction sanitize_status_text(text: string): string {\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, ' ')\n\t\t.replace(/ +/g, ' ')\n\t\t.trim();\n}\n\nfunction format_token_count(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function render_footer_status_line(\n\ttheme: ExtensionContext['ui']['theme'],\n\twidth: number,\n\tleft_items: string[],\n\tright_item?: string,\n): string | undefined {\n\tconst left = sanitize_status_text(left_items.join(' '));\n\tconst right = right_item ? sanitize_status_text(right_item) : '';\n\tif (!left && !right) return undefined;\n\tif (!right) {\n\t\treturn truncateToWidth(\n\t\t\ttheme.fg('dim', left),\n\t\t\twidth,\n\t\t\ttheme.fg('dim', '...'),\n\t\t);\n\t}\n\tif (!left) {\n\t\tconst themed_right = theme.fg('dim', right);\n\t\tconst right_width = visibleWidth(themed_right);\n\t\treturn right_width >= width\n\t\t\t? truncateToWidth(themed_right, width, theme.fg('dim', '...'))\n\t\t\t: `${' '.repeat(width - right_width)}${themed_right}`;\n\t}\n\n\tconst right_width = visibleWidth(right);\n\tif (right_width >= width) {\n\t\treturn truncateToWidth(\n\t\t\ttheme.fg('dim', right),\n\t\t\twidth,\n\t\t\ttheme.fg('dim', '...'),\n\t\t);\n\t}\n\n\tconst min_gap = 1;\n\tconst available_left = Math.max(0, width - right_width - min_gap);\n\tconst truncated_left = truncateToWidth(left, available_left, '...');\n\tconst left_width = visibleWidth(truncated_left);\n\tconst gap = Math.max(min_gap, width - left_width - right_width);\n\treturn (\n\t\ttheme.fg('dim', truncated_left) +\n\t\t' '.repeat(gap) +\n\t\ttheme.fg('dim', right)\n\t);\n}\n\nconst VALID_THINKING_LEVELS = new Set<ModelThinkingLevel>([\n\t'off',\n\t'minimal',\n\t'low',\n\t'medium',\n\t'high',\n\t'xhigh',\n]);\n\nfunction is_model_thinking_level(\n\tlevel: string,\n): level is ModelThinkingLevel {\n\treturn VALID_THINKING_LEVELS.has(level as ModelThinkingLevel);\n}\n\nexport function get_default_footer_thinking_level(\n\tmodel: ExtensionContext['model'],\n): ModelThinkingLevel {\n\tif (!model?.reasoning) return 'off';\n\treturn clampThinkingLevel(model, 'medium');\n}\n\nexport function get_current_thinking_level(\n\tctx: Pick<ExtensionContext, 'model' | 'sessionManager'>,\n): ModelThinkingLevel {\n\tconst entries = ctx.sessionManager.getEntries();\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i] as {\n\t\t\ttype?: string;\n\t\t\tthinkingLevel?: string;\n\t\t};\n\t\tif (\n\t\t\tentry.type === 'thinking_level_change' &&\n\t\t\ttypeof entry.thinkingLevel === 'string' &&\n\t\t\tis_model_thinking_level(entry.thinkingLevel)\n\t\t) {\n\t\t\tif (!ctx.model?.reasoning) return 'off';\n\t\t\treturn getSupportedThinkingLevels(ctx.model).includes(\n\t\t\t\tentry.thinkingLevel,\n\t\t\t)\n\t\t\t\t? entry.thinkingLevel\n\t\t\t\t: clampThinkingLevel(ctx.model, entry.thinkingLevel);\n\t\t}\n\t}\n\treturn get_default_footer_thinking_level(ctx.model);\n}\n\nfunction render_footer_lines(\n\tctx: ExtensionContext,\n\ttheme: ExtensionContext['ui']['theme'],\n\tfooter_data: ReadonlyFooterDataProvider,\n\twidth: number,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): string[] {\n\tlet total_input = 0;\n\tlet total_output = 0;\n\tlet total_cache_read = 0;\n\tlet total_cache_write = 0;\n\tlet total_cost = 0;\n\tfor (const entry of ctx.sessionManager.getEntries()) {\n\t\tif (\n\t\t\tentry.type === 'message' &&\n\t\t\tentry.message.role === 'assistant'\n\t\t) {\n\t\t\ttotal_input += entry.message.usage.input;\n\t\t\ttotal_output += entry.message.usage.output;\n\t\t\ttotal_cache_read += entry.message.usage.cacheRead;\n\t\t\ttotal_cache_write += entry.message.usage.cacheWrite;\n\t\t\ttotal_cost += entry.message.usage.cost.total;\n\t\t}\n\t}\n\n\tconst context_usage = ctx.getContextUsage();\n\tconst context_window =\n\t\tcontext_usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;\n\tconst context_percent_value = context_usage?.percent ?? 0;\n\tconst context_percent =\n\t\tcontext_usage?.percent !== null\n\t\t\t? context_percent_value.toFixed(1)\n\t\t\t: '?';\n\n\tlet pwd = ctx.cwd;\n\tconst home = process.env.HOME || process.env.USERPROFILE;\n\tif (home && pwd.startsWith(home)) {\n\t\tpwd = `~${pwd.slice(home.length)}`;\n\t}\n\n\tconst branch = footer_data.getGitBranch();\n\tif (branch) {\n\t\tpwd = `${pwd} (${branch})`;\n\t}\n\n\tconst session_name = ctx.sessionManager.getSessionName();\n\tif (session_name) {\n\t\tpwd = `${pwd} • ${session_name}`;\n\t}\n\n\tconst stats_parts: string[] = [];\n\tif (total_input)\n\t\tstats_parts.push(`↑${format_token_count(total_input)}`);\n\tif (total_output)\n\t\tstats_parts.push(`↓${format_token_count(total_output)}`);\n\tif (total_cache_read)\n\t\tstats_parts.push(`R${format_token_count(total_cache_read)}`);\n\tif (total_cache_write)\n\t\tstats_parts.push(`W${format_token_count(total_cache_write)}`);\n\n\tconst using_subscription = ctx.model\n\t\t? ctx.modelRegistry.isUsingOAuth(ctx.model)\n\t\t: false;\n\tif (total_cost || using_subscription) {\n\t\tstats_parts.push(\n\t\t\t`$${total_cost.toFixed(3)}${using_subscription ? ' (sub)' : ''}`,\n\t\t);\n\t}\n\n\tconst context_percent_display =\n\t\tcontext_percent === '?'\n\t\t\t? `?/${format_token_count(context_window)}`\n\t\t\t: `${context_percent}%/${format_token_count(context_window)}`;\n\tlet context_percent_str = context_percent_display;\n\tif (context_percent_value > 90) {\n\t\tcontext_percent_str = theme.fg('error', context_percent_display);\n\t} else if (context_percent_value > 70) {\n\t\tcontext_percent_str = theme.fg(\n\t\t\t'warning',\n\t\t\tcontext_percent_display,\n\t\t);\n\t}\n\tstats_parts.push(context_percent_str);\n\n\tlet stats_left = stats_parts.join(' ');\n\tlet stats_left_width = visibleWidth(stats_left);\n\tif (stats_left_width > width) {\n\t\tstats_left = truncateToWidth(stats_left, width, '...');\n\t\tstats_left_width = visibleWidth(stats_left);\n\t}\n\n\tconst model_name = ctx.model?.id || 'no-model';\n\tconst thinking_level = get_current_thinking_level(ctx);\n\tlet right_side_without_provider = model_name;\n\tif (ctx.model?.reasoning) {\n\t\tright_side_without_provider =\n\t\t\tthinking_level === 'off'\n\t\t\t\t? `${model_name} • thinking off`\n\t\t\t\t: `${model_name} • ${thinking_level}`;\n\t}\n\n\tlet right_side = right_side_without_provider;\n\tif (footer_data.getAvailableProviderCount() > 1 && ctx.model) {\n\t\tright_side = `(${ctx.model.provider}) ${right_side_without_provider}`;\n\t\tif (stats_left_width + 2 + visibleWidth(right_side) > width) {\n\t\t\tright_side = right_side_without_provider;\n\t\t}\n\t}\n\n\tconst right_side_width = visibleWidth(right_side);\n\tconst total_needed = stats_left_width + 2 + right_side_width;\n\tlet stats_line: string;\n\tif (total_needed <= width) {\n\t\tconst padding = ' '.repeat(\n\t\t\twidth - stats_left_width - right_side_width,\n\t\t);\n\t\tstats_line = stats_left + padding + right_side;\n\t} else {\n\t\tconst available_for_right = width - stats_left_width - 2;\n\t\tif (available_for_right > 0) {\n\t\t\tconst truncated_right = truncateToWidth(\n\t\t\t\tright_side,\n\t\t\t\tavailable_for_right,\n\t\t\t\t'',\n\t\t\t);\n\t\t\tconst truncated_right_width = visibleWidth(truncated_right);\n\t\t\tconst padding = ' '.repeat(\n\t\t\t\tMath.max(0, width - stats_left_width - truncated_right_width),\n\t\t\t);\n\t\t\tstats_line = stats_left + padding + truncated_right;\n\t\t} else {\n\t\t\tstats_line = stats_left;\n\t\t}\n\t}\n\n\tconst dim_stats_left = theme.fg('dim', stats_left);\n\tconst remainder = stats_line.slice(stats_left.length);\n\tconst dim_remainder = theme.fg('dim', remainder);\n\tconst lines = [\n\t\ttruncateToWidth(\n\t\t\ttheme.fg('dim', pwd),\n\t\t\twidth,\n\t\t\ttheme.fg('dim', '...'),\n\t\t),\n\t\tdim_stats_left + dim_remainder,\n\t];\n\n\tconst prompt_status = get_footer_prompt_status(\n\t\tactive_base_name,\n\t\tactive_layers,\n\t);\n\n\tconst other_statuses = Array.from(\n\t\tfooter_data.getExtensionStatuses().entries(),\n\t)\n\t\t.filter(([key]) => key !== 'preset')\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([, text]) => sanitize_status_text(text));\n\tconst combined_status_line = render_footer_status_line(\n\t\ttheme,\n\t\twidth,\n\t\tother_statuses,\n\t\tprompt_status,\n\t);\n\tif (combined_status_line) {\n\t\tlines.push(combined_status_line);\n\t}\n\n\treturn lines;\n}\n\nexport function set_status(\n\tctx: ExtensionContext,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): void {\n\tctx.ui.setStatus('preset', undefined);\n\tif (!ctx.hasUI) return;\n\tctx.ui.setFooter((tui, theme, footer_data) => {\n\t\tconst unsubscribe = footer_data.onBranchChange(() =>\n\t\t\ttui.requestRender(),\n\t\t);\n\t\treturn {\n\t\t\tdispose: unsubscribe,\n\t\t\tinvalidate() {},\n\t\t\trender(width: number) {\n\t\t\t\treturn render_footer_lines(\n\t\t\t\t\tctx,\n\t\t\t\t\ttheme,\n\t\t\t\t\tfooter_data,\n\t\t\t\t\twidth,\n\t\t\t\t\tactive_base_name,\n\t\t\t\t\tactive_layers,\n\t\t\t\t);\n\t\t\t},\n\t\t};\n\t});\n}\n","export function is_subcommand(command: string): boolean {\n\treturn [\n\t\t'help',\n\t\t'list',\n\t\t'show',\n\t\t'clear',\n\t\t'edit',\n\t\t'edit-global',\n\t\t'export-defaults',\n\t\t'delete',\n\t\t'reset',\n\t\t'reload',\n\t\t'base',\n\t\t'enable',\n\t\t'disable',\n\t\t'toggle',\n\t].includes(command);\n}\n\nexport function format_prompt_preset_help(): string {\n\treturn `Prompt presets append instructions to the system prompt.\n\nCommands:\n- /prompt-preset Open the preset picker\n- /prompt-preset show Show the active base and layers\n- /prompt-preset <name> Activate a base preset or toggle a layer\n- /prompt-preset base <name> Activate a base preset\n- /prompt-preset enable <layer> Enable a layer\n- /prompt-preset disable <layer> Disable a layer\n- /prompt-preset edit <name> Edit/create .pi/presets/<name>.md\n- /prompt-preset edit-global <name> Edit/create ~/.pi/agent/presets/<name>.md\n- /prompt-preset export-defaults Export built-ins to ~/.pi/agent/presets/*.md\n- /prompt-preset export-defaults project Export built-ins to .pi/presets/*.md\n- /prompt-preset reload Reload presets after manual file edits\n- /prompt-preset clear Clear active base and layers\n\nExamples:\n- /prompt-preset export-defaults\n- /prompt-preset edit-global terse\n- /prompt-preset base detailed\n- /prompt-preset enable bullets\n- /prompt-preset show\n\nAlias: /preset`;\n}\n","import { getAgentDir } from '@earendil-works/pi-coding-agent';\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { DEFAULT_PROMPT_PRESETS } from './defaults.js';\nimport type {\n\tLoadedPromptPreset,\n\tPromptPreset,\n\tPromptPresetMap,\n\tPromptPresetSource,\n\tPromptPresetState,\n} from './types.js';\n\nconst PROJECT_PROMPT_PRESETS_ENV = 'MY_PI_PROMPT_PRESETS_PROJECT';\n\ninterface PersistedPromptPresetStates {\n\tversion: number;\n\tprojects: Record<string, PromptPresetState>;\n}\n\nexport function normalize_prompt_presets(\n\tinput: unknown,\n): PromptPresetMap {\n\tif (!input || typeof input !== 'object') return {};\n\n\tconst normalized: PromptPresetMap = {};\n\tfor (const [raw_name, raw_value] of Object.entries(input)) {\n\t\tconst name = raw_name.trim();\n\t\tif (!name) continue;\n\n\t\tif (typeof raw_value === 'string') {\n\t\t\tnormalized[name] = {\n\t\t\t\tkind: 'base',\n\t\t\t\tinstructions: raw_value,\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!raw_value || typeof raw_value !== 'object') continue;\n\t\tconst candidate = raw_value as {\n\t\t\tkind?: unknown;\n\t\t\tdescription?: unknown;\n\t\t\tinstructions?: unknown;\n\t\t};\n\t\tif (typeof candidate.instructions !== 'string') continue;\n\n\t\tnormalized[name] = {\n\t\t\tinstructions: candidate.instructions,\n\t\t\t...(candidate.kind === 'layer'\n\t\t\t\t? { kind: 'layer' as const }\n\t\t\t\t: {}),\n\t\t\t...(typeof candidate.description === 'string'\n\t\t\t\t? { description: candidate.description }\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\treturn normalized;\n}\n\nexport function merge_prompt_presets(\n\t...sources: PromptPresetMap[]\n): PromptPresetMap {\n\treturn Object.assign({}, ...sources);\n}\n\nfunction to_loaded_prompt_presets(\n\tpresets: PromptPresetMap,\n\tsource: PromptPresetSource,\n): Record<string, LoadedPromptPreset> {\n\treturn Object.fromEntries(\n\t\tObject.entries(presets).map(([name, preset]) => [\n\t\t\tname,\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tkind: preset.kind === 'layer' ? 'layer' : 'base',\n\t\t\t\tsource,\n\t\t\t\t...preset,\n\t\t\t},\n\t\t]),\n\t);\n}\n\nfunction get_global_presets_path(): string {\n\treturn join(getAgentDir(), 'presets.json');\n}\n\nfunction get_project_presets_path(cwd: string): string {\n\treturn join(cwd, '.pi', 'presets.json');\n}\n\nexport function get_global_presets_dir(): string {\n\treturn join(getAgentDir(), 'presets');\n}\n\nexport function get_project_presets_dir(cwd: string): string {\n\treturn join(cwd, '.pi', 'presets');\n}\n\nfunction sanitize_prompt_preset_file_name(name: string): string {\n\tconst sanitized = name\n\t\t.trim()\n\t\t.replace(/[\\\\/:*?\"<>|]/g, '-')\n\t\t.replace(/^\\.+$/, '')\n\t\t.replace(/^\\.+/, '')\n\t\t.replace(/\\.+$/, '');\n\tif (!sanitized) {\n\t\tthrow new Error(\n\t\t\t'Prompt preset name must contain a file-safe character',\n\t\t);\n\t}\n\treturn sanitized;\n}\n\nexport function get_prompt_preset_file_path(\n\tdir: string,\n\tname: string,\n): string {\n\treturn join(dir, `${sanitize_prompt_preset_file_name(name)}.md`);\n}\n\nfunction get_persisted_prompt_state_path(): string {\n\treturn join(getAgentDir(), 'prompt-preset-state.json');\n}\n\nfunction read_prompt_presets_file(path: string): PromptPresetMap {\n\tif (!existsSync(path)) return {};\n\n\ttry {\n\t\treturn normalize_prompt_presets(\n\t\t\tJSON.parse(readFileSync(path, 'utf-8')),\n\t\t);\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction unquote_frontmatter_value(value: string): string {\n\tconst trimmed = value.trim();\n\tif (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n\t\ttry {\n\t\t\treturn JSON.parse(trimmed) as string;\n\t\t} catch {\n\t\t\treturn trimmed.slice(1, -1);\n\t\t}\n\t}\n\tif (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n\t\treturn trimmed.slice(1, -1);\n\t}\n\treturn trimmed;\n}\n\nfunction parse_prompt_preset_markdown(content: string): {\n\tmetadata: Record<string, string>;\n\tbody: string;\n} {\n\tconst normalized = content.replace(/\\r\\n/g, '\\n');\n\tif (!normalized.startsWith('---\\n')) {\n\t\treturn { metadata: {}, body: normalized.trim() };\n\t}\n\n\tconst lines = normalized.split('\\n');\n\tconst end = lines.findIndex(\n\t\t(line, index) => index > 0 && line.trim() === '---',\n\t);\n\tif (end === -1) {\n\t\treturn { metadata: {}, body: normalized.trim() };\n\t}\n\n\tconst metadata: Record<string, string> = {};\n\tfor (const line of lines.slice(1, end)) {\n\t\tconst separator = line.indexOf(':');\n\t\tif (separator === -1) continue;\n\t\tconst key = line.slice(0, separator).trim().toLowerCase();\n\t\tconst value = line.slice(separator + 1).trim();\n\t\tif (!key) continue;\n\t\tmetadata[key] = unquote_frontmatter_value(value);\n\t}\n\n\treturn {\n\t\tmetadata,\n\t\tbody: lines\n\t\t\t.slice(end + 1)\n\t\t\t.join('\\n')\n\t\t\t.trim(),\n\t};\n}\n\nexport function read_prompt_presets_dir(\n\tpath: string,\n): PromptPresetMap {\n\tif (!existsSync(path)) return {};\n\n\ttry {\n\t\tconst presets: PromptPresetMap = {};\n\t\tfor (const entry of readdirSync(path, { withFileTypes: true })\n\t\t\t.filter((item) => item.isFile() && item.name.endsWith('.md'))\n\t\t\t.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\t\tconst name = entry.name.slice(0, -3).trim();\n\t\t\tif (!name) continue;\n\t\t\tconst { metadata, body } = parse_prompt_preset_markdown(\n\t\t\t\treadFileSync(join(path, entry.name), 'utf-8'),\n\t\t\t);\n\t\t\tif (!body) continue;\n\t\t\tpresets[name] = {\n\t\t\t\tkind: metadata.kind === 'layer' ? 'layer' : 'base',\n\t\t\t\tinstructions: body,\n\t\t\t\t...(metadata.description\n\t\t\t\t\t? { description: metadata.description }\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\t}\n\t\treturn presets;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction format_prompt_preset_markdown(preset: PromptPreset): string {\n\tconst lines = [\n\t\t'---',\n\t\t`kind: ${preset.kind === 'layer' ? 'layer' : 'base'}`,\n\t];\n\tif (preset.description?.trim()) {\n\t\tlines.push(\n\t\t\t`description: ${JSON.stringify(preset.description.trim())}`,\n\t\t);\n\t}\n\tlines.push('---', '', preset.instructions.trim(), '');\n\treturn lines.join('\\n');\n}\n\nexport function save_prompt_preset_file(\n\tdir: string,\n\tname: string,\n\tpreset: PromptPreset,\n): string {\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst path = get_prompt_preset_file_path(dir, name);\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(tmp, format_prompt_preset_markdown(preset), {\n\t\tmode: 0o600,\n\t});\n\trenameSync(tmp, path);\n\treturn path;\n}\n\nexport function save_project_prompt_preset_file(\n\tcwd: string,\n\tname: string,\n\tpreset: PromptPreset,\n): string {\n\treturn save_prompt_preset_file(\n\t\tget_project_presets_dir(cwd),\n\t\tname,\n\t\tpreset,\n\t);\n}\n\nexport function save_global_prompt_preset_file(\n\tname: string,\n\tpreset: PromptPreset,\n): string {\n\treturn save_prompt_preset_file(\n\t\tget_global_presets_dir(),\n\t\tname,\n\t\tpreset,\n\t);\n}\n\nfunction should_load_project_prompt_presets(): boolean {\n\tconst normalized = process.env[PROJECT_PROMPT_PRESETS_ENV]\n\t\t?.trim()\n\t\t.toLowerCase();\n\treturn !['0', 'false', 'no', 'skip', 'disable'].includes(\n\t\tnormalized ?? '',\n\t);\n}\n\nexport function load_prompt_presets(\n\tcwd: string,\n): Record<string, LoadedPromptPreset> {\n\treturn Object.assign(\n\t\t{},\n\t\tto_loaded_prompt_presets(DEFAULT_PROMPT_PRESETS, 'builtin'),\n\t\tto_loaded_prompt_presets(\n\t\t\tread_prompt_presets_file(get_global_presets_path()),\n\t\t\t'user',\n\t\t),\n\t\tto_loaded_prompt_presets(\n\t\t\tread_prompt_presets_dir(get_global_presets_dir()),\n\t\t\t'user',\n\t\t),\n\t\t...(should_load_project_prompt_presets()\n\t\t\t? [\n\t\t\t\t\tto_loaded_prompt_presets(\n\t\t\t\t\t\tread_prompt_presets_file(get_project_presets_path(cwd)),\n\t\t\t\t\t\t'project',\n\t\t\t\t\t),\n\t\t\t\t\tto_loaded_prompt_presets(\n\t\t\t\t\t\tread_prompt_presets_dir(get_project_presets_dir(cwd)),\n\t\t\t\t\t\t'project',\n\t\t\t\t\t),\n\t\t\t\t]\n\t\t\t: []),\n\t);\n}\n\nfunction sort_prompt_presets(\n\tpresets: PromptPresetMap,\n): PromptPresetMap {\n\treturn Object.fromEntries(\n\t\tObject.entries(presets).sort(([a], [b]) => a.localeCompare(b)),\n\t);\n}\n\nexport function save_project_prompt_presets(\n\tcwd: string,\n\tpresets: PromptPresetMap,\n): string {\n\tconst path = get_project_presets_path(cwd);\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(\n\t\ttmp,\n\t\tJSON.stringify(sort_prompt_presets(presets), null, '\\t') + '\\n',\n\t\t{ mode: 0o600 },\n\t);\n\trenameSync(tmp, path);\n\treturn path;\n}\n\nexport function remove_project_prompt_preset(\n\tcwd: string,\n\tname: string,\n): {\n\tremoved: boolean;\n\tpath: string;\n\tremaining: number;\n} {\n\tconst json_path = get_project_presets_path(cwd);\n\tconst project_presets = read_prompt_presets_file(json_path);\n\tlet removed = false;\n\tlet removed_path = json_path;\n\n\tif (name in project_presets) {\n\t\tdelete project_presets[name];\n\t\tremoved = true;\n\t\tremoved_path = json_path;\n\t\tif (Object.keys(project_presets).length === 0) {\n\t\t\tif (existsSync(json_path)) {\n\t\t\t\tunlinkSync(json_path);\n\t\t\t}\n\t\t} else {\n\t\t\tsave_project_prompt_presets(cwd, project_presets);\n\t\t}\n\t}\n\n\tconst file_path = get_prompt_preset_file_path(\n\t\tget_project_presets_dir(cwd),\n\t\tname,\n\t);\n\tif (existsSync(file_path)) {\n\t\tunlinkSync(file_path);\n\t\tremoved = true;\n\t\tremoved_path = file_path;\n\t}\n\n\tconst remaining =\n\t\tObject.keys(read_prompt_presets_file(json_path)).length +\n\t\tObject.keys(read_prompt_presets_dir(get_project_presets_dir(cwd)))\n\t\t\t.length;\n\n\treturn { removed, path: removed_path, remaining };\n}\n\nfunction normalize_prompt_preset_state(\n\tinput: unknown,\n): PromptPresetState | undefined {\n\tif (!input || typeof input !== 'object') return undefined;\n\n\tconst candidate = input as {\n\t\tbase_name?: unknown;\n\t\tlayer_names?: unknown;\n\t};\n\tconst base_name =\n\t\ttypeof candidate.base_name === 'string' &&\n\t\tcandidate.base_name.trim()\n\t\t\t? candidate.base_name.trim()\n\t\t\t: null;\n\tconst layer_names = Array.isArray(candidate.layer_names)\n\t\t? [\n\t\t\t\t...new Set(\n\t\t\t\t\tcandidate.layer_names\n\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t(value): value is string =>\n\t\t\t\t\t\t\t\ttypeof value === 'string' && value.trim().length > 0,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.map((value) => value.trim()),\n\t\t\t\t),\n\t\t\t].sort()\n\t\t: [];\n\n\treturn {\n\t\tbase_name,\n\t\tlayer_names,\n\t};\n}\n\nfunction read_persisted_prompt_states(\n\tpath = get_persisted_prompt_state_path(),\n): PersistedPromptPresetStates {\n\tif (!existsSync(path)) {\n\t\treturn { version: 1, projects: {} };\n\t}\n\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, 'utf-8')) as {\n\t\t\tversion?: unknown;\n\t\t\tprojects?: unknown;\n\t\t};\n\t\tconst raw_projects =\n\t\t\tparsed.projects && typeof parsed.projects === 'object'\n\t\t\t\t? parsed.projects\n\t\t\t\t: {};\n\t\tconst projects: Record<string, PromptPresetState> = {};\n\t\tfor (const [cwd, value] of Object.entries(raw_projects)) {\n\t\t\tconst normalized = normalize_prompt_preset_state(value);\n\t\t\tif (!normalized) continue;\n\t\t\tprojects[cwd] = normalized;\n\t\t}\n\t\treturn {\n\t\t\tversion:\n\t\t\t\ttypeof parsed.version === 'number' ? parsed.version : 1,\n\t\t\tprojects,\n\t\t};\n\t} catch {\n\t\treturn { version: 1, projects: {} };\n\t}\n}\n\nexport function load_persisted_prompt_state(\n\tcwd: string,\n\tpath = get_persisted_prompt_state_path(),\n): PromptPresetState | undefined {\n\treturn read_persisted_prompt_states(path).projects[cwd];\n}\n\nexport function save_persisted_prompt_state(\n\tcwd: string,\n\tstate: PromptPresetState,\n\tpath = get_persisted_prompt_state_path(),\n): string {\n\tconst persisted = read_persisted_prompt_states(path);\n\tpersisted.projects[cwd] = normalize_prompt_preset_state(state) ?? {\n\t\tbase_name: null,\n\t\tlayer_names: [],\n\t};\n\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\n\tconst tmp = `${path}.tmp-${Date.now()}`;\n\twriteFileSync(\n\t\ttmp,\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tversion: 1,\n\t\t\t\tprojects: Object.fromEntries(\n\t\t\t\t\tObject.entries(persisted.projects).sort(([a], [b]) =>\n\t\t\t\t\t\ta.localeCompare(b),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t},\n\t\t\tnull,\n\t\t\t'\\t',\n\t\t) + '\\n',\n\t\t{ mode: 0o600 },\n\t);\n\trenameSync(tmp, path);\n\treturn path;\n}\n","import type {\n\tExtensionAPI,\n\tExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport { save_persisted_prompt_state } from './storage.js';\nimport type {\n\tLoadedPromptPreset,\n\tPromptPresetState,\n} from './types.js';\n\nexport const PRESET_STATE_TYPE = 'prompt-preset-state';\nexport const ENABLED = '● enabled';\nexport const DISABLED = '○ disabled';\nexport const SELECTED = '● selected';\nexport const UNSELECTED = '○';\nexport const NONE_BASE_ID = '__base_none__';\n\nexport function get_last_preset_state(\n\tctx: ExtensionContext,\n): PromptPresetState | undefined {\n\tconst entries = ctx.sessionManager.getEntries();\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i] as {\n\t\t\ttype?: string;\n\t\t\tcustomType?: string;\n\t\t\tdata?: PromptPresetState;\n\t\t};\n\t\tif (\n\t\t\tentry.type === 'custom' &&\n\t\t\tentry.customType === PRESET_STATE_TYPE &&\n\t\t\tentry.data\n\t\t) {\n\t\t\treturn entry.data;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function sets_equal(\n\ta: ReadonlySet<string>,\n\tb: ReadonlySet<string>,\n): boolean {\n\tif (a.size !== b.size) return false;\n\tfor (const value of a) {\n\t\tif (!b.has(value)) return false;\n\t}\n\treturn true;\n}\n\nexport function persist_state(\n\tpi: ExtensionAPI,\n\tctx: ExtensionContext,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): void {\n\tconst state = {\n\t\tbase_name: active_base_name ?? null,\n\t\tlayer_names: [...active_layers].sort(),\n\t};\n\tpi.appendEntry(PRESET_STATE_TYPE, state);\n\tsave_persisted_prompt_state(ctx.cwd, state);\n}\n\nexport function normalize_active_state(\n\tpresets: Record<string, LoadedPromptPreset>,\n\tactive_base_name: string | undefined,\n\tactive_layers: ReadonlySet<string>,\n): {\n\tactive_base_name: string | undefined;\n\tactive_layers: Set<string>;\n} {\n\tconst next_base_name =\n\t\tactive_base_name && presets[active_base_name]?.kind === 'base'\n\t\t\t? active_base_name\n\t\t\t: undefined;\n\tconst next_layers = new Set(\n\t\t[...active_layers].filter(\n\t\t\t(name) => presets[name]?.kind === 'layer',\n\t\t),\n\t);\n\treturn {\n\t\tactive_base_name: next_base_name,\n\t\tactive_layers: next_layers,\n\t};\n}\n\nexport function parse_preset_flag(flag: string): string[] {\n\treturn flag\n\t\t.split(',')\n\t\t.map((item) => item.trim())\n\t\t.filter(Boolean);\n}\n","import {\n\ttype ExtensionAPI,\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport type { SettingItem } from '@earendil-works/pi-tui';\nimport { show_settings_modal } from '@spences10/pi-tui-modal';\nimport { existsSync } from 'node:fs';\nimport {\n\tformat_active_details,\n\tformat_summary,\n\tget_prompt_source_label,\n\tlist_base_presets,\n\tlist_layer_presets,\n} from './catalog.js';\nimport {\n\tDEFAULT_BASE_PROMPT_PRESET_NAME,\n\tDEFAULT_PROMPT_PRESETS,\n} from './defaults.js';\nimport { set_status } from './footer.js';\nimport { format_prompt_preset_help, is_subcommand } from './help.js';\nimport {\n\tDISABLED,\n\tENABLED,\n\tget_last_preset_state,\n\tNONE_BASE_ID,\n\tnormalize_active_state,\n\tparse_preset_flag,\n\tpersist_state,\n\tSELECTED,\n\tsets_equal,\n\tUNSELECTED,\n} from './state.js';\nimport {\n\tget_global_presets_dir,\n\tget_project_presets_dir,\n\tget_prompt_preset_file_path,\n\tload_persisted_prompt_state,\n\tload_prompt_presets,\n\tremove_project_prompt_preset,\n\tsave_global_prompt_preset_file,\n\tsave_project_prompt_preset_file,\n\tsave_prompt_preset_file,\n} from './storage.js';\nimport type {\n\tLoadedPromptPreset,\n\tPromptPresetKind,\n} from './types.js';\n\nexport {\n\tDEFAULT_BASE_PROMPT_PRESET_NAME,\n\tDEFAULT_PROMPT_PRESETS,\n} from './defaults.js';\nexport {\n\tget_current_thinking_level,\n\tget_default_footer_thinking_level,\n\trender_footer_status_line,\n} from './footer.js';\nexport {\n\tload_persisted_prompt_state,\n\tload_prompt_presets,\n\tmerge_prompt_presets,\n\tnormalize_prompt_presets,\n\tread_prompt_presets_dir,\n\tremove_project_prompt_preset,\n\tsave_persisted_prompt_state,\n\tsave_project_prompt_presets,\n\tsave_prompt_preset_file,\n} from './storage.js';\nexport type {\n\tLoadedPromptPreset,\n\tPromptPreset,\n\tPromptPresetKind,\n\tPromptPresetMap,\n\tPromptPresetSource,\n\tPromptPresetState,\n} from './types.js';\n\nexport default async function prompt_presets(pi: ExtensionAPI) {\n\tlet presets: Record<string, LoadedPromptPreset> = {};\n\tlet active_base_name: string | undefined;\n\tlet active_layers = new Set<string>();\n\n\tfunction get_base(\n\t\tname: string | undefined,\n\t): LoadedPromptPreset | undefined {\n\t\treturn name ? presets[name] : undefined;\n\t}\n\n\tfunction get_layer(name: string): LoadedPromptPreset | undefined {\n\t\tconst preset = presets[name];\n\t\treturn preset?.kind === 'layer' ? preset : undefined;\n\t}\n\n\tfunction commit_state(\n\t\tctx: ExtensionContext,\n\t\tnext_base_name: string | undefined,\n\t\tnext_layers: ReadonlySet<string>,\n\t\toptions?: { persist?: boolean; notify?: string },\n\t): void {\n\t\tactive_base_name = next_base_name;\n\t\tactive_layers = new Set(next_layers);\n\t\tset_status(ctx, active_base_name, active_layers);\n\t\tif (options?.persist !== false) {\n\t\t\tpersist_state(pi, ctx, active_base_name, active_layers);\n\t\t}\n\t\tif (options?.notify) {\n\t\t\tctx.ui.notify(options.notify, 'info');\n\t\t}\n\t}\n\n\tfunction activate_base(\n\t\tname: string | undefined,\n\t\tctx: ExtensionContext,\n\t\toptions?: { persist?: boolean },\n\t): boolean {\n\t\tif (!name) {\n\t\t\tcommit_state(ctx, undefined, active_layers, {\n\t\t\t\tpersist: options?.persist,\n\t\t\t\tnotify: 'Base preset cleared',\n\t\t\t});\n\t\t\treturn true;\n\t\t}\n\n\t\tconst preset = get_base(name);\n\t\tif (!preset) {\n\t\t\tctx.ui.notify(`Unknown base preset: ${name}`, 'warning');\n\t\t\treturn false;\n\t\t}\n\n\t\tcommit_state(ctx, preset.name, active_layers, {\n\t\t\tpersist: options?.persist,\n\t\t\tnotify: `Base preset \"${preset.name}\" activated`,\n\t\t});\n\t\treturn true;\n\t}\n\n\tfunction set_layer_enabled(\n\t\tname: string,\n\t\tenabled: boolean,\n\t\tctx: ExtensionContext,\n\t\toptions?: { persist?: boolean },\n\t): boolean {\n\t\tconst preset = get_layer(name);\n\t\tif (!preset) {\n\t\t\tctx.ui.notify(`Unknown prompt layer: ${name}`, 'warning');\n\t\t\treturn false;\n\t\t}\n\n\t\tconst next_layers = new Set(active_layers);\n\t\tif (enabled) {\n\t\t\tnext_layers.add(preset.name);\n\t\t} else {\n\t\t\tnext_layers.delete(preset.name);\n\t\t}\n\n\t\tcommit_state(ctx, active_base_name, next_layers, {\n\t\t\tpersist: options?.persist,\n\t\t\tnotify: enabled\n\t\t\t\t? `Layer \"${preset.name}\" enabled`\n\t\t\t\t: `Layer \"${preset.name}\" disabled`,\n\t\t});\n\t\treturn true;\n\t}\n\n\tfunction toggle_layer(\n\t\tname: string,\n\t\tctx: ExtensionContext,\n\t\toptions?: { persist?: boolean },\n\t): boolean {\n\t\treturn set_layer_enabled(\n\t\t\tname,\n\t\t\t!active_layers.has(name),\n\t\t\tctx,\n\t\t\toptions,\n\t\t);\n\t}\n\n\tasync function edit_preset(\n\t\tname: string,\n\t\tctx: ExtensionCommandContext,\n\t\tscope: 'project' | 'global' = 'project',\n\t): Promise<void> {\n\t\tconst existing = presets[name];\n\t\tconst kind_choice = await ctx.ui.select('Preset kind', [\n\t\t\texisting?.kind === 'layer'\n\t\t\t\t? 'layer (current)'\n\t\t\t\t: 'base (current)',\n\t\t\texisting?.kind === 'layer' ? 'base' : 'layer',\n\t\t]);\n\t\tif (!kind_choice) return;\n\t\tconst kind: PromptPresetKind = kind_choice.startsWith('layer')\n\t\t\t? 'layer'\n\t\t\t: 'base';\n\n\t\tconst description = await ctx.ui.input(\n\t\t\t`Description for ${name}`,\n\t\t\texisting?.description ?? '',\n\t\t);\n\t\tif (description === undefined) return;\n\n\t\tconst instructions = await ctx.ui.editor(\n\t\t\t`Edit ${kind} preset: ${name}`,\n\t\t\texisting?.instructions ?? '',\n\t\t);\n\t\tif (instructions === undefined) return;\n\n\t\tconst saved_path =\n\t\t\tscope === 'global'\n\t\t\t\t? save_global_prompt_preset_file(name, {\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tinstructions,\n\t\t\t\t\t\t...(description.trim()\n\t\t\t\t\t\t\t? { description: description.trim() }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})\n\t\t\t\t: save_project_prompt_preset_file(ctx.cwd, name, {\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tinstructions,\n\t\t\t\t\t\t...(description.trim()\n\t\t\t\t\t\t\t? { description: description.trim() }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t});\n\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\n\t\tif (kind === 'base') {\n\t\t\tactivate_base(name, ctx);\n\t\t} else {\n\t\t\tset_layer_enabled(name, true, ctx);\n\t\t}\n\t\tctx.ui.notify(`Saved preset \"${name}\" to ${saved_path}`, 'info');\n\t}\n\n\tfunction export_default_presets(\n\t\tctx: ExtensionCommandContext,\n\t\tscope: 'project' | 'global',\n\t): void {\n\t\tconst dir =\n\t\t\tscope === 'global'\n\t\t\t\t? get_global_presets_dir()\n\t\t\t\t: get_project_presets_dir(ctx.cwd);\n\t\tlet written = 0;\n\t\tlet skipped = 0;\n\t\tfor (const [name, preset] of Object.entries(\n\t\t\tDEFAULT_PROMPT_PRESETS,\n\t\t)) {\n\t\t\tconst path = get_prompt_preset_file_path(dir, name);\n\t\t\tif (existsSync(path)) {\n\t\t\t\tskipped += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsave_prompt_preset_file(dir, name, preset);\n\t\t\twritten += 1;\n\t\t}\n\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\t\tset_status(ctx, active_base_name, active_layers);\n\n\t\tctx.ui.notify(\n\t\t\t`Exported ${written} built-in preset file(s) to ${dir}${skipped ? ` (${skipped} already existed)` : ''}`,\n\t\t\t'info',\n\t\t);\n\t}\n\n\tfunction remove_custom_preset(\n\t\tname: string,\n\t\tctx: ExtensionCommandContext,\n\t\tmode: 'delete' | 'reset',\n\t): void {\n\t\tconst result = remove_project_prompt_preset(ctx.cwd, name);\n\t\tif (!result.removed) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`No project-local preset named \"${name}\" to ${mode}`,\n\t\t\t\t'warning',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\t\tset_status(ctx, active_base_name, active_layers);\n\t\tpersist_state(pi, ctx, active_base_name, active_layers);\n\n\t\tconst fallback = presets[name];\n\t\tif (mode === 'reset' && fallback) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Reset \"${name}\" to ${get_prompt_source_label(fallback.source)} preset`,\n\t\t\t\t'info',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tctx.ui.notify(\n\t\t\tresult.remaining === 0\n\t\t\t\t? `Removed \"${name}\" and deleted ${result.path}`\n\t\t\t\t: `Removed \"${name}\" from ${result.path}`,\n\t\t\t'info',\n\t\t);\n\t}\n\n\tasync function show_manager(\n\t\tctx: ExtensionCommandContext,\n\t): Promise<void> {\n\t\tconst base_presets = list_base_presets(presets);\n\t\tconst layer_presets = list_layer_presets(presets);\n\t\tif (base_presets.length === 0 && layer_presets.length === 0) {\n\t\t\tctx.ui.notify('No prompt presets available', 'warning');\n\t\t\treturn;\n\t\t}\n\n\t\tconst initial_base = active_base_name;\n\t\tconst initial_layers = new Set(active_layers);\n\t\tlet selected_base = active_base_name;\n\t\tconst enabled_layers = new Set(active_layers);\n\n\t\tconst items: SettingItem[] = [];\n\t\tconst base_ids = new Set<string>();\n\t\tconst layer_ids = new Set<string>();\n\n\t\titems.push({\n\t\t\tid: '__header_base__',\n\t\t\tlabel: `── Base presets (${base_presets.length + 1}) ──`,\n\t\t\tdescription: '',\n\t\t\tcurrentValue: '',\n\t\t});\n\t\titems.push({\n\t\t\tid: NONE_BASE_ID,\n\t\t\tlabel: '(none)',\n\t\t\tdescription: 'No active base preset',\n\t\t\tcurrentValue: UNSELECTED,\n\t\t\tvalues: [SELECTED, UNSELECTED],\n\t\t});\n\t\tbase_ids.add(NONE_BASE_ID);\n\n\t\tfor (const preset of base_presets) {\n\t\t\titems.push({\n\t\t\t\tid: preset.name,\n\t\t\t\tlabel: preset.name,\n\t\t\t\tdescription: [\n\t\t\t\t\t`${get_prompt_source_label(preset.source)} • ${preset.description ?? 'base preset'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t\tcurrentValue: UNSELECTED,\n\t\t\t\tvalues: [SELECTED, UNSELECTED],\n\t\t\t});\n\t\t\tbase_ids.add(preset.name);\n\t\t}\n\n\t\titems.push({\n\t\t\tid: '__header_layers__',\n\t\t\tlabel: `── Prompt layers (${layer_presets.length}) ──`,\n\t\t\tdescription: '',\n\t\t\tcurrentValue: '',\n\t\t});\n\t\tfor (const preset of layer_presets) {\n\t\t\titems.push({\n\t\t\t\tid: preset.name,\n\t\t\t\tlabel: preset.name,\n\t\t\t\tdescription: [\n\t\t\t\t\t`${get_prompt_source_label(preset.source)} • ${preset.description ?? 'layer'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t\tcurrentValue: DISABLED,\n\t\t\t\tvalues: [ENABLED, DISABLED],\n\t\t\t});\n\t\t\tlayer_ids.add(preset.name);\n\t\t}\n\n\t\tfunction sync_values() {\n\t\t\tfor (const item of items) {\n\t\t\t\tif (base_ids.has(item.id)) {\n\t\t\t\t\tconst is_selected =\n\t\t\t\t\t\t(item.id === NONE_BASE_ID && !selected_base) ||\n\t\t\t\t\t\titem.id === selected_base;\n\t\t\t\t\titem.currentValue = is_selected ? SELECTED : UNSELECTED;\n\t\t\t\t} else if (layer_ids.has(item.id)) {\n\t\t\t\t\titem.currentValue = enabled_layers.has(item.id)\n\t\t\t\t\t\t? ENABLED\n\t\t\t\t\t\t: DISABLED;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsync_values();\n\n\t\tawait show_settings_modal(ctx, {\n\t\t\ttitle: 'Prompt presets',\n\t\t\tsubtitle: () =>\n\t\t\t\t`base: ${selected_base ?? '(none)'} • ${enabled_layers.size} layer(s) enabled`,\n\t\t\titems,\n\t\t\tmax_visible: Math.min(Math.max(items.length + 4, 8), 24),\n\t\t\tenable_search: true,\n\t\t\ton_change: (id, new_value) => {\n\t\t\t\tif (id.startsWith('__header_')) return;\n\n\t\t\t\tif (base_ids.has(id)) {\n\t\t\t\t\tselected_base =\n\t\t\t\t\t\tnew_value === SELECTED && id !== NONE_BASE_ID\n\t\t\t\t\t\t\t? id\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\tsync_values();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (layer_ids.has(id)) {\n\t\t\t\t\tif (new_value === ENABLED) {\n\t\t\t\t\t\tenabled_layers.add(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tenabled_layers.delete(id);\n\t\t\t\t\t}\n\t\t\t\t\tsync_values();\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\tif (\n\t\t\tselected_base !== initial_base ||\n\t\t\t!sets_equal(initial_layers, enabled_layers)\n\t\t) {\n\t\t\tcommit_state(ctx, selected_base, enabled_layers, {\n\t\t\t\tnotify: 'Updated prompt preset selection',\n\t\t\t});\n\t\t}\n\t}\n\n\tpi.registerFlag('preset', {\n\t\tdescription:\n\t\t\t'Activate prompt config on startup. Accepts a base preset or comma-separated preset/layer names.',\n\t\ttype: 'string',\n\t});\n\n\tconst prompt_preset_command: Parameters<\n\t\tExtensionAPI['registerCommand']\n\t>[1] = {\n\t\tdescription:\n\t\t\t'Manage prompt presets and layers. Try: /prompt-preset help, /prompt-preset export-defaults, /prompt-preset edit-global terse',\n\t\tgetArgumentCompletions: (prefix) => {\n\t\t\tconst trimmed = prefix.trim();\n\t\t\tconst parts = trimmed ? trimmed.split(/\\s+/) : [];\n\t\t\tconst base_names = list_base_presets(presets).map(\n\t\t\t\t(preset) => preset.name,\n\t\t\t);\n\t\t\tconst layer_names = list_layer_presets(presets).map(\n\t\t\t\t(preset) => preset.name,\n\t\t\t);\n\t\t\tconst all_names = [...base_names, ...layer_names];\n\n\t\t\tif (parts.length <= 1) {\n\t\t\t\tconst query = parts[0] ?? '';\n\t\t\t\tconst subcommands = [\n\t\t\t\t\t'help',\n\t\t\t\t\t'list',\n\t\t\t\t\t'show',\n\t\t\t\t\t'clear',\n\t\t\t\t\t'edit',\n\t\t\t\t\t'edit-global',\n\t\t\t\t\t'export-defaults',\n\t\t\t\t\t'delete',\n\t\t\t\t\t'reset',\n\t\t\t\t\t'reload',\n\t\t\t\t\t'base',\n\t\t\t\t\t'enable',\n\t\t\t\t\t'disable',\n\t\t\t\t\t'toggle',\n\t\t\t\t];\n\t\t\t\treturn [\n\t\t\t\t\t...subcommands\n\t\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t\t.map((item) => ({ value: item, label: item })),\n\t\t\t\t\t...all_names\n\t\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t\t.map((item) => ({ value: item, label: item })),\n\t\t\t\t];\n\t\t\t}\n\n\t\t\tconst command = parts[0];\n\t\t\tconst query = parts.slice(1).join(' ');\n\t\t\tif (command === 'base') {\n\t\t\t\treturn base_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({ value: `base ${item}`, label: item }));\n\t\t\t}\n\t\t\tif (['enable', 'disable', 'toggle'].includes(command)) {\n\t\t\t\treturn layer_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tvalue: `${command} ${item}`,\n\t\t\t\t\t\tlabel: item,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\tif (command === 'edit' || command === 'edit-global') {\n\t\t\t\treturn all_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tvalue: `${command} ${item}`,\n\t\t\t\t\t\tlabel: item,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\tif (['delete', 'reset'].includes(command)) {\n\t\t\t\treturn all_names\n\t\t\t\t\t.filter((item) => item.startsWith(query))\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tvalue: `${command} ${item}`,\n\t\t\t\t\t\tlabel: item,\n\t\t\t\t\t}));\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tconst trimmed = args.trim();\n\t\t\tif (!trimmed) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tawait show_manager(ctx);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\tformat_summary(active_base_name, active_layers, presets),\n\t\t\t\t\t'info',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst [first, ...rest] = trimmed.split(/\\s+/);\n\t\t\tconst arg = rest.join(' ').trim();\n\n\t\t\tswitch (first) {\n\t\t\t\tcase 'help':\n\t\t\t\t\tctx.ui.notify(format_prompt_preset_help(), 'info');\n\t\t\t\t\treturn;\n\t\t\t\tcase 'list':\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\tformat_summary(active_base_name, active_layers, presets),\n\t\t\t\t\t\t'info',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'show':\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\tformat_active_details(\n\t\t\t\t\t\t\tactive_base_name,\n\t\t\t\t\t\t\tactive_layers,\n\t\t\t\t\t\t\tpresets,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t'info',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'clear':\n\t\t\t\t\tcommit_state(ctx, undefined, new Set(), {\n\t\t\t\t\t\tnotify: 'Cleared base preset and prompt layers',\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\tcase 'reload': {\n\t\t\t\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\t\t\t\tconst normalized = normalize_active_state(\n\t\t\t\t\t\tpresets,\n\t\t\t\t\t\tactive_base_name,\n\t\t\t\t\t\tactive_layers,\n\t\t\t\t\t);\n\t\t\t\t\tactive_base_name = normalized.active_base_name;\n\t\t\t\t\tactive_layers = normalized.active_layers;\n\t\t\t\t\tset_status(ctx, active_base_name, active_layers);\n\t\t\t\t\tctx.ui.notify('Reloaded prompt presets', 'info');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase 'base':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset base <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tactivate_base(arg, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'enable':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset enable <layer> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tset_layer_enabled(arg, true, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'disable':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset disable <layer> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tset_layer_enabled(arg, false, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'toggle':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset toggle <layer> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttoggle_layer(arg, ctx);\n\t\t\t\t\treturn;\n\t\t\t\tcase 'edit': {\n\t\t\t\t\tlet scope: 'project' | 'global' = 'project';\n\t\t\t\t\tlet name = arg;\n\t\t\t\t\tif (arg.startsWith('--global ')) {\n\t\t\t\t\t\tscope = 'global';\n\t\t\t\t\t\tname = arg.slice('--global '.length).trim();\n\t\t\t\t\t} else if (arg.startsWith('--project ')) {\n\t\t\t\t\t\tname = arg.slice('--project '.length).trim();\n\t\t\t\t\t}\n\t\t\t\t\tif (!name) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset edit [--global|--project] <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait edit_preset(name, ctx, scope);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase 'edit-global':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset edit-global <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait edit_preset(arg, ctx, 'global');\n\t\t\t\t\treturn;\n\t\t\t\tcase 'export-defaults': {\n\t\t\t\t\tconst scope = arg || 'global';\n\t\t\t\t\tif (scope !== 'global' && scope !== 'project') {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset export-defaults [global|project] (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\texport_default_presets(ctx, scope);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase 'delete':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset delete <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tremove_custom_preset(arg, ctx, 'delete');\n\t\t\t\t\treturn;\n\t\t\t\tcase 'reset':\n\t\t\t\t\tif (!arg) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t'Usage: /prompt-preset reset <name> (alias: /preset)',\n\t\t\t\t\t\t\t'warning',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tremove_custom_preset(arg, ctx, 'reset');\n\t\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (is_subcommand(first)) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`Unsupported preset command: ${first}`,\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst preset = presets[trimmed];\n\t\t\tif (!preset) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`Unknown preset or layer: ${trimmed}. Try /prompt-preset help.`,\n\t\t\t\t\t'warning',\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (preset.kind === 'base') {\n\t\t\t\tactivate_base(preset.name, ctx);\n\t\t\t} else {\n\t\t\t\ttoggle_layer(preset.name, ctx);\n\t\t\t}\n\t\t},\n\t};\n\n\tfor (const command_name of ['prompt-preset', 'preset']) {\n\t\tpi.registerCommand(command_name, prompt_preset_command);\n\t}\n\n\tpi.on('session_start', async (_event, ctx) => {\n\t\tpresets = load_prompt_presets(ctx.cwd);\n\t\tactive_base_name = undefined;\n\t\tactive_layers = new Set();\n\n\t\tconst preset_flag = pi.getFlag('preset');\n\t\tif (typeof preset_flag === 'string' && preset_flag.trim()) {\n\t\t\tfor (const name of parse_preset_flag(preset_flag)) {\n\t\t\t\tconst preset = presets[name];\n\t\t\t\tif (!preset) continue;\n\t\t\t\tif (preset.kind === 'base') {\n\t\t\t\t\tactive_base_name = name;\n\t\t\t\t} else {\n\t\t\t\t\tactive_layers.add(name);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst normalized = normalize_active_state(\n\t\t\t\tpresets,\n\t\t\t\tactive_base_name,\n\t\t\t\tactive_layers,\n\t\t\t);\n\t\t\tactive_base_name = normalized.active_base_name;\n\t\t\tactive_layers = normalized.active_layers;\n\t\t\tset_status(ctx, active_base_name, active_layers);\n\t\t\treturn;\n\t\t}\n\n\t\tconst restored = get_last_preset_state(ctx) ??\n\t\t\tload_persisted_prompt_state(ctx.cwd) ?? {\n\t\t\t\tbase_name: DEFAULT_BASE_PROMPT_PRESET_NAME,\n\t\t\t\tlayer_names: [],\n\t\t\t};\n\t\tactive_base_name = restored.base_name ?? undefined;\n\t\tactive_layers = new Set(restored.layer_names ?? []);\n\t\tconst normalized = normalize_active_state(\n\t\t\tpresets,\n\t\t\tactive_base_name,\n\t\t\tactive_layers,\n\t\t);\n\t\tactive_base_name = normalized.active_base_name;\n\t\tactive_layers = normalized.active_layers;\n\t\tset_status(ctx, active_base_name, active_layers);\n\t});\n\n\tpi.on('before_agent_start', async (event) => {\n\t\tconst blocks: string[] = [];\n\t\tconst base = get_base(active_base_name);\n\t\tif (base?.instructions.trim()) {\n\t\t\tblocks.push(\n\t\t\t\t`## Active Base Prompt: ${base.name}\\n${base.instructions.trim()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst layer_blocks = [...active_layers]\n\t\t\t.sort()\n\t\t\t.map((name) => presets[name])\n\t\t\t.filter((preset): preset is LoadedPromptPreset =>\n\t\t\t\tBoolean(preset?.instructions.trim()),\n\t\t\t)\n\t\t\t.map(\n\t\t\t\t(preset) =>\n\t\t\t\t\t`### ${preset.name}\\n${preset.instructions.trim()}`,\n\t\t\t);\n\t\tif (layer_blocks.length > 0) {\n\t\t\tblocks.push(\n\t\t\t\t`## Active Prompt Layers\\n\\n${layer_blocks.join('\\n\\n')}`,\n\t\t\t);\n\t\t}\n\n\t\tif (blocks.length === 0) return;\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n\\n${blocks.join('\\n\\n')}`,\n\t\t};\n\t});\n\n\tpi.on('session_shutdown', async (_event, ctx) => {\n\t\tctx.ui.setStatus('preset', undefined);\n\t\tctx.ui.setFooter(undefined);\n\t});\n}\n"],"mappings":"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"}
|