my-pi 0.3.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -252
- package/dist/extensions.d.ts +11 -0
- package/dist/extensions.js +148 -0
- package/dist/extensions.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +40 -523
- package/dist/index.js.map +1 -1
- package/dist/manager.d.ts +3 -0
- package/dist/manager.js +71 -0
- package/dist/manager.js.map +1 -0
- package/dist/settings.d.ts +3 -0
- package/dist/settings.js +16 -0
- package/dist/settings.js.map +1 -0
- package/package.json +33 -78
- package/dist/api.d.ts +0 -494
- package/dist/api.js +0 -532
- package/dist/api.js.map +0 -1
- package/dist/builtin-registry-wSfsQBi4.js +0 -563
- package/dist/builtin-registry-wSfsQBi4.js.map +0 -1
- package/dist/footer-BAZIMVSb.js +0 -1
- package/dist/handoff-C6wR2mSG.js +0 -28
- package/dist/handoff-C6wR2mSG.js.map +0 -1
- package/dist/hooks-resolution-qlhPfMFJ.js +0 -485
- package/dist/hooks-resolution-qlhPfMFJ.js.map +0 -1
- package/dist/openrouter-fusion-config-BWsHBPQv.js +0 -65
- package/dist/openrouter-fusion-config-BWsHBPQv.js.map +0 -1
- package/dist/prompt-presets-XraV03Ed.js +0 -1402
- package/dist/prompt-presets-XraV03Ed.js.map +0 -1
- package/dist/session-name-CD6TVRnh.js +0 -158
- package/dist/session-name-CD6TVRnh.js.map +0 -1
- package/dist/settings-BCn3P9qH.js +0 -177
- package/dist/settings-BCn3P9qH.js.map +0 -1
- package/dist/startup-screen-DUeBWuAc.js +0 -218
- package/dist/startup-screen-DUeBWuAc.js.map +0 -1
- package/dist/turn-timer-CoyDI4gQ.js +0 -64
- package/dist/turn-timer-CoyDI4gQ.js.map +0 -1
- package/dist/umans-provider-C2UJ4qkO.js +0 -307
- package/dist/umans-provider-C2UJ4qkO.js.map +0 -1
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { basename, dirname, join } from "node:path";
|
|
3
|
-
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { get_settings_path, read_settings, write_settings } from "@spences10/pi-settings";
|
|
5
|
-
import { homedir } from "node:os";
|
|
6
|
-
//#region src/settings/schema.ts
|
|
7
|
-
const DEFAULT_SETTINGS = {
|
|
8
|
-
version: 1,
|
|
9
|
-
extensions: { enabled: {} }
|
|
10
|
-
};
|
|
11
|
-
function normalize_settings(value) {
|
|
12
|
-
const raw = value;
|
|
13
|
-
const enabled = {};
|
|
14
|
-
const raw_enabled = raw?.extensions?.enabled;
|
|
15
|
-
if (raw_enabled && typeof raw_enabled === "object") {
|
|
16
|
-
for (const [key, state] of Object.entries(raw_enabled)) if (typeof state === "boolean") enabled[key] = state;
|
|
17
|
-
}
|
|
18
|
-
return {
|
|
19
|
-
...raw && typeof raw === "object" ? raw : {},
|
|
20
|
-
version: 1,
|
|
21
|
-
extensions: { enabled }
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/settings/current.ts
|
|
26
|
-
function current_settings_exists() {
|
|
27
|
-
return existsSync(get_settings_path());
|
|
28
|
-
}
|
|
29
|
-
function read_current_settings() {
|
|
30
|
-
if (!current_settings_exists()) return { ...DEFAULT_SETTINGS };
|
|
31
|
-
return normalize_settings(read_settings());
|
|
32
|
-
}
|
|
33
|
-
function write_current_settings(settings) {
|
|
34
|
-
write_settings(settings);
|
|
35
|
-
}
|
|
36
|
-
function ensure_current_settings() {
|
|
37
|
-
if (!current_settings_exists()) write_current_settings(DEFAULT_SETTINGS);
|
|
38
|
-
return read_current_settings();
|
|
39
|
-
}
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/settings/legacy.ts
|
|
42
|
-
function get_legacy_builtin_extensions_config_path() {
|
|
43
|
-
const xdg = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
44
|
-
return join(xdg, "my-pi", "extensions.json");
|
|
45
|
-
}
|
|
46
|
-
function read_json_file(path) {
|
|
47
|
-
if (!existsSync(path)) return void 0;
|
|
48
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
49
|
-
}
|
|
50
|
-
function maybe_file(path) {
|
|
51
|
-
const config = read_json_file(path);
|
|
52
|
-
return config === void 0 ? void 0 : {
|
|
53
|
-
path,
|
|
54
|
-
config
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function find_legacy_settings_files() {
|
|
58
|
-
const agent = getAgentDir();
|
|
59
|
-
const xdg = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
60
|
-
return {
|
|
61
|
-
extensions: maybe_file(get_legacy_builtin_extensions_config_path()),
|
|
62
|
-
mcpPolicy: maybe_file(join(agent, "mcp-policy.json")),
|
|
63
|
-
codingPreferences: maybe_file(join(agent, "coding-preferences.json")),
|
|
64
|
-
promptPresets: maybe_file(join(agent, "presets.json")),
|
|
65
|
-
promptPresetState: maybe_file(join(agent, "prompt-preset-state.json")),
|
|
66
|
-
trustedHooks: maybe_file(join(agent, "trusted-hooks.json")),
|
|
67
|
-
trustedMcpProjects: maybe_file(join(agent, "trusted-mcp-projects.json")),
|
|
68
|
-
trustedLspBinaries: maybe_file(join(agent, "trusted-lsp-binaries.json")),
|
|
69
|
-
telemetry: maybe_file(join(agent, "telemetry.json")),
|
|
70
|
-
footer: maybe_file(join(agent, "extensions", "pi-footer.json")),
|
|
71
|
-
skills: maybe_file(join(xdg, "my-pi", "skills.json")),
|
|
72
|
-
svelteGuardrails: maybe_file(join(xdg, "my-pi", "svelte-guardrails.json")),
|
|
73
|
-
context: maybe_file(join(xdg, "my-pi", "context.json"))
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function has_legacy_settings_files() {
|
|
77
|
-
return Object.values(find_legacy_settings_files()).some(Boolean);
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region src/settings/migrate.ts
|
|
81
|
-
function timestamp_for_filename(date = /* @__PURE__ */ new Date()) {
|
|
82
|
-
return date.toISOString().replace(/[:.]/g, "-");
|
|
83
|
-
}
|
|
84
|
-
function backup_path_for(original_path, backup_dir) {
|
|
85
|
-
const parent = basename(dirname(original_path));
|
|
86
|
-
return join(backup_dir, `${parent}-${basename(original_path)}`);
|
|
87
|
-
}
|
|
88
|
-
function move_file_to_backup(source, target) {
|
|
89
|
-
try {
|
|
90
|
-
renameSync(source, target);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
if (error instanceof Error && "code" in error && error.code === "EXDEV") {
|
|
93
|
-
copyFileSync(source, target);
|
|
94
|
-
unlinkSync(source);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function migrate_legacy_settings() {
|
|
101
|
-
const legacy = find_legacy_settings_files();
|
|
102
|
-
const entries = Object.values(legacy).filter((entry) => entry !== void 0);
|
|
103
|
-
const settings = read_settings();
|
|
104
|
-
if (legacy.extensions) settings.extensions = {
|
|
105
|
-
...settings.extensions,
|
|
106
|
-
enabled: {
|
|
107
|
-
...settings.extensions?.enabled,
|
|
108
|
-
...legacy.extensions.config.enabled
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
if (legacy.mcpPolicy) settings.mcp = {
|
|
112
|
-
...settings.mcp,
|
|
113
|
-
policy: legacy.mcpPolicy.config
|
|
114
|
-
};
|
|
115
|
-
if (legacy.codingPreferences) settings.codingPreferences = legacy.codingPreferences.config;
|
|
116
|
-
if (legacy.promptPresets || legacy.promptPresetState) settings.promptPresets = {
|
|
117
|
-
...settings.promptPresets,
|
|
118
|
-
...legacy.promptPresets && { global: legacy.promptPresets.config },
|
|
119
|
-
...legacy.promptPresetState && { state: legacy.promptPresetState.config }
|
|
120
|
-
};
|
|
121
|
-
settings.trust = {
|
|
122
|
-
...settings.trust,
|
|
123
|
-
...legacy.trustedHooks && { hooks: legacy.trustedHooks.config },
|
|
124
|
-
...legacy.trustedMcpProjects && { mcpProjects: legacy.trustedMcpProjects.config },
|
|
125
|
-
...legacy.trustedLspBinaries && { lspBinaries: legacy.trustedLspBinaries.config }
|
|
126
|
-
};
|
|
127
|
-
settings.packages = {
|
|
128
|
-
...settings.packages,
|
|
129
|
-
...legacy.telemetry && { telemetry: legacy.telemetry.config },
|
|
130
|
-
...legacy.footer && { footer: legacy.footer.config },
|
|
131
|
-
...legacy.skills && { skills: legacy.skills.config },
|
|
132
|
-
...legacy.svelteGuardrails && { svelteGuardrails: legacy.svelteGuardrails.config },
|
|
133
|
-
...legacy.context && { context: legacy.context.config }
|
|
134
|
-
};
|
|
135
|
-
write_settings(settings);
|
|
136
|
-
if (entries.length === 0) return {
|
|
137
|
-
migrated: false,
|
|
138
|
-
moved_files: [],
|
|
139
|
-
settings: normalize_settings(settings)
|
|
140
|
-
};
|
|
141
|
-
const backup_dir = join(getAgentDir(), `legacy-config-backup-${timestamp_for_filename()}`);
|
|
142
|
-
mkdirSync(backup_dir, {
|
|
143
|
-
recursive: true,
|
|
144
|
-
mode: 448
|
|
145
|
-
});
|
|
146
|
-
const moved_files = [];
|
|
147
|
-
for (const entry of entries) {
|
|
148
|
-
if (!existsSync(entry.path)) continue;
|
|
149
|
-
const target = backup_path_for(entry.path, backup_dir);
|
|
150
|
-
move_file_to_backup(entry.path, target);
|
|
151
|
-
moved_files.push(entry.path);
|
|
152
|
-
}
|
|
153
|
-
writeFileSync(join(backup_dir, "migration-report.json"), JSON.stringify({
|
|
154
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
155
|
-
settings_path: join(getAgentDir(), "my-pi-settings.json"),
|
|
156
|
-
moved_files
|
|
157
|
-
}, null, " ") + "\n", { mode: 384 });
|
|
158
|
-
return {
|
|
159
|
-
migrated: true,
|
|
160
|
-
backup_dir,
|
|
161
|
-
moved_files,
|
|
162
|
-
settings: normalize_settings(settings)
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
//#endregion
|
|
166
|
-
//#region src/settings/index.ts
|
|
167
|
-
function load_settings() {
|
|
168
|
-
if (has_legacy_settings_files()) return migrate_legacy_settings().settings;
|
|
169
|
-
return ensure_current_settings();
|
|
170
|
-
}
|
|
171
|
-
function save_settings(settings) {
|
|
172
|
-
write_current_settings(settings);
|
|
173
|
-
}
|
|
174
|
-
//#endregion
|
|
175
|
-
export { save_settings as n, load_settings as t };
|
|
176
|
-
|
|
177
|
-
//# sourceMappingURL=settings-BCn3P9qH.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"settings-BCn3P9qH.js","names":[],"sources":["../src/settings/schema.ts","../src/settings/current.ts","../src/settings/legacy.ts","../src/settings/migrate.ts","../src/settings/index.ts"],"sourcesContent":["import type { BuiltinExtensionKey } from '../extensions/builtin-registry.js';\n\nexport interface MyPiSettings {\n\tversion: 1;\n\textensions: {\n\t\tenabled: Partial<Record<BuiltinExtensionKey, boolean>>;\n\t};\n\tmcp?: { policy?: unknown };\n\tcodingPreferences?: unknown;\n\tpromptPresets?: { global?: unknown; state?: unknown };\n\topenRouterFusion?: {\n\t\tanalysisModels?: string[];\n\t\tjudgeModel?: string;\n\t\tforce?: boolean;\n\t};\n\ttrust?: Record<string, unknown>;\n\tpackages?: Record<string, unknown>;\n}\n\nexport const DEFAULT_SETTINGS: MyPiSettings = {\n\tversion: 1,\n\textensions: {\n\t\tenabled: {},\n\t},\n};\n\nexport function normalize_settings(value: unknown): MyPiSettings {\n\tconst raw = value as Partial<MyPiSettings> | null | undefined;\n\tconst enabled: MyPiSettings['extensions']['enabled'] = {};\n\tconst raw_enabled = raw?.extensions?.enabled;\n\tif (raw_enabled && typeof raw_enabled === 'object') {\n\t\tfor (const [key, state] of Object.entries(raw_enabled)) {\n\t\t\tif (typeof state === 'boolean') {\n\t\t\t\tenabled[key as BuiltinExtensionKey] = state;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\t...(raw && typeof raw === 'object' ? raw : {}),\n\t\tversion: 1,\n\t\textensions: { enabled },\n\t};\n}\n","import {\n\tget_settings_path,\n\tread_settings,\n\twrite_settings,\n} from '@spences10/pi-settings';\nimport { existsSync } from 'node:fs';\nimport {\n\tDEFAULT_SETTINGS,\n\tnormalize_settings,\n\ttype MyPiSettings,\n} from './schema.js';\n\nexport { get_settings_path } from '@spences10/pi-settings';\n\nexport function current_settings_exists(): boolean {\n\treturn existsSync(get_settings_path());\n}\n\nexport function read_current_settings(): MyPiSettings {\n\tif (!current_settings_exists()) return { ...DEFAULT_SETTINGS };\n\treturn normalize_settings(read_settings());\n}\n\nexport function write_current_settings(settings: MyPiSettings): void {\n\twrite_settings(settings);\n}\n\nexport function ensure_current_settings(): MyPiSettings {\n\tif (!current_settings_exists())\n\t\twrite_current_settings(DEFAULT_SETTINGS);\n\treturn read_current_settings();\n}\n","import { getAgentDir } from '@earendil-works/pi-coding-agent';\n// Temporary migration bridge: keep for two minor releases after\n// my-pi-settings.json ships, then remove with migrate.ts and related tests.\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { type BuiltinExtensionKey } from '../extensions/builtin-registry.js';\n\nexport interface LegacyBuiltinExtensionsConfig {\n\tversion?: number;\n\tenabled?: Partial<Record<BuiltinExtensionKey, boolean>>;\n}\n\nexport interface LegacySettingsFiles {\n\textensions?: {\n\t\tpath: string;\n\t\tconfig: LegacyBuiltinExtensionsConfig;\n\t};\n\tmcpPolicy?: { path: string; config: unknown };\n\tcodingPreferences?: { path: string; config: unknown };\n\tpromptPresets?: { path: string; config: unknown };\n\tpromptPresetState?: { path: string; config: unknown };\n\ttrustedHooks?: { path: string; config: unknown };\n\ttrustedMcpProjects?: { path: string; config: unknown };\n\ttrustedLspBinaries?: { path: string; config: unknown };\n\ttelemetry?: { path: string; config: unknown };\n\tfooter?: { path: string; config: unknown };\n\tskills?: { path: string; config: unknown };\n\tsvelteGuardrails?: { path: string; config: unknown };\n\tcontext?: { path: string; config: unknown };\n}\n\nexport function get_legacy_builtin_extensions_config_path(): string {\n\tconst xdg =\n\t\tprocess.env.XDG_CONFIG_HOME || join(homedir(), '.config');\n\treturn join(xdg, 'my-pi', 'extensions.json');\n}\n\nfunction read_json_file<T>(path: string): T | undefined {\n\tif (!existsSync(path)) return undefined;\n\treturn JSON.parse(readFileSync(path, 'utf-8')) as T;\n}\n\nfunction maybe_file<T>(\n\tpath: string,\n): { path: string; config: T } | undefined {\n\tconst config = read_json_file<T>(path);\n\treturn config === undefined ? undefined : { path, config };\n}\n\nexport function find_legacy_settings_files(): LegacySettingsFiles {\n\tconst agent = getAgentDir();\n\tconst xdg =\n\t\tprocess.env.XDG_CONFIG_HOME || join(homedir(), '.config');\n\treturn {\n\t\textensions: maybe_file<LegacyBuiltinExtensionsConfig>(\n\t\t\tget_legacy_builtin_extensions_config_path(),\n\t\t),\n\t\tmcpPolicy: maybe_file(join(agent, 'mcp-policy.json')),\n\t\tcodingPreferences: maybe_file(\n\t\t\tjoin(agent, 'coding-preferences.json'),\n\t\t),\n\t\tpromptPresets: maybe_file(join(agent, 'presets.json')),\n\t\tpromptPresetState: maybe_file(\n\t\t\tjoin(agent, 'prompt-preset-state.json'),\n\t\t),\n\t\ttrustedHooks: maybe_file(join(agent, 'trusted-hooks.json')),\n\t\ttrustedMcpProjects: maybe_file(\n\t\t\tjoin(agent, 'trusted-mcp-projects.json'),\n\t\t),\n\t\ttrustedLspBinaries: maybe_file(\n\t\t\tjoin(agent, 'trusted-lsp-binaries.json'),\n\t\t),\n\t\ttelemetry: maybe_file(join(agent, 'telemetry.json')),\n\t\tfooter: maybe_file(join(agent, 'extensions', 'pi-footer.json')),\n\t\tskills: maybe_file(join(xdg, 'my-pi', 'skills.json')),\n\t\tsvelteGuardrails: maybe_file(\n\t\t\tjoin(xdg, 'my-pi', 'svelte-guardrails.json'),\n\t\t),\n\t\tcontext: maybe_file(join(xdg, 'my-pi', 'context.json')),\n\t};\n}\n\nexport function has_legacy_settings_files(): boolean {\n\treturn Object.values(find_legacy_settings_files()).some(Boolean);\n}\n","import { getAgentDir } from '@earendil-works/pi-coding-agent';\nimport {\n\tread_settings,\n\twrite_settings,\n} from '@spences10/pi-settings';\nimport {\n\tcopyFileSync,\n\texistsSync,\n\tmkdirSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport { find_legacy_settings_files } from './legacy.js';\nimport { normalize_settings, type MyPiSettings } from './schema.js';\n\nexport interface SettingsMigrationResult {\n\tmigrated: boolean;\n\tbackup_dir?: string;\n\tmoved_files: string[];\n\tsettings: MyPiSettings;\n}\n\nfunction timestamp_for_filename(date = new Date()): string {\n\treturn date.toISOString().replace(/[:.]/g, '-');\n}\n\nfunction backup_path_for(\n\toriginal_path: string,\n\tbackup_dir: string,\n): string {\n\tconst parent = basename(dirname(original_path));\n\treturn join(backup_dir, `${parent}-${basename(original_path)}`);\n}\n\nfunction move_file_to_backup(source: string, target: string): void {\n\ttry {\n\t\trenameSync(source, target);\n\t} catch (error) {\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\t'code' in error &&\n\t\t\terror.code === 'EXDEV'\n\t\t) {\n\t\t\tcopyFileSync(source, target);\n\t\t\tunlinkSync(source);\n\t\t\treturn;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport function migrate_legacy_settings(): SettingsMigrationResult {\n\tconst legacy = find_legacy_settings_files();\n\tconst entries = Object.values(legacy).filter(\n\t\t(entry) => entry !== undefined,\n\t);\n\tconst settings = read_settings();\n\n\tif (legacy.extensions) {\n\t\tsettings.extensions = {\n\t\t\t...settings.extensions,\n\t\t\tenabled: {\n\t\t\t\t...settings.extensions?.enabled,\n\t\t\t\t...legacy.extensions.config.enabled,\n\t\t\t},\n\t\t};\n\t}\n\tif (legacy.mcpPolicy) {\n\t\tsettings.mcp = {\n\t\t\t...settings.mcp,\n\t\t\tpolicy: legacy.mcpPolicy.config,\n\t\t};\n\t}\n\tif (legacy.codingPreferences) {\n\t\tsettings.codingPreferences = legacy.codingPreferences.config;\n\t}\n\tif (legacy.promptPresets || legacy.promptPresetState) {\n\t\tsettings.promptPresets = {\n\t\t\t...settings.promptPresets,\n\t\t\t...(legacy.promptPresets && {\n\t\t\t\tglobal: legacy.promptPresets.config,\n\t\t\t}),\n\t\t\t...(legacy.promptPresetState && {\n\t\t\t\tstate: legacy.promptPresetState.config,\n\t\t\t}),\n\t\t};\n\t}\n\tsettings.trust = {\n\t\t...settings.trust,\n\t\t...(legacy.trustedHooks && { hooks: legacy.trustedHooks.config }),\n\t\t...(legacy.trustedMcpProjects && {\n\t\t\tmcpProjects: legacy.trustedMcpProjects.config,\n\t\t}),\n\t\t...(legacy.trustedLspBinaries && {\n\t\t\tlspBinaries: legacy.trustedLspBinaries.config,\n\t\t}),\n\t};\n\tsettings.packages = {\n\t\t...settings.packages,\n\t\t...(legacy.telemetry && { telemetry: legacy.telemetry.config }),\n\t\t...(legacy.footer && { footer: legacy.footer.config }),\n\t\t...(legacy.skills && { skills: legacy.skills.config }),\n\t\t...(legacy.svelteGuardrails && {\n\t\t\tsvelteGuardrails: legacy.svelteGuardrails.config,\n\t\t}),\n\t\t...(legacy.context && { context: legacy.context.config }),\n\t};\n\n\twrite_settings(settings);\n\n\tif (entries.length === 0) {\n\t\treturn {\n\t\t\tmigrated: false,\n\t\t\tmoved_files: [],\n\t\t\tsettings: normalize_settings(settings),\n\t\t};\n\t}\n\n\tconst backup_dir = join(\n\t\tgetAgentDir(),\n\t\t`legacy-config-backup-${timestamp_for_filename()}`,\n\t);\n\tmkdirSync(backup_dir, { recursive: true, mode: 0o700 });\n\n\tconst moved_files: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (!existsSync(entry.path)) continue;\n\t\tconst target = backup_path_for(entry.path, backup_dir);\n\t\tmove_file_to_backup(entry.path, target);\n\t\tmoved_files.push(entry.path);\n\t}\n\n\twriteFileSync(\n\t\tjoin(backup_dir, 'migration-report.json'),\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t\tsettings_path: join(getAgentDir(), 'my-pi-settings.json'),\n\t\t\t\tmoved_files,\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\n\treturn {\n\t\tmigrated: true,\n\t\tbackup_dir,\n\t\tmoved_files,\n\t\tsettings: normalize_settings(settings),\n\t};\n}\n","import {\n\tensure_current_settings,\n\tread_current_settings,\n\twrite_current_settings,\n} from './current.js';\nimport { has_legacy_settings_files } from './legacy.js';\nimport { migrate_legacy_settings } from './migrate.js';\nimport type { MyPiSettings } from './schema.js';\n\nexport { get_settings_path } from './current.js';\nexport { migrate_legacy_settings } from './migrate.js';\nexport type { MyPiSettings } from './schema.js';\n\nexport function load_settings(): MyPiSettings {\n\tif (has_legacy_settings_files())\n\t\treturn migrate_legacy_settings().settings;\n\treturn ensure_current_settings();\n}\n\nexport function save_settings(settings: MyPiSettings): void {\n\twrite_current_settings(settings);\n}\n\nexport function update_settings(\n\tupdater: (settings: MyPiSettings) => MyPiSettings,\n): MyPiSettings {\n\tconst next = updater(read_current_settings());\n\twrite_current_settings(next);\n\treturn next;\n}\n"],"mappings":"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"}
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { basename } from "node:path";
|
|
3
|
-
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
|
-
//#region src/extensions/startup-screen/index.ts
|
|
5
|
-
const RESET = "\x1B[0m";
|
|
6
|
-
const BOLD = "\x1B[1m";
|
|
7
|
-
const TRUECOLOR_FG_PREFIX = "\x1B[38;2;";
|
|
8
|
-
const XTERM_FG_PREFIX = "\x1B[38;5;";
|
|
9
|
-
const FALLBACK_PALETTE = [
|
|
10
|
-
[
|
|
11
|
-
22,
|
|
12
|
-
83,
|
|
13
|
-
189
|
|
14
|
-
],
|
|
15
|
-
[
|
|
16
|
-
48,
|
|
17
|
-
129,
|
|
18
|
-
247
|
|
19
|
-
],
|
|
20
|
-
[
|
|
21
|
-
93,
|
|
22
|
-
171,
|
|
23
|
-
255
|
|
24
|
-
],
|
|
25
|
-
[
|
|
26
|
-
151,
|
|
27
|
-
205,
|
|
28
|
-
255
|
|
29
|
-
],
|
|
30
|
-
[
|
|
31
|
-
93,
|
|
32
|
-
171,
|
|
33
|
-
255
|
|
34
|
-
],
|
|
35
|
-
[
|
|
36
|
-
48,
|
|
37
|
-
129,
|
|
38
|
-
247
|
|
39
|
-
]
|
|
40
|
-
];
|
|
41
|
-
const THEME_GRADIENT_TOKENS = [
|
|
42
|
-
"accent",
|
|
43
|
-
"borderAccent",
|
|
44
|
-
"mdHeading",
|
|
45
|
-
"syntaxFunction",
|
|
46
|
-
"thinkingHigh",
|
|
47
|
-
"mdCode"
|
|
48
|
-
];
|
|
49
|
-
const XTERM_CUBE_VALUES = [
|
|
50
|
-
0,
|
|
51
|
-
95,
|
|
52
|
-
135,
|
|
53
|
-
175,
|
|
54
|
-
215,
|
|
55
|
-
255
|
|
56
|
-
];
|
|
57
|
-
const XTERM_GRAY_START = 232;
|
|
58
|
-
const TITLE_LINES = [
|
|
59
|
-
"███╗ ███╗ ██████╗ ██╗",
|
|
60
|
-
"████╗ ████║ ██╗ ██╗ ██╔══██╗ ",
|
|
61
|
-
"██╔████╔██║ ╚██╗ ██╔╝ ████╗ ██████╔╝██╗",
|
|
62
|
-
"██║╚██╔╝██║ ╚████╔╝ ╚═══╝ ██╔═══╝ ██║",
|
|
63
|
-
"██║ ╚═╝ ██║ ╚██╔╝ ██║ ██║",
|
|
64
|
-
"╚═╝ ╚═╝ ██╔╝ ╚═╝ ╚═╝"
|
|
65
|
-
];
|
|
66
|
-
const TITLE_WIDTH = Math.max(...TITLE_LINES.map((line) => line.length));
|
|
67
|
-
function read_my_pi_version() {
|
|
68
|
-
const candidates = [new URL("../../../package.json", import.meta.url), new URL("../package.json", import.meta.url)];
|
|
69
|
-
for (const candidate of candidates) try {
|
|
70
|
-
const version = JSON.parse(readFileSync(candidate, "utf-8"))?.version;
|
|
71
|
-
if (typeof version === "string") return version;
|
|
72
|
-
} catch {}
|
|
73
|
-
return "dev";
|
|
74
|
-
}
|
|
75
|
-
const MY_PI_VERSION = read_my_pi_version();
|
|
76
|
-
function mix(a, b, t) {
|
|
77
|
-
return Math.round(a + (b - a) * t);
|
|
78
|
-
}
|
|
79
|
-
function sample_gradient(position, palette) {
|
|
80
|
-
const scaled = (position % 1 + 1) % 1 * palette.length;
|
|
81
|
-
const index = Math.floor(scaled);
|
|
82
|
-
const next_index = (index + 1) % palette.length;
|
|
83
|
-
const t = scaled - index;
|
|
84
|
-
const a = palette[index];
|
|
85
|
-
const b = palette[next_index];
|
|
86
|
-
return [
|
|
87
|
-
mix(a[0], b[0], t),
|
|
88
|
-
mix(a[1], b[1], t),
|
|
89
|
-
mix(a[2], b[2], t)
|
|
90
|
-
];
|
|
91
|
-
}
|
|
92
|
-
function ansi_fg([r, g, b], text) {
|
|
93
|
-
return `\x1b[38;2;${r};${g};${b}m${text}${RESET}`;
|
|
94
|
-
}
|
|
95
|
-
function rgb_from_xterm(index) {
|
|
96
|
-
if (index < 0 || index > 255) return void 0;
|
|
97
|
-
if (index < 16) return void 0;
|
|
98
|
-
if (index >= XTERM_GRAY_START) {
|
|
99
|
-
const gray = 8 + (index - XTERM_GRAY_START) * 10;
|
|
100
|
-
return [
|
|
101
|
-
gray,
|
|
102
|
-
gray,
|
|
103
|
-
gray
|
|
104
|
-
];
|
|
105
|
-
}
|
|
106
|
-
const cube = index - 16;
|
|
107
|
-
return [
|
|
108
|
-
XTERM_CUBE_VALUES[Math.floor(cube / 36)],
|
|
109
|
-
XTERM_CUBE_VALUES[Math.floor(cube % 36 / 6)],
|
|
110
|
-
XTERM_CUBE_VALUES[cube % 6]
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
|
-
function ansi_params(ansi, prefix) {
|
|
114
|
-
if (!ansi.startsWith(prefix)) return void 0;
|
|
115
|
-
const end = ansi.indexOf("m", prefix.length);
|
|
116
|
-
if (end === -1) return void 0;
|
|
117
|
-
return ansi.slice(prefix.length, end).split(";");
|
|
118
|
-
}
|
|
119
|
-
function rgb_from_ansi(ansi) {
|
|
120
|
-
const truecolor = ansi_params(ansi, TRUECOLOR_FG_PREFIX);
|
|
121
|
-
if (truecolor?.length === 3) return [
|
|
122
|
-
Number(truecolor[0]),
|
|
123
|
-
Number(truecolor[1]),
|
|
124
|
-
Number(truecolor[2])
|
|
125
|
-
];
|
|
126
|
-
const xterm = ansi_params(ansi, XTERM_FG_PREFIX);
|
|
127
|
-
return xterm?.length === 1 ? rgb_from_xterm(Number(xterm[0])) : void 0;
|
|
128
|
-
}
|
|
129
|
-
function theme_gradient_palette(theme) {
|
|
130
|
-
const palette = [];
|
|
131
|
-
const seen = /* @__PURE__ */ new Set();
|
|
132
|
-
for (const token of THEME_GRADIENT_TOKENS) {
|
|
133
|
-
const rgb = rgb_from_ansi(theme.getFgAnsi(token));
|
|
134
|
-
if (!rgb) continue;
|
|
135
|
-
const key = rgb.join(",");
|
|
136
|
-
if (seen.has(key)) continue;
|
|
137
|
-
seen.add(key);
|
|
138
|
-
palette.push(rgb);
|
|
139
|
-
}
|
|
140
|
-
return palette.length >= 2 ? palette : FALLBACK_PALETTE;
|
|
141
|
-
}
|
|
142
|
-
function gradient_text(text, phase, palette) {
|
|
143
|
-
const chars = text.split("");
|
|
144
|
-
const span = Math.max(chars.length - 1, 1);
|
|
145
|
-
return chars.map((char, index) => {
|
|
146
|
-
if (char === " ") return char;
|
|
147
|
-
return ansi_fg(sample_gradient(index / span + phase, palette), char);
|
|
148
|
-
}).join("");
|
|
149
|
-
}
|
|
150
|
-
function center_line(line, width) {
|
|
151
|
-
const clipped = visibleWidth(line) > width ? truncateToWidth(line, width, "") : line;
|
|
152
|
-
const padding = Math.max(0, Math.floor((width - visibleWidth(clipped)) / 2));
|
|
153
|
-
return `${" ".repeat(padding)}${clipped}`;
|
|
154
|
-
}
|
|
155
|
-
function color_line(theme, palette, line, phase) {
|
|
156
|
-
return theme.getColorMode() === "truecolor" ? gradient_text(line, phase, palette) : theme.fg("accent", line);
|
|
157
|
-
}
|
|
158
|
-
function gradient_or_theme(theme, palette, line, phase) {
|
|
159
|
-
return theme.getColorMode() === "truecolor" ? `${BOLD}${gradient_text(line, phase, palette)}${RESET}` : theme.bold(theme.fg("accent", line));
|
|
160
|
-
}
|
|
161
|
-
function render_brand(theme, palette, width) {
|
|
162
|
-
return gradient_or_theme(theme, palette, center_line(`My-Pi v${MY_PI_VERSION}`, width), .12);
|
|
163
|
-
}
|
|
164
|
-
function render_subtitle(ctx, theme, palette, model_id, width) {
|
|
165
|
-
return gradient_or_theme(theme, palette, center_line(`${model_id} · ${basename(ctx.cwd) || ctx.cwd}`, width), .18);
|
|
166
|
-
}
|
|
167
|
-
function render_startup_header(ctx, theme, width, model_id = ctx.model?.id ?? "no model selected") {
|
|
168
|
-
if (width < 24) return [center_line(theme.bold(theme.fg("accent", `My-Pi v${MY_PI_VERSION}`)), width), center_line(`${model_id} · ${basename(ctx.cwd) || ctx.cwd}`, width)];
|
|
169
|
-
const palette = theme_gradient_palette(theme);
|
|
170
|
-
const logo = TITLE_LINES.map((line, row) => color_line(theme, palette, center_line(line.padEnd(TITLE_WIDTH), width), row * .045));
|
|
171
|
-
return [
|
|
172
|
-
"",
|
|
173
|
-
render_brand(theme, palette, width),
|
|
174
|
-
...logo,
|
|
175
|
-
render_subtitle(ctx, theme, palette, model_id, width),
|
|
176
|
-
""
|
|
177
|
-
];
|
|
178
|
-
}
|
|
179
|
-
function startup_screen_extension(pi) {
|
|
180
|
-
let request_render;
|
|
181
|
-
let current_model_id = "no model selected";
|
|
182
|
-
function install_header(ctx) {
|
|
183
|
-
ctx.ui.setHeader((tui, theme) => {
|
|
184
|
-
request_render = () => tui.requestRender();
|
|
185
|
-
return {
|
|
186
|
-
invalidate() {
|
|
187
|
-
tui.requestRender();
|
|
188
|
-
},
|
|
189
|
-
render(width) {
|
|
190
|
-
return render_startup_header(ctx, theme, width, current_model_id);
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
196
|
-
current_model_id = ctx.model?.id ?? "no model selected";
|
|
197
|
-
if (!ctx.hasUI) return;
|
|
198
|
-
install_header(ctx);
|
|
199
|
-
});
|
|
200
|
-
pi.on("model_select", (event) => {
|
|
201
|
-
current_model_id = event.model.id;
|
|
202
|
-
request_render?.();
|
|
203
|
-
});
|
|
204
|
-
pi.on("session_shutdown", (_event, ctx) => {
|
|
205
|
-
if (ctx.hasUI) ctx.ui.setHeader(void 0);
|
|
206
|
-
});
|
|
207
|
-
pi.registerCommand("builtin-header", {
|
|
208
|
-
description: "Restore the built-in pi startup header",
|
|
209
|
-
handler: async (_args, ctx) => {
|
|
210
|
-
ctx.ui.setHeader(void 0);
|
|
211
|
-
ctx.ui.notify("Built-in startup header restored", "info");
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
//#endregion
|
|
216
|
-
export { startup_screen_extension as default };
|
|
217
|
-
|
|
218
|
-
//# sourceMappingURL=startup-screen-DUeBWuAc.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"startup-screen-DUeBWuAc.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,64 +0,0 @@
|
|
|
1
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
2
|
-
//#region src/extensions/turn-timer/index.ts
|
|
3
|
-
const TURN_TIMER_ENTRY = "turn-timer";
|
|
4
|
-
function format_clock(duration_ms) {
|
|
5
|
-
const total_seconds = Math.max(0, Math.floor(duration_ms / 1e3));
|
|
6
|
-
const hours = Math.floor(total_seconds / 3600);
|
|
7
|
-
const minutes = Math.floor(total_seconds % 3600 / 60);
|
|
8
|
-
const seconds = total_seconds % 60;
|
|
9
|
-
return hours > 0 ? `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}` : `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
10
|
-
}
|
|
11
|
-
function format_duration(duration_ms) {
|
|
12
|
-
if (duration_ms < 1e3) return `${Math.max(0, Math.round(duration_ms))}ms`;
|
|
13
|
-
if (duration_ms < 6e4) return `${(duration_ms / 1e3).toFixed(1)}s`;
|
|
14
|
-
return format_clock(duration_ms);
|
|
15
|
-
}
|
|
16
|
-
function turn_timer(pi) {
|
|
17
|
-
let started_at;
|
|
18
|
-
let refresh_timer;
|
|
19
|
-
let active_context;
|
|
20
|
-
const clear_timer = () => {
|
|
21
|
-
if (refresh_timer) clearInterval(refresh_timer);
|
|
22
|
-
refresh_timer = void 0;
|
|
23
|
-
};
|
|
24
|
-
const render_timer = () => {
|
|
25
|
-
if (started_at === void 0 || !active_context) return;
|
|
26
|
-
const timer = active_context.ui.theme.fg("success", format_clock(Date.now() - started_at));
|
|
27
|
-
active_context.ui.setWorkingMessage(`Working... ${timer}`);
|
|
28
|
-
};
|
|
29
|
-
const reset = () => {
|
|
30
|
-
clear_timer();
|
|
31
|
-
if (active_context?.mode === "tui") active_context.ui.setWorkingMessage(void 0);
|
|
32
|
-
started_at = void 0;
|
|
33
|
-
active_context = void 0;
|
|
34
|
-
};
|
|
35
|
-
pi.registerEntryRenderer(TURN_TIMER_ENTRY, (entry, _options, theme) => {
|
|
36
|
-
if (!entry.data || typeof entry.data.duration_ms !== "number" || !Number.isFinite(entry.data.duration_ms)) return;
|
|
37
|
-
return new Text(theme.fg("success", `⏱ Completed in ${format_duration(entry.data.duration_ms)}`), 0, 0);
|
|
38
|
-
});
|
|
39
|
-
pi.on("agent_start", async (_event, ctx) => {
|
|
40
|
-
if (started_at !== void 0) return;
|
|
41
|
-
started_at = Date.now();
|
|
42
|
-
active_context = ctx;
|
|
43
|
-
if (ctx.mode !== "tui") return;
|
|
44
|
-
render_timer();
|
|
45
|
-
refresh_timer = setInterval(render_timer, 1e3);
|
|
46
|
-
refresh_timer.unref?.();
|
|
47
|
-
});
|
|
48
|
-
pi.on("agent_settled", async () => {
|
|
49
|
-
if (started_at === void 0) return;
|
|
50
|
-
const duration_ms = Date.now() - started_at;
|
|
51
|
-
reset();
|
|
52
|
-
pi.appendEntry(TURN_TIMER_ENTRY, {
|
|
53
|
-
duration_ms,
|
|
54
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
pi.on("session_shutdown", async () => {
|
|
58
|
-
reset();
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
export { turn_timer as default };
|
|
63
|
-
|
|
64
|
-
//# sourceMappingURL=turn-timer-CoyDI4gQ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"turn-timer-CoyDI4gQ.js","names":[],"sources":["../src/extensions/turn-timer/index.ts"],"sourcesContent":["import type {\n\tExtensionAPI,\n\tExtensionContext,\n} from '@earendil-works/pi-coding-agent';\nimport { Text } from '@earendil-works/pi-tui';\n\nexport const TURN_TIMER_ENTRY = 'turn-timer';\nexport interface TurnTimerEntry {\n\tduration_ms: number;\n\tcompleted_at: string;\n}\n\nexport function format_clock(duration_ms: number): string {\n\tconst total_seconds = Math.max(0, Math.floor(duration_ms / 1_000));\n\tconst hours = Math.floor(total_seconds / 3_600);\n\tconst minutes = Math.floor((total_seconds % 3_600) / 60);\n\tconst seconds = total_seconds % 60;\n\n\treturn hours > 0\n\t\t? `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`\n\t\t: `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;\n}\n\nexport function format_duration(duration_ms: number): string {\n\tif (duration_ms < 1_000)\n\t\treturn `${Math.max(0, Math.round(duration_ms))}ms`;\n\tif (duration_ms < 60_000)\n\t\treturn `${(duration_ms / 1_000).toFixed(1)}s`;\n\treturn format_clock(duration_ms);\n}\n\nexport default function turn_timer(pi: ExtensionAPI): void {\n\tlet started_at: number | undefined;\n\tlet refresh_timer: NodeJS.Timeout | undefined;\n\tlet active_context: ExtensionContext | undefined;\n\n\tconst clear_timer = (): void => {\n\t\tif (refresh_timer) clearInterval(refresh_timer);\n\t\trefresh_timer = undefined;\n\t};\n\n\tconst render_timer = (): void => {\n\t\tif (started_at === undefined || !active_context) return;\n\t\tconst timer = active_context.ui.theme.fg(\n\t\t\t'success',\n\t\t\tformat_clock(Date.now() - started_at),\n\t\t);\n\t\tactive_context.ui.setWorkingMessage(`Working... ${timer}`);\n\t};\n\n\tconst reset = (): void => {\n\t\tclear_timer();\n\t\tif (active_context?.mode === 'tui') {\n\t\t\tactive_context.ui.setWorkingMessage(undefined);\n\t\t}\n\t\tstarted_at = undefined;\n\t\tactive_context = undefined;\n\t};\n\n\tpi.registerEntryRenderer<TurnTimerEntry>(\n\t\tTURN_TIMER_ENTRY,\n\t\t(entry, _options, theme) => {\n\t\t\tif (\n\t\t\t\t!entry.data ||\n\t\t\t\ttypeof entry.data.duration_ms !== 'number' ||\n\t\t\t\t!Number.isFinite(entry.data.duration_ms)\n\t\t\t) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn new Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t'success',\n\t\t\t\t\t`⏱ Completed in ${format_duration(entry.data.duration_ms)}`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t},\n\t);\n\n\tpi.on('agent_start', async (_event, ctx) => {\n\t\tif (started_at !== undefined) return;\n\t\tstarted_at = Date.now();\n\t\tactive_context = ctx;\n\n\t\tif (ctx.mode !== 'tui') return;\n\t\trender_timer();\n\t\trefresh_timer = setInterval(render_timer, 1_000);\n\t\trefresh_timer.unref?.();\n\t});\n\n\tpi.on('agent_settled', async () => {\n\t\tif (started_at === undefined) return;\n\t\tconst duration_ms = Date.now() - started_at;\n\t\treset();\n\t\tpi.appendEntry<TurnTimerEntry>(TURN_TIMER_ENTRY, {\n\t\t\tduration_ms,\n\t\t\tcompleted_at: new Date().toISOString(),\n\t\t});\n\t});\n\n\tpi.on('session_shutdown', async () => {\n\t\treset();\n\t});\n}\n"],"mappings":";;AAMA,MAAa,mBAAmB;AAMhC,SAAgB,aAAa,aAA6B;CACzD,MAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,GAAK,CAAC;CACjE,MAAM,QAAQ,KAAK,MAAM,gBAAgB,IAAK;CAC9C,MAAM,UAAU,KAAK,MAAO,gBAAgB,OAAS,EAAE;CACvD,MAAM,UAAU,gBAAgB;CAEhC,OAAO,QAAQ,IACZ,GAAG,MAAM,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,QAAQ,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,QAAQ,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,MACjH,GAAG,QAAQ,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,QAAQ,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG;AAChF;AAEA,SAAgB,gBAAgB,aAA6B;CAC5D,IAAI,cAAc,KACjB,OAAO,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,CAAC,EAAE;CAChD,IAAI,cAAc,KACjB,OAAO,IAAI,cAAc,IAAA,CAAO,QAAQ,CAAC,EAAE;CAC5C,OAAO,aAAa,WAAW;AAChC;AAEA,SAAwB,WAAW,IAAwB;CAC1D,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,oBAA0B;EAC/B,IAAI,eAAe,cAAc,aAAa;EAC9C,gBAAgB,KAAA;CACjB;CAEA,MAAM,qBAA2B;EAChC,IAAI,eAAe,KAAA,KAAa,CAAC,gBAAgB;EACjD,MAAM,QAAQ,eAAe,GAAG,MAAM,GACrC,WACA,aAAa,KAAK,IAAI,IAAI,UAAU,CACrC;EACA,eAAe,GAAG,kBAAkB,cAAc,OAAO;CAC1D;CAEA,MAAM,cAAoB;EACzB,YAAY;EACZ,IAAI,gBAAgB,SAAS,OAC5B,eAAe,GAAG,kBAAkB,KAAA,CAAS;EAE9C,aAAa,KAAA;EACb,iBAAiB,KAAA;CAClB;CAEA,GAAG,sBACF,mBACC,OAAO,UAAU,UAAU;EAC3B,IACC,CAAC,MAAM,QACP,OAAO,MAAM,KAAK,gBAAgB,YAClC,CAAC,OAAO,SAAS,MAAM,KAAK,WAAW,GAEvC;EAED,OAAO,IAAI,KACV,MAAM,GACL,WACA,kBAAkB,gBAAgB,MAAM,KAAK,WAAW,GACzD,GACA,GACA,CACD;CACD,CACD;CAEA,GAAG,GAAG,eAAe,OAAO,QAAQ,QAAQ;EAC3C,IAAI,eAAe,KAAA,GAAW;EAC9B,aAAa,KAAK,IAAI;EACtB,iBAAiB;EAEjB,IAAI,IAAI,SAAS,OAAO;EACxB,aAAa;EACb,gBAAgB,YAAY,cAAc,GAAK;EAC/C,cAAc,QAAQ;CACvB,CAAC;CAED,GAAG,GAAG,iBAAiB,YAAY;EAClC,IAAI,eAAe,KAAA,GAAW;EAC9B,MAAM,cAAc,KAAK,IAAI,IAAI;EACjC,MAAM;EACN,GAAG,YAA4B,kBAAkB;GAChD;GACA,+BAAc,IAAI,KAAK,EAAA,CAAE,YAAY;EACtC,CAAC;CACF,CAAC;CAED,GAAG,GAAG,oBAAoB,YAAY;EACrC,MAAM;CACP,CAAC;AACF"}
|