@cydm/pie 2.7.9 → 2.7.11
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 -2
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +3 -3
- package/dist/builtin/extensions/subagent/index.js +4 -4
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/chunks/{chunk-ABZOXNDK.js → chunk-3NFKVBGY.js} +22 -3
- package/dist/chunks/{chunk-SMGBZQI5.js → chunk-3VEIP2VY.js} +96 -18
- package/dist/chunks/{chunk-AX5QEIKP.js → chunk-XIRBNP2S.js} +34 -6
- package/dist/chunks/{chunk-5SP2H5QK.js → chunk-XVF6V6Q5.js} +1 -1
- package/dist/chunks/{src-BQUDKBQ7.js → src-2RCV3I3P.js} +2 -2
- package/dist/chunks/{test-stream-A5KBYYZD.js → test-stream-Y2S3H7DK.js} +1 -1
- package/dist/cli.js +172 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -240,7 +240,7 @@ Pie uses a hierarchical slash-command menu. The current built-in commands includ
|
|
|
240
240
|
| `pie extensions list/enable/disable` | Inspect and toggle extensions non-interactively |
|
|
241
241
|
| `/sessions/compact` | Summarize history and create a compact checkpoint |
|
|
242
242
|
| `/sessions/new` | Start a new session |
|
|
243
|
-
| `/sessions/resume` | Resume a
|
|
243
|
+
| `/sessions/resume` | Resume a session (defaults to current-directory sessions; press `g` in the selector to show the full loaded recent list) |
|
|
244
244
|
| `/sessions/tree` | Navigate the session tree |
|
|
245
245
|
| `/sessions/info` | Show session information |
|
|
246
246
|
| `/sessions/fork` | Fork from an earlier message |
|
|
@@ -363,7 +363,7 @@ Pie exposes one default model-visible web tool: `web_research`. Use it for publi
|
|
|
363
363
|
|
|
364
364
|
## Permissions
|
|
365
365
|
|
|
366
|
-
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.
|
|
366
|
+
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; the confirmation dialog also offers a time-boxed `Yolo (5 min)` option that suppresses further high-risk prompts for five minutes without enabling full 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.
|
|
367
367
|
|
|
368
368
|
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. When the plan is ready, the agent submits the ordered steps with `plan_submit` and you choose to execute immediately (progress is tracked through `[DONE:n]` markers in responses), keep planning, or refine the plan in a prefilled editor; a plan written as plain text under a `Plan:`/`计划:` heading is still detected as a fallback. Leave Plan mode before changing workspace files.
|
|
369
369
|
|
|
@@ -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-XIRBNP2S.js";
|
|
5
|
+
import "../../../chunks/chunk-XVF6V6Q5.js";
|
|
6
|
+
import "../../../chunks/chunk-3VEIP2VY.js";
|
|
7
7
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
8
8
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
9
9
|
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
extractPlanTodoItems,
|
|
7
7
|
markCompletedPlanSteps,
|
|
8
8
|
restoreExecutionState
|
|
9
|
-
} from "../../../chunks/chunk-
|
|
10
|
-
import "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
9
|
+
} from "../../../chunks/chunk-XIRBNP2S.js";
|
|
10
|
+
import "../../../chunks/chunk-XVF6V6Q5.js";
|
|
11
|
+
import "../../../chunks/chunk-3VEIP2VY.js";
|
|
12
12
|
import {
|
|
13
13
|
Type
|
|
14
14
|
} from "../../../chunks/chunk-XXGYUYXI.js";
|
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
formatTransportLifecycle,
|
|
5
5
|
getConfigDir,
|
|
6
6
|
logTransportLifecycle
|
|
7
|
-
} from "../../../chunks/chunk-
|
|
7
|
+
} from "../../../chunks/chunk-3NFKVBGY.js";
|
|
8
8
|
import {
|
|
9
9
|
SUBAGENT_SESSION_RECORD_VERSION,
|
|
10
10
|
createPolicyEnforcedTools,
|
|
11
11
|
createSharedFileSystemTools,
|
|
12
12
|
createSubagentCapability
|
|
13
|
-
} from "../../../chunks/chunk-
|
|
14
|
-
import "../../../chunks/chunk-
|
|
15
|
-
import "../../../chunks/chunk-
|
|
13
|
+
} from "../../../chunks/chunk-XIRBNP2S.js";
|
|
14
|
+
import "../../../chunks/chunk-XVF6V6Q5.js";
|
|
15
|
+
import "../../../chunks/chunk-3VEIP2VY.js";
|
|
16
16
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
17
17
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
18
18
|
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
executeManageTodoList,
|
|
9
9
|
executionStateToTodos,
|
|
10
10
|
restoreExecutionState
|
|
11
|
-
} from "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
13
|
-
import "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-XIRBNP2S.js";
|
|
12
|
+
import "../../../chunks/chunk-XVF6V6Q5.js";
|
|
13
|
+
import "../../../chunks/chunk-3VEIP2VY.js";
|
|
14
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
15
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
16
16
|
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
defaultShellKindForPlatform,
|
|
8
8
|
interpretShellExit,
|
|
9
9
|
requestInteraction
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XIRBNP2S.js";
|
|
11
11
|
import {
|
|
12
12
|
getLogger
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-3VEIP2VY.js";
|
|
14
14
|
import {
|
|
15
15
|
Type
|
|
16
16
|
} from "./chunk-XXGYUYXI.js";
|
|
@@ -687,10 +687,28 @@ async function requestHighRiskConfirmation(request) {
|
|
|
687
687
|
"",
|
|
688
688
|
request.command
|
|
689
689
|
].join("\n"),
|
|
690
|
-
timeoutMs: 12e4
|
|
690
|
+
timeoutMs: 12e4,
|
|
691
|
+
// An entry labeled Yolo (e.g. "Yolo (5 min)") is a time-boxed YOLO
|
|
692
|
+
// grant: hosts that understand it answer with yoloGrantMs so subsequent
|
|
693
|
+
// confirmations are bypassed for that window; hosts without support
|
|
694
|
+
// render the labels as plain options and a selection still confirms
|
|
695
|
+
// this one command.
|
|
696
|
+
options: ["Yes", "No", "Yolo (5 min)"]
|
|
691
697
|
});
|
|
698
|
+
const yoloGrantMs = response.type === "confirm" ? response.yoloGrantMs : void 0;
|
|
699
|
+
if (yoloGrantMs && yoloGrantMs > 0) notifyYoloGrantAwarded(yoloGrantMs);
|
|
692
700
|
return response.type === "confirm" && response.confirmed === true;
|
|
693
701
|
}
|
|
702
|
+
var yoloGrantListener;
|
|
703
|
+
function setYoloGrantListener(listener) {
|
|
704
|
+
yoloGrantListener = listener;
|
|
705
|
+
}
|
|
706
|
+
function notifyYoloGrantAwarded(grantMs) {
|
|
707
|
+
try {
|
|
708
|
+
yoloGrantListener?.(grantMs);
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
}
|
|
694
712
|
function validateWorkingDirectory(cwd) {
|
|
695
713
|
if (!existsSync2(cwd)) {
|
|
696
714
|
throw new Error(`Invalid bash cwd: ${cwd} does not exist. Use the current workspace path or pass an existing directory in cwd.`);
|
|
@@ -1600,6 +1618,7 @@ export {
|
|
|
1600
1618
|
createCliWebResearchHealthStore,
|
|
1601
1619
|
truncateHeadTail,
|
|
1602
1620
|
formatSize,
|
|
1621
|
+
setYoloGrantListener,
|
|
1603
1622
|
cleanupBashOutputArtifacts,
|
|
1604
1623
|
createBashTool,
|
|
1605
1624
|
formatTransportLifecycle,
|
|
@@ -3074,11 +3074,17 @@ var FileSystemGateway = class {
|
|
|
3074
3074
|
this.validatePath(destination, "copy");
|
|
3075
3075
|
const platform = detectPlatform();
|
|
3076
3076
|
const dir = this.dirname(destination);
|
|
3077
|
-
this.mkdir(dir, { recursive: true });
|
|
3078
3077
|
if (platform === "puerts" && typeof CS !== "undefined") {
|
|
3078
|
+
if (isPuertsReparsePoint(source) || isPuertsReparsePoint(destination) || containsPuertsReparsePoint(dir) || containsPuertsReparsePoint(this.dirname(source))) {
|
|
3079
|
+
throw new Error(
|
|
3080
|
+
`Refusing to copy through a reparse point (symlink/junction): '${source}' -> '${destination}'; resolve the link or copy inside it explicitly`
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3083
|
+
this.mkdir(dir, { recursive: true });
|
|
3079
3084
|
CS.System.IO.File.Copy(source, destination, true);
|
|
3080
3085
|
return;
|
|
3081
3086
|
}
|
|
3087
|
+
this.mkdir(dir, { recursive: true });
|
|
3082
3088
|
const fs = nodeRequire("fs");
|
|
3083
3089
|
fs.copyFileSync(source, destination);
|
|
3084
3090
|
}
|
|
@@ -3093,14 +3099,39 @@ var FileSystemGateway = class {
|
|
|
3093
3099
|
this.validatePath(destination, "rename");
|
|
3094
3100
|
const platform = detectPlatform();
|
|
3095
3101
|
const dir = this.dirname(destination);
|
|
3096
|
-
this.mkdir(dir, { recursive: true });
|
|
3097
3102
|
if (platform === "puerts" && typeof CS !== "undefined") {
|
|
3103
|
+
if (isPuertsReparsePoint(source) || isPuertsReparsePoint(destination) || containsPuertsReparsePoint(dir) || containsPuertsReparsePoint(this.dirname(source))) {
|
|
3104
|
+
throw new Error(
|
|
3105
|
+
`Refusing to rename through a reparse point (symlink/junction): '${source}' -> '${destination}'; resolve the link or move inside it explicitly`
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
this.mkdir(dir, { recursive: true });
|
|
3109
|
+
if (!CS.System.IO.File.Exists(source)) {
|
|
3110
|
+
throw new Error(`File not found: ${source}`);
|
|
3111
|
+
}
|
|
3112
|
+
if (this.normalizePath(source) === this.normalizePath(destination)) {
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
3098
3115
|
if (CS.System.IO.File.Exists(destination)) {
|
|
3116
|
+
const staged = `${destination}.pie-replace-${Date.now()}.tmp`;
|
|
3117
|
+
CS.System.IO.File.Copy(source, staged, false);
|
|
3099
3118
|
CS.System.IO.File.Delete(destination);
|
|
3119
|
+
try {
|
|
3120
|
+
CS.System.IO.File.Move(staged, destination);
|
|
3121
|
+
} catch (error) {
|
|
3122
|
+
try {
|
|
3123
|
+
CS.System.IO.File.Move(staged, destination);
|
|
3124
|
+
} catch {
|
|
3125
|
+
}
|
|
3126
|
+
throw error;
|
|
3127
|
+
}
|
|
3128
|
+
CS.System.IO.File.Delete(source);
|
|
3129
|
+
return;
|
|
3100
3130
|
}
|
|
3101
3131
|
CS.System.IO.File.Move(source, destination);
|
|
3102
3132
|
return;
|
|
3103
3133
|
}
|
|
3134
|
+
this.mkdir(dir, { recursive: true });
|
|
3104
3135
|
const fs = nodeRequire("fs");
|
|
3105
3136
|
fs.renameSync(source, destination);
|
|
3106
3137
|
}
|
|
@@ -3170,8 +3201,8 @@ var FileSystemGateway = class {
|
|
|
3170
3201
|
throw new Error(`Directory not found: ${source}`);
|
|
3171
3202
|
}
|
|
3172
3203
|
if (CS.System.IO.Directory.Exists(destination)) {
|
|
3173
|
-
const destinationFiles =
|
|
3174
|
-
const destinationDirs =
|
|
3204
|
+
const destinationFiles = csharpStringArray(CS.System.IO.Directory.GetFiles(destination));
|
|
3205
|
+
const destinationDirs = csharpStringArray(CS.System.IO.Directory.GetDirectories(destination));
|
|
3175
3206
|
const isEmpty = destinationFiles.length === 0 && destinationDirs.length === 0;
|
|
3176
3207
|
if (!isEmpty) {
|
|
3177
3208
|
throw new Error(`Move target already exists: ${destination}`);
|
|
@@ -3225,14 +3256,10 @@ var FileSystemGateway = class {
|
|
|
3225
3256
|
}
|
|
3226
3257
|
const files = CS.System.IO.Directory.GetFiles(path);
|
|
3227
3258
|
const dirs = CS.System.IO.Directory.GetDirectories(path);
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
for (let i = 0; i < dirs.Length; i++) {
|
|
3233
|
-
result.push(this.basename(dirs[i]));
|
|
3234
|
-
}
|
|
3235
|
-
return result;
|
|
3259
|
+
return [
|
|
3260
|
+
...csharpStringArray(files).map((entry) => this.basename(entry)),
|
|
3261
|
+
...csharpStringArray(dirs).map((entry) => this.basename(entry))
|
|
3262
|
+
];
|
|
3236
3263
|
}
|
|
3237
3264
|
const fs = nodeRequire("fs");
|
|
3238
3265
|
if (!fs.existsSync(path)) {
|
|
@@ -3303,6 +3330,21 @@ var FileSystemGateway = class {
|
|
|
3303
3330
|
return this.config;
|
|
3304
3331
|
}
|
|
3305
3332
|
};
|
|
3333
|
+
function csharpStringArray(value) {
|
|
3334
|
+
if (Array.isArray(value)) {
|
|
3335
|
+
return value.map((entry) => String(entry ?? ""));
|
|
3336
|
+
}
|
|
3337
|
+
if (value && typeof value.Length === "number") {
|
|
3338
|
+
const array = value;
|
|
3339
|
+
const results = [];
|
|
3340
|
+
for (let i = 0; i < array.Length; i++) {
|
|
3341
|
+
const entry = typeof array.get_Item === "function" ? array.get_Item(i) : array[i];
|
|
3342
|
+
results.push(String(entry ?? ""));
|
|
3343
|
+
}
|
|
3344
|
+
return results;
|
|
3345
|
+
}
|
|
3346
|
+
return [];
|
|
3347
|
+
}
|
|
3306
3348
|
function movePuertsDirectoryContents(source, destination) {
|
|
3307
3349
|
const directory = CS.System.IO.Directory;
|
|
3308
3350
|
const file = CS.System.IO.File;
|
|
@@ -3317,16 +3359,16 @@ function movePuertsDirectoryContents(source, destination) {
|
|
|
3317
3359
|
);
|
|
3318
3360
|
}
|
|
3319
3361
|
directory.CreateDirectory(destination);
|
|
3320
|
-
for (const entry of
|
|
3362
|
+
for (const entry of csharpStringArray(directory.GetFiles(source))) {
|
|
3321
3363
|
const name = String(entry).replace(/\\/g, "/").split("/").pop();
|
|
3322
3364
|
file.Copy(String(entry), `${destination}/${name}`, true);
|
|
3323
3365
|
}
|
|
3324
|
-
for (const subdir of
|
|
3366
|
+
for (const subdir of csharpStringArray(directory.GetDirectories(source))) {
|
|
3325
3367
|
const name = String(subdir).replace(/\\/g, "/").split("/").pop();
|
|
3326
3368
|
if (isPuertsReparsePoint(String(subdir))) continue;
|
|
3327
3369
|
movePuertsDirectoryContents(String(subdir), `${destination}/${name}`);
|
|
3328
3370
|
}
|
|
3329
|
-
for (const entry of
|
|
3371
|
+
for (const entry of csharpStringArray(directory.GetFiles(source))) {
|
|
3330
3372
|
try {
|
|
3331
3373
|
file.Delete(String(entry));
|
|
3332
3374
|
} catch {
|
|
@@ -3341,7 +3383,7 @@ function isPuertsReparsePoint(path) {
|
|
|
3341
3383
|
warnedMissingPuertsGetAttributes = true;
|
|
3342
3384
|
try {
|
|
3343
3385
|
console.warn(
|
|
3344
|
-
"[platform] File.GetAttributes is unbound on this host; directory symlink checks are disabled (move/delete follow links)"
|
|
3386
|
+
"[platform] File.GetAttributes is unbound on this host; directory symlink checks are disabled (move/delete/copy follow links)"
|
|
3345
3387
|
);
|
|
3346
3388
|
} catch {
|
|
3347
3389
|
}
|
|
@@ -3358,6 +3400,42 @@ function isPuertsReparsePoint(path) {
|
|
|
3358
3400
|
return false;
|
|
3359
3401
|
}
|
|
3360
3402
|
}
|
|
3403
|
+
function containsPuertsReparsePoint(directory) {
|
|
3404
|
+
const slashed = directory.replace(/\\/g, "/");
|
|
3405
|
+
const trimmed = slashed.replace(/\/+$/, "");
|
|
3406
|
+
if (!trimmed || trimmed === "/") return false;
|
|
3407
|
+
const unc = /^\/\/([^/]+)\/([^/]+)/.exec(trimmed);
|
|
3408
|
+
let prefix;
|
|
3409
|
+
let rest;
|
|
3410
|
+
if (unc) {
|
|
3411
|
+
prefix = unc[0];
|
|
3412
|
+
rest = trimmed.slice(prefix.length);
|
|
3413
|
+
} else {
|
|
3414
|
+
const driveRoot = /^([a-zA-Z]:)\//.exec(trimmed);
|
|
3415
|
+
if (driveRoot) {
|
|
3416
|
+
prefix = `${driveRoot[1]}/`;
|
|
3417
|
+
rest = trimmed.slice(prefix.length);
|
|
3418
|
+
} else {
|
|
3419
|
+
const bareDrive = /^[a-zA-Z]:$/.test(trimmed);
|
|
3420
|
+
if (bareDrive) {
|
|
3421
|
+
return isPuertsReparsePoint(trimmed);
|
|
3422
|
+
}
|
|
3423
|
+
if (trimmed.startsWith("/")) {
|
|
3424
|
+
prefix = "/";
|
|
3425
|
+
rest = trimmed.slice(1);
|
|
3426
|
+
} else {
|
|
3427
|
+
prefix = "";
|
|
3428
|
+
rest = trimmed;
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
let current = prefix;
|
|
3433
|
+
for (const part of rest.split("/").filter((segment) => segment.length > 0 && segment !== ".")) {
|
|
3434
|
+
current = current ? current.endsWith("/") ? `${current}${part}` : `${current}/${part}` : part;
|
|
3435
|
+
if (isPuertsReparsePoint(current)) return true;
|
|
3436
|
+
}
|
|
3437
|
+
return false;
|
|
3438
|
+
}
|
|
3361
3439
|
var warnedPuertsDeletionShells = false;
|
|
3362
3440
|
function warnPuertsDeletionShellsOnce(path) {
|
|
3363
3441
|
if (warnedPuertsDeletionShells) return;
|
|
@@ -3382,8 +3460,8 @@ function deletePuertsDirectoryByEnumeration(path, recursive) {
|
|
|
3382
3460
|
`Refusing to delete '${path}' through a reparse point (symlink/junction); resolve the link or delete it directly`
|
|
3383
3461
|
);
|
|
3384
3462
|
}
|
|
3385
|
-
const files =
|
|
3386
|
-
const subdirs =
|
|
3463
|
+
const files = csharpStringArray(directory.GetFiles(path));
|
|
3464
|
+
const subdirs = csharpStringArray(directory.GetDirectories(path));
|
|
3387
3465
|
if (!recursive) {
|
|
3388
3466
|
if (files.length > 0 || subdirs.length > 0) {
|
|
3389
3467
|
throw new Error(`Directory not empty: ${path}`);
|
|
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from "node:module"; const require =
|
|
|
2
2
|
import {
|
|
3
3
|
Agent,
|
|
4
4
|
getToolCallerIdentity
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XVF6V6Q5.js";
|
|
6
6
|
import {
|
|
7
7
|
AssistantMessageEventStream,
|
|
8
8
|
FileSystemGateway,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
getPlatformConfig,
|
|
13
13
|
hashText,
|
|
14
14
|
streamSimple
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-3VEIP2VY.js";
|
|
16
16
|
import {
|
|
17
17
|
Type
|
|
18
18
|
} from "./chunk-XXGYUYXI.js";
|
|
@@ -1005,7 +1005,7 @@ var PLAN_POWERSHELL_READ_ALIASES = /* @__PURE__ */ new Set(["cat", "ls", "pwd",
|
|
|
1005
1005
|
var PLAN_POWERSHELL_SAFE_PARAMETERS = /^(?:-(?:Raw|TotalCount|Head|Tail|First|Last|Wait|LiteralPath|Path|Name|Pattern|Recurse|Filter|Include|Exclude|SimpleMatch|CaseSensitive|Quiet|Word|Line|Character|Encoding|ErrorAction|WarningAction))$/i;
|
|
1006
1006
|
var PLAN_POWERSHELL_SEPARATORS = /[;\n\r\t]|[<>]{1,2}|\||&&|\|\|/;
|
|
1007
1007
|
var PLAN_POWERSHELL_NON_ASCII = /[^\x20-\x7E]/;
|
|
1008
|
-
var PLAN_POWERSHELL_UNSAFE_TOKENS = /\$\(|`|%\{|[(){}\[\]]|\bsource\b|\.\s+[/~]|\b(bash|sh|zsh|pwsh|powershell|cmd|npm|npx|node|python3
|
|
1008
|
+
var PLAN_POWERSHELL_UNSAFE_TOKENS = /\$\(|`|%\{|[(){}\[\]]|\bsource\b|\.\s+[/~]|\b(bash|sh|zsh|pwsh|powershell|cmd|npm|npx|node|python3?)\b/i;
|
|
1009
1009
|
function isPlanModeSafePowerShellCommand(command) {
|
|
1010
1010
|
const trimmed = command.trim();
|
|
1011
1011
|
if (!trimmed) return false;
|
|
@@ -1015,6 +1015,18 @@ function isPlanModeSafePowerShellCommand(command) {
|
|
|
1015
1015
|
const tokens = trimmed.split(/\s+/).filter(Boolean);
|
|
1016
1016
|
const head = tokens[0].toLowerCase();
|
|
1017
1017
|
if (!head) return false;
|
|
1018
|
+
if (head === "git" || head === "rg") {
|
|
1019
|
+
if (/["']/.test(trimmed)) return false;
|
|
1020
|
+
if (/[$@]/.test(trimmed)) return false;
|
|
1021
|
+
}
|
|
1022
|
+
if (head === "git") {
|
|
1023
|
+
const subcommand = tokens[1]?.toLowerCase() ?? "";
|
|
1024
|
+
if (!GIT_READ_SUBCOMMANDS.has(subcommand)) return false;
|
|
1025
|
+
return !tokens.slice(2).some((token) => UNSAFE_GIT_FLAGS.test(token) || token === "--no-pager" || token === "-c");
|
|
1026
|
+
}
|
|
1027
|
+
if (head === "rg") {
|
|
1028
|
+
return !tokens.slice(1).some((token) => UNSAFE_RG_FLAGS.test(token) || token === "--pre" || token === "--pre-glob");
|
|
1029
|
+
}
|
|
1018
1030
|
if (!PLAN_POWERSHELL_READ_COMMANDS.has(head) && !PLAN_POWERSHELL_READ_ALIASES.has(head)) return false;
|
|
1019
1031
|
for (const token of tokens.slice(1)) {
|
|
1020
1032
|
if (token.startsWith("-") && !PLAN_POWERSHELL_SAFE_PARAMETERS.test(token)) return false;
|
|
@@ -2886,6 +2898,7 @@ var FileSessionStore = class {
|
|
|
2886
2898
|
const heads = [];
|
|
2887
2899
|
for (const name of this.gateway.readdir(this.sessionsDir)) {
|
|
2888
2900
|
if (name.startsWith(STAGING_SESSION_PREFIX)) continue;
|
|
2901
|
+
if (!name.trim()) continue;
|
|
2889
2902
|
const dirPath = this.gateway.join(this.sessionsDir, name);
|
|
2890
2903
|
if (sessionDirIsSymlink(dirPath)) {
|
|
2891
2904
|
console.warn(`[FileSessionStore] Skipping session directory that is a symbolic link: ${dirPath}`);
|
|
@@ -8466,8 +8479,11 @@ var POWERSHELL_DESTRUCTIVE_PATTERNS = [
|
|
|
8466
8479
|
// PowerShell resolves these aliases before execution. The classifier must
|
|
8467
8480
|
// treat the aliases exactly like their canonical cmdlets; otherwise a
|
|
8468
8481
|
// guarded shell can run `ri -Recurse -Force` without the confirmation that
|
|
8469
|
-
// `Remove-Item -Recurse -Force` receives.
|
|
8470
|
-
|
|
8482
|
+
// `Remove-Item -Recurse -Force` receives. PowerShell parameters are
|
|
8483
|
+
// prefix-abbreviatable (`-r` == `-Recurse`, `-fo` == `-Force`), so the
|
|
8484
|
+
// parameter matcher below accepts any unambiguous-style abbreviation,
|
|
8485
|
+
// not just the full spellings.
|
|
8486
|
+
{ pattern: buildPowerShellRemoveItemPattern(), warning: "may recursively or forcefully remove files", commandClass: "filesystem_write" },
|
|
8471
8487
|
{ pattern: /\b(?:Remove-Item|ri|rm|rmdir|del|erase|rd)\b[^;\n|]*(?:HKLM:|HKCU:|Registry::)/i, warning: "may remove registry entries", commandClass: "infra_destructive" },
|
|
8472
8488
|
// These write aliases are not all destructive in the recursive-delete sense,
|
|
8473
8489
|
// but they can overwrite or create arbitrary files. Keep them behind the
|
|
@@ -8481,7 +8497,10 @@ var POWERSHELL_DESTRUCTIVE_PATTERNS = [
|
|
|
8481
8497
|
];
|
|
8482
8498
|
var CMD_DESTRUCTIVE_PATTERNS = [
|
|
8483
8499
|
{ pattern: /\b(del|erase)\b[^&|\n]*(\/s|\/q)/i, warning: "may recursively or quietly delete files", commandClass: "filesystem_write" },
|
|
8484
|
-
|
|
8500
|
+
// `rd` is cmd's documented synonym for rmdir and accepts the same /s /q
|
|
8501
|
+
// switches; classifying only `rmdir` let `rd /s /q C:\\anywhere` run as an
|
|
8502
|
+
// undetected recursive deletion.
|
|
8503
|
+
{ pattern: /\b(?:rmdir|rd)\b[^&|\n]*(\/s|\/q)/i, warning: "may recursively remove directories", commandClass: "filesystem_write" },
|
|
8485
8504
|
{ pattern: /\bformat\s+[a-z]:/i, warning: "may format a drive", commandClass: "infra_destructive" },
|
|
8486
8505
|
{ pattern: /\b(takeown|icacls)\b[^&|\n]*(\/grant|\/reset|\/remove)/i, warning: "may alter ownership or permissions", commandClass: "privilege_escalation" },
|
|
8487
8506
|
{ pattern: /\bgit\s+reset\s+--hard\b/i, warning: "may discard uncommitted changes", commandClass: "git_destructive" },
|
|
@@ -8493,6 +8512,15 @@ function splitCommand(command) {
|
|
|
8493
8512
|
function firstWord(command) {
|
|
8494
8513
|
return command.trim().split(/\s+/)[0] || "";
|
|
8495
8514
|
}
|
|
8515
|
+
function buildPowerShellRemoveItemPattern() {
|
|
8516
|
+
const removeVerb = "(?:Remove-Item|ri|rm|rmdir|del|erase|rd)";
|
|
8517
|
+
const recurseg = "-(?:r(?:e(?:c(?:u(?:r(?:s(?:e?)?)?)?)?)?)?)";
|
|
8518
|
+
const force = "-(?:f(?:o(?:r(?:c(?:e?)?)?)?)?)";
|
|
8519
|
+
return new RegExp(
|
|
8520
|
+
`\\b${removeVerb}\\b[^;\\n|]*(?:${recurseg}|${force})\\b`,
|
|
8521
|
+
"i"
|
|
8522
|
+
);
|
|
8523
|
+
}
|
|
8496
8524
|
function lastPipelineCommand(command) {
|
|
8497
8525
|
const segments = command.split("|").map((part) => part.trim()).filter(Boolean);
|
|
8498
8526
|
return segments[segments.length - 1] || command;
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
bindToolCallerIdentity,
|
|
7
7
|
createToolCallerIdentity,
|
|
8
8
|
getToolCallerIdentity
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-XVF6V6Q5.js";
|
|
10
|
+
import "./chunk-3VEIP2VY.js";
|
|
11
11
|
import "./chunk-XXGYUYXI.js";
|
|
12
12
|
import "./chunk-LZQXQOPJ.js";
|
|
13
13
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
EventStream
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3VEIP2VY.js";
|
|
5
5
|
import "./chunk-XXGYUYXI.js";
|
|
6
6
|
import "./chunk-LZQXQOPJ.js";
|
|
7
7
|
|
package/dist/cli.js
CHANGED
|
@@ -22,8 +22,9 @@ import {
|
|
|
22
22
|
getThemesDir,
|
|
23
23
|
logTransportLifecycle,
|
|
24
24
|
migrateConfigFromAgentDir,
|
|
25
|
+
setYoloGrantListener,
|
|
25
26
|
truncateHeadTail
|
|
26
|
-
} from "./chunks/chunk-
|
|
27
|
+
} from "./chunks/chunk-3NFKVBGY.js";
|
|
27
28
|
import {
|
|
28
29
|
resolveCliProjectRoot
|
|
29
30
|
} from "./chunks/chunk-WLFOBECN.js";
|
|
@@ -88,8 +89,8 @@ import {
|
|
|
88
89
|
shouldPreserveExecutionStateForUserText,
|
|
89
90
|
supersedeExecutionState,
|
|
90
91
|
verifyPreparedCompactionCommit
|
|
91
|
-
} from "./chunks/chunk-
|
|
92
|
-
import "./chunks/chunk-
|
|
92
|
+
} from "./chunks/chunk-XIRBNP2S.js";
|
|
93
|
+
import "./chunks/chunk-XVF6V6Q5.js";
|
|
93
94
|
import {
|
|
94
95
|
Deref,
|
|
95
96
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
@@ -114,7 +115,7 @@ import {
|
|
|
114
115
|
sortToolModelCandidatesByCapability,
|
|
115
116
|
streamSimple,
|
|
116
117
|
type_exports
|
|
117
|
-
} from "./chunks/chunk-
|
|
118
|
+
} from "./chunks/chunk-3VEIP2VY.js";
|
|
118
119
|
import {
|
|
119
120
|
IsArray,
|
|
120
121
|
IsBigInt,
|
|
@@ -59666,6 +59667,13 @@ var SelectList = class {
|
|
|
59666
59667
|
this.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));
|
|
59667
59668
|
this.selectedIndex = 0;
|
|
59668
59669
|
}
|
|
59670
|
+
/** Replace the item set (e.g. a scope toggle) and reset the cursor. */
|
|
59671
|
+
setItems(items) {
|
|
59672
|
+
this.items = items;
|
|
59673
|
+
this.filteredItems = items;
|
|
59674
|
+
this.selectedIndex = 0;
|
|
59675
|
+
if (items[0]) this.onSelectionChange?.(items[0]);
|
|
59676
|
+
}
|
|
59669
59677
|
getVisibleRange() {
|
|
59670
59678
|
const startIndex = Math.max(
|
|
59671
59679
|
0,
|
|
@@ -70004,6 +70012,39 @@ function createCliFileSystemTools(cwd, options) {
|
|
|
70004
70012
|
});
|
|
70005
70013
|
}
|
|
70006
70014
|
|
|
70015
|
+
// src/runtime/yolo-grant.ts
|
|
70016
|
+
var YoloGrantTracker = class {
|
|
70017
|
+
untilMs = 0;
|
|
70018
|
+
isActive(now = Date.now()) {
|
|
70019
|
+
return this.untilMs > now;
|
|
70020
|
+
}
|
|
70021
|
+
award(grantMs, now = Date.now()) {
|
|
70022
|
+
this.untilMs = now + Math.max(0, grantMs);
|
|
70023
|
+
}
|
|
70024
|
+
expire() {
|
|
70025
|
+
this.untilMs = 0;
|
|
70026
|
+
}
|
|
70027
|
+
/** Expiry timestamp (0 when no grant is held); useful for display. */
|
|
70028
|
+
get until() {
|
|
70029
|
+
return this.untilMs;
|
|
70030
|
+
}
|
|
70031
|
+
};
|
|
70032
|
+
function renderYoloGrantBanner(grantMs, sink) {
|
|
70033
|
+
const minutes = Math.max(1, Math.round(grantMs / 6e4));
|
|
70034
|
+
sink.addChild(new Spacer(1));
|
|
70035
|
+
sink.addChild(
|
|
70036
|
+
new Text(theme.fg("warning", `\u26A0\uFE0F YOLO granted for ${minutes} min (high-risk commands skip confirmation)`), 1, 0)
|
|
70037
|
+
);
|
|
70038
|
+
sink.addChild(new Spacer(1));
|
|
70039
|
+
}
|
|
70040
|
+
function parseYoloGrantMs(options, selected) {
|
|
70041
|
+
const yoloOption = options.find((option) => /^\s*yolo(\s*\(|\s|$)/i.test(option));
|
|
70042
|
+
if (!yoloOption || selected !== yoloOption) return void 0;
|
|
70043
|
+
const minutesMatch = /\(\s*(\d+(?:\.\d+)?)\s*min/i.exec(yoloOption);
|
|
70044
|
+
const minutes = minutesMatch ? Number(minutesMatch[1]) : 5;
|
|
70045
|
+
return Math.round(minutes * 6e4);
|
|
70046
|
+
}
|
|
70047
|
+
|
|
70007
70048
|
// src/execution/state-manager.ts
|
|
70008
70049
|
function getTextFromMessageContent(content) {
|
|
70009
70050
|
if (typeof content === "string") {
|
|
@@ -70502,6 +70543,14 @@ function normalizeForComparison(value, flavor) {
|
|
|
70502
70543
|
const withoutTrailingSeparators = normalized.length > root.length ? normalized.replace(flavor === "windows" ? /[\\/]+$/ : /\/+$/, "") : normalized;
|
|
70503
70544
|
return flavor === "windows" ? withoutTrailingSeparators.toLowerCase() : withoutTrailingSeparators;
|
|
70504
70545
|
}
|
|
70546
|
+
function sessionBelongsToCwd(sessionCwd, currentCwd) {
|
|
70547
|
+
if (typeof sessionCwd !== "string" || sessionCwd.length === 0) return true;
|
|
70548
|
+
if (!currentCwd) return true;
|
|
70549
|
+
const sessionFlavor = getPathFlavor(sessionCwd, currentCwd);
|
|
70550
|
+
const currentFlavor = getPathFlavor(currentCwd, sessionCwd);
|
|
70551
|
+
if (sessionFlavor !== currentFlavor) return false;
|
|
70552
|
+
return normalizeForComparison(sessionCwd, sessionFlavor) === normalizeForComparison(currentCwd, currentFlavor);
|
|
70553
|
+
}
|
|
70505
70554
|
function formatSessionCwdTag(sessionCwd, currentCwd, homeDir) {
|
|
70506
70555
|
if (typeof sessionCwd !== "string" || sessionCwd.length === 0 || !currentCwd) return void 0;
|
|
70507
70556
|
const sessionFlavor = getPathFlavor(sessionCwd, currentCwd);
|
|
@@ -70527,31 +70576,47 @@ var SessionSelectorComponent = class extends Container {
|
|
|
70527
70576
|
callbacks;
|
|
70528
70577
|
options;
|
|
70529
70578
|
items;
|
|
70579
|
+
/** All sessions ever handed to the selector; the visible list is the current scope's filter. */
|
|
70580
|
+
allSessions;
|
|
70581
|
+
globalScope;
|
|
70530
70582
|
refreshAttempted = /* @__PURE__ */ new Set();
|
|
70531
70583
|
refreshInFlight = false;
|
|
70532
70584
|
refreshQueue = [];
|
|
70533
70585
|
refreshQueued = /* @__PURE__ */ new Set();
|
|
70534
70586
|
refreshTimer;
|
|
70535
70587
|
destroyed = false;
|
|
70588
|
+
titleText;
|
|
70589
|
+
hintText;
|
|
70536
70590
|
constructor(sessions, callbacks, options = {}) {
|
|
70537
70591
|
super();
|
|
70538
70592
|
this.sessions = sessions;
|
|
70593
|
+
this.allSessions = sessions;
|
|
70594
|
+
this.globalScope = options.globalScope ?? false;
|
|
70539
70595
|
this.callbacks = callbacks;
|
|
70540
70596
|
this.options = options;
|
|
70541
|
-
const
|
|
70542
|
-
|
|
70543
|
-
this.
|
|
70597
|
+
const scoped = this.globalScope ? sessions : sessions.filter((session) => sessionBelongsToCwd(session.cwd, options.currentCwd));
|
|
70598
|
+
this.sessions = scoped;
|
|
70599
|
+
const title = this.isWindowTruncated() ? `Resume Session (recent ${scoped.length} of ${options.totalCount})` : "Resume Session";
|
|
70600
|
+
this.titleText = new Text(theme.bold(theme.fg("accent", title)), 0, 0);
|
|
70601
|
+
this.addChild(this.titleText);
|
|
70544
70602
|
this.addChild(new Spacer(1));
|
|
70545
|
-
this.items =
|
|
70603
|
+
this.items = scoped.map((session) => this.createItem(session));
|
|
70546
70604
|
this.selectList = new SelectList(
|
|
70547
70605
|
this.items,
|
|
70548
|
-
|
|
70606
|
+
8,
|
|
70549
70607
|
{
|
|
70550
70608
|
selectedPrefix: (text) => theme.fg("accent", text),
|
|
70551
70609
|
selectedText: (text) => theme.fg("accent", text),
|
|
70552
70610
|
description: (text) => theme.fg("muted", text),
|
|
70553
70611
|
scrollInfo: (text) => theme.fg("dim", text),
|
|
70554
|
-
noMatch
|
|
70612
|
+
// The noMatch hook carries the empty-directory-scope copy (SelectList
|
|
70613
|
+
// hardcodes "No matching commands", which is wrong for sessions).
|
|
70614
|
+
// When the loaded list is a truncated recent window, `g` cannot show
|
|
70615
|
+
// this directory's older sessions either — promise nothing it can't do.
|
|
70616
|
+
noMatch: () => theme.fg(
|
|
70617
|
+
"dim",
|
|
70618
|
+
this.options.totalCount !== void 0 && this.options.totalCount > this.allSessions.length ? " No recent sessions in this directory" : " No sessions in this directory \xB7 g shows all sessions"
|
|
70619
|
+
)
|
|
70555
70620
|
}
|
|
70556
70621
|
);
|
|
70557
70622
|
this.selectList.onSelect = (item) => {
|
|
@@ -70569,14 +70634,49 @@ var SessionSelectorComponent = class extends Container {
|
|
|
70569
70634
|
};
|
|
70570
70635
|
this.addChild(this.selectList);
|
|
70571
70636
|
this.addChild(new Spacer(1));
|
|
70572
|
-
this.
|
|
70573
|
-
|
|
70574
|
-
);
|
|
70637
|
+
this.hintText = new Text(theme.fg("dim", this.buildHintLine()), 0, 0);
|
|
70638
|
+
this.addChild(this.hintText);
|
|
70575
70639
|
this.scheduleVisibleRefreshes();
|
|
70576
70640
|
}
|
|
70641
|
+
/** True when the visible list is the unfiltered window AND that window is
|
|
70642
|
+
* truncated vs the disk total (only then does "recent N of M" describe it). */
|
|
70643
|
+
isWindowTruncated() {
|
|
70644
|
+
return this.sessions.length === this.allSessions.length && this.options.totalCount !== void 0 && this.options.totalCount > this.allSessions.length;
|
|
70645
|
+
}
|
|
70646
|
+
/** Shared count expression so the title and the `g` hint never disagree. */
|
|
70647
|
+
scopeCountText(count) {
|
|
70648
|
+
return this.options.totalCount !== void 0 && this.options.totalCount > count ? `recent ${count} of ${this.options.totalCount}` : `all ${count}`;
|
|
70649
|
+
}
|
|
70650
|
+
buildHintLine() {
|
|
70651
|
+
const scopeNote = this.globalScope ? `${this.scopeCountText(this.allSessions.length)} sessions` : `${this.sessions.length} in this directory`;
|
|
70652
|
+
return ` \u2191\u2193 navigate \xB7 \u2190\u2192 page \xB7 g global (${scopeNote}) \xB7 Enter select \xB7 Esc cancel`;
|
|
70653
|
+
}
|
|
70577
70654
|
handleInput(data) {
|
|
70655
|
+
if (this.destroyed) return;
|
|
70656
|
+
if (data === "g" || data === "G") {
|
|
70657
|
+
this.toggleScope();
|
|
70658
|
+
return;
|
|
70659
|
+
}
|
|
70578
70660
|
this.selectList.handleInput(data);
|
|
70579
70661
|
}
|
|
70662
|
+
/** Toggle between current-directory sessions and the full loaded recent list. */
|
|
70663
|
+
toggleScope() {
|
|
70664
|
+
if (this.destroyed) return;
|
|
70665
|
+
this.globalScope = !this.globalScope;
|
|
70666
|
+
this.sessions = this.globalScope ? this.allSessions : this.allSessions.filter((session) => sessionBelongsToCwd(session.cwd, this.options.currentCwd));
|
|
70667
|
+
this.items = this.sessions.map((session) => this.createItem(session));
|
|
70668
|
+
this.selectList.setItems(this.items);
|
|
70669
|
+
this.updateTitle();
|
|
70670
|
+
this.updateHint();
|
|
70671
|
+
this.scheduleVisibleRefreshes();
|
|
70672
|
+
}
|
|
70673
|
+
updateTitle() {
|
|
70674
|
+
const windowText = this.isWindowTruncated() ? ` (recent ${this.sessions.length} of ${this.options.totalCount})` : "";
|
|
70675
|
+
this.titleText.setText(theme.bold(theme.fg("accent", `Resume Session${windowText}`)));
|
|
70676
|
+
}
|
|
70677
|
+
updateHint() {
|
|
70678
|
+
this.hintText.setText(theme.fg("dim", this.buildHintLine()));
|
|
70679
|
+
}
|
|
70580
70680
|
getSelectList() {
|
|
70581
70681
|
return this.selectList;
|
|
70582
70682
|
}
|
|
@@ -70584,10 +70684,11 @@ var SessionSelectorComponent = class extends Container {
|
|
|
70584
70684
|
const cwdTag = formatSessionCwdTag(session.cwd, this.options.currentCwd, this.options.homeDir);
|
|
70585
70685
|
const unknownTag = cwdTag === void 0 && this.options.currentCwd && !(typeof session.cwd === "string" && session.cwd.length > 0) ? "unknown path" : void 0;
|
|
70586
70686
|
const tag = cwdTag ?? unknownTag;
|
|
70687
|
+
const meta = `${session.id} \xB7 ${session.messageCount} messages \xB7 ${formatDate(session.updatedAt)}`;
|
|
70587
70688
|
return {
|
|
70588
70689
|
value: session.id,
|
|
70589
70690
|
label: session.name || `Session ${session.id.slice(0, 8)}`,
|
|
70590
|
-
description: tag ? `${tag} \xB7 ${
|
|
70691
|
+
description: tag ? `${tag} \xB7 ${meta}` : meta
|
|
70591
70692
|
};
|
|
70592
70693
|
}
|
|
70593
70694
|
clearRefreshTimer() {
|
|
@@ -70634,6 +70735,8 @@ var SessionSelectorComponent = class extends Container {
|
|
|
70634
70735
|
updateItem(metadata) {
|
|
70635
70736
|
const sessionIndex = this.sessions.findIndex((session) => session.id === metadata.id);
|
|
70636
70737
|
if (sessionIndex >= 0) this.sessions[sessionIndex] = metadata;
|
|
70738
|
+
const allIndex = this.allSessions.findIndex((session) => session.id === metadata.id);
|
|
70739
|
+
if (allIndex >= 0) this.allSessions[allIndex] = metadata;
|
|
70637
70740
|
const itemIndex = this.items.findIndex((item2) => item2.value === metadata.id);
|
|
70638
70741
|
if (itemIndex < 0) return;
|
|
70639
70742
|
const nextItem = this.createItem(metadata);
|
|
@@ -72622,8 +72725,8 @@ async function handleResumeCommand(host) {
|
|
|
72622
72725
|
host.showSelector((done) => {
|
|
72623
72726
|
const selector = new SessionSelectorComponent(sessions, {
|
|
72624
72727
|
onSelect: async (sessionId) => {
|
|
72625
|
-
await host.loadSession(sessionId);
|
|
72626
72728
|
done();
|
|
72729
|
+
await host.loadSession(sessionId);
|
|
72627
72730
|
},
|
|
72628
72731
|
onCancel: () => {
|
|
72629
72732
|
done();
|
|
@@ -72635,7 +72738,7 @@ async function handleResumeCommand(host) {
|
|
|
72635
72738
|
requestRender: () => host.ui.requestRender(),
|
|
72636
72739
|
totalCount
|
|
72637
72740
|
});
|
|
72638
|
-
return { component: selector, focus: selector
|
|
72741
|
+
return { component: selector, focus: selector };
|
|
72639
72742
|
});
|
|
72640
72743
|
}
|
|
72641
72744
|
async function loadSession(host, sessionId) {
|
|
@@ -76373,6 +76476,7 @@ function cleanupAndExit(host) {
|
|
|
76373
76476
|
exitingHosts.add(host);
|
|
76374
76477
|
console.log("\n[Cleanup] Stopping file status monitor...");
|
|
76375
76478
|
const shutdown = shutdownInteractiveHost(host);
|
|
76479
|
+
const sessionId = host.sessionManager?.getActiveSessionId();
|
|
76376
76480
|
void (async () => {
|
|
76377
76481
|
try {
|
|
76378
76482
|
await shutdown;
|
|
@@ -76380,7 +76484,7 @@ function cleanupAndExit(host) {
|
|
|
76380
76484
|
console.error("Interactive shutdown failed:", error);
|
|
76381
76485
|
process.exitCode = 1;
|
|
76382
76486
|
}
|
|
76383
|
-
console.log(
|
|
76487
|
+
console.log(`[Cleanup] Goodbye!${sessionId ? ` session: ${sessionId}` : ""}`);
|
|
76384
76488
|
process.exit(process.exitCode || 0);
|
|
76385
76489
|
})();
|
|
76386
76490
|
}
|
|
@@ -80502,6 +80606,13 @@ function restoreEditor(host) {
|
|
|
80502
80606
|
host.ui.invalidate();
|
|
80503
80607
|
host.ui.requestRender();
|
|
80504
80608
|
}
|
|
80609
|
+
function showMissingModelConfigurationNotice(host) {
|
|
80610
|
+
const message = "No model configured. Add one in ~/.pie/models.json, then use /settings/model.";
|
|
80611
|
+
host.chatContainer.addChild(new Spacer(1));
|
|
80612
|
+
host.chatContainer.addChild(new Text(theme.fg("warning", `\u26A0 ${message}`), 1, 0));
|
|
80613
|
+
host.chatContainer.addChild(new Spacer(1));
|
|
80614
|
+
host.showStatus(message);
|
|
80615
|
+
}
|
|
80505
80616
|
|
|
80506
80617
|
// src/runtime/interactive-continuation.ts
|
|
80507
80618
|
function getContinuationTimeoutMs() {
|
|
@@ -81266,7 +81377,7 @@ function createInteractiveExtensionUIContext(host) {
|
|
|
81266
81377
|
return {
|
|
81267
81378
|
notify: (message, type = "info", opts) => showExtensionNotification(host, message, type, opts),
|
|
81268
81379
|
select: (title, options, opts) => interact(() => showExtensionSelector2(host, title, options, opts)),
|
|
81269
|
-
confirm: async (title, message, opts) => await interact(() => showExtensionConfirm(host, title, message, opts)) === true,
|
|
81380
|
+
confirm: async (title, message, opts) => (await interact(() => showExtensionConfirm(host, title, message, opts)))?.confirmed === true,
|
|
81270
81381
|
input: (title, placeholder, opts) => interact(() => showExtensionInput(host, title, placeholder, opts)),
|
|
81271
81382
|
editor: (title, prefill) => interact(() => showExtensionEditor(host, title, prefill)),
|
|
81272
81383
|
custom: (factory, options) => interact(() => showExtensionCustom(host, factory, options)),
|
|
@@ -81365,15 +81476,28 @@ function installInteractiveInteractionHandler(host) {
|
|
|
81365
81476
|
prompt: request.prompt,
|
|
81366
81477
|
detail: request.detail
|
|
81367
81478
|
});
|
|
81368
|
-
const { value
|
|
81369
|
-
(signal) => showExtensionConfirm(host, request.prompt, request.detail ?? "", {
|
|
81479
|
+
const { value, timedOut } = await waitForUser(
|
|
81480
|
+
(signal) => showExtensionConfirm(host, request.prompt, request.detail ?? "", {
|
|
81481
|
+
signal,
|
|
81482
|
+
options: request.options
|
|
81483
|
+
})
|
|
81370
81484
|
);
|
|
81485
|
+
const confirmed = value?.confirmed;
|
|
81486
|
+
const yoloGrantMs = value?.yoloGrantMs;
|
|
81371
81487
|
host.logDebug("interaction:confirm:end", {
|
|
81372
81488
|
id: request.id,
|
|
81373
81489
|
confirmed,
|
|
81490
|
+
yoloGrantMs,
|
|
81374
81491
|
timedOut
|
|
81375
81492
|
});
|
|
81376
|
-
return {
|
|
81493
|
+
return {
|
|
81494
|
+
type: "confirm",
|
|
81495
|
+
id: request.id,
|
|
81496
|
+
confirmed: confirmed === true,
|
|
81497
|
+
timedOut,
|
|
81498
|
+
skipped: timedOut || confirmed === void 0,
|
|
81499
|
+
yoloGrantMs
|
|
81500
|
+
};
|
|
81377
81501
|
}
|
|
81378
81502
|
case "text_input": {
|
|
81379
81503
|
host.logDebug("interaction:text_input:start", {
|
|
@@ -81467,9 +81591,15 @@ function showExtensionSelector2(host, title, options, opts) {
|
|
|
81467
81591
|
});
|
|
81468
81592
|
}
|
|
81469
81593
|
async function showExtensionConfirm(host, title, message, opts) {
|
|
81594
|
+
const options = opts?.options?.length ? opts.options : ["Yes", "No"];
|
|
81470
81595
|
const result = await showExtensionSelector2(host, `${title}
|
|
81471
|
-
${message}`,
|
|
81472
|
-
|
|
81596
|
+
${message}`, options, opts);
|
|
81597
|
+
if (result === void 0) return void 0;
|
|
81598
|
+
const yoloGrantMs = parseYoloGrantMs(options, result);
|
|
81599
|
+
if (yoloGrantMs !== void 0) {
|
|
81600
|
+
return { confirmed: true, yoloGrantMs };
|
|
81601
|
+
}
|
|
81602
|
+
return { confirmed: result === "Yes" };
|
|
81473
81603
|
}
|
|
81474
81604
|
function showExtensionInput(host, title, placeholder, opts) {
|
|
81475
81605
|
return new Promise((resolve7) => {
|
|
@@ -82017,6 +82147,8 @@ var InteractiveMode = class {
|
|
|
82017
82147
|
mentionPickerOptions = [];
|
|
82018
82148
|
attachmentResolver;
|
|
82019
82149
|
yoloMode = false;
|
|
82150
|
+
yoloGrant = new YoloGrantTracker();
|
|
82151
|
+
// time-boxed confirm-dialog grant ("Yolo (5 min)")
|
|
82020
82152
|
pristineTools = [];
|
|
82021
82153
|
// Pristine (extension-unwrapped) tool assembly: the mode-rebuild source.
|
|
82022
82154
|
/** Calm mode: render only questions and answers (display-only; persisted). */
|
|
@@ -82108,16 +82240,9 @@ var InteractiveMode = class {
|
|
|
82108
82240
|
hasConfiguredModel() {
|
|
82109
82241
|
return Boolean(this.options.apiKey) && this.options.model?.provider !== "unconfigured";
|
|
82110
82242
|
}
|
|
82111
|
-
showMissingModelConfigurationNotice() {
|
|
82112
|
-
const message = "No model configured. Add one in ~/.pie/models.json, then use /settings/model.";
|
|
82113
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
82114
|
-
this.chatContainer.addChild(new Text(theme.fg("warning", `\u26A0 ${message}`), 1, 0));
|
|
82115
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
82116
|
-
this.showStatus(message);
|
|
82117
|
-
}
|
|
82118
82243
|
ensureAgentPromptReady() {
|
|
82119
82244
|
if (this.hasConfiguredModel()) return true;
|
|
82120
|
-
this.
|
|
82245
|
+
showMissingModelConfigurationNotice(this.filePipelineHost);
|
|
82121
82246
|
this.safeRequestRender();
|
|
82122
82247
|
return false;
|
|
82123
82248
|
}
|
|
@@ -82177,14 +82302,17 @@ var InteractiveMode = class {
|
|
|
82177
82302
|
}
|
|
82178
82303
|
getPolicyContext = () => ({
|
|
82179
82304
|
mode: this.planModeEnabled ? "plan" : "normal",
|
|
82180
|
-
yoloMode: this.yoloMode,
|
|
82305
|
+
yoloMode: this.yoloMode || this.yoloGrant.isActive(),
|
|
82181
82306
|
confirmationPolicy: "allow"
|
|
82182
82307
|
});
|
|
82183
82308
|
rebuildSkillAwareTools(sourceTools) {
|
|
82184
82309
|
const preservedTools = sourceTools.filter(
|
|
82185
82310
|
(tool) => !CLI_FILESYSTEM_TOOL_NAMES.includes(tool.name) && tool.name !== "bash" && tool.name !== "shell"
|
|
82186
82311
|
);
|
|
82187
|
-
const bashTool = createBashTool(this.options.cwd, {
|
|
82312
|
+
const bashTool = createBashTool(this.options.cwd, {
|
|
82313
|
+
isYoloMode: () => this.yoloMode || this.yoloGrant.isActive(),
|
|
82314
|
+
getEnv: () => computerUseOwnerEnv(this.sessionManager.getActiveSessionId() || COMPUTER_USE_STANDALONE_OWNER, String(process.pid))
|
|
82315
|
+
});
|
|
82188
82316
|
const fileSystemToolOptions = (allowlistedDirs) => ({
|
|
82189
82317
|
...buildCliFileAccessOptions({
|
|
82190
82318
|
cwd: this.options.cwd,
|
|
@@ -82332,7 +82460,7 @@ var InteractiveMode = class {
|
|
|
82332
82460
|
async init() {
|
|
82333
82461
|
const activeSession = this.sessionManager.getActiveSession();
|
|
82334
82462
|
this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
|
|
82335
|
-
const { Agent } = await import("./chunks/src-
|
|
82463
|
+
const { Agent } = await import("./chunks/src-2RCV3I3P.js");
|
|
82336
82464
|
this.agent = new Agent({
|
|
82337
82465
|
initialState: {
|
|
82338
82466
|
systemPrompt: this.buildSystemPrompt(),
|
|
@@ -82376,7 +82504,7 @@ var InteractiveMode = class {
|
|
|
82376
82504
|
await this.initializeFileManager();
|
|
82377
82505
|
this.syncSessionModelMetadata();
|
|
82378
82506
|
if (!this.hasConfiguredModel()) {
|
|
82379
|
-
this.
|
|
82507
|
+
showMissingModelConfigurationNotice(this.filePipelineHost);
|
|
82380
82508
|
}
|
|
82381
82509
|
}
|
|
82382
82510
|
createExtensionContextForCommands() {
|
|
@@ -82421,6 +82549,11 @@ var InteractiveMode = class {
|
|
|
82421
82549
|
async loadExtensions() {
|
|
82422
82550
|
this.extensionUIContext = createInteractiveExtensionUIContext(this);
|
|
82423
82551
|
installInteractiveInteractionHandler(this);
|
|
82552
|
+
setYoloGrantListener((grantMs) => {
|
|
82553
|
+
this.yoloGrant.award(grantMs);
|
|
82554
|
+
renderYoloGrantBanner(grantMs, this.chatContainer);
|
|
82555
|
+
this.ui.requestRender();
|
|
82556
|
+
});
|
|
82424
82557
|
await loadInteractiveExtensions(this.extensionLoaderHost);
|
|
82425
82558
|
}
|
|
82426
82559
|
/**
|
|
@@ -83210,7 +83343,7 @@ async function runPrintMode(params) {
|
|
|
83210
83343
|
`);
|
|
83211
83344
|
console.log("Assistant: ");
|
|
83212
83345
|
}
|
|
83213
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
83346
|
+
const { Agent: AgentClass } = await import("./chunks/src-2RCV3I3P.js");
|
|
83214
83347
|
let agent;
|
|
83215
83348
|
const printModeExtensions = await loadPrintModeExtensions({
|
|
83216
83349
|
cwd: runtime.cwd,
|
|
@@ -84099,7 +84232,7 @@ async function runJsonEventsMode(params) {
|
|
|
84099
84232
|
return;
|
|
84100
84233
|
}
|
|
84101
84234
|
const parent = agent;
|
|
84102
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
84235
|
+
const { Agent: AgentClass } = await import("./chunks/src-2RCV3I3P.js");
|
|
84103
84236
|
const sideAgent = new AgentClass({
|
|
84104
84237
|
initialState: {
|
|
84105
84238
|
systemPrompt: parent.state.systemPrompt,
|
|
@@ -84459,7 +84592,7 @@ async function runJsonEventsMode(params) {
|
|
|
84459
84592
|
if (runtime.initialModel.unconfigured || controller) {
|
|
84460
84593
|
return;
|
|
84461
84594
|
}
|
|
84462
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
84595
|
+
const { Agent: AgentClass } = await import("./chunks/src-2RCV3I3P.js");
|
|
84463
84596
|
if (runtimeClosing) return;
|
|
84464
84597
|
const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
|
|
84465
84598
|
if (runtimeClosing) {
|
|
@@ -85121,7 +85254,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
|
|
|
85121
85254
|
}
|
|
85122
85255
|
async function createCliTestStreamFnFromEnv() {
|
|
85123
85256
|
if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
|
|
85124
|
-
return (await import("./chunks/test-stream-
|
|
85257
|
+
return (await import("./chunks/test-stream-Y2S3H7DK.js")).createTestStreamFnFromSequenceEnv();
|
|
85125
85258
|
}
|
|
85126
85259
|
function resolveJsonEventsDetailFlag() {
|
|
85127
85260
|
for (let index = 0; index < process.argv.length; index += 1) {
|