@difflab/pi 0.1.0-rc.202609140747.4d45e72.2 → 1.0.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 +2 -3
- package/dist/extensions/index.js +13580 -168
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +158 -96
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mise.d.ts +1 -1
- package/dist/mise.d.ts.map +1 -1
- package/dist/pi.d.ts.map +1 -1
- package/dist/process.d.ts.map +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/tools/index.d.ts +3 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +215 -135
- package/dist/tools/reload.d.ts +3 -0
- package/dist/tools/reload.d.ts.map +1 -0
- package/dist/tools/setup.d.ts +2 -13
- package/dist/tools/setup.d.ts.map +1 -1
- package/package.json +6 -6
- package/skills/diffpi-setup/SKILL.md +13 -6
package/dist/tools/index.js
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
|
-
// src/tools/
|
|
1
|
+
// src/tools/reload.ts
|
|
2
2
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import {
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
var reloadParametersSchema = z.object({});
|
|
5
|
+
var reloadParameters = z.toJSONSchema(reloadParametersSchema, { io: "input" });
|
|
6
|
+
function createDiffpiReloadTool(pi) {
|
|
7
|
+
return defineTool({
|
|
8
|
+
name: "diffpi_reload",
|
|
9
|
+
label: "diffpi reload",
|
|
10
|
+
description: "Reload pi extensions, skills, prompts, themes, and context files after setup changes.",
|
|
11
|
+
promptSnippet: "Reload pi after diffpi_setup installs or updates pi resources",
|
|
12
|
+
promptGuidelines: [
|
|
13
|
+
"Call diffpi_reload after diffpi_setup reports that pi resources changed.",
|
|
14
|
+
"Do not call diffpi_reload after a read-only diffpi_validate run."
|
|
15
|
+
],
|
|
16
|
+
parameters: reloadParameters,
|
|
17
|
+
executionMode: "sequential",
|
|
18
|
+
execute() {
|
|
19
|
+
pi.sendUserMessage("/diffpi-reload", { deliverAs: "followUp", expandPromptTemplates: true });
|
|
20
|
+
return Promise.resolve({
|
|
21
|
+
content: [{ type: "text", text: "Queued /diffpi-reload as a follow-up command." }],
|
|
22
|
+
details: {}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/tools/setup.ts
|
|
29
|
+
import { defineTool as defineTool2 } from "@earendil-works/pi-coding-agent";
|
|
30
|
+
import { z as z2 } from "zod";
|
|
4
31
|
|
|
5
32
|
// src/setup.ts
|
|
6
33
|
import { homedir as homedir4 } from "node:os";
|
|
@@ -16,8 +43,8 @@ var mcp = {
|
|
|
16
43
|
},
|
|
17
44
|
async serversEnsure(servers, options = {}) {
|
|
18
45
|
const path = options.path ?? mcp.globalConfigPath();
|
|
19
|
-
const currentText = await
|
|
20
|
-
const current =
|
|
46
|
+
const currentText = await getOptionalFile(path);
|
|
47
|
+
const current = getParsedConfig(currentText, path);
|
|
21
48
|
const nextServers = { ...current.mcpServers };
|
|
22
49
|
for (const [name, entry] of Object.entries(servers)) {
|
|
23
50
|
nextServers[name] = mergeEntry(nextServers[name], entry);
|
|
@@ -38,7 +65,7 @@ function mergeEntry(current, required) {
|
|
|
38
65
|
merged.env = { ...current?.env, ...required.env };
|
|
39
66
|
return merged;
|
|
40
67
|
}
|
|
41
|
-
function
|
|
68
|
+
function getParsedConfig(content, path) {
|
|
42
69
|
if (!content?.trim())
|
|
43
70
|
return { mcpServers: {} };
|
|
44
71
|
try {
|
|
@@ -53,7 +80,7 @@ function parseConfig(content, path) {
|
|
|
53
80
|
throw new Error(`Expected a valid pi-mcp-adapter configuration in ${path}.`);
|
|
54
81
|
}
|
|
55
82
|
}
|
|
56
|
-
async function
|
|
83
|
+
async function getOptionalFile(path) {
|
|
57
84
|
try {
|
|
58
85
|
return await readFile(path, "utf8");
|
|
59
86
|
} catch (error) {
|
|
@@ -76,6 +103,7 @@ import { constants } from "node:fs";
|
|
|
76
103
|
import { access } from "node:fs/promises";
|
|
77
104
|
import { delimiter, join as join2 } from "node:path";
|
|
78
105
|
import { spawn } from "node:child_process";
|
|
106
|
+
var MAX_CAPTURED_OUTPUT_LENGTH = 65536;
|
|
79
107
|
async function findExecutable(name) {
|
|
80
108
|
if (name.includes("/")) {
|
|
81
109
|
try {
|
|
@@ -124,10 +152,12 @@ async function runChecked(command, args, options = {}) {
|
|
|
124
152
|
}
|
|
125
153
|
function appendBounded(current, next) {
|
|
126
154
|
const combined = current + next;
|
|
127
|
-
return combined.length <=
|
|
155
|
+
return combined.length <= MAX_CAPTURED_OUTPUT_LENGTH ? combined : combined.slice(-MAX_CAPTURED_OUTPUT_LENGTH);
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
// src/mise.ts
|
|
159
|
+
var MISE_HOOK_START = "# >>> @difflab/pi mise >>>";
|
|
160
|
+
var MISE_HOOK_END = "# <<< @difflab/pi mise <<<";
|
|
131
161
|
var mise = {
|
|
132
162
|
async executableCheck(name = "mise") {
|
|
133
163
|
return findExecutable(name);
|
|
@@ -148,8 +178,8 @@ var mise = {
|
|
|
148
178
|
},
|
|
149
179
|
async hookEnsure(executable, options = {}) {
|
|
150
180
|
const homeDir = options.homeDir ?? homedir2();
|
|
151
|
-
const hook =
|
|
152
|
-
const current = await
|
|
181
|
+
const hook = getShellHook(basename(options.shell ?? process.env.SHELL ?? ""), executable, homeDir);
|
|
182
|
+
const current = await getOptionalFile2(hook.path);
|
|
153
183
|
if (current.includes(MISE_HOOK_START))
|
|
154
184
|
return { path: hook.path, changed: false, planned: false };
|
|
155
185
|
if (options.dryRun)
|
|
@@ -161,16 +191,16 @@ var mise = {
|
|
|
161
191
|
await writeFile2(hook.path, `${current}${separator}${hook.content}`, "utf8");
|
|
162
192
|
return { path: hook.path, changed: true, planned: false };
|
|
163
193
|
},
|
|
164
|
-
async toolCheckGlobal(executable, tool,
|
|
194
|
+
async toolCheckGlobal(executable, tool, minimumVersion) {
|
|
165
195
|
const result = await run(executable, ["ls", "--global", "--installed", tool, "--json"]);
|
|
166
|
-
return result.code === 0 &&
|
|
196
|
+
return result.code === 0 && isToolInstalled(result.stdout, minimumVersion);
|
|
167
197
|
},
|
|
168
198
|
async toolInstallGlobal(executable, specification) {
|
|
169
199
|
await runChecked(executable, ["use", "--global", specification]);
|
|
170
200
|
},
|
|
171
201
|
async toolCheckLocal(executable, tool, cwd = process.cwd()) {
|
|
172
202
|
const result = await run(executable, ["ls", "--local", "--installed", tool, "--json"], { cwd });
|
|
173
|
-
return result.code === 0 &&
|
|
203
|
+
return result.code === 0 && isToolInstalled(result.stdout);
|
|
174
204
|
},
|
|
175
205
|
async toolInstallLocal(executable, specification, cwd = process.cwd()) {
|
|
176
206
|
await runChecked(executable, ["use", "--path", cwd, specification], { cwd });
|
|
@@ -179,40 +209,76 @@ var mise = {
|
|
|
179
209
|
await runChecked(executable, ["upgrade"], { cwd: homeDir });
|
|
180
210
|
}
|
|
181
211
|
};
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
content: `${MISE_HOOK_START}
|
|
190
|
-
eval "$(${command} activate bash)"
|
|
191
|
-
${MISE_HOOK_END}
|
|
192
|
-
`
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
if (shell === "zsh") {
|
|
196
|
-
return {
|
|
197
|
-
path: join3(homeDir, ".zshrc"),
|
|
198
|
-
content: `${MISE_HOOK_START}
|
|
212
|
+
function getShellHook(shell, executable, homeDir) {
|
|
213
|
+
const command = getShellQuoted(executable);
|
|
214
|
+
switch (shell.toLowerCase()) {
|
|
215
|
+
case "zsh":
|
|
216
|
+
return {
|
|
217
|
+
path: join3(homeDir, ".zshrc"),
|
|
218
|
+
content: `${MISE_HOOK_START}
|
|
199
219
|
eval "$(${command} activate zsh)"
|
|
200
220
|
${MISE_HOOK_END}
|
|
201
221
|
`
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
content: `${MISE_HOOK_START}
|
|
222
|
+
};
|
|
223
|
+
case "fish":
|
|
224
|
+
return {
|
|
225
|
+
path: join3(homeDir, ".config", "fish", "config.fish"),
|
|
226
|
+
content: `${MISE_HOOK_START}
|
|
208
227
|
${command} activate fish | source
|
|
209
228
|
${MISE_HOOK_END}
|
|
210
229
|
`
|
|
211
|
-
|
|
230
|
+
};
|
|
231
|
+
case "nu":
|
|
232
|
+
case "nushell":
|
|
233
|
+
return {
|
|
234
|
+
path: join3(homeDir, ".config", "nushell", "config.nu"),
|
|
235
|
+
content: `${MISE_HOOK_START}
|
|
236
|
+
let mise_bin = ${command}
|
|
237
|
+
let mise_path = $nu.default-config-dir | path join mise.nu
|
|
238
|
+
^$mise_bin activate nu | save $mise_path --force
|
|
239
|
+
use ($nu.default-config-dir | path join mise.nu)
|
|
240
|
+
${MISE_HOOK_END}
|
|
241
|
+
`
|
|
242
|
+
};
|
|
243
|
+
case "xonsh":
|
|
244
|
+
return {
|
|
245
|
+
path: join3(homeDir, ".xonshrc"),
|
|
246
|
+
content: `${MISE_HOOK_START}
|
|
247
|
+
execx($(${command} activate xonsh))
|
|
248
|
+
${MISE_HOOK_END}
|
|
249
|
+
`
|
|
250
|
+
};
|
|
251
|
+
case "elvish":
|
|
252
|
+
return {
|
|
253
|
+
path: join3(homeDir, ".config", "elvish", "rc.elv"),
|
|
254
|
+
content: `${MISE_HOOK_START}
|
|
255
|
+
var mise: = (ns [&])
|
|
256
|
+
eval (${command} activate elvish | slurp) &ns=$mise: &on-end={|ns| set mise: = $ns }
|
|
257
|
+
mise:activate
|
|
258
|
+
${MISE_HOOK_END}
|
|
259
|
+
`
|
|
260
|
+
};
|
|
261
|
+
case "pwsh":
|
|
262
|
+
case "powershell":
|
|
263
|
+
return {
|
|
264
|
+
path: join3(homeDir, ".config", "powershell", "Microsoft.PowerShell_profile.ps1"),
|
|
265
|
+
content: `${MISE_HOOK_START}
|
|
266
|
+
(& ${command} activate pwsh) | Out-String | Invoke-Expression
|
|
267
|
+
${MISE_HOOK_END}
|
|
268
|
+
`
|
|
269
|
+
};
|
|
270
|
+
case "bash":
|
|
271
|
+
default:
|
|
272
|
+
return {
|
|
273
|
+
path: join3(homeDir, ".bashrc"),
|
|
274
|
+
content: `${MISE_HOOK_START}
|
|
275
|
+
eval "$(${command} activate bash)"
|
|
276
|
+
${MISE_HOOK_END}
|
|
277
|
+
`
|
|
278
|
+
};
|
|
212
279
|
}
|
|
213
|
-
throw new Error(`Unsupported shell "${shell || "unknown"}". Supported shells: bash, zsh, fish.`);
|
|
214
280
|
}
|
|
215
|
-
function
|
|
281
|
+
function isToolInstalled(output, minimumVersion) {
|
|
216
282
|
try {
|
|
217
283
|
const value = JSON.parse(output);
|
|
218
284
|
if (!Array.isArray(value))
|
|
@@ -220,17 +286,28 @@ function hasInstalledTool(output, minimumMajor = 0) {
|
|
|
220
286
|
return value.some((entry) => {
|
|
221
287
|
if (!entry || typeof entry !== "object" || !("installed" in entry) || entry.installed !== true)
|
|
222
288
|
return false;
|
|
223
|
-
if (
|
|
289
|
+
if (!minimumVersion)
|
|
224
290
|
return true;
|
|
225
291
|
if (!("version" in entry) || typeof entry.version !== "string")
|
|
226
292
|
return false;
|
|
227
|
-
return
|
|
293
|
+
return isVersionAtLeast(entry.version, minimumVersion);
|
|
228
294
|
});
|
|
229
295
|
} catch {
|
|
230
296
|
return false;
|
|
231
297
|
}
|
|
232
298
|
}
|
|
233
|
-
|
|
299
|
+
function isVersionAtLeast(version, minimumVersion) {
|
|
300
|
+
const current = version.match(/^v?(\d+)\.(\d+)\.(\d+)/)?.slice(1).map(Number);
|
|
301
|
+
const minimum = minimumVersion.match(/^v?(\d+)\.(\d+)\.(\d+)/)?.slice(1).map(Number);
|
|
302
|
+
if (!current || !minimum)
|
|
303
|
+
return false;
|
|
304
|
+
for (let index = 0;index < minimum.length; index += 1) {
|
|
305
|
+
if (current[index] !== minimum[index])
|
|
306
|
+
return current[index] > minimum[index];
|
|
307
|
+
}
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
async function getOptionalFile2(path) {
|
|
234
311
|
try {
|
|
235
312
|
return await readFile2(path, "utf8");
|
|
236
313
|
} catch (error) {
|
|
@@ -239,7 +316,7 @@ async function readOptional2(path) {
|
|
|
239
316
|
throw error;
|
|
240
317
|
}
|
|
241
318
|
}
|
|
242
|
-
function
|
|
319
|
+
function getShellQuoted(value) {
|
|
243
320
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
244
321
|
}
|
|
245
322
|
|
|
@@ -263,12 +340,12 @@ var pi = {
|
|
|
263
340
|
await runChecked(executable, ["install", source]);
|
|
264
341
|
},
|
|
265
342
|
agentDir(homeDir = homedir3()) {
|
|
266
|
-
return
|
|
343
|
+
return getAgentDir(homeDir);
|
|
267
344
|
},
|
|
268
|
-
async skillCheckGlobal(name, agentDir =
|
|
345
|
+
async skillCheckGlobal(name, agentDir = getAgentDir(), sharedSkillsDir = join4(homedir3(), ".agents", "skills")) {
|
|
269
346
|
const roots = [join4(agentDir, "skills"), sharedSkillsDir];
|
|
270
347
|
for (const root of roots) {
|
|
271
|
-
if (await
|
|
348
|
+
if (await getOptionalFile3(join4(root, name, "SKILL.md")) !== undefined)
|
|
272
349
|
return true;
|
|
273
350
|
}
|
|
274
351
|
return false;
|
|
@@ -292,8 +369,8 @@ var pi = {
|
|
|
292
369
|
]);
|
|
293
370
|
},
|
|
294
371
|
async configEnsure(path, update, dryRun = false) {
|
|
295
|
-
const currentText = await
|
|
296
|
-
const current =
|
|
372
|
+
const currentText = await getOptionalFile3(path);
|
|
373
|
+
const current = getParsedObject(currentText, path);
|
|
297
374
|
const next = update(current);
|
|
298
375
|
const changed = JSON.stringify(current) !== JSON.stringify(next);
|
|
299
376
|
if (changed && !dryRun) {
|
|
@@ -304,10 +381,10 @@ var pi = {
|
|
|
304
381
|
return { path, changed, existed: currentText !== undefined, planned: changed && dryRun };
|
|
305
382
|
}
|
|
306
383
|
};
|
|
307
|
-
function
|
|
384
|
+
function getAgentDir(homeDir = homedir3()) {
|
|
308
385
|
return process.env.PI_CODING_AGENT_DIR ?? (process.env.XDG_CONFIG_HOME ? join4(process.env.XDG_CONFIG_HOME, "pi") : join4(homeDir, ".pi", "agent"));
|
|
309
386
|
}
|
|
310
|
-
async function
|
|
387
|
+
async function getOptionalFile3(path) {
|
|
311
388
|
try {
|
|
312
389
|
return await readFile3(path, "utf8");
|
|
313
390
|
} catch (error) {
|
|
@@ -316,7 +393,7 @@ async function readOptional3(path) {
|
|
|
316
393
|
throw error;
|
|
317
394
|
}
|
|
318
395
|
}
|
|
319
|
-
function
|
|
396
|
+
function getParsedObject(content, path) {
|
|
320
397
|
if (!content?.trim())
|
|
321
398
|
return {};
|
|
322
399
|
try {
|
|
@@ -328,44 +405,77 @@ function parseObject(content, path) {
|
|
|
328
405
|
}
|
|
329
406
|
|
|
330
407
|
// src/setup.ts
|
|
408
|
+
var MISE_DEPENDENCIES = [
|
|
409
|
+
{ name: "node", tool: "node", spec: "node@22", minimumVersion: "22.19.0" },
|
|
410
|
+
{ name: "zellij", tool: "zellij", spec: "zellij@latest", minimumVersion: undefined },
|
|
411
|
+
{ name: "helix", tool: "helix", spec: "helix@latest", minimumVersion: undefined },
|
|
412
|
+
{
|
|
413
|
+
name: "tuicr",
|
|
414
|
+
tool: "github:agavra/tuicr",
|
|
415
|
+
spec: "github:agavra/tuicr@latest",
|
|
416
|
+
minimumVersion: undefined
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
name: "context-mode",
|
|
420
|
+
tool: "npm:context-mode",
|
|
421
|
+
spec: "npm:context-mode@latest",
|
|
422
|
+
minimumVersion: undefined
|
|
423
|
+
}
|
|
424
|
+
];
|
|
425
|
+
var PI_PACKAGES = [
|
|
426
|
+
"npm:@tintinweb/pi-subagents",
|
|
427
|
+
"npm:pi-schedule-prompt",
|
|
428
|
+
"npm:@narumitw/pi-btw",
|
|
429
|
+
"npm:pi-web-access",
|
|
430
|
+
"npm:@gitawego/pi-lsp",
|
|
431
|
+
"npm:context-mode"
|
|
432
|
+
];
|
|
433
|
+
var PI_SKILL_SOURCES = [
|
|
434
|
+
{ repository: "arabold/docs-mcp-server", skills: ["docs-manage", "docs-search", "fetch-url"] },
|
|
435
|
+
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] }
|
|
436
|
+
];
|
|
437
|
+
var MCP_ADAPTER_PACKAGE = "npm:pi-mcp-adapter";
|
|
331
438
|
async function ensureMise(options = {}) {
|
|
332
439
|
const homeDir = options.homeDir ?? homedir4();
|
|
333
440
|
const current = await mise.executableCheck() ?? await mise.executableCheck(join5(homeDir, ".local", "bin", "mise"));
|
|
334
441
|
if (current)
|
|
335
|
-
return { executable: current, action:
|
|
336
|
-
|
|
442
|
+
return { executable: current, action: createSetupAction("mise", "ready", current) };
|
|
443
|
+
reportProgress(options, "Installing mise");
|
|
337
444
|
const executable = await mise.install({
|
|
338
445
|
dryRun: options.dryRun,
|
|
339
446
|
homeDir: options.homeDir,
|
|
340
447
|
platform: options.platform
|
|
341
448
|
});
|
|
342
|
-
return {
|
|
449
|
+
return {
|
|
450
|
+
executable,
|
|
451
|
+
action: createSetupAction("mise", options.dryRun ? "planned" : "installed", executable)
|
|
452
|
+
};
|
|
343
453
|
}
|
|
344
454
|
async function ensureMiseHooks(miseExecutable, options = {}) {
|
|
345
455
|
if (options.installMiseHook === false)
|
|
346
|
-
return
|
|
456
|
+
return createSetupAction("mise shell hook", "skipped", "disabled");
|
|
347
457
|
const result = await mise.hookEnsure(miseExecutable, {
|
|
348
458
|
dryRun: options.dryRun,
|
|
349
459
|
homeDir: options.homeDir,
|
|
350
460
|
shell: options.shell
|
|
351
461
|
});
|
|
352
462
|
if (!result.changed)
|
|
353
|
-
return
|
|
354
|
-
return
|
|
463
|
+
return createSetupAction("mise shell hook", "ready", result.path);
|
|
464
|
+
return createSetupAction("mise shell hook", result.planned ? "planned" : "installed", result.path);
|
|
355
465
|
}
|
|
356
466
|
async function ensureMiseDeps(miseExecutable, options = {}) {
|
|
357
467
|
const canRunMise = Boolean(await mise.executableCheck(miseExecutable));
|
|
358
468
|
const actions = [];
|
|
359
469
|
for (const dependency of MISE_DEPENDENCIES) {
|
|
360
|
-
const installed = canRunMise && await mise.toolCheckGlobal(miseExecutable, dependency.tool, dependency.
|
|
470
|
+
const installed = canRunMise && await mise.toolCheckGlobal(miseExecutable, dependency.tool, dependency.minimumVersion);
|
|
361
471
|
if (installed) {
|
|
362
|
-
actions.push(
|
|
472
|
+
actions.push(createSetupAction(dependency.name, "ready", dependency.spec));
|
|
363
473
|
continue;
|
|
364
474
|
}
|
|
365
|
-
|
|
475
|
+
reportProgress(options, `Installing ${dependency.name} with mise`);
|
|
366
476
|
if (!options.dryRun)
|
|
367
477
|
await mise.toolInstallGlobal(miseExecutable, dependency.spec);
|
|
368
|
-
actions.push(
|
|
478
|
+
actions.push(createSetupAction(dependency.name, options.dryRun ? "planned" : "installed", dependency.spec));
|
|
369
479
|
}
|
|
370
480
|
return actions;
|
|
371
481
|
}
|
|
@@ -373,12 +483,12 @@ async function ensurePiPlugins(options = {}) {
|
|
|
373
483
|
const actions = await ensurePiPackages(PI_PACKAGES, options);
|
|
374
484
|
const agentDir = options.agentDir ?? pi.agentDir(options.homeDir);
|
|
375
485
|
const webSearch = await pi.configEnsure(join5(agentDir, "web-search.json"), (config) => ({ ...config, workflow: "auto-summary" }), options.dryRun);
|
|
376
|
-
actions.push(
|
|
486
|
+
actions.push(getConfigSetupAction("web search settings", webSearch));
|
|
377
487
|
const lsp = await pi.configEnsure(join5(agentDir, "pi-lsp.json"), (config) => ({
|
|
378
488
|
...config,
|
|
379
|
-
progressive: { ...
|
|
489
|
+
progressive: { ...getRecord(config.progressive), enabled: true, inject: "none" }
|
|
380
490
|
}), options.dryRun);
|
|
381
|
-
actions.push(
|
|
491
|
+
actions.push(getConfigSetupAction("pi-lsp settings", lsp));
|
|
382
492
|
return actions;
|
|
383
493
|
}
|
|
384
494
|
async function ensurePiSkills(miseExecutable, options = {}) {
|
|
@@ -389,17 +499,17 @@ async function ensurePiSkills(miseExecutable, options = {}) {
|
|
|
389
499
|
const missing = [];
|
|
390
500
|
for (const name of source.skills) {
|
|
391
501
|
if (await pi.skillCheckGlobal(name, agentDir, sharedSkillsDir))
|
|
392
|
-
actions.push(
|
|
502
|
+
actions.push(createSetupAction(`pi skill ${name}`, "ready", source.repository));
|
|
393
503
|
else
|
|
394
504
|
missing.push(name);
|
|
395
505
|
}
|
|
396
506
|
if (missing.length === 0)
|
|
397
507
|
continue;
|
|
398
|
-
|
|
508
|
+
reportProgress(options, `Installing skills from ${source.repository}`);
|
|
399
509
|
if (!options.dryRun)
|
|
400
510
|
await pi.skillInstallGlobal(miseExecutable, source.repository, missing);
|
|
401
511
|
for (const name of missing) {
|
|
402
|
-
actions.push(
|
|
512
|
+
actions.push(createSetupAction(`pi skill ${name}`, options.dryRun ? "planned" : "installed", source.repository));
|
|
403
513
|
}
|
|
404
514
|
}
|
|
405
515
|
return actions;
|
|
@@ -431,7 +541,7 @@ async function ensureMcpAdapters(miseExecutable, options = {}) {
|
|
|
431
541
|
dryRun: options.dryRun,
|
|
432
542
|
path: mcp.globalConfigPath(options.homeDir)
|
|
433
543
|
});
|
|
434
|
-
actions.push(
|
|
544
|
+
actions.push(getConfigSetupAction("MCP configuration", result));
|
|
435
545
|
return actions;
|
|
436
546
|
}
|
|
437
547
|
async function setupPi(options = {}) {
|
|
@@ -447,27 +557,6 @@ async function setupPi(options = {}) {
|
|
|
447
557
|
restartPi: actions.some((item) => (item.status === "installed" || item.status === "updated") && (item.name.startsWith("pi package ") || item.name.startsWith("pi skill ") || item.name === "MCP configuration" || item.name === "web search settings" || item.name === "pi-lsp settings"))
|
|
448
558
|
};
|
|
449
559
|
}
|
|
450
|
-
var MISE_DEPENDENCIES = [
|
|
451
|
-
{ name: "node", tool: "node", spec: "node@22", minimumMajor: 22 },
|
|
452
|
-
{ name: "zellij", tool: "zellij", spec: "zellij@latest", minimumMajor: 0 },
|
|
453
|
-
{ name: "helix", tool: "helix", spec: "helix@latest", minimumMajor: 0 },
|
|
454
|
-
{ name: "tuicr", tool: "github:agavra/tuicr", spec: "github:agavra/tuicr@latest", minimumMajor: 0 },
|
|
455
|
-
{ name: "context-mode", tool: "npm:context-mode", spec: "npm:context-mode@latest", minimumMajor: 0 }
|
|
456
|
-
];
|
|
457
|
-
var PI_PACKAGES = [
|
|
458
|
-
"npm:@tintinweb/pi-subagents",
|
|
459
|
-
"npm:pi-schedule-prompt",
|
|
460
|
-
"npm:@narumitw/pi-btw",
|
|
461
|
-
"npm:pi-web-access",
|
|
462
|
-
"npm:@gitawego/pi-lsp",
|
|
463
|
-
"npm:@juicesharp/rpiv-ask-user-question",
|
|
464
|
-
"npm:context-mode"
|
|
465
|
-
];
|
|
466
|
-
var PI_SKILL_SOURCES = [
|
|
467
|
-
{ repository: "arabold/docs-mcp-server", skills: ["docs-manage", "docs-search", "fetch-url"] },
|
|
468
|
-
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] }
|
|
469
|
-
];
|
|
470
|
-
var MCP_ADAPTER_PACKAGE = "npm:pi-mcp-adapter";
|
|
471
560
|
async function ensurePiPackages(packages, options) {
|
|
472
561
|
const executable = await pi.executableCheck();
|
|
473
562
|
if (!executable && !options.dryRun)
|
|
@@ -476,65 +565,59 @@ async function ensurePiPackages(packages, options) {
|
|
|
476
565
|
const actions = [];
|
|
477
566
|
for (const source of packages) {
|
|
478
567
|
if (pi.packageCheck(installed, source)) {
|
|
479
|
-
actions.push(
|
|
568
|
+
actions.push(createSetupAction(`pi package ${source}`, "ready", source));
|
|
480
569
|
continue;
|
|
481
570
|
}
|
|
482
|
-
|
|
571
|
+
reportProgress(options, `Installing pi package ${source}`);
|
|
483
572
|
if (!options.dryRun) {
|
|
484
573
|
await pi.packageInstall(executable, source);
|
|
485
574
|
installed += `
|
|
486
575
|
${source}`;
|
|
487
576
|
}
|
|
488
|
-
actions.push(
|
|
577
|
+
actions.push(createSetupAction(`pi package ${source}`, options.dryRun ? "planned" : "installed", source));
|
|
489
578
|
}
|
|
490
579
|
return actions;
|
|
491
580
|
}
|
|
492
|
-
function
|
|
581
|
+
function getConfigSetupAction(name, result) {
|
|
493
582
|
if (!result.changed)
|
|
494
|
-
return
|
|
583
|
+
return createSetupAction(name, "ready", result.path);
|
|
495
584
|
if (result.planned)
|
|
496
|
-
return
|
|
497
|
-
return
|
|
585
|
+
return createSetupAction(name, "planned", result.path);
|
|
586
|
+
return createSetupAction(name, result.existed ? "updated" : "installed", result.path);
|
|
498
587
|
}
|
|
499
|
-
function
|
|
588
|
+
function createSetupAction(name, status, detail) {
|
|
500
589
|
return { name, status, detail };
|
|
501
590
|
}
|
|
502
|
-
function
|
|
591
|
+
function reportProgress(options, message) {
|
|
503
592
|
options.onProgress?.(message);
|
|
504
593
|
}
|
|
505
|
-
function
|
|
594
|
+
function getRecord(value) {
|
|
506
595
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
507
596
|
}
|
|
508
597
|
|
|
509
598
|
// src/tools/setup.ts
|
|
510
|
-
var
|
|
511
|
-
issueTracker:
|
|
512
|
-
description: "Issue tracker MCP server to configure. Use none unless the user explicitly selects Linear or Jira.",
|
|
513
|
-
enum: ["none", "linear", "jira"],
|
|
514
|
-
default: "none"
|
|
515
|
-
})),
|
|
516
|
-
installMiseHook: Type.Optional(Type.Boolean({
|
|
517
|
-
description: "Add the mise activation hook to the current shell configuration. Set false only when the user declines.",
|
|
518
|
-
default: true
|
|
519
|
-
}))
|
|
599
|
+
var setupParametersSchema = z2.object({
|
|
600
|
+
issueTracker: z2.enum(["none", "linear", "jira"]).default("none").describe("Issue tracker MCP server to configure. Use none unless the user explicitly selects Linear or Jira.")
|
|
520
601
|
});
|
|
521
|
-
var
|
|
602
|
+
var setupParameters = z2.toJSONSchema(setupParametersSchema, { io: "input" });
|
|
603
|
+
var diffpiSetupTool = defineTool2({
|
|
522
604
|
name: "diffpi_setup",
|
|
523
605
|
label: "diffpi setup",
|
|
524
606
|
description: "Install or repair the @difflab/pi environment. This mutates user-level tool installations and configuration files.",
|
|
525
607
|
promptSnippet: "Install or repair @difflab/pi only after the user approves the setup choices",
|
|
526
608
|
promptGuidelines: [
|
|
527
|
-
"Call
|
|
528
|
-
"Use ask_user_question for unspecified setup choices before calling
|
|
529
|
-
'
|
|
530
|
-
"Use diffpi_validate instead when the user asks only to inspect or verify setup."
|
|
609
|
+
"Call diffpi_setup only when the user explicitly asks to install, configure, or repair the environment.",
|
|
610
|
+
"Use ask_user_question for unspecified setup choices before calling diffpi_setup.",
|
|
611
|
+
'Call diffpi_setup with issueTracker="none" unless the user explicitly selects Linear or Jira.',
|
|
612
|
+
"Use diffpi_validate instead of diffpi_setup when the user asks only to inspect or verify setup."
|
|
531
613
|
],
|
|
532
|
-
parameters,
|
|
614
|
+
parameters: setupParameters,
|
|
533
615
|
executionMode: "sequential",
|
|
534
|
-
async execute(_toolCallId,
|
|
616
|
+
async execute(_toolCallId, input, _signal, onUpdate) {
|
|
617
|
+
const params = setupParametersSchema.parse(input);
|
|
535
618
|
const result = await setupPi({
|
|
536
|
-
issueTracker:
|
|
537
|
-
installMiseHook:
|
|
619
|
+
issueTracker: params.issueTracker,
|
|
620
|
+
installMiseHook: true,
|
|
538
621
|
onProgress(message) {
|
|
539
622
|
onUpdate?.({ content: [{ type: "text", text: message }], details: {} });
|
|
540
623
|
}
|
|
@@ -542,35 +625,29 @@ var diffpiSetupTool = defineTool({
|
|
|
542
625
|
return formatResult(result, "Setup complete.");
|
|
543
626
|
}
|
|
544
627
|
});
|
|
545
|
-
var diffpiValidateTool =
|
|
628
|
+
var diffpiValidateTool = defineTool2({
|
|
546
629
|
name: "diffpi_validate",
|
|
547
630
|
label: "diffpi validate",
|
|
548
631
|
description: "Inspect the @difflab/pi environment without installing software or changing configuration files.",
|
|
549
632
|
promptSnippet: "Validate @difflab/pi safely before setup or when the user asks for an environment check",
|
|
550
633
|
promptGuidelines: [
|
|
551
|
-
"Prefer
|
|
552
|
-
"
|
|
553
|
-
'
|
|
634
|
+
"Prefer diffpi_validate before diffpi_setup when the requested action is unclear.",
|
|
635
|
+
"diffpi_validate is read-only; do not describe its planned actions as completed changes.",
|
|
636
|
+
'Call diffpi_validate with issueTracker="none" unless the user asks to validate Linear or Jira configuration.'
|
|
554
637
|
],
|
|
555
|
-
parameters,
|
|
638
|
+
parameters: setupParameters,
|
|
556
639
|
executionMode: "sequential",
|
|
557
|
-
async execute(_toolCallId,
|
|
640
|
+
async execute(_toolCallId, input) {
|
|
641
|
+
const params = setupParametersSchema.parse(input);
|
|
558
642
|
const result = await setupPi({
|
|
559
|
-
issueTracker:
|
|
560
|
-
installMiseHook:
|
|
643
|
+
issueTracker: params.issueTracker,
|
|
644
|
+
installMiseHook: true,
|
|
561
645
|
dryRun: true
|
|
562
646
|
});
|
|
563
647
|
const incomplete = result.actions.some((item) => item.status === "planned");
|
|
564
648
|
return formatResult(result, incomplete ? "Setup is incomplete." : "Setup is ready.");
|
|
565
649
|
}
|
|
566
650
|
});
|
|
567
|
-
function parseIssueTracker(value) {
|
|
568
|
-
if (!value || value === "none")
|
|
569
|
-
return "none";
|
|
570
|
-
if (value === "linear" || value === "jira")
|
|
571
|
-
return value;
|
|
572
|
-
throw new Error(`Unknown issue tracker: ${value}`);
|
|
573
|
-
}
|
|
574
651
|
function formatResult(result, heading) {
|
|
575
652
|
const changed = result.actions.some((item) => item.status === "installed" || item.status === "updated" || item.status === "planned");
|
|
576
653
|
const lines = result.actions.map((item) => `${item.status.padEnd(9)} ${item.name}: ${item.detail}`);
|
|
@@ -586,9 +663,12 @@ ${lines.join(`
|
|
|
586
663
|
}
|
|
587
664
|
|
|
588
665
|
// src/tools/index.ts
|
|
589
|
-
|
|
666
|
+
function createPiTools(pi) {
|
|
667
|
+
return [diffpiSetupTool, diffpiValidateTool, createDiffpiReloadTool(pi)];
|
|
668
|
+
}
|
|
590
669
|
export {
|
|
670
|
+
createDiffpiReloadTool,
|
|
671
|
+
createPiTools,
|
|
591
672
|
diffpiSetupTool,
|
|
592
|
-
diffpiValidateTool
|
|
593
|
-
piTools
|
|
673
|
+
diffpiValidateTool
|
|
594
674
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reload.d.ts","sourceRoot":"","sources":["../../src/tools/reload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAUrG,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,GAAG,cAAc,CAoBhG"}
|
package/dist/tools/setup.d.ts
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import { type ToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
declare const parameters: Type.TObject<{
|
|
5
|
-
issueTracker: Type.TOptional<Type.TString>;
|
|
6
|
-
installMiseHook: Type.TOptional<Type.TBoolean>;
|
|
7
|
-
}>;
|
|
8
|
-
export interface ToolDetails {
|
|
9
|
-
changed?: boolean;
|
|
10
|
-
result?: SetupResult;
|
|
11
|
-
}
|
|
12
|
-
export declare const diffpiSetupTool: ToolDefinition<typeof parameters, ToolDetails>;
|
|
13
|
-
export declare const diffpiValidateTool: ToolDefinition<typeof parameters, ToolDetails>;
|
|
14
|
-
export {};
|
|
2
|
+
export declare const diffpiSetupTool: ToolDefinition;
|
|
3
|
+
export declare const diffpiValidateTool: ToolDefinition;
|
|
15
4
|
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/tools/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/tools/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAgBlF,eAAO,MAAM,eAAe,EAAE,cA0B5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,cAsB/B,CAAC"}
|