@cydm/pie 1.0.36 → 1.0.38
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 -0
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +71 -6
- package/dist/builtin/extensions/subagent/index.js +4 -4
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/chunks/{chunk-MGZHZSHB.js → chunk-2PLCSYFF.js} +272 -46
- package/dist/chunks/{chunk-64XJIKVK.js → chunk-2WHIT2UB.js} +1708 -1694
- package/dist/chunks/{chunk-QXTAEPLR.js → chunk-IKIEQTVJ.js} +2 -2
- package/dist/chunks/{chunk-4B42ZU4B.js → chunk-NTFKTUOW.js} +1 -1
- package/dist/chunks/{src-27UD2ZBZ.js → src-PBRYPFUI.js} +2 -2
- package/dist/chunks/{test-stream-L4PUYWQQ.js → test-stream-EO6L26M5.js} +1 -1
- package/dist/cli.js +380 -86
- package/models.schema.json +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -309,6 +309,8 @@ Pie exposes one default model-visible web tool: `web_research`. Use it for publi
|
|
|
309
309
|
|
|
310
310
|
Pie's default tools operate from the current workspace. File tools are workspace-scoped, `~/.pie` is allowlisted for Pie configuration/session support, and shell commands return structured timeout/truncation/error details. The canonical shell tool is still named `bash` for compatibility; on Windows `shell:auto` uses PowerShell, and callers can explicitly request `bash`, `powershell`, or `cmd`. High-risk shell commands require confirmation outside YOLO mode. `/settings/yolo` relaxes filesystem sandbox directory restrictions and should only be used in trusted workspaces. `pie permissions` prints the current policy-derived safety summary.
|
|
311
311
|
|
|
312
|
+
In interactive Plan mode (`/tools/plan`), workspace editing tools are unavailable. The `bash` guard accepts simple read commands and read-only pipelines such as `rg 'TODO' . | head -20`; it blocks redirects, command substitution, and write-capable subcommands. Use `plan_scratch` to write, read, or list temporary text drafts in a directory dedicated to the current session. Shell redirection to `/tmp` remains blocked in Plan mode. Leave Plan mode before changing workspace files.
|
|
313
|
+
|
|
312
314
|
## Code Intelligence
|
|
313
315
|
|
|
314
316
|
`code_intel` provides read-only JS/TS diagnostics, definition, references, symbols, and hover. CLI uses an isolated TypeScript worker by default and falls back to bounded lightweight text analysis on worker startup/OOM/crash/timeout failures; aborts, permission errors, and path escapes do not fallback. Unity uses a Node sidecar contract for TypeScript intelligence so the PuerTS bundle does not import Node-only parser dependencies.
|
|
@@ -1,9 +1,9 @@
|
|
|
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-2PLCSYFF.js";
|
|
5
|
+
import "../../../chunks/chunk-NTFKTUOW.js";
|
|
6
|
+
import "../../../chunks/chunk-2WHIT2UB.js";
|
|
7
7
|
import "../../../chunks/chunk-TG2EQLX2.js";
|
|
8
8
|
|
|
9
9
|
// builtin/extensions/ask-user/index.ts
|
|
@@ -7,14 +7,23 @@ import {
|
|
|
7
7
|
isPlanModeSafeCommand,
|
|
8
8
|
markCompletedPlanSteps,
|
|
9
9
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import
|
|
10
|
+
} from "../../../chunks/chunk-2PLCSYFF.js";
|
|
11
|
+
import "../../../chunks/chunk-NTFKTUOW.js";
|
|
12
|
+
import {
|
|
13
|
+
Type
|
|
14
|
+
} from "../../../chunks/chunk-2WHIT2UB.js";
|
|
13
15
|
import "../../../chunks/chunk-TG2EQLX2.js";
|
|
14
16
|
|
|
15
17
|
// builtin/extensions/plan-mode/index.ts
|
|
18
|
+
import { randomUUID } from "node:crypto";
|
|
19
|
+
import { promises as fs, constants as fsConstants } from "node:fs";
|
|
20
|
+
import os from "node:os";
|
|
21
|
+
import path from "node:path";
|
|
16
22
|
var SESSION_METADATA_KEY = "planModeEnabled";
|
|
17
23
|
var EXECUTION_METADATA_KEY = "executionState";
|
|
24
|
+
var SCRATCH_METADATA_KEY = "planScratchId";
|
|
25
|
+
var SCRATCH_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;
|
|
26
|
+
var MAX_SCRATCH_CHARS = 64e3;
|
|
18
27
|
var planModeEnabled = false;
|
|
19
28
|
var executionMode = false;
|
|
20
29
|
function toPlanTodoItems(state) {
|
|
@@ -26,6 +35,62 @@ function toPlanTodoItems(state) {
|
|
|
26
35
|
}
|
|
27
36
|
function planModeExtension(ctx) {
|
|
28
37
|
const capability = createPlanCapability();
|
|
38
|
+
function scratchDirectory() {
|
|
39
|
+
const metadata = ctx.getSessionMetadata();
|
|
40
|
+
let id = metadata?.[SCRATCH_METADATA_KEY];
|
|
41
|
+
if (typeof id !== "string" || !/^[0-9a-f-]{36}$/.test(id)) {
|
|
42
|
+
id = randomUUID();
|
|
43
|
+
ctx.setSessionMetadata(SCRATCH_METADATA_KEY, id);
|
|
44
|
+
}
|
|
45
|
+
return path.join(os.tmpdir(), `pie-plan-${id}`);
|
|
46
|
+
}
|
|
47
|
+
ctx.registerTool({
|
|
48
|
+
name: "plan_scratch",
|
|
49
|
+
label: "plan_scratch",
|
|
50
|
+
description: "Read, write, or list session-local temporary text drafts while planning. Use a simple filename; files stay outside the workspace. Shell output redirection is blocked in Plan mode.",
|
|
51
|
+
parameters: Type.Object({
|
|
52
|
+
action: Type.Union([Type.Literal("write"), Type.Literal("read"), Type.Literal("list")]),
|
|
53
|
+
name: Type.Optional(Type.String({ description: "Simple filename within this session's scratch directory" })),
|
|
54
|
+
content: Type.Optional(Type.String({ description: "Text to write (maximum 64,000 characters)" }))
|
|
55
|
+
}),
|
|
56
|
+
risk: { riskClass: "session_mutation", permissionScope: "session", mutatesSession: true, availableInPlanMode: true },
|
|
57
|
+
async execute(args) {
|
|
58
|
+
const reply = (text, isError = false) => ({ content: [{ type: "text", text }], isError });
|
|
59
|
+
try {
|
|
60
|
+
const directory = scratchDirectory();
|
|
61
|
+
await fs.mkdir(directory, { recursive: true, mode: 448 });
|
|
62
|
+
if (!(await fs.lstat(directory)).isDirectory()) return reply("Temporary draft directory is invalid.", true);
|
|
63
|
+
if (args.action === "list") {
|
|
64
|
+
const names = (await fs.readdir(directory)).filter((name) => SCRATCH_NAME.test(name)).sort();
|
|
65
|
+
return reply(names.length ? names.join("\n") : "No temporary drafts in this session.");
|
|
66
|
+
}
|
|
67
|
+
if (!args.name || !SCRATCH_NAME.test(args.name) || args.name === "." || args.name === "..") {
|
|
68
|
+
return reply("Invalid draft filename. Use letters, digits, dots, underscores, or hyphens without directories.", true);
|
|
69
|
+
}
|
|
70
|
+
const filename = path.join(directory, args.name);
|
|
71
|
+
if (args.action === "read") {
|
|
72
|
+
const handle2 = await fs.open(filename, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW || 0));
|
|
73
|
+
try {
|
|
74
|
+
return reply(await handle2.readFile("utf8"));
|
|
75
|
+
} finally {
|
|
76
|
+
await handle2.close();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (typeof args.content !== "string" || args.content.length > MAX_SCRATCH_CHARS) {
|
|
80
|
+
return reply(`Draft content must be text of at most ${MAX_SCRATCH_CHARS} characters.`, true);
|
|
81
|
+
}
|
|
82
|
+
const handle = await fs.open(filename, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_TRUNC | (fsConstants.O_NOFOLLOW || 0), 384);
|
|
83
|
+
try {
|
|
84
|
+
await handle.writeFile(args.content, "utf8");
|
|
85
|
+
} finally {
|
|
86
|
+
await handle.close();
|
|
87
|
+
}
|
|
88
|
+
return reply(`Saved ${args.name} (${args.content.length} characters).`);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return reply(`Temporary draft failed: ${error instanceof Error ? error.message : String(error)}`, true);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
29
94
|
function readPersistedPlanMode() {
|
|
30
95
|
return ctx.getSessionMetadata()?.[SESSION_METADATA_KEY] === true;
|
|
31
96
|
}
|
|
@@ -45,7 +110,7 @@ function planModeExtension(ctx) {
|
|
|
45
110
|
const completed = state.steps.filter((step) => step.status === "completed").length;
|
|
46
111
|
ctx.ui.notify(`\u{1F4CB} Plan: ${completed}/${state.steps.length} completed`, "info");
|
|
47
112
|
} else if (planModeEnabled) {
|
|
48
|
-
ctx.ui.notify("\u23F8\uFE0F Plan mode active (read-only)", "info");
|
|
113
|
+
ctx.ui.notify("\u23F8\uFE0F Plan mode active (workspace read-only; session drafts available)", "info");
|
|
49
114
|
}
|
|
50
115
|
}
|
|
51
116
|
function applyPlanModeState(enabled, forcePromptInjection = false) {
|
|
@@ -84,11 +149,11 @@ function planModeExtension(ctx) {
|
|
|
84
149
|
const command = event.args?.command;
|
|
85
150
|
if (command && !isPlanModeSafeCommand(command)) {
|
|
86
151
|
ctx.ui.notify(
|
|
87
|
-
`Plan mode: Command blocked
|
|
152
|
+
`Plan mode: Command blocked. Use read-only commands, or plan_scratch for temporary drafts. Use /plan to leave Plan mode.
|
|
88
153
|
Command: ${command}`,
|
|
89
154
|
"error"
|
|
90
155
|
);
|
|
91
|
-
return { block: true, reason: `Plan mode: command "${command}" is not
|
|
156
|
+
return { block: true, reason: `Plan mode: command "${command}" is not a read-only shell command. Use plan_scratch for temporary drafts, or /plan to leave Plan mode.` };
|
|
92
157
|
}
|
|
93
158
|
});
|
|
94
159
|
ctx.on("agent:start", async () => {
|
|
@@ -1,13 +1,13 @@
|
|
|
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-IKIEQTVJ.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-2PLCSYFF.js";
|
|
9
|
+
import "../../../chunks/chunk-NTFKTUOW.js";
|
|
10
|
+
import "../../../chunks/chunk-2WHIT2UB.js";
|
|
11
11
|
import "../../../chunks/chunk-TG2EQLX2.js";
|
|
12
12
|
|
|
13
13
|
// builtin/extensions/subagent/index.ts
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
executeManageTodoList,
|
|
8
8
|
executionStateToTodos,
|
|
9
9
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
10
|
+
} from "../../../chunks/chunk-2PLCSYFF.js";
|
|
11
|
+
import "../../../chunks/chunk-NTFKTUOW.js";
|
|
12
|
+
import "../../../chunks/chunk-2WHIT2UB.js";
|
|
13
13
|
import "../../../chunks/chunk-TG2EQLX2.js";
|
|
14
14
|
|
|
15
15
|
// builtin/extensions/todo/index.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
Agent
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NTFKTUOW.js";
|
|
5
5
|
import {
|
|
6
6
|
FileSystemGateway,
|
|
7
7
|
Type,
|
|
@@ -11,7 +11,241 @@ import {
|
|
|
11
11
|
getPlatformConfig,
|
|
12
12
|
hashText,
|
|
13
13
|
streamSimple
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2WHIT2UB.js";
|
|
15
|
+
import {
|
|
16
|
+
__commonJS,
|
|
17
|
+
__toESM
|
|
18
|
+
} from "./chunk-TG2EQLX2.js";
|
|
19
|
+
|
|
20
|
+
// ../../node_modules/shell-quote/quote.js
|
|
21
|
+
var require_quote = __commonJS({
|
|
22
|
+
"../../node_modules/shell-quote/quote.js"(exports, module) {
|
|
23
|
+
"use strict";
|
|
24
|
+
module.exports = function quote(xs) {
|
|
25
|
+
return xs.map(function(s) {
|
|
26
|
+
if (s === "") {
|
|
27
|
+
return "''";
|
|
28
|
+
}
|
|
29
|
+
if (s && typeof s === "object") {
|
|
30
|
+
return s.op.replace(/(.)/g, "\\$1");
|
|
31
|
+
}
|
|
32
|
+
if (/["\s\\]/.test(s) && !/'/.test(s)) {
|
|
33
|
+
return "'" + s.replace(/(['])/g, "\\$1") + "'";
|
|
34
|
+
}
|
|
35
|
+
if (/["'\s]/.test(s)) {
|
|
36
|
+
return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
|
|
37
|
+
}
|
|
38
|
+
return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
|
|
39
|
+
}).join(" ");
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// ../../node_modules/shell-quote/parse.js
|
|
45
|
+
var require_parse = __commonJS({
|
|
46
|
+
"../../node_modules/shell-quote/parse.js"(exports, module) {
|
|
47
|
+
"use strict";
|
|
48
|
+
var CONTROL = "(?:" + [
|
|
49
|
+
"\\|\\|",
|
|
50
|
+
"\\&\\&",
|
|
51
|
+
";;",
|
|
52
|
+
"\\|\\&",
|
|
53
|
+
"\\<\\(",
|
|
54
|
+
"\\<\\<\\<",
|
|
55
|
+
">>",
|
|
56
|
+
">\\&",
|
|
57
|
+
"<\\&",
|
|
58
|
+
"[&;()|<>]"
|
|
59
|
+
].join("|") + ")";
|
|
60
|
+
var controlRE = new RegExp("^" + CONTROL + "$");
|
|
61
|
+
var META = "|&;()<> \\t";
|
|
62
|
+
var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
|
|
63
|
+
var DOUBLE_QUOTE = "'((\\\\'|[^'])*?)'";
|
|
64
|
+
var hash = /^#$/;
|
|
65
|
+
var SQ = "'";
|
|
66
|
+
var DQ = '"';
|
|
67
|
+
var DS = "$";
|
|
68
|
+
var TOKEN = "";
|
|
69
|
+
var mult = 4294967296;
|
|
70
|
+
for (i = 0; i < 4; i++) {
|
|
71
|
+
TOKEN += (mult * Math.random()).toString(16);
|
|
72
|
+
}
|
|
73
|
+
var i;
|
|
74
|
+
var startsWithToken = new RegExp("^" + TOKEN);
|
|
75
|
+
function matchAll(s, r) {
|
|
76
|
+
var origIndex = r.lastIndex;
|
|
77
|
+
var matches = [];
|
|
78
|
+
var matchObj;
|
|
79
|
+
while (matchObj = r.exec(s)) {
|
|
80
|
+
matches.push(matchObj);
|
|
81
|
+
if (r.lastIndex === matchObj.index) {
|
|
82
|
+
r.lastIndex += 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
r.lastIndex = origIndex;
|
|
86
|
+
return matches;
|
|
87
|
+
}
|
|
88
|
+
function getVar(env, pre, key) {
|
|
89
|
+
var r = typeof env === "function" ? env(key) : env[key];
|
|
90
|
+
if (typeof r === "undefined" && key != "") {
|
|
91
|
+
r = "";
|
|
92
|
+
} else if (typeof r === "undefined") {
|
|
93
|
+
r = "$";
|
|
94
|
+
}
|
|
95
|
+
if (typeof r === "object") {
|
|
96
|
+
return pre + TOKEN + JSON.stringify(r) + TOKEN;
|
|
97
|
+
}
|
|
98
|
+
return pre + r;
|
|
99
|
+
}
|
|
100
|
+
function parseInternal(string, env, opts) {
|
|
101
|
+
if (!opts) {
|
|
102
|
+
opts = {};
|
|
103
|
+
}
|
|
104
|
+
var BS = opts.escape || "\\";
|
|
105
|
+
var BAREWORD = "(\\" + BS + `['"` + META + `]|[^\\s'"` + META + "])+";
|
|
106
|
+
var chunker = new RegExp([
|
|
107
|
+
"(" + CONTROL + ")",
|
|
108
|
+
// control chars
|
|
109
|
+
"(" + BAREWORD + "|" + SINGLE_QUOTE + "|" + DOUBLE_QUOTE + ")+"
|
|
110
|
+
].join("|"), "g");
|
|
111
|
+
var matches = matchAll(string, chunker);
|
|
112
|
+
if (matches.length === 0) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
if (!env) {
|
|
116
|
+
env = {};
|
|
117
|
+
}
|
|
118
|
+
var commented = false;
|
|
119
|
+
return matches.map(function(match2) {
|
|
120
|
+
var s = match2[0];
|
|
121
|
+
if (!s || commented) {
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
if (controlRE.test(s)) {
|
|
125
|
+
return { op: s };
|
|
126
|
+
}
|
|
127
|
+
var quote = false;
|
|
128
|
+
var esc = false;
|
|
129
|
+
var out = "";
|
|
130
|
+
var isGlob = false;
|
|
131
|
+
var i2;
|
|
132
|
+
function parseEnvVar() {
|
|
133
|
+
i2 += 1;
|
|
134
|
+
var varend;
|
|
135
|
+
var varname;
|
|
136
|
+
var char = s.charAt(i2);
|
|
137
|
+
if (char === "{") {
|
|
138
|
+
i2 += 1;
|
|
139
|
+
if (s.charAt(i2) === "}") {
|
|
140
|
+
throw new Error("Bad substitution: " + s.slice(i2 - 2, i2 + 1));
|
|
141
|
+
}
|
|
142
|
+
varend = s.indexOf("}", i2);
|
|
143
|
+
if (varend < 0) {
|
|
144
|
+
throw new Error("Bad substitution: " + s.slice(i2));
|
|
145
|
+
}
|
|
146
|
+
varname = s.slice(i2, varend);
|
|
147
|
+
i2 = varend;
|
|
148
|
+
} else if (/[*@#?$!_-]/.test(char)) {
|
|
149
|
+
varname = char;
|
|
150
|
+
i2 += 1;
|
|
151
|
+
} else {
|
|
152
|
+
var slicedFromI = s.slice(i2);
|
|
153
|
+
varend = slicedFromI.match(/[^\w\d_]/);
|
|
154
|
+
if (!varend) {
|
|
155
|
+
varname = slicedFromI;
|
|
156
|
+
i2 = s.length;
|
|
157
|
+
} else {
|
|
158
|
+
varname = slicedFromI.slice(0, varend.index);
|
|
159
|
+
i2 += varend.index - 1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return getVar(env, "", varname);
|
|
163
|
+
}
|
|
164
|
+
for (i2 = 0; i2 < s.length; i2++) {
|
|
165
|
+
var c = s.charAt(i2);
|
|
166
|
+
isGlob = isGlob || !quote && (c === "*" || c === "?");
|
|
167
|
+
if (esc) {
|
|
168
|
+
out += c;
|
|
169
|
+
esc = false;
|
|
170
|
+
} else if (quote) {
|
|
171
|
+
if (c === quote) {
|
|
172
|
+
quote = false;
|
|
173
|
+
} else if (quote == SQ) {
|
|
174
|
+
out += c;
|
|
175
|
+
} else {
|
|
176
|
+
if (c === BS) {
|
|
177
|
+
i2 += 1;
|
|
178
|
+
c = s.charAt(i2);
|
|
179
|
+
if (c === DQ || c === BS || c === DS) {
|
|
180
|
+
out += c;
|
|
181
|
+
} else {
|
|
182
|
+
out += BS + c;
|
|
183
|
+
}
|
|
184
|
+
} else if (c === DS) {
|
|
185
|
+
out += parseEnvVar();
|
|
186
|
+
} else {
|
|
187
|
+
out += c;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} else if (c === DQ || c === SQ) {
|
|
191
|
+
quote = c;
|
|
192
|
+
} else if (controlRE.test(c)) {
|
|
193
|
+
return { op: s };
|
|
194
|
+
} else if (hash.test(c)) {
|
|
195
|
+
commented = true;
|
|
196
|
+
var commentObj = { comment: string.slice(match2.index + i2 + 1) };
|
|
197
|
+
if (out.length) {
|
|
198
|
+
return [out, commentObj];
|
|
199
|
+
}
|
|
200
|
+
return [commentObj];
|
|
201
|
+
} else if (c === BS) {
|
|
202
|
+
esc = true;
|
|
203
|
+
} else if (c === DS) {
|
|
204
|
+
out += parseEnvVar();
|
|
205
|
+
} else {
|
|
206
|
+
out += c;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (isGlob) {
|
|
210
|
+
return { op: "glob", pattern: out };
|
|
211
|
+
}
|
|
212
|
+
return out;
|
|
213
|
+
}).reduce(function(prev, arg) {
|
|
214
|
+
return typeof arg === "undefined" ? prev : prev.concat(arg);
|
|
215
|
+
}, []);
|
|
216
|
+
}
|
|
217
|
+
module.exports = function parse2(s, env, opts) {
|
|
218
|
+
var mapped = parseInternal(s, env, opts);
|
|
219
|
+
if (typeof env !== "function") {
|
|
220
|
+
return mapped;
|
|
221
|
+
}
|
|
222
|
+
return mapped.reduce(function(acc, s2) {
|
|
223
|
+
if (typeof s2 === "object") {
|
|
224
|
+
return acc.concat(s2);
|
|
225
|
+
}
|
|
226
|
+
var xs = s2.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
|
|
227
|
+
if (xs.length === 1) {
|
|
228
|
+
return acc.concat(xs[0]);
|
|
229
|
+
}
|
|
230
|
+
return acc.concat(xs.filter(Boolean).map(function(x) {
|
|
231
|
+
if (startsWithToken.test(x)) {
|
|
232
|
+
return JSON.parse(x.split(TOKEN)[1]);
|
|
233
|
+
}
|
|
234
|
+
return x;
|
|
235
|
+
}));
|
|
236
|
+
}, []);
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// ../../node_modules/shell-quote/index.js
|
|
242
|
+
var require_shell_quote = __commonJS({
|
|
243
|
+
"../../node_modules/shell-quote/index.js"(exports) {
|
|
244
|
+
"use strict";
|
|
245
|
+
exports.quote = require_quote();
|
|
246
|
+
exports.parse = require_parse();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
15
249
|
|
|
16
250
|
// ../../packages/shared-headless-capabilities/src/loop.ts
|
|
17
251
|
function nowIso() {
|
|
@@ -445,6 +679,7 @@ var BUILTIN_TOOL_CAPABILITY_METADATA = {
|
|
|
445
679
|
unity_log_read: { riskClass: "read_only", concurrencySafe: true, permissionScope: "unity", readsHostResource: true, availableInPlanMode: true, allowedForSubagentByDefault: true, maxOutputChars: 1e5 },
|
|
446
680
|
unity_scene_object_edit: { riskClass: "external_side_effect", concurrencySafe: false, requiresPermission: true, permissionScope: "unity", externalSideEffect: true, highRisk: true },
|
|
447
681
|
unity_refresh: { riskClass: "external_side_effect", concurrencySafe: false, permissionScope: "unity", externalSideEffect: true },
|
|
682
|
+
unity_tool_call: { riskClass: "external_side_effect", concurrencySafe: false, requiresPermission: true, permissionScope: "unity", externalSideEffect: true, highRisk: true },
|
|
448
683
|
unity_script_run: { riskClass: "external_side_effect", concurrencySafe: false, requiresPermission: true, permissionScope: "unity", externalSideEffect: true, highRisk: true }
|
|
449
684
|
};
|
|
450
685
|
function getToolCapabilityMetadata(tool) {
|
|
@@ -493,39 +728,27 @@ function selectToolsForRuntimePolicy(tools, mode) {
|
|
|
493
728
|
var DEFAULT_PLAN_MODE_TOOL_NAMES = Object.entries(BUILTIN_TOOL_CAPABILITY_METADATA).filter(([, metadata]) => metadata.availableInPlanMode).map(([name]) => name);
|
|
494
729
|
|
|
495
730
|
// ../../packages/shared-headless-capabilities/src/plan.ts
|
|
496
|
-
var
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
"
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
"
|
|
510
|
-
"
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
"
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
var DANGEROUS_PATTERNS = [
|
|
518
|
-
/\brm\s+-[rf]*/i,
|
|
519
|
-
/>[\s]*\/dev\//,
|
|
520
|
-
/\|.*\brm\b/,
|
|
521
|
-
/git\s+push/i,
|
|
522
|
-
/git\s+reset/i,
|
|
523
|
-
/git\s+checkout\s+-/,
|
|
524
|
-
/git\s+revert/i,
|
|
525
|
-
/npm\s+publish/i,
|
|
526
|
-
/npm\s+uninstall/i,
|
|
527
|
-
/npm\s+rm/i
|
|
528
|
-
];
|
|
731
|
+
var import_shell_quote = __toESM(require_shell_quote(), 1);
|
|
732
|
+
var SIMPLE_READ_COMMANDS = /* @__PURE__ */ new Set(["pwd", "ls", "cat", "head", "tail", "wc", "grep", "rg", "which", "type", "echo", "printf", "cd", "true", "false"]);
|
|
733
|
+
var GIT_READ_SUBCOMMANDS = /* @__PURE__ */ new Set(["status", "log", "diff", "show", "rev-parse", "ls-files", "ls-tree"]);
|
|
734
|
+
var UNSAFE_GIT_FLAGS = /^(?:-c|--config-env|--exec|--output|--ext-diff|--textconv)(?:=|$)/;
|
|
735
|
+
var UNSAFE_RG_FLAGS = /^(?:--pre|--pre-glob)(?:=|$)/;
|
|
736
|
+
function isReadOnlySegment(words) {
|
|
737
|
+
if (words.length === 0) return false;
|
|
738
|
+
const [program, ...args] = words;
|
|
739
|
+
if (program === "git") {
|
|
740
|
+
const subcommand = args[0] ?? "";
|
|
741
|
+
const isReadSubcommand = GIT_READ_SUBCOMMANDS.has(subcommand) || subcommand === "branch" && args.slice(1).every((arg) => ["-a", "--all", "-r", "--remotes", "--list"].includes(arg)) || subcommand === "remote" && args.length === 2 && args[1] === "-v" || subcommand === "config" && args.length === 2 && args[1] === "--list";
|
|
742
|
+
return isReadSubcommand && !args.some((arg) => UNSAFE_GIT_FLAGS.test(arg) || arg === "--no-pager" || arg === "-c");
|
|
743
|
+
}
|
|
744
|
+
if (program === "npm") return ["list", "view"].includes(args[0] ?? "") && !args.some((arg) => arg === "--script-shell");
|
|
745
|
+
if (program === "find") {
|
|
746
|
+
return !args.some((arg) => /^-(?:exec|execdir|ok|okdir|delete|fprint|fls|fprintf)/.test(arg));
|
|
747
|
+
}
|
|
748
|
+
if (!SIMPLE_READ_COMMANDS.has(program)) return false;
|
|
749
|
+
if (program === "rg") return !args.some((arg) => UNSAFE_RG_FLAGS.test(arg) || arg === "--pre" || arg === "--pre-glob");
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
529
752
|
function extractPlanTodoItems(text) {
|
|
530
753
|
const items = [];
|
|
531
754
|
const planMatch = text.match(/Plan:\s*\n?([\s\S]*?)(?=\n\n|\n[A-Z]|$)/i);
|
|
@@ -545,20 +768,23 @@ function extractPlanTodoItems(text) {
|
|
|
545
768
|
}
|
|
546
769
|
function isPlanModeSafeCommand(command) {
|
|
547
770
|
const trimmed = command.trim();
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
771
|
+
if (!trimmed || /[$`\n\r\0]/.test(trimmed)) return false;
|
|
772
|
+
let tokens;
|
|
773
|
+
try {
|
|
774
|
+
tokens = (0, import_shell_quote.parse)(trimmed);
|
|
775
|
+
} catch {
|
|
776
|
+
return false;
|
|
552
777
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
778
|
+
const segment = [];
|
|
779
|
+
for (const token of tokens) {
|
|
780
|
+
if (typeof token === "string") {
|
|
781
|
+
segment.push(token);
|
|
782
|
+
continue;
|
|
556
783
|
}
|
|
784
|
+
if (!("op" in token) || !["|", "&&", "||", ";"].includes(String(token.op)) || !isReadOnlySegment(segment)) return false;
|
|
785
|
+
segment.length = 0;
|
|
557
786
|
}
|
|
558
|
-
|
|
559
|
-
return ["pwd", "ls", "clear", "whoami"].includes(trimmed);
|
|
560
|
-
}
|
|
561
|
-
return false;
|
|
787
|
+
return isReadOnlySegment(segment);
|
|
562
788
|
}
|
|
563
789
|
function extractDoneSteps(text) {
|
|
564
790
|
const steps = [];
|