@cydm/pie 1.0.49 → 1.0.51
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 +1 -1
- package/dist/builtin/extensions/ask-user/index.js +4 -11
- package/dist/builtin/extensions/ask-user/package.json +0 -7
- package/dist/builtin/extensions/changelog/index.js +15 -20
- package/dist/builtin/extensions/document-attachments/index.js +51 -1
- package/dist/builtin/extensions/document-attachments/package.json +1 -1
- package/dist/builtin/extensions/init/index.js +0 -13
- package/dist/builtin/extensions/plan-mode/index.js +31 -19
- package/dist/builtin/extensions/subagent/index.js +19 -40
- package/dist/builtin/extensions/todo/index.js +6 -10
- package/dist/builtin/skills/skill-creator/SKILL.md +15 -43
- package/dist/builtin/skills/skill-creator/eval-viewer/generate_review.mjs +1 -1
- package/dist/builtin/skills/skill-creator/eval-viewer/viewer.html +2 -2
- package/dist/builtin/skills/skill-creator/references/schemas.md +1 -1
- package/dist/builtin/skills/skill-creator/scripts/generate_report.mjs +1 -1
- package/dist/builtin/skills/skill-creator/scripts/improve_description.mjs +3 -3
- package/dist/builtin/skills/skill-creator/scripts/pie_runner.mjs +32 -4
- package/dist/builtin/skills/skill-creator/scripts/run_loop.mjs +1 -1
- package/dist/chunks/{chunk-7RYOIXA2.js → chunk-A644H2XX.js} +104 -20
- package/dist/chunks/{chunk-FKAO25XH.js → chunk-B3SMW2XW.js} +1 -1
- package/dist/chunks/{chunk-J6PEH6ST.js → chunk-KDPAGHYY.js} +2 -2
- package/dist/chunks/{chunk-K6ZOCJ4V.js → chunk-S2J3SZZX.js} +44 -1
- package/dist/chunks/{src-HYZFAW4V.js → src-UKCIAX6F.js} +2 -2
- package/dist/chunks/{test-stream-5T7E7C25.js → test-stream-NCBFPM2I.js} +1 -1
- package/dist/cli.js +49 -22
- package/package.json +3 -3
- package/dist/builtin/extensions/deploy/index.js +0 -11
- package/dist/builtin/extensions/deploy/package.json +0 -11
- package/dist/builtin/extensions/files/index.js +0 -10
- package/dist/builtin/extensions/files/package.json +0 -14
- package/dist/builtin/skills/skill-creator/scripts/claude_cli.mjs +0 -115
package/README.md
CHANGED
|
@@ -274,7 +274,7 @@ That is part of what makes Pie embeddable: the CLI is only one interface on top
|
|
|
274
274
|
|
|
275
275
|
Extensions are discovered from four sources in ascending priority (later sources shadow earlier ones by stable extension identity):
|
|
276
276
|
|
|
277
|
-
1. `builtin` — shipped with the CLI (`ask-user`, `todo`, `plan-mode`, `subagent`, `init`, `changelog`,
|
|
277
|
+
1. `builtin` — shipped with the CLI (`ask-user`, `todo`, `plan-mode`, `subagent`, `init`, `changelog`, attachment handlers)
|
|
278
278
|
2. `global` — `~/.pie/extensions/`
|
|
279
279
|
3. `project` — `./.pie/extensions/`
|
|
280
280
|
4. `configured` — repeated `--extension-path <dir>` flags
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createAskUserCapability
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
5
|
-
import "../../../chunks/chunk-
|
|
6
|
-
import "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-A644H2XX.js";
|
|
5
|
+
import "../../../chunks/chunk-B3SMW2XW.js";
|
|
6
|
+
import "../../../chunks/chunk-S2J3SZZX.js";
|
|
7
7
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
8
8
|
|
|
9
9
|
// builtin/extensions/ask-user/index.ts
|
|
10
10
|
function askUserExtension(ctx) {
|
|
11
11
|
ctx.log("Ask user extension loaded");
|
|
12
12
|
const capability = createAskUserCapability();
|
|
13
|
-
|
|
14
|
-
ctx.registerTool({
|
|
15
|
-
...tool,
|
|
16
|
-
async execute(args) {
|
|
17
|
-
ctx.log(`[${tool.name}] Called: ${JSON.stringify(args)}`);
|
|
18
|
-
return tool.execute(args);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
13
|
+
ctx.registerTool(capability.tools[0]);
|
|
21
14
|
}
|
|
22
15
|
export {
|
|
23
16
|
askUserExtension as default
|
|
@@ -2,15 +2,8 @@
|
|
|
2
2
|
"name": "@pie/ask-user-extension",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
5
|
"pie": {
|
|
7
6
|
"name": "ask-user",
|
|
8
7
|
"main": "index.ts"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc"
|
|
12
|
-
},
|
|
13
|
-
"dependencies": {
|
|
14
|
-
"@sinclair/typebox": "^0.34.0"
|
|
15
8
|
}
|
|
16
9
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
-
import
|
|
3
|
-
__require
|
|
4
|
-
} from "../../../chunks/chunk-LZQXQOPJ.js";
|
|
2
|
+
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
5
3
|
|
|
6
4
|
// builtin/extensions/changelog/index.ts
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
var RECENT_COMMIT_COUNT = 15;
|
|
9
|
+
var RECENT_COMMIT_RANGE = "HEAD~5";
|
|
7
10
|
function getRecentCommits(cwd, count = 10) {
|
|
8
11
|
try {
|
|
9
|
-
const { spawnSync } = __require("child_process");
|
|
10
12
|
const result = spawnSync(
|
|
11
13
|
"git",
|
|
12
14
|
["log", `--max-count=${count}`, "--pretty=format:%h %s", "--no-merges"],
|
|
@@ -19,10 +21,9 @@ function getRecentCommits(cwd, count = 10) {
|
|
|
19
21
|
}
|
|
20
22
|
function getChangedFiles(cwd) {
|
|
21
23
|
try {
|
|
22
|
-
const { spawnSync } = __require("child_process");
|
|
23
24
|
const result = spawnSync(
|
|
24
25
|
"git",
|
|
25
|
-
["diff",
|
|
26
|
+
["diff", RECENT_COMMIT_RANGE, "--name-only", "--stat"],
|
|
26
27
|
{ cwd, encoding: "utf8" }
|
|
27
28
|
);
|
|
28
29
|
return result.status === 0 ? result.stdout : "";
|
|
@@ -32,8 +33,6 @@ function getChangedFiles(cwd) {
|
|
|
32
33
|
}
|
|
33
34
|
async function readChangelog(cwd) {
|
|
34
35
|
try {
|
|
35
|
-
const fs = await import("fs");
|
|
36
|
-
const path = await import("path");
|
|
37
36
|
const changelogPath = path.join(cwd, "CHANGELOG.md");
|
|
38
37
|
if (fs.existsSync(changelogPath)) {
|
|
39
38
|
return fs.readFileSync(changelogPath, "utf-8");
|
|
@@ -48,8 +47,6 @@ function changelogExtension(ctx) {
|
|
|
48
47
|
path: ["tools", "changelog"],
|
|
49
48
|
description: "Smart changelog management with gap detection",
|
|
50
49
|
handler: async (ctx2, args) => {
|
|
51
|
-
const fs = await import("fs");
|
|
52
|
-
const path = await import("path");
|
|
53
50
|
const changelogPath = path.join(ctx2.cwd, "CHANGELOG.md");
|
|
54
51
|
if (args?.includes("--show")) {
|
|
55
52
|
if (!fs.existsSync(changelogPath)) {
|
|
@@ -59,7 +56,7 @@ function changelogExtension(ctx) {
|
|
|
59
56
|
return "Current CHANGELOG:\n\n" + content.slice(0, 2e3) + (content.length > 2e3 ? "\n\n..." : "");
|
|
60
57
|
}
|
|
61
58
|
if (args?.trim() === "check") {
|
|
62
|
-
const commits2 = getRecentCommits(ctx2.cwd,
|
|
59
|
+
const commits2 = getRecentCommits(ctx2.cwd, RECENT_COMMIT_COUNT);
|
|
63
60
|
const changelog2 = await readChangelog(ctx2.cwd);
|
|
64
61
|
const changedFiles2 = getChangedFiles(ctx2.cwd);
|
|
65
62
|
if (!commits2) {
|
|
@@ -97,8 +94,7 @@ ${existingChangelog ? `
|
|
|
97
94
|
Use this existing style as reference:
|
|
98
95
|
\`\`\`
|
|
99
96
|
${existingChangelog.slice(0, 800)}
|
|
100
|
-
|
|
101
|
-
\`\`\`` : ""}
|
|
97
|
+
...\`\`\`` : ""}
|
|
102
98
|
|
|
103
99
|
Requirements:
|
|
104
100
|
1. Choose the right category: **Added** / **Changed** / **Fixed** / **Removed** / **Deprecated** / **Security**.
|
|
@@ -118,16 +114,15 @@ Use the write tool to update CHANGELOG.md:
|
|
|
118
114
|
const versionHint = args.slice(7).trim();
|
|
119
115
|
const existingChangelog = await readChangelog(ctx2.cwd);
|
|
120
116
|
if (!existingChangelog) {
|
|
121
|
-
return "No CHANGELOG.md found. Create one first with /changelog";
|
|
117
|
+
return "No CHANGELOG.md found. Create one first with /tools changelog";
|
|
122
118
|
}
|
|
123
|
-
ctx2.ui.notify(
|
|
119
|
+
ctx2.ui.notify(`Preparing release ${versionHint || "..."}`, "info");
|
|
124
120
|
return `Prepare the [Unreleased] section as a new release.
|
|
125
121
|
|
|
126
122
|
Current CHANGELOG:
|
|
127
123
|
\`\`\`
|
|
128
124
|
${existingChangelog.slice(0, 1500)}
|
|
129
|
-
|
|
130
|
-
\`\`\`
|
|
125
|
+
...\`\`\`
|
|
131
126
|
|
|
132
127
|
Version hint: ${versionHint || "infer from changes (patch/minor/major)"}
|
|
133
128
|
|
|
@@ -146,11 +141,11 @@ Tasks:
|
|
|
146
141
|
|
|
147
142
|
Use the write tool to update CHANGELOG.md.`;
|
|
148
143
|
}
|
|
149
|
-
const commits = getRecentCommits(ctx2.cwd,
|
|
144
|
+
const commits = getRecentCommits(ctx2.cwd, RECENT_COMMIT_COUNT);
|
|
150
145
|
const changelog = await readChangelog(ctx2.cwd);
|
|
151
146
|
const changedFiles = getChangedFiles(ctx2.cwd);
|
|
152
147
|
if (!commits && !changelog) {
|
|
153
|
-
return "No git history or CHANGELOG.md found. Initialize with: /changelog add <description>";
|
|
148
|
+
return "No git history or CHANGELOG.md found. Initialize with: /tools changelog add <description>";
|
|
154
149
|
}
|
|
155
150
|
ctx2.ui.notify("Analyzing changes and checking for missing changelog entries...", "info");
|
|
156
151
|
return `Smart changelog update
|
|
@@ -164,7 +159,7 @@ ${commits || "(git history unavailable)"}
|
|
|
164
159
|
${changedFiles || "(unavailable)"}
|
|
165
160
|
|
|
166
161
|
## Current CHANGELOG.md
|
|
167
|
-
${changelog ? "\n```\n" + changelog.slice(0, 2e3) + "\n
|
|
162
|
+
${changelog ? "\n```\n" + changelog.slice(0, 2e3) + "\n...```" : "(file does not exist; create it if needed)"}
|
|
168
163
|
|
|
169
164
|
## Tasks
|
|
170
165
|
|
|
@@ -8,12 +8,27 @@ import { spawnSync } from "node:child_process";
|
|
|
8
8
|
var MAX_TEXT_CHARS = 24e3;
|
|
9
9
|
var PYTHON_CANDIDATES = [
|
|
10
10
|
process.env.PYTHON,
|
|
11
|
-
"/opt/anaconda3/bin/python3",
|
|
12
11
|
"python3"
|
|
13
12
|
].filter((value) => Boolean(value));
|
|
14
13
|
function isTextCapable(model) {
|
|
15
14
|
return (model.input ?? []).includes("text");
|
|
16
15
|
}
|
|
16
|
+
function supportsInputKind(model, kind) {
|
|
17
|
+
return (model.input ?? []).includes(kind);
|
|
18
|
+
}
|
|
19
|
+
function mediaKindFor(mimeType) {
|
|
20
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
21
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
var DEFAULT_INLINE_LIMIT_MB = {
|
|
25
|
+
image: 10,
|
|
26
|
+
video: 15
|
|
27
|
+
};
|
|
28
|
+
function inlineLimitMb(model, kind) {
|
|
29
|
+
const configured = model.fileCapabilities?.[kind]?.maxFileSizeMb;
|
|
30
|
+
return typeof configured === "number" && configured > 0 ? configured : DEFAULT_INLINE_LIMIT_MB[kind];
|
|
31
|
+
}
|
|
17
32
|
function isSupportedDocument(attachment) {
|
|
18
33
|
return attachment.mimeType === "application/pdf" || attachment.mimeType === "text/html" || attachment.mimeType === "text/plain" || attachment.mimeType === "text/markdown" || attachment.mimeType === "application/json" || attachment.name.endsWith(".html") || attachment.name.endsWith(".htm") || attachment.name.endsWith(".md") || attachment.name.endsWith(".txt") || attachment.name.endsWith(".json") || attachment.name.endsWith(".pdf");
|
|
19
34
|
}
|
|
@@ -139,6 +154,41 @@ function documentAttachmentsExtension(ctx) {
|
|
|
139
154
|
};
|
|
140
155
|
}
|
|
141
156
|
});
|
|
157
|
+
ctx.registerAttachmentHandler({
|
|
158
|
+
name: "local-media-inline",
|
|
159
|
+
priority: 20,
|
|
160
|
+
matches(model, attachment) {
|
|
161
|
+
const kind = mediaKindFor(attachment.mimeType);
|
|
162
|
+
return Boolean(kind) && supportsInputKind(model, kind) && Boolean(attachment.path);
|
|
163
|
+
},
|
|
164
|
+
async prepare(model, attachment, prepareCtx) {
|
|
165
|
+
prepareCtx.log(`Media handler inlining ${attachment.mimeType} attachment ${attachment.name}`);
|
|
166
|
+
const kind = mediaKindFor(attachment.mimeType);
|
|
167
|
+
const limitMb = inlineLimitMb(model, kind);
|
|
168
|
+
const sizeMb = fs.statSync(attachment.path).size / (1024 * 1024);
|
|
169
|
+
if (sizeMb > limitMb) {
|
|
170
|
+
prepareCtx.log(`Media handler skipped ${attachment.name}: ${sizeMb.toFixed(1)}MB exceeds the ${limitMb}MB inline limit`);
|
|
171
|
+
return {
|
|
172
|
+
items: [
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
text: `[${attachment.name}: ${sizeMb.toFixed(1)}MB exceeds the ${limitMb}MB inline limit for this model \u2014 not attached. Compress or shrink the file first.]`
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
warnings: [`${attachment.name} (${sizeMb.toFixed(1)}MB) exceeds the ${limitMb}MB inline limit and was not attached`]
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
items: [
|
|
183
|
+
{
|
|
184
|
+
type: kind,
|
|
185
|
+
mimeType: attachment.mimeType,
|
|
186
|
+
path: attachment.path
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
});
|
|
142
192
|
}
|
|
143
193
|
export {
|
|
144
194
|
documentAttachmentsExtension as default
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie/extension-document-attachments",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Local document attachment preprocessing (PDF, HTML, plain text)",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"pie": {
|
|
@@ -96,24 +96,11 @@ CLI file tools use the project root as their access boundary; do not pass an ext
|
|
|
96
96
|
}
|
|
97
97
|
async function initExtension(ctx) {
|
|
98
98
|
ctx.log("Init extension loaded");
|
|
99
|
-
let cachedKnowledge = null;
|
|
100
|
-
try {
|
|
101
|
-
const existing = await loadExistingKnowledge(ctx.cwd);
|
|
102
|
-
cachedKnowledge = existing.content;
|
|
103
|
-
if (cachedKnowledge) {
|
|
104
|
-
ctx.log(`Pre-loaded root AGENTS.md (${cachedKnowledge.length} chars) from ${existing.target.agentsPath}`);
|
|
105
|
-
} else {
|
|
106
|
-
ctx.log(`No existing root AGENTS.md found at ${existing.target.agentsPath}`);
|
|
107
|
-
}
|
|
108
|
-
} catch (err) {
|
|
109
|
-
ctx.log(`Failed to pre-load root AGENTS.md: ${err}`);
|
|
110
|
-
}
|
|
111
99
|
const handler = async (ctx2, args) => {
|
|
112
100
|
const existing = await loadExistingKnowledge(ctx2.cwd);
|
|
113
101
|
const existingContent = existing.content;
|
|
114
102
|
const isUpdate = !!existing.content;
|
|
115
103
|
const userIntent = args?.trim();
|
|
116
|
-
cachedKnowledge = existingContent;
|
|
117
104
|
if (isUpdate) {
|
|
118
105
|
if (userIntent) {
|
|
119
106
|
ctx2.ui.notify(`Updating project knowledge (${userIntent})...`, "info");
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
isPlanModeSafeCommand,
|
|
8
8
|
markCompletedPlanSteps,
|
|
9
9
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
10
|
+
} from "../../../chunks/chunk-A644H2XX.js";
|
|
11
|
+
import "../../../chunks/chunk-B3SMW2XW.js";
|
|
12
12
|
import {
|
|
13
13
|
Type
|
|
14
|
-
} from "../../../chunks/chunk-
|
|
14
|
+
} from "../../../chunks/chunk-S2J3SZZX.js";
|
|
15
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
16
16
|
|
|
17
17
|
// builtin/extensions/plan-mode/index.ts
|
|
@@ -21,11 +21,10 @@ import os from "node:os";
|
|
|
21
21
|
import path from "node:path";
|
|
22
22
|
var SESSION_METADATA_KEY = "planModeEnabled";
|
|
23
23
|
var EXECUTION_METADATA_KEY = "executionState";
|
|
24
|
+
var EXECUTION_FLAG_KEY = "planExecution";
|
|
24
25
|
var SCRATCH_METADATA_KEY = "planScratchId";
|
|
25
26
|
var SCRATCH_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;
|
|
26
27
|
var MAX_SCRATCH_CHARS = 64e3;
|
|
27
|
-
var planModeEnabled = false;
|
|
28
|
-
var executionMode = false;
|
|
29
28
|
function toPlanTodoItems(state) {
|
|
30
29
|
return state.steps.map((step) => ({
|
|
31
30
|
step: step.id,
|
|
@@ -35,6 +34,18 @@ function toPlanTodoItems(state) {
|
|
|
35
34
|
}
|
|
36
35
|
function planModeExtension(ctx) {
|
|
37
36
|
const capability = createPlanCapability();
|
|
37
|
+
let planModeEnabled = false;
|
|
38
|
+
let executingPlan = false;
|
|
39
|
+
function setExecutingPlan(value) {
|
|
40
|
+
executingPlan = value;
|
|
41
|
+
ctx.setSessionMetadata(EXECUTION_FLAG_KEY, value);
|
|
42
|
+
}
|
|
43
|
+
function readPersistedPlanMode() {
|
|
44
|
+
return ctx.getSessionMetadata()?.[SESSION_METADATA_KEY] === true;
|
|
45
|
+
}
|
|
46
|
+
function readPersistedExecuting() {
|
|
47
|
+
return ctx.getSessionMetadata()?.[EXECUTION_FLAG_KEY] === true;
|
|
48
|
+
}
|
|
38
49
|
function scratchDirectory() {
|
|
39
50
|
const metadata = ctx.getSessionMetadata();
|
|
40
51
|
let id = metadata?.[SCRATCH_METADATA_KEY];
|
|
@@ -91,9 +102,6 @@ function planModeExtension(ctx) {
|
|
|
91
102
|
}
|
|
92
103
|
}
|
|
93
104
|
});
|
|
94
|
-
function readPersistedPlanMode() {
|
|
95
|
-
return ctx.getSessionMetadata()?.[SESSION_METADATA_KEY] === true;
|
|
96
|
-
}
|
|
97
105
|
function readExecutionState() {
|
|
98
106
|
return restoreExecutionState(ctx.getSessionMetadata()?.[EXECUTION_METADATA_KEY] ?? ctx.getExecutionState());
|
|
99
107
|
}
|
|
@@ -106,7 +114,7 @@ function planModeExtension(ctx) {
|
|
|
106
114
|
}
|
|
107
115
|
function updateStatus() {
|
|
108
116
|
const state = readExecutionState();
|
|
109
|
-
if (
|
|
117
|
+
if (executingPlan && state.steps.length > 0) {
|
|
110
118
|
const completed = state.steps.filter((step) => step.status === "completed").length;
|
|
111
119
|
ctx.ui.notify(`\u{1F4CB} Plan: ${completed}/${state.steps.length} completed`, "info");
|
|
112
120
|
} else if (planModeEnabled) {
|
|
@@ -115,14 +123,14 @@ function planModeExtension(ctx) {
|
|
|
115
123
|
}
|
|
116
124
|
function applyPlanModeState(enabled, forcePromptInjection = false) {
|
|
117
125
|
planModeEnabled = enabled;
|
|
118
|
-
if (
|
|
119
|
-
|
|
126
|
+
if (enabled) {
|
|
127
|
+
setExecutingPlan(false);
|
|
120
128
|
}
|
|
121
129
|
ctx.setPlanMode(enabled, { forcePromptInjection });
|
|
122
130
|
}
|
|
123
131
|
function togglePlanMode() {
|
|
124
132
|
planModeEnabled = !planModeEnabled;
|
|
125
|
-
|
|
133
|
+
setExecutingPlan(false);
|
|
126
134
|
writeExecutionState(null);
|
|
127
135
|
ctx.setSessionMetadata(SESSION_METADATA_KEY, planModeEnabled);
|
|
128
136
|
applyPlanModeState(planModeEnabled, true);
|
|
@@ -146,8 +154,8 @@ function planModeExtension(ctx) {
|
|
|
146
154
|
});
|
|
147
155
|
ctx.on("tool:call", async (event) => {
|
|
148
156
|
if (!planModeEnabled || event.toolName !== "bash") return;
|
|
149
|
-
const command = event.args
|
|
150
|
-
if (command && !isPlanModeSafeCommand(command)) {
|
|
157
|
+
const command = typeof event.args === "object" && event.args !== null ? event.args.command : void 0;
|
|
158
|
+
if (typeof command === "string" && !isPlanModeSafeCommand(command)) {
|
|
151
159
|
ctx.ui.notify(
|
|
152
160
|
`Plan mode: Command blocked. Use read-only commands, or plan_scratch for temporary drafts. Use /plan to leave Plan mode.
|
|
153
161
|
Command: ${command}`,
|
|
@@ -159,16 +167,18 @@ Command: ${command}`,
|
|
|
159
167
|
ctx.on("agent:start", async () => {
|
|
160
168
|
const persisted = readPersistedPlanMode();
|
|
161
169
|
applyPlanModeState(persisted);
|
|
170
|
+
executingPlan = !persisted && readPersistedExecuting();
|
|
162
171
|
writeExecutionState(readExecutionState());
|
|
163
172
|
});
|
|
164
173
|
ctx.on("session:changed", async () => {
|
|
165
174
|
const enabled = readPersistedPlanMode();
|
|
166
175
|
applyPlanModeState(enabled, enabled);
|
|
176
|
+
executingPlan = !enabled && readPersistedExecuting();
|
|
167
177
|
writeExecutionState(readExecutionState());
|
|
168
178
|
});
|
|
169
179
|
ctx.on("turn:end", async (event) => {
|
|
170
180
|
const state = readExecutionState();
|
|
171
|
-
if (!
|
|
181
|
+
if (!executingPlan || state.steps.length === 0) return;
|
|
172
182
|
const message = event.message;
|
|
173
183
|
if (message?.role !== "assistant" || !Array.isArray(message.content)) return;
|
|
174
184
|
const text = message.content.filter((item) => item.type === "text").map((item) => item.text).join("\n");
|
|
@@ -180,13 +190,13 @@ Command: ${command}`,
|
|
|
180
190
|
});
|
|
181
191
|
ctx.on("agent:end", async (event) => {
|
|
182
192
|
const state = readExecutionState();
|
|
183
|
-
if (
|
|
193
|
+
if (executingPlan && state.steps.length > 0) {
|
|
184
194
|
if (state.steps.every((step) => step.status === "completed")) {
|
|
185
195
|
const completedList = state.steps.map((step) => `\u2713 ${step.title}`).join("\n");
|
|
186
196
|
ctx.ui.notify(`**Plan Complete!** \u2713
|
|
187
197
|
|
|
188
198
|
${completedList}`, "info");
|
|
189
|
-
|
|
199
|
+
setExecutingPlan(false);
|
|
190
200
|
writeExecutionState(null);
|
|
191
201
|
}
|
|
192
202
|
return;
|
|
@@ -197,7 +207,9 @@ ${completedList}`, "info");
|
|
|
197
207
|
(message) => message.role === "assistant" && Array.isArray(message.content)
|
|
198
208
|
);
|
|
199
209
|
if (!lastAssistant) return;
|
|
200
|
-
const
|
|
210
|
+
const content = lastAssistant.content;
|
|
211
|
+
if (!Array.isArray(content)) return;
|
|
212
|
+
const text = content.filter((item) => item.type === "text").map((item) => item.text).join("\n");
|
|
201
213
|
const extracted = extractPlanTodoItems(text);
|
|
202
214
|
if (extracted.length === 0) return;
|
|
203
215
|
const extractedState = writeExecutionState(createExecutionStateFromPlan(extracted));
|
|
@@ -211,7 +223,7 @@ ${todoListText}`, "info");
|
|
|
211
223
|
]);
|
|
212
224
|
if (choice?.startsWith("Execute")) {
|
|
213
225
|
planModeEnabled = false;
|
|
214
|
-
|
|
226
|
+
setExecutingPlan(extractedState.steps.length > 0);
|
|
215
227
|
ctx.setSessionMetadata(SESSION_METADATA_KEY, false);
|
|
216
228
|
ctx.setPlanMode(false);
|
|
217
229
|
updateStatus();
|
|
@@ -1,64 +1,43 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createCliHostCapabilities
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-KDPAGHYY.js";
|
|
5
5
|
import {
|
|
6
6
|
createSharedFileSystemTools,
|
|
7
7
|
createSubagentCapability
|
|
8
|
-
} from "../../../chunks/chunk-
|
|
9
|
-
import "../../../chunks/chunk-
|
|
10
|
-
import "../../../chunks/chunk-
|
|
8
|
+
} from "../../../chunks/chunk-A644H2XX.js";
|
|
9
|
+
import "../../../chunks/chunk-B3SMW2XW.js";
|
|
10
|
+
import "../../../chunks/chunk-S2J3SZZX.js";
|
|
11
11
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
12
12
|
|
|
13
13
|
// builtin/extensions/subagent/index.ts
|
|
14
14
|
import * as os from "os";
|
|
15
15
|
import * as path from "path";
|
|
16
|
-
import * as fs from "fs";
|
|
17
|
-
function debugLog(module, message, data) {
|
|
18
|
-
try {
|
|
19
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
20
|
-
const logDir = path.join(homeDir, ".pie", "sessions");
|
|
21
|
-
const files = fs.readdirSync(logDir).filter((f) => f.endsWith(".log")).sort().reverse();
|
|
22
|
-
if (files.length > 0) {
|
|
23
|
-
const logPath = path.join(logDir, files[0]);
|
|
24
|
-
const entry = `[${(/* @__PURE__ */ new Date()).toISOString()}] [subagent:${module}] ${message}${data ? " " + JSON.stringify(data) : ""}
|
|
25
|
-
`;
|
|
26
|
-
fs.appendFileSync(logPath, entry);
|
|
27
|
-
}
|
|
28
|
-
} catch {
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
16
|
function subagentExtension(ctx) {
|
|
32
17
|
ctx.log("Subagent extension loaded (transparent parallel mode)");
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
model
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
reasoning: false,
|
|
40
|
-
input: ["text"],
|
|
41
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
42
|
-
contextWindow: 2e5,
|
|
43
|
-
maxTokens: 8192
|
|
44
|
-
};
|
|
45
|
-
}
|
|
18
|
+
const resolveRuntimePair = () => {
|
|
19
|
+
if (ctx.model && ctx.apiKey) return { model: ctx.model, apiKey: ctx.apiKey };
|
|
20
|
+
const fallback = ctx.resolveModelClass?.("balanced");
|
|
21
|
+
if (fallback?.model && fallback?.apiKey) return { model: fallback.model, apiKey: fallback.apiKey };
|
|
22
|
+
return {};
|
|
23
|
+
};
|
|
46
24
|
const skills = ctx.skills || [];
|
|
47
|
-
if (!apiKey) {
|
|
48
|
-
ctx.log("Warning: No API key available for subagent.");
|
|
49
|
-
}
|
|
50
25
|
const capability = createSubagentCapability({
|
|
51
|
-
apiKey
|
|
52
|
-
|
|
26
|
+
get apiKey() {
|
|
27
|
+
return resolveRuntimePair().apiKey;
|
|
28
|
+
},
|
|
29
|
+
get model() {
|
|
30
|
+
return resolveRuntimePair().model;
|
|
31
|
+
},
|
|
53
32
|
skills,
|
|
54
33
|
yoloMode: ctx.yoloMode,
|
|
55
34
|
getParentTools: () => ctx.getAllTools(),
|
|
56
35
|
log: (message) => ctx.log(message),
|
|
57
|
-
notify: ctx.hasUI ? (message, type) => ctx.ui.notify(message, type) : void 0,
|
|
58
|
-
debugLog,
|
|
36
|
+
notify: ctx.hasUI ? (message, type) => ctx.ui.notify(message, type === "success" ? "info" : type) : void 0,
|
|
37
|
+
debugLog: (module, message, data) => ctx.log(`[subagent:${module}] ${message}${data !== void 0 ? ` ${JSON.stringify(data)}` : ""}`),
|
|
59
38
|
resolveModelClass: (modelClass) => ctx.resolveModelClass?.(modelClass),
|
|
60
39
|
createRuntimeTools: () => {
|
|
61
|
-
const parentRuntimeTools = ctx.getRuntimeTools
|
|
40
|
+
const parentRuntimeTools = ctx.getRuntimeTools();
|
|
62
41
|
if (Array.isArray(parentRuntimeTools) && parentRuntimeTools.length > 0) {
|
|
63
42
|
return parentRuntimeTools.filter((tool) => tool?.name !== "spawn_subagents_parallel");
|
|
64
43
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
+
MANAGE_TODO_LIST_TOOL_DESCRIPTION,
|
|
3
4
|
ManageTodoListParamsSchema,
|
|
4
5
|
buildExecutionReminder,
|
|
5
6
|
createExecutionStateFromTodos,
|
|
@@ -7,18 +8,13 @@ import {
|
|
|
7
8
|
executeManageTodoList,
|
|
8
9
|
executionStateToTodos,
|
|
9
10
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-A644H2XX.js";
|
|
12
|
+
import "../../../chunks/chunk-B3SMW2XW.js";
|
|
13
|
+
import "../../../chunks/chunk-S2J3SZZX.js";
|
|
13
14
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
14
15
|
|
|
15
16
|
// builtin/extensions/todo/index.ts
|
|
16
17
|
var EXECUTION_METADATA_KEY = "executionState";
|
|
17
|
-
var TOOL_DESCRIPTION = `Manage a session-local todo list. Use when the user explicitly asks to use the todo tool, create/manage todos, track tasks, follow a todo list, show tasks, or mark a task done.
|
|
18
|
-
NEVER use for: internal planning, tracking your own progress, remembering subtasks, or creating checklists for yourself.
|
|
19
|
-
Use action=create with items to create a list; the tool starts item 1 automatically. Use action=complete_current after finishing the current item; the tool advances to the next item or clears the list after the final item.
|
|
20
|
-
When a todo list exists, keep executing from the current in-progress item until it is cleared. If the work cannot continue, explain the failure and use action=clear with a reason.
|
|
21
|
-
Actions: create, read, complete_current, clear.`;
|
|
22
18
|
function persistExecutionState(ctx, state) {
|
|
23
19
|
const nextState = state ?? restoreExecutionState(null);
|
|
24
20
|
ctx.setSessionMetadata(EXECUTION_METADATA_KEY, nextState);
|
|
@@ -27,7 +23,7 @@ function persistExecutionState(ctx, state) {
|
|
|
27
23
|
return nextState;
|
|
28
24
|
}
|
|
29
25
|
function notifyWidget(ctx, state) {
|
|
30
|
-
if (!ctx.hasUI
|
|
26
|
+
if (!ctx.hasUI) return;
|
|
31
27
|
const steps = createTodoWidgetView(state);
|
|
32
28
|
if (steps.length === 0) return;
|
|
33
29
|
const completed = steps.filter((step) => step.status === "completed").length;
|
|
@@ -37,7 +33,7 @@ function todoExtension(ctx) {
|
|
|
37
33
|
ctx.registerTool({
|
|
38
34
|
name: "manage_todo_list",
|
|
39
35
|
label: "manage_todo_list",
|
|
40
|
-
description:
|
|
36
|
+
description: MANAGE_TODO_LIST_TOOL_DESCRIPTION,
|
|
41
37
|
parameters: ManageTodoListParamsSchema,
|
|
42
38
|
async execute(args) {
|
|
43
39
|
const currentTodos = executionStateToTodos(ctx.getExecutionState());
|