@aipack-ai/cli 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,3 @@
1
- // src/cli.ts
2
- import chalk7 from "chalk";
3
-
4
- // src/commands/approvals.ts
5
- import path2 from "path";
6
- import chalk from "chalk";
7
- import { FileApprovalStore, createApprovalManager } from "@aipack-ai/agent";
8
-
9
1
  // src/version.ts
10
2
  import os from "os";
11
3
  import path from "path";
@@ -13,13 +5,13 @@ import path from "path";
13
5
  // package.json
14
6
  var package_default = {
15
7
  name: "@aipack-ai/cli",
16
- version: "0.0.1",
8
+ version: "1.0.0",
17
9
  description: "aipack CLI - \u57FA\u4E8E @aipack-ai/agent \u7684\u7EC8\u7AEF AI \u52A9\u624B",
18
10
  type: "module",
19
11
  main: "./dist/index.js",
20
12
  types: "./dist/index.d.ts",
21
13
  bin: {
22
- aipack: "dist/cli.js"
14
+ aipack: "dist/bin.js"
23
15
  },
24
16
  exports: {
25
17
  ".": {
@@ -33,9 +25,10 @@ var package_default = {
33
25
  ],
34
26
  scripts: {
35
27
  build: "tsup",
36
- prebuild: "pnpm --filter @aipack-ai/agent build",
28
+ prebuild: "[ -f ../agent/dist/index.d.ts ] || pnpm --filter @aipack-ai/agent build",
37
29
  typecheck: "tsc --noEmit",
38
- dev: "tsx src/cli.ts"
30
+ test: "node --import tsx --test test/*.test.ts",
31
+ dev: "tsx src/bin.ts"
39
32
  },
40
33
  keywords: [
41
34
  "cli",
@@ -50,6 +43,7 @@ var package_default = {
50
43
  },
51
44
  dependencies: {
52
45
  "@aipack-ai/agent": "workspace:*",
46
+ "@aipack-ai/compression": "workspace:*",
53
47
  chalk: "^5.3.0"
54
48
  },
55
49
  devDependencies: {
@@ -61,7 +55,7 @@ var package_default = {
61
55
  };
62
56
 
63
57
  // src/version.ts
64
- var APP_NAME = package_default.name.replace(/^@[^/]+\//, "");
58
+ var APP_NAME = Object.keys(package_default.bin ?? {})[0] ?? package_default.name.replace(/^@[^/]+\//, "");
65
59
  var VERSION = package_default.version;
66
60
  function defaultConfigDir() {
67
61
  return process.env.AIPACK_CONFIG_DIR ?? path.join(os.homedir(), ".aipack");
@@ -73,101 +67,6 @@ function encodeDir(p) {
73
67
  return p.replace(/[^a-zA-Z0-9_-]/g, "_");
74
68
  }
75
69
 
76
- // src/commands/approvals.ts
77
- function createStore() {
78
- return new FileApprovalStore({
79
- baseDir: path2.join(defaultConfigDir(), "approvals")
80
- });
81
- }
82
- async function handleApprovalsCommand(args) {
83
- const [sub, ...rest] = args;
84
- if (!sub || sub === "help" || sub === "--help") {
85
- printUsage();
86
- return 0;
87
- }
88
- const store = createStore();
89
- if (sub === "list") {
90
- const pending = await store.load();
91
- if (pending.length === 0) {
92
- console.log(chalk.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\u5355\uFF09"));
93
- return 0;
94
- }
95
- for (const p of pending) {
96
- printApproval(p);
97
- }
98
- return 0;
99
- }
100
- if (sub === "approve" || sub === "deny") {
101
- const id = rest[0];
102
- if (!id) {
103
- console.error(chalk.red(`\u7528\u6CD5: aipack approvals ${sub} <id>`));
104
- return 1;
105
- }
106
- const manager = createApprovalManager({ store });
107
- await manager.restore();
108
- const ok = manager.resolve(id, sub === "approve");
109
- manager.close();
110
- if (!ok) {
111
- console.error(chalk.yellow(`\u5BA1\u6279\u5355 ${id} \u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97`));
112
- return 1;
113
- }
114
- console.log(chalk.green(`\u5DF2${sub === "approve" ? "\u6279\u51C6" : "\u9A73\u56DE"} ${id}`));
115
- return 0;
116
- }
117
- printUsage();
118
- console.error(chalk.red(`\u672A\u77E5\u5B50\u547D\u4EE4: ${sub}`));
119
- return 1;
120
- }
121
- function printApproval(p) {
122
- const created = new Date(p.createdAt).toLocaleString();
123
- const expires = p.expiresAt ? chalk.dim(` \u8FC7\u671F ${new Date(p.expiresAt).toLocaleTimeString()}`) : "";
124
- console.log(`${chalk.cyan(p.id)} ${chalk.bold(p.toolName)} ${chalk.dim(created)}${expires}`);
125
- if (p.permissions.length > 0) {
126
- console.log(chalk.dim(` \u80FD\u529B: ${p.permissions.join(", ")}`));
127
- }
128
- const argsStr = JSON.stringify(p.args);
129
- if (argsStr && argsStr !== "{}") {
130
- console.log(chalk.dim(` \u53C2\u6570: ${argsStr.length > 120 ? `${argsStr.slice(0, 120)}\u2026` : argsStr}`));
131
- }
132
- }
133
- function printUsage() {
134
- console.log(`\u7528\u6CD5:
135
- aipack approvals list \u5217\u51FA\u672A\u51B3\u5BA1\u6279\u5355
136
- aipack approvals approve <id> \u6279\u51C6
137
- aipack approvals deny <id> \u9A73\u56DE`);
138
- }
139
-
140
- // src/commands/models.ts
141
- import chalk2 from "chalk";
142
- import { getBuiltinProviders, getBuiltinModels, hasProviderConfigured } from "@aipack-ai/agent";
143
- function listModels(search) {
144
- const term = typeof search === "string" ? search.toLowerCase() : void 0;
145
- let total = 0;
146
- for (const provider of getBuiltinProviders()) {
147
- const models = getBuiltinModels(provider.id);
148
- const matched = term ? models.filter((m) => m.id.toLowerCase().includes(term) || m.name.toLowerCase().includes(term) || provider.id.includes(term)) : models;
149
- if (matched.length === 0) continue;
150
- const configured = hasProviderConfigured(provider.id);
151
- const badge = configured ? chalk2.green("\u2713") : chalk2.dim("\xB7");
152
- console.log(`${badge} ${chalk2.bold(provider.name)} ${chalk2.dim(`(${provider.id})`)}`);
153
- for (const m of matched) {
154
- const flags = [
155
- m.reasoning ? chalk2.dim("\u63A8\u7406") : null,
156
- `${m.contextWindow / 1e3 | 0}k`
157
- ].filter(Boolean).join(" ");
158
- console.log(` ${m.id.padEnd(44)} ${chalk2.dim(flags)}`);
159
- total++;
160
- }
161
- }
162
- console.log(chalk2.dim(`
163
- \u5171 ${total} \u4E2A\u6A21\u578B\u3002\u2713 = \u5DF2\u914D\u7F6E API Key\uFF08${getEnvHint()}\uFF09`));
164
- return 0;
165
- }
166
- function getEnvHint() {
167
- const provider = getBuiltinProviders().find((p) => hasProviderConfigured(p.id));
168
- return provider ? `${provider.envVar} \u5DF2\u8BBE\u7F6E` : "\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 API Key";
169
- }
170
-
171
70
  // src/args.ts
172
71
  var VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "max"];
173
72
  function isValidThinkingLevel(level) {
@@ -237,6 +136,10 @@ function parseArgs(args) {
237
136
  result.noTools = true;
238
137
  } else if (arg === "--safe") {
239
138
  result.safe = true;
139
+ } else if (arg === "--no-compaction") {
140
+ result.noCompaction = true;
141
+ } else if (arg === "--compaction-config" && i + 1 < args.length) {
142
+ result.compactionConfig = args[++i];
240
143
  } else if (arg === "--print" || arg === "-p") {
241
144
  result.print = true;
242
145
  const next = args[i + 1];
@@ -301,11 +204,13 @@ ${"\u5DE5\u5177\u9009\u9879:"}
301
204
  --no-tools, -nt \u7981\u7528\u5168\u90E8\u5DE5\u5177
302
205
  --safe \u4FDD\u5B88\u6A21\u5F0F\uFF1A\u5199\u6587\u4EF6/shell \u5168\u90E8\u4EBA\u5DE5\u786E\u8BA4
303
206
 
304
- \u5185\u7F6E\u5DE5\u5177: read, write, edit, bash
207
+ \u5185\u7F6E\u5DE5\u5177: read, write, edit, bash, find, grep, ls
305
208
  \u9ED8\u8BA4\u6743\u9650: \u8BFB\u5199\u6587\u4EF6\u9759\u9ED8\u653E\u884C\uFF08\u5DE5\u4F5C\u533A\u8303\u56F4\u5185\uFF09\uFF1Bbash \u4EC5\u5371\u9669\u547D\u4EE4
306
209
  \uFF08sudo\u3001rm -rf ~\u3001\u78C1\u76D8\u5199\u5165\u3001\u8FDC\u7A0B\u811A\u672C\u7BA1\u9053\u7B49\uFF09\u9700\u786E\u8BA4
307
210
 
308
211
  ${"\u5176\u4ED6:"}
212
+ --no-compaction \u5173\u95ED\u4E0A\u4E0B\u6587\u538B\u7F29\uFF08\u957F\u4F1A\u8BDD\u53EF\u80FD\u6EA2\u51FA\uFF09
213
+ --compaction-config <\u6587\u4EF6> \u538B\u7F29\u914D\u7F6E JSON\uFF08\u8986\u76D6\u9ED8\u8BA4\u9608\u503C\uFF09
309
214
  --system-prompt <\u6587\u672C> \u66FF\u6362\u9ED8\u8BA4\u7CFB\u7EDF\u63D0\u793A\u8BCD
310
215
  --append-system-prompt <\u6587\u672C> \u8FFD\u52A0\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u53EF\u591A\u6B21\uFF09
311
216
  --help, -h \u663E\u793A\u5E2E\u52A9
@@ -339,32 +244,13 @@ ${"\u73AF\u5883\u53D8\u91CF:"}
339
244
  `);
340
245
  }
341
246
 
342
- // src/builder.ts
343
- import fs2 from "fs/promises";
344
- import path4 from "path";
345
- import { pathToFileURL } from "url";
346
- import {
347
- createRuntime,
348
- adaptAiModel,
349
- createStreamFnFromAi,
350
- getBuiltinModel,
351
- getBuiltinModels as getBuiltinModels2,
352
- getBuiltinProviders as getBuiltinProviders2,
353
- BUILTIN_PROVIDERS,
354
- hasProviderConfigured as hasProviderConfigured2,
355
- createFileSessionStorage,
356
- createPermissionPolicy,
357
- createApprovalManager as createApprovalManager2,
358
- FileApprovalStore as FileApprovalStore2
359
- } from "@aipack-ai/agent";
360
-
361
247
  // src/tools.ts
362
248
  import fs from "fs/promises";
363
- import path3 from "path";
249
+ import path2 from "path";
364
250
  import { spawn } from "child_process";
365
251
  var workspaceRoot = process.cwd();
366
252
  function resolveInWorkspace(p) {
367
- const abs = path3.resolve(workspaceRoot, p);
253
+ const abs = path2.resolve(workspaceRoot, p);
368
254
  if (!abs.startsWith(workspaceRoot)) {
369
255
  throw new Error(`\u8DEF\u5F84\u8D8A\u754C\uFF1A${p}\uFF08\u5DE5\u4F5C\u533A\uFF1A${workspaceRoot}\uFF09`);
370
256
  }
@@ -430,7 +316,7 @@ var writeTool = {
430
316
  const args = rawArgs;
431
317
  try {
432
318
  const abs = resolveInWorkspace(args.file);
433
- await fs.mkdir(path3.dirname(abs), { recursive: true });
319
+ await fs.mkdir(path2.dirname(abs), { recursive: true });
434
320
  await fs.writeFile(abs, args.content, "utf8");
435
321
  return textResult(`\u5DF2\u5199\u5165 ${args.file}\uFF08${args.content.length} \u5B57\u7B26\uFF09`, { file: args.file });
436
322
  } catch (err) {
@@ -541,7 +427,222 @@ ${stderr.slice(0, MAX_READ_CHARS)}`);
541
427
  }
542
428
  }
543
429
  };
544
- var BUILTIN_TOOLS = [readTool, writeTool, editTool, bashTool];
430
+ var PRUNED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", ".turbo", "coverage"]);
431
+ var MAX_GREP_FILE_BYTES = 2 * 1024 * 1024;
432
+ function globToRegExp(pattern) {
433
+ let re = "";
434
+ for (let i = 0; i < pattern.length; i++) {
435
+ const c = pattern[i];
436
+ if (c === "*") {
437
+ if (pattern[i + 1] === "*") {
438
+ re += ".*";
439
+ i++;
440
+ if (pattern[i + 1] === "/") i++;
441
+ } else {
442
+ re += "[^/]*";
443
+ }
444
+ } else if (c === "?") {
445
+ re += "[^/]";
446
+ } else {
447
+ re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
448
+ }
449
+ }
450
+ return new RegExp(`^${re}$`);
451
+ }
452
+ async function walkFiles(root, maxEntries) {
453
+ const out = [];
454
+ const queue = [""];
455
+ while (queue.length > 0 && out.length < maxEntries) {
456
+ const rel = queue.shift();
457
+ const abs = path2.join(root, rel);
458
+ let entries;
459
+ try {
460
+ entries = await fs.readdir(abs, { withFileTypes: true });
461
+ } catch {
462
+ continue;
463
+ }
464
+ for (const e of entries) {
465
+ if (out.length >= maxEntries) break;
466
+ const childRel = rel ? `${rel}/${e.name}` : e.name;
467
+ if (e.isDirectory()) {
468
+ if (!PRUNED_DIRS.has(e.name)) queue.push(childRel);
469
+ } else if (e.isFile()) {
470
+ out.push(childRel);
471
+ }
472
+ }
473
+ }
474
+ return out;
475
+ }
476
+ var findTool = {
477
+ name: "find",
478
+ description: '\u6309 glob \u6A21\u5F0F\u67E5\u627E\u6587\u4EF6\u3002\u652F\u6301 ** \u8DE8\u76EE\u5F55\u5339\u914D\u3002\u793A\u4F8B: "**/*.ts"\u3001"src/**/*.spec.ts"',
479
+ parameters: {
480
+ type: "object",
481
+ properties: {
482
+ pattern: { type: "string", description: 'glob \u6A21\u5F0F\uFF0C\u5982 "*.md" \u6216 "**/*.ts"' },
483
+ path: { type: "string", description: "\u641C\u7D22\u76EE\u5F55\uFF08\u76F8\u5BF9\u5DE5\u4F5C\u533A\uFF0C\u9ED8\u8BA4 .\uFF09" },
484
+ limit: { type: "number", description: "\u6700\u5927\u7ED3\u679C\u6570\uFF08\u9ED8\u8BA4 1000\uFF09" }
485
+ },
486
+ required: ["pattern"]
487
+ },
488
+ permissions: ["fs:read"],
489
+ async execute(_id, rawArgs) {
490
+ const args = rawArgs;
491
+ const limit = args.limit ?? 1e3;
492
+ try {
493
+ const root = resolveInWorkspace(args.path ?? ".");
494
+ const re = globToRegExp(args.pattern);
495
+ const files = await walkFiles(root, Math.max(limit * 10, 1e4));
496
+ const matches = files.filter((f) => re.test(f));
497
+ const limited = matches.slice(0, limit);
498
+ if (limited.length === 0) {
499
+ return textResult(`\u672A\u627E\u5230\u5339\u914D "${args.pattern}" \u7684\u6587\u4EF6`, { pattern: args.pattern });
500
+ }
501
+ const suffix = matches.length > limited.length ? `
502
+ ...[\u5171 ${matches.length} \u4E2A\uFF0C\u5DF2\u622A\u65AD\u81F3 ${limit}]` : "";
503
+ return textResult(`${limited.join("\n")}${suffix}`, {
504
+ pattern: args.pattern,
505
+ count: matches.length,
506
+ truncated: matches.length > limited.length
507
+ });
508
+ } catch (err) {
509
+ return errorResult(String(err instanceof Error ? err.message : err));
510
+ }
511
+ }
512
+ };
513
+ var grepTool = {
514
+ name: "grep",
515
+ description: "\u5728\u6587\u4EF6\u5185\u5BB9\u4E2D\u641C\u7D22\u6A21\u5F0F\uFF08\u9ED8\u8BA4\u6B63\u5219\uFF09\u3002\u81EA\u52A8\u8DF3\u8FC7\u4E8C\u8FDB\u5236/\u8D85\u5927\u6587\u4EF6\u4E0E node_modules\u3002\u8F93\u51FA file:line: text",
516
+ parameters: {
517
+ type: "object",
518
+ properties: {
519
+ pattern: { type: "string", description: "\u641C\u7D22\u6A21\u5F0F\uFF08\u6B63\u5219\uFF0C\u6216\u914D\u5408 literal \u4F7F\u7528\u5B57\u9762\u91CF\uFF09" },
520
+ path: { type: "string", description: "\u641C\u7D22\u7684\u76EE\u5F55\u6216\u6587\u4EF6\uFF08\u76F8\u5BF9\u5DE5\u4F5C\u533A\uFF0C\u9ED8\u8BA4 .\uFF09" },
521
+ glob: { type: "string", description: '\u6587\u4EF6\u540D\u8FC7\u6EE4 glob\uFF0C\u5982 "*.ts"' },
522
+ ignoreCase: { type: "boolean", description: "\u5FFD\u7565\u5927\u5C0F\u5199\uFF08\u9ED8\u8BA4 false\uFF09" },
523
+ literal: { type: "boolean", description: "\u6309\u5B57\u9762\u91CF\u800C\u975E\u6B63\u5219\u89E3\u91CA pattern\uFF08\u9ED8\u8BA4 false\uFF09" },
524
+ context: { type: "number", description: "\u6BCF\u4E2A\u5339\u914D\u524D\u540E\u663E\u793A\u7684\u884C\u6570\uFF08\u9ED8\u8BA4 0\uFF09" },
525
+ limit: { type: "number", description: "\u6700\u5927\u5339\u914D\u6570\uFF08\u9ED8\u8BA4 100\uFF09" }
526
+ },
527
+ required: ["pattern"]
528
+ },
529
+ permissions: ["fs:read"],
530
+ async execute(_id, rawArgs) {
531
+ const args = rawArgs;
532
+ const limit = args.limit ?? 100;
533
+ const context = args.context ?? 0;
534
+ try {
535
+ const target = resolveInWorkspace(args.path ?? ".");
536
+ const re = new RegExp(
537
+ args.literal ? args.pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") : args.pattern,
538
+ args.ignoreCase ? "i" : ""
539
+ );
540
+ const globRe = args.glob ? globToRegExp(args.glob) : void 0;
541
+ let files;
542
+ const stat = await fs.stat(target);
543
+ if (stat.isFile()) {
544
+ files = [{ rel: path2.relative(workspaceRoot, target), abs: target }];
545
+ } else if (stat.isDirectory()) {
546
+ files = (await walkFiles(target, 2e4)).filter((f) => !globRe || globRe.test(f) || globRe.test(f.split("/").pop())).map((f) => ({ rel: f, abs: path2.join(target, f) }));
547
+ } else {
548
+ return errorResult(`\u4E0D\u662F\u6587\u4EF6\u6216\u76EE\u5F55: ${args.path}`);
549
+ }
550
+ const out = [];
551
+ let matchCount = 0;
552
+ let truncated = false;
553
+ for (const file of files) {
554
+ if (matchCount >= limit) {
555
+ truncated = true;
556
+ break;
557
+ }
558
+ let buf;
559
+ try {
560
+ const st = await fs.stat(file.abs);
561
+ if (st.size > MAX_GREP_FILE_BYTES) continue;
562
+ buf = await fs.readFile(file.abs);
563
+ } catch {
564
+ continue;
565
+ }
566
+ if (buf.includes(0)) continue;
567
+ const lines = buf.toString("utf8").split("\n");
568
+ const hitLines = [];
569
+ for (let i = 0; i < lines.length && matchCount + hitLines.length < limit; i++) {
570
+ if (re.test(lines[i])) hitLines.push(i);
571
+ }
572
+ if (hitLines.length === 0) continue;
573
+ matchCount += hitLines.length;
574
+ const show = /* @__PURE__ */ new Set();
575
+ for (const h of hitLines) {
576
+ for (let i = Math.max(0, h - context); i <= Math.min(lines.length - 1, h + context); i++) {
577
+ show.add(i);
578
+ }
579
+ }
580
+ for (const i of [...show].sort((a, b) => a - b)) {
581
+ const marker = hitLines.includes(i) ? ">" : " ";
582
+ out.push(`${file.rel}:${i + 1}:${marker} ${lines[i].slice(0, 500)}`);
583
+ }
584
+ }
585
+ if (out.length === 0) {
586
+ return textResult(`\u672A\u627E\u5230\u5339\u914D "${args.pattern}" \u7684\u5185\u5BB9`, { pattern: args.pattern, count: 0 });
587
+ }
588
+ const suffix = truncated ? `
589
+ ...[\u5DF2\u8FBE ${limit} \u4E2A\u5339\u914D\u4E0A\u9650\uFF0C\u622A\u65AD]` : "";
590
+ return textResult(`${out.join("\n")}${suffix}`, {
591
+ pattern: args.pattern,
592
+ count: matchCount,
593
+ truncated
594
+ });
595
+ } catch (err) {
596
+ return errorResult(String(err instanceof Error ? err.message : err));
597
+ }
598
+ }
599
+ };
600
+ var lsTool = {
601
+ name: "ls",
602
+ description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9\uFF08\u76EE\u5F55\u5E26 / \u540E\u7F00\uFF0C\u76EE\u5F55\u5728\u524D\uFF09\u3002\u63A2\u7D22\u9879\u76EE\u7ED3\u6784\u65F6\u4F18\u5148\u4F7F\u7528\u3002",
603
+ parameters: {
604
+ type: "object",
605
+ properties: {
606
+ path: { type: "string", description: "\u76EE\u5F55\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5DE5\u4F5C\u533A\uFF0C\u9ED8\u8BA4 .\uFF09" },
607
+ limit: { type: "number", description: "\u6700\u5927\u6761\u76EE\u6570\uFF08\u9ED8\u8BA4 500\uFF09" }
608
+ }
609
+ },
610
+ permissions: ["fs:read"],
611
+ async execute(_id, rawArgs) {
612
+ const args = rawArgs;
613
+ const limit = args.limit ?? 500;
614
+ try {
615
+ const abs = resolveInWorkspace(args.path ?? ".");
616
+ const stat = await fs.stat(abs);
617
+ if (!stat.isDirectory()) {
618
+ return textResult(path2.relative(workspaceRoot, abs) || abs);
619
+ }
620
+ const entries = await fs.readdir(abs, { withFileTypes: true });
621
+ const sorted = entries.filter((e) => e.isDirectory() || e.isFile() || e.isSymbolicLink()).sort((a, b) => {
622
+ const ad = a.isDirectory() ? 0 : 1;
623
+ const bd = b.isDirectory() ? 0 : 1;
624
+ return ad !== bd ? ad - bd : a.name.localeCompare(b.name);
625
+ });
626
+ const limited = sorted.slice(0, limit);
627
+ if (limited.length === 0) {
628
+ return textResult("\uFF08\u7A7A\u76EE\u5F55\uFF09", {});
629
+ }
630
+ const lines = limited.map(
631
+ (e) => e.isDirectory() ? `${e.name}/` : e.isSymbolicLink() ? `${e.name}@` : e.name
632
+ );
633
+ const suffix = sorted.length > limited.length ? `
634
+ ...[\u5171 ${sorted.length} \u9879\uFF0C\u5DF2\u622A\u65AD\u81F3 ${limit}]` : "";
635
+ return textResult(`${lines.join("\n")}${suffix}`, {
636
+ path: args.path ?? ".",
637
+ count: sorted.length,
638
+ truncated: sorted.length > limited.length
639
+ });
640
+ } catch (err) {
641
+ return errorResult(String(err instanceof Error ? err.message : err));
642
+ }
643
+ }
644
+ };
645
+ var BUILTIN_TOOLS = [readTool, writeTool, editTool, bashTool, findTool, grepTool, lsTool];
545
646
  function selectTools(options) {
546
647
  if (options.noTools) return [];
547
648
  let selected = [...BUILTIN_TOOLS];
@@ -557,9 +658,30 @@ function selectTools(options) {
557
658
  }
558
659
 
559
660
  // src/builder.ts
661
+ import fs2 from "fs/promises";
662
+ import path3 from "path";
663
+ import { pathToFileURL } from "url";
664
+ import {
665
+ createRuntime,
666
+ adaptAiModel,
667
+ createStreamFnFromAi,
668
+ getBuiltinModel,
669
+ getBuiltinModels,
670
+ getBuiltinProviders,
671
+ BUILTIN_PROVIDERS,
672
+ hasProviderConfigured,
673
+ createFileSessionStorage,
674
+ createPermissionPolicy,
675
+ createApprovalManager,
676
+ FileApprovalStore
677
+ } from "@aipack-ai/agent";
678
+ import {
679
+ createCompressionTransformer,
680
+ loadCompressionConfig
681
+ } from "@aipack-ai/compression";
560
682
  async function loadConfig(cwd) {
561
683
  for (const file of ["aipack.config.js", "aipack.config.mjs"]) {
562
- const full = path4.join(cwd, file);
684
+ const full = path3.join(cwd, file);
563
685
  try {
564
686
  await fs2.access(full);
565
687
  const mod = await import(pathToFileURL(full).href);
@@ -578,9 +700,9 @@ function splitModelSpec(args) {
578
700
  return { provider: args.provider, modelId: args.model };
579
701
  }
580
702
  function detectDefaultProvider() {
581
- for (const p of getBuiltinProviders2()) {
582
- if (hasProviderConfigured2(p.id)) {
583
- const models = getBuiltinModels2(p.id);
703
+ for (const p of getBuiltinProviders()) {
704
+ if (hasProviderConfigured(p.id)) {
705
+ const models = getBuiltinModels(p.id);
584
706
  if (models.length > 0) return { id: p.id, modelId: models[0].id };
585
707
  }
586
708
  }
@@ -633,6 +755,40 @@ async function resolveSessionKey(args, storage) {
633
755
  function sanitizeKey(name) {
634
756
  return name.replace(/[^a-zA-Z0-9_\-:.]/g, "_");
635
757
  }
758
+ async function loadCompressionSettings(args, config) {
759
+ const overrides = {};
760
+ const fromConfigFile = config.compression;
761
+ if (fromConfigFile) Object.assign(overrides, fromConfigFile);
762
+ if (args.compactionConfig) {
763
+ try {
764
+ const raw = await fs2.readFile(args.compactionConfig, "utf8");
765
+ Object.assign(overrides, JSON.parse(raw));
766
+ } catch (err) {
767
+ console.warn(
768
+ `[aipack] \u538B\u7F29\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25\uFF08${args.compactionConfig}\uFF09\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E:`,
769
+ err instanceof Error ? err.message : String(err)
770
+ );
771
+ }
772
+ }
773
+ return loadCompressionConfig(overrides);
774
+ }
775
+ async function buildCompressionTransformer(opts) {
776
+ if (opts.args.noCompaction) return void 0;
777
+ const compressionConfig = await loadCompressionSettings(opts.args, opts.config);
778
+ const transformer = createCompressionTransformer({
779
+ config: compressionConfig,
780
+ model: adaptAiModel(opts.model.aiModel),
781
+ streamFn: opts.streamFn,
782
+ sessionStorage: opts.storage,
783
+ contextWindow: opts.model.aiModel.contextWindow
784
+ });
785
+ transformer.setHandoffHook(({ handoff }) => {
786
+ console.warn(
787
+ `[aipack] \u4E0A\u4E0B\u6587\u5DF2\u8FBE\u6781\u9650\uFF0C\u5DF2\u751F\u6210\u4EA4\u63A5\u6587\u6863\u5E76\u5207\u6362\u5230\u65B0\u4F1A\u8BDD ${handoff.newSessionId}\u3002\u6062\u590D: aipack --session ${handoff.newSessionId}`
788
+ );
789
+ });
790
+ return transformer;
791
+ }
636
792
  var DEFAULT_APPROVAL_CAPABILITIES = ["fs:write", "shell:exec"];
637
793
  async function buildRuntime(options) {
638
794
  const { args, cwd } = options;
@@ -654,9 +810,9 @@ async function buildRuntime(options) {
654
810
  const approvalCaps = new Set(config.approvals?.capabilities ?? DEFAULT_APPROVAL_CAPABILITIES);
655
811
  let approvalManager;
656
812
  if (approvalsEnabled) {
657
- approvalManager = createApprovalManager2({
658
- store: new FileApprovalStore2({
659
- baseDir: path4.join(defaultConfigDir(), "approvals")
813
+ approvalManager = createApprovalManager({
814
+ store: new FileApprovalStore({
815
+ baseDir: path3.join(defaultConfigDir(), "approvals")
660
816
  })
661
817
  });
662
818
  await approvalManager.restore();
@@ -669,6 +825,13 @@ async function buildRuntime(options) {
669
825
  confirmFn: options.confirmFn
670
826
  });
671
827
  const systemPrompt = buildSystemPrompt(args);
828
+ const compressionTransformer = await buildCompressionTransformer({
829
+ args,
830
+ config,
831
+ model,
832
+ streamFn,
833
+ storage
834
+ });
672
835
  const runtime = await createRuntime({
673
836
  model: adaptAiModel(model.aiModel),
674
837
  streamFn,
@@ -681,7 +844,9 @@ async function buildRuntime(options) {
681
844
  permissionPolicy: policy,
682
845
  approvals: approvalManager,
683
846
  maxTurns: 50,
684
- compaction: { enabled: true }
847
+ transformers: compressionTransformer ? [compressionTransformer] : [],
848
+ // --no-compaction 时一并关闭内置摘要压缩(仅保留硬截断兜底)
849
+ compaction: args.noCompaction ? { enabled: false } : { enabled: true }
685
850
  });
686
851
  return {
687
852
  runtime,
@@ -689,7 +854,8 @@ async function buildRuntime(options) {
689
854
  storage,
690
855
  approvalManager,
691
856
  model,
692
- config
857
+ config,
858
+ compressionTransformer
693
859
  };
694
860
  }
695
861
  function buildPermissionPolicy(opts) {
@@ -731,14 +897,14 @@ function buildSystemPrompt(args) {
731
897
 
732
898
  // src/initial-message.ts
733
899
  import fs3 from "fs/promises";
734
- import path5 from "path";
900
+ import path4 from "path";
735
901
  var IMAGE_EXT = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
736
902
  async function buildInitialMessage(messages, fileArgs, stdinText) {
737
903
  const parts = [];
738
904
  const media = [];
739
905
  for (const file of fileArgs) {
740
- const abs = path5.resolve(process.cwd(), file);
741
- const ext = path5.extname(abs).toLowerCase();
906
+ const abs = path4.resolve(process.cwd(), file);
907
+ const ext = path4.extname(abs).toLowerCase();
742
908
  try {
743
909
  if (IMAGE_EXT.has(ext)) {
744
910
  const buf = await fs3.readFile(abs);
@@ -765,10 +931,10 @@ ${stdinText.trim()}
765
931
  }
766
932
 
767
933
  // src/modes/print.ts
768
- import chalk4 from "chalk";
934
+ import chalk2 from "chalk";
769
935
 
770
936
  // src/modes/render.ts
771
- import chalk3 from "chalk";
937
+ import chalk from "chalk";
772
938
  var ChunkRenderer = class {
773
939
  constructor(opts = {}) {
774
940
  this.opts = opts;
@@ -784,26 +950,26 @@ var ChunkRenderer = class {
784
950
  break;
785
951
  case "thinking": {
786
952
  if (this.opts.showThinking && chunk.content) {
787
- process.stdout.write(chalk3.dim(chunk.content));
953
+ process.stdout.write(chalk.dim(chunk.content));
788
954
  } else if (!this.thinkingShown) {
789
955
  this.thinkingShown = true;
790
- err.write(chalk3.dim(" (\u601D\u8003\u4E2D...)\n"));
956
+ err.write(chalk.dim(" (\u601D\u8003\u4E2D...)\n"));
791
957
  }
792
958
  break;
793
959
  }
794
960
  case "tool_start":
795
961
  this.inTool = true;
796
- err.write(chalk3.cyan(`
962
+ err.write(chalk.cyan(`
797
963
  \u2699 ${chunk.toolName} `));
798
964
  break;
799
965
  case "tool_end":
800
966
  if (this.inTool) {
801
- err.write(chunk.isError ? chalk3.red(" \u2717\n") : chalk3.green(" \u2713\n"));
967
+ err.write(chunk.isError ? chalk.red(" \u2717\n") : chalk.green(" \u2713\n"));
802
968
  this.inTool = false;
803
969
  }
804
970
  break;
805
971
  case "error":
806
- err.write(chalk3.red(`
972
+ err.write(chalk.red(`
807
973
  \u9519\u8BEF: ${chunk.content ?? "\u672A\u77E5\u9519\u8BEF"}
808
974
  `));
809
975
  break;
@@ -822,17 +988,23 @@ var ChunkRenderer = class {
822
988
  async function runPrintMode(runtime, request) {
823
989
  const renderer = new ChunkRenderer({ toolStream: process.stderr });
824
990
  let error;
991
+ let usage;
825
992
  try {
826
993
  for await (const chunk of runtime.stream(request)) {
827
994
  if (chunk.type === "error") error = chunk.content;
995
+ if (chunk.type === "done" && chunk.result?.usage) usage = chunk.result.usage;
828
996
  renderer.render(chunk);
829
997
  }
830
998
  } catch (err) {
831
- process.stderr.write(chalk4.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}
999
+ process.stderr.write(chalk2.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}
832
1000
  `));
833
1001
  process.exitCode = 1;
834
1002
  return;
835
1003
  }
1004
+ if (usage && (usage.input || usage.output)) {
1005
+ process.stderr.write(chalk2.dim(`tokens: \u2191${(usage.input ?? 0).toLocaleString()} \u2193${(usage.output ?? 0).toLocaleString()}
1006
+ `));
1007
+ }
836
1008
  if (error) process.exitCode = 1;
837
1009
  }
838
1010
 
@@ -848,6 +1020,10 @@ async function runJsonMode(runtime, request) {
848
1020
  toolName: chunk.toolName,
849
1021
  toolCallId: chunk.toolCallId,
850
1022
  isError: chunk.isError,
1023
+ // done 类型:透出最终 Result 摘要(usage / stopReason / toolsUsed)供程序消费
1024
+ usage: chunk.result?.usage,
1025
+ stopReason: chunk.result?.stopReason,
1026
+ toolsUsed: chunk.result?.toolsUsed,
851
1027
  timestamp: Date.now()
852
1028
  });
853
1029
  process.stdout.write(`${line}
@@ -867,9 +1043,9 @@ async function runJsonMode(runtime, request) {
867
1043
 
868
1044
  // src/modes/interactive.ts
869
1045
  import readline2 from "readline";
870
- import chalk5 from "chalk";
1046
+ import chalk3 from "chalk";
871
1047
  import {
872
- getBuiltinModels as getBuiltinModels3,
1048
+ getBuiltinModels as getBuiltinModels2,
873
1049
  adaptAiModel as adaptAiModel2
874
1050
  } from "@aipack-ai/agent";
875
1051
 
@@ -921,20 +1097,20 @@ async function runInteractiveMode(opts) {
921
1097
  rl = readline2.createInterface({
922
1098
  input: process.stdin,
923
1099
  output: process.stdout,
924
- prompt: chalk5.blue("aipack> ")
1100
+ prompt: chalk3.blue("aipack> ")
925
1101
  });
926
1102
  rl.on("SIGINT", () => {
927
1103
  if (busy) {
928
- console.log(chalk5.yellow("\n\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C..."));
1104
+ console.log(chalk3.yellow("\n\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C..."));
929
1105
  runtime.abort(activeKey);
930
1106
  return;
931
1107
  }
932
1108
  sigintCount++;
933
1109
  if (sigintCount >= 2) {
934
- console.log(chalk5.dim("\n\u518D\u89C1"));
1110
+ console.log(chalk3.dim("\n\u518D\u89C1"));
935
1111
  rl.close();
936
1112
  } else {
937
- console.log(chalk5.dim("\uFF08\u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA\uFF09"));
1113
+ console.log(chalk3.dim("\uFF08\u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA\uFF09"));
938
1114
  rl.prompt();
939
1115
  setTimeout(() => {
940
1116
  sigintCount = 0;
@@ -947,6 +1123,7 @@ async function runInteractiveMode(opts) {
947
1123
  rl.on("line", onLine);
948
1124
  rl.prompt();
949
1125
  }
1126
+ let usageTotal = { input: 0, output: 0 };
950
1127
  async function send(text) {
951
1128
  if (!text.trim()) return;
952
1129
  busy = true;
@@ -962,9 +1139,17 @@ async function runInteractiveMode(opts) {
962
1139
  try {
963
1140
  for await (const chunk of runtime.stream(request)) {
964
1141
  renderer.render(chunk);
1142
+ if (chunk.type === "done" && chunk.result?.usage) {
1143
+ const u = chunk.result.usage;
1144
+ usageTotal.input += u.input ?? 0;
1145
+ usageTotal.output += u.output ?? 0;
1146
+ }
1147
+ }
1148
+ if (usageTotal.input > 0 || usageTotal.output > 0) {
1149
+ console.log(chalk3.dim(` tokens: \u2191${usageTotal.input.toLocaleString()} \u2193${usageTotal.output.toLocaleString()}\uFF08\u7D2F\u8BA1\uFF09`));
965
1150
  }
966
1151
  } catch (err) {
967
- console.log(chalk5.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}`));
1152
+ console.log(chalk3.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}`));
968
1153
  } finally {
969
1154
  busy = false;
970
1155
  rl.prompt();
@@ -984,110 +1169,123 @@ async function runInteractiveMode(opts) {
984
1169
  return;
985
1170
  case "/model": {
986
1171
  if (!rest) {
987
- console.log(chalk5.dim(`\u5F53\u524D\u6A21\u578B: ${model.aiModel.provider}/${model.aiModel.id}`));
988
- console.log(chalk5.dim("\u7528\u6CD5: /model provider/model-id\uFF08\u5982 /model deepseek/deepseek-chat\uFF09"));
1172
+ console.log(chalk3.dim(`\u5F53\u524D\u6A21\u578B: ${model.aiModel.provider}/${model.aiModel.id}`));
1173
+ console.log(chalk3.dim("\u7528\u6CD5: /model provider/model-id\uFF08\u5982 /model deepseek/deepseek-chat\uFF09"));
989
1174
  break;
990
1175
  }
991
1176
  const slash = rest.indexOf("/");
992
1177
  const provider = slash === -1 ? model.aiModel.provider : rest.slice(0, slash);
993
1178
  const id = slash === -1 ? rest : rest.slice(slash + 1);
994
- const found = getBuiltinModels3(provider).find((m) => m.id === id);
1179
+ const found = getBuiltinModels2(provider).find((m) => m.id === id);
995
1180
  if (!found) {
996
- console.log(chalk5.yellow(`\u672A\u627E\u5230\u5185\u7F6E\u6A21\u578B ${provider}/${id}\uFF0C\u53EF\u7528:`));
997
- console.log(getBuiltinModels3(provider).map((m) => ` ${m.id}`).join("\n") || " (\u65E0)");
1181
+ console.log(chalk3.yellow(`\u672A\u627E\u5230\u5185\u7F6E\u6A21\u578B ${provider}/${id}\uFF0C\u53EF\u7528:`));
1182
+ console.log(getBuiltinModels2(provider).map((m) => ` ${m.id}`).join("\n") || " (\u65E0)");
998
1183
  break;
999
1184
  }
1000
1185
  runtime.setModel(adaptAiModel2(found));
1001
1186
  model.aiModel = found;
1002
1187
  model.custom = false;
1003
- console.log(chalk5.green(`\u5DF2\u5207\u6362\u5230 ${provider}/${id}`));
1188
+ console.log(chalk3.green(`\u5DF2\u5207\u6362\u5230 ${provider}/${id}`));
1004
1189
  break;
1005
1190
  }
1006
1191
  case "/thinking": {
1007
1192
  if (!VALID_THINKING.has(rest)) {
1008
- console.log(chalk5.dim("\u7528\u6CD5: /thinking <off|minimal|low|medium|high|max>"));
1193
+ console.log(chalk3.dim("\u7528\u6CD5: /thinking <off|minimal|low|medium|high|max>"));
1009
1194
  break;
1010
1195
  }
1011
1196
  runtime.setThinkingLevel(rest);
1012
- console.log(chalk5.green(`\u601D\u8003\u7EA7\u522B: ${rest}`));
1197
+ console.log(chalk3.green(`\u601D\u8003\u7EA7\u522B: ${rest}`));
1013
1198
  break;
1014
1199
  }
1015
1200
  case "/system": {
1016
1201
  if (!rest) {
1017
- console.log(chalk5.dim("\u7528\u6CD5: /system <\u65B0\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD>"));
1202
+ console.log(chalk3.dim("\u7528\u6CD5: /system <\u65B0\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD>"));
1018
1203
  break;
1019
1204
  }
1020
1205
  runtime.setSystemPrompt(rest);
1021
- console.log(chalk5.green("\u7CFB\u7EDF\u63D0\u793A\u8BCD\u5DF2\u66F4\u65B0"));
1206
+ console.log(chalk3.green("\u7CFB\u7EDF\u63D0\u793A\u8BCD\u5DF2\u66F4\u65B0"));
1022
1207
  break;
1023
1208
  }
1024
1209
  case "/session":
1025
- console.log(`\u4F1A\u8BDD key: ${chalk5.cyan(activeKey)}`);
1210
+ console.log(`\u4F1A\u8BDD key: ${chalk3.cyan(activeKey)}`);
1026
1211
  console.log(`\u6D88\u606F\u6570: ${runtime.getMessages(activeKey).length}`);
1027
- console.log(`\u6301\u4E45\u5316: ${args.noSession ? chalk5.yellow("\u5426\uFF08--no-session\uFF09") : chalk5.green(storage ? "\u662F" : "\u5426\uFF08\u65E0\u5B58\u50A8\uFF09")}`);
1212
+ console.log(`\u6301\u4E45\u5316: ${args.noSession ? chalk3.yellow("\u5426\uFF08--no-session\uFF09") : chalk3.green(storage ? "\u662F" : "\u5426\uFF08\u65E0\u5B58\u50A8\uFF09")}`);
1028
1213
  break;
1029
1214
  case "/sessions": {
1030
1215
  if (!storage) {
1031
- console.log(chalk5.yellow("\u5F53\u524D\u4E3A\u4E34\u65F6\u4F1A\u8BDD\uFF0C\u65E0\u6301\u4E45\u5316\u5B58\u50A8"));
1216
+ console.log(chalk3.yellow("\u5F53\u524D\u4E3A\u4E34\u65F6\u4F1A\u8BDD\uFF0C\u65E0\u6301\u4E45\u5316\u5B58\u50A8"));
1032
1217
  break;
1033
1218
  }
1034
1219
  const sessions = await listSessionsByRecency(storage);
1035
1220
  if (sessions.length === 0) {
1036
- console.log(chalk5.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF09"));
1221
+ console.log(chalk3.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF09"));
1037
1222
  break;
1038
1223
  }
1039
- console.log(sessions.slice(0, 10).map((s, i) => `${s === activeKey ? chalk5.green("\u25B8 ") : " "}${i + 1}. ${s}`).join("\n"));
1040
- console.log(chalk5.dim("\u5207\u6362: \u9000\u51FA\u540E\u7528 aipack --session <key> \u6062\u590D"));
1224
+ console.log(sessions.slice(0, 10).map((s, i) => `${s === activeKey ? chalk3.green("\u25B8 ") : " "}${i + 1}. ${s}`).join("\n"));
1225
+ console.log(chalk3.dim("\u5207\u6362: \u9000\u51FA\u540E\u7528 aipack --session <key> \u6062\u590D"));
1041
1226
  break;
1042
1227
  }
1043
1228
  case "/clear":
1044
1229
  runtime.clearSession(activeKey);
1045
- console.log(chalk5.green("\u4F1A\u8BDD\u5DF2\u6E05\u7A7A\uFF08\u4EC5\u5185\u5B58\uFF09"));
1230
+ usageTotal = { input: 0, output: 0 };
1231
+ console.log(chalk3.green("\u4F1A\u8BDD\u5DF2\u6E05\u7A7A\uFF08\u4EC5\u5185\u5B58\uFF09"));
1232
+ break;
1233
+ case "/compact": {
1234
+ console.log(chalk3.dim("\u538B\u7F29\u4F1A\u8BDD\u5386\u53F2..."));
1235
+ const mode = await runtime.compact(activeKey);
1236
+ if (mode === null) {
1237
+ console.log(chalk3.yellow("\u65E0\u53EF\u538B\u7F29\u5185\u5BB9\uFF08\u6D88\u606F\u8FC7\u5C11\u6216\u538B\u7F29\u5DF2\u901A\u8FC7 --no-compaction \u5173\u95ED\uFF09"));
1238
+ } else {
1239
+ console.log(chalk3.green(`\u5DF2\u5B8C\u6210${mode === "summary" ? "\u6458\u8981\u538B\u7F29" : "\u622A\u65AD\u538B\u7F29"}\uFF0C\u6D88\u606F\u6570: ${runtime.getMessages(activeKey).length}`));
1240
+ }
1046
1241
  break;
1242
+ }
1047
1243
  case "/tools":
1048
- console.log(chalk5.dim("\u5185\u7F6E\u5DE5\u5177\u901A\u8FC7 --tools/--exclude-tools \u914D\u7F6E\uFF1B\u5F53\u524D\u8FD0\u884C\u65F6\u672A\u63D0\u4F9B\u5217\u4E3E\u63A5\u53E3"));
1244
+ console.log(chalk3.dim("\u5185\u7F6E\u5DE5\u5177: read, write, edit, bash, find, grep, ls"));
1245
+ console.log(chalk3.dim("\u901A\u8FC7 --tools / --exclude-tools / --no-tools \u914D\u7F6E\u542F\u505C"));
1049
1246
  break;
1050
1247
  case "/approvals": {
1051
1248
  if (!approvalManager) {
1052
- console.log(chalk5.yellow("\u5BA1\u6279\u672A\u542F\u7528\uFF08\u5728 aipack.config.js \u4E2D\u914D\u7F6E approvals.enabled: true\uFF09"));
1249
+ console.log(chalk3.yellow("\u5BA1\u6279\u672A\u542F\u7528\uFF08\u5728 aipack.config.js \u4E2D\u914D\u7F6E approvals.enabled: true\uFF09"));
1053
1250
  break;
1054
1251
  }
1055
1252
  const pending = approvalManager.list();
1056
1253
  if (pending.length === 0) {
1057
- console.log(chalk5.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\uFF09"));
1254
+ console.log(chalk3.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\uFF09"));
1058
1255
  break;
1059
1256
  }
1060
1257
  for (const p of pending) {
1061
- console.log(`${chalk5.cyan(p.id)} ${p.request.toolName} ${chalk5.dim(new Date(p.createdAt).toLocaleString())}${p.restored ? chalk5.yellow(" (\u5B64\u513F)") : ""}`);
1258
+ console.log(`${chalk3.cyan(p.id)} ${p.request.toolName} ${chalk3.dim(new Date(p.createdAt).toLocaleString())}${p.restored ? chalk3.yellow(" (\u5B64\u513F)") : ""}`);
1062
1259
  }
1063
1260
  break;
1064
1261
  }
1065
1262
  case "/approve":
1066
1263
  case "/deny": {
1067
1264
  if (!approvalManager) {
1068
- console.log(chalk5.yellow("\u5BA1\u6279\u672A\u542F\u7528"));
1265
+ console.log(chalk3.yellow("\u5BA1\u6279\u672A\u542F\u7528"));
1069
1266
  break;
1070
1267
  }
1071
1268
  if (!rest) {
1072
- console.log(chalk5.dim(`\u7528\u6CD5: ${cmd} <\u5BA1\u6279\u5355 id>`));
1269
+ console.log(chalk3.dim(`\u7528\u6CD5: ${cmd} <\u5BA1\u6279\u5355 id>`));
1073
1270
  break;
1074
1271
  }
1075
1272
  const ok = approvalManager.resolve(rest, cmd === "/approve");
1076
- console.log(ok ? chalk5.green("\u5DF2\u751F\u6548") : chalk5.yellow("\u5BA1\u6279\u5355\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97"));
1273
+ console.log(ok ? chalk3.green("\u5DF2\u751F\u6548") : chalk3.yellow("\u5BA1\u6279\u5355\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97"));
1077
1274
  break;
1078
1275
  }
1079
1276
  default:
1080
- console.log(chalk5.yellow(`\u672A\u77E5\u547D\u4EE4: ${cmd}\uFF08/help \u67E5\u770B\u5168\u90E8\uFF09`));
1277
+ console.log(chalk3.yellow(`\u672A\u77E5\u547D\u4EE4: ${cmd}\uFF08/help \u67E5\u770B\u5168\u90E8\uFF09`));
1081
1278
  }
1082
1279
  }
1083
1280
  function printSlashHelp() {
1084
- console.log(`${chalk5.bold("\u547D\u4EE4:")}
1281
+ console.log(`${chalk3.bold("\u547D\u4EE4:")}
1085
1282
  /model [provider/id] \u5207\u6362\u6A21\u578B\uFF08\u65E0\u53C2\u663E\u793A\u5F53\u524D\uFF09
1086
1283
  /thinking <\u7EA7\u522B> off/minimal/low/medium/high/max
1087
1284
  /system <\u6587\u672C> \u66FF\u6362\u7CFB\u7EDF\u63D0\u793A\u8BCD
1088
1285
  /session \u5F53\u524D\u4F1A\u8BDD\u4FE1\u606F
1089
1286
  /sessions \u5217\u51FA\u5386\u53F2\u4F1A\u8BDD
1090
1287
  /clear \u6E05\u7A7A\u5F53\u524D\u4F1A\u8BDD\uFF08\u4EC5\u5185\u5B58\uFF09
1288
+ /compact \u624B\u52A8\u538B\u7F29\u4F1A\u8BDD\u5386\u53F2\uFF08\u91CA\u653E\u4E0A\u4E0B\u6587\u7A7A\u95F4\uFF09
1091
1289
  /approvals \u672A\u51B3\u5BA1\u6279\u5355
1092
1290
  /approve <id> \u6279\u51C6
1093
1291
  /deny <id> \u9A73\u56DE
@@ -1100,7 +1298,7 @@ async function runInteractiveMode(opts) {
1100
1298
  return;
1101
1299
  }
1102
1300
  if (busy) {
1103
- console.log(chalk5.dim("\uFF08\u8FD0\u884C\u4E2D\uFF0C\u8F93\u5165\u88AB\u5FFD\u7565\uFF1BCtrl+C \u4E2D\u65AD\uFF09"));
1301
+ console.log(chalk3.dim("\uFF08\u8FD0\u884C\u4E2D\uFF0C\u8F93\u5165\u88AB\u5FFD\u7565\uFF1BCtrl+C \u4E2D\u65AD\uFF09"));
1104
1302
  rl.prompt();
1105
1303
  return;
1106
1304
  }
@@ -1123,10 +1321,10 @@ async function runInteractiveMode(opts) {
1123
1321
  }
1124
1322
  };
1125
1323
  }
1126
- const modelLabel = `${model.aiModel.provider}/${model.aiModel.id}${model.custom ? chalk5.yellow(" (\u81EA\u5B9A\u4E49)") : ""}`;
1127
- console.log(chalk5.bold(`${APP_NAME} ${VERSION}`) + chalk5.dim(` \u4F1A\u8BDD: ${activeKey}${args.noSession ? " (\u4E34\u65F6)" : ""}`));
1128
- console.log(chalk5.dim(`\u6A21\u578B: ${modelLabel}`));
1129
- console.log(chalk5.dim("\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\uFF0CCtrl+C \u4E2D\u65AD\u8FD0\u884C\uFF0C\u8FDE\u6309\u4E24\u6B21\u9000\u51FA\n"));
1324
+ const modelLabel = `${model.aiModel.provider}/${model.aiModel.id}${model.custom ? chalk3.yellow(" (\u81EA\u5B9A\u4E49)") : ""}`;
1325
+ console.log(chalk3.bold(`${APP_NAME} ${VERSION}`) + chalk3.dim(` \u4F1A\u8BDD: ${activeKey}${args.noSession ? " (\u4E34\u65F6)" : ""}`));
1326
+ console.log(chalk3.dim(`\u6A21\u578B: ${modelLabel}`));
1327
+ console.log(chalk3.dim("\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\uFF0CCtrl+C \u4E2D\u65AD\u8FD0\u884C\uFF0C\u8FDE\u6309\u4E24\u6B21\u9000\u51FA\n"));
1130
1328
  setupRl();
1131
1329
  if (opts.initialMessages && opts.initialMessages.length > 0) {
1132
1330
  await send(opts.initialMessages.join("\n"));
@@ -1136,14 +1334,14 @@ async function runInteractiveMode(opts) {
1136
1334
  async function pickSessionInteractively(storage, currentKey) {
1137
1335
  const sessions = await listSessionsByRecency(storage);
1138
1336
  if (sessions.length === 0) {
1139
- console.log(chalk5.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF0C\u5C06\u65B0\u5EFA\uFF09"));
1337
+ console.log(chalk3.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF0C\u5C06\u65B0\u5EFA\uFF09"));
1140
1338
  return void 0;
1141
1339
  }
1142
- console.log(chalk5.bold("\u9009\u62E9\u4F1A\u8BDD:"));
1340
+ console.log(chalk3.bold("\u9009\u62E9\u4F1A\u8BDD:"));
1143
1341
  sessions.slice(0, 15).forEach((s, i) => {
1144
- console.log(`${s === currentKey ? chalk5.green("\u25B8 ") : " "}${i + 1}. ${s}`);
1342
+ console.log(`${s === currentKey ? chalk3.green("\u25B8 ") : " "}${i + 1}. ${s}`);
1145
1343
  });
1146
- console.log(chalk5.dim(" n. \u65B0\u4F1A\u8BDD"));
1344
+ console.log(chalk3.dim(" n. \u65B0\u4F1A\u8BDD"));
1147
1345
  const answer = await ask("\u7F16\u53F7: ");
1148
1346
  if (answer === "" || answer.toLowerCase() === "n") return void 0;
1149
1347
  const idx = Number.parseInt(answer, 10);
@@ -1154,7 +1352,7 @@ async function pickSessionInteractively(storage, currentKey) {
1154
1352
  }
1155
1353
 
1156
1354
  // src/select.ts
1157
- import chalk6 from "chalk";
1355
+ import chalk4 from "chalk";
1158
1356
  async function select(question, options, defaultIndex = 0) {
1159
1357
  const stdin = process.stdin;
1160
1358
  const out = process.stdout;
@@ -1168,7 +1366,7 @@ async function select(question, options, defaultIndex = 0) {
1168
1366
  function render() {
1169
1367
  for (let i = 0; i < options.length; i++) {
1170
1368
  const opt = options[i];
1171
- const line = i === selected ? `${chalk6.cyan("\u276F ")}${chalk6.bold(opt.label)}` : ` ${opt.label}`;
1369
+ const line = i === selected ? `${chalk4.cyan("\u276F ")}${chalk4.bold(opt.label)}` : ` ${opt.label}`;
1172
1370
  out.write(`\x1B[2K\r${line}
1173
1371
  `);
1174
1372
  }
@@ -1184,7 +1382,7 @@ async function select(question, options, defaultIndex = 0) {
1184
1382
  for (let i = 0; i < options.length; i++) out.write("\x1B[2K\r\n");
1185
1383
  out.write(`\x1B[${options.length}A`);
1186
1384
  const chosen = options.find((o) => o.value === value);
1187
- const summary = chosen ? chalk6.green(`\u2713 ${chosen.label}`) : chalk6.dim("\u5DF2\u53D6\u6D88");
1385
+ const summary = chosen ? chalk4.green(`\u2713 ${chosen.label}`) : chalk4.dim("\u5DF2\u53D6\u6D88");
1188
1386
  out.write(`\x1B[2K\r ${summary}
1189
1387
  `);
1190
1388
  resolve(value);
@@ -1212,7 +1410,7 @@ async function select(question, options, defaultIndex = 0) {
1212
1410
  }
1213
1411
  render();
1214
1412
  }
1215
- out.write(`${chalk6.yellow("?")} ${chalk6.bold(question)}
1413
+ out.write(`${chalk4.yellow("?")} ${chalk4.bold(question)}
1216
1414
  `);
1217
1415
  render();
1218
1416
  stdin.on("data", onData);
@@ -1275,6 +1473,107 @@ function createToolConfirmHandler(options = {}) {
1275
1473
  };
1276
1474
  }
1277
1475
 
1476
+ // src/cli.ts
1477
+ import chalk7 from "chalk";
1478
+
1479
+ // src/commands/approvals.ts
1480
+ import path5 from "path";
1481
+ import chalk5 from "chalk";
1482
+ import { FileApprovalStore as FileApprovalStore2, createApprovalManager as createApprovalManager2 } from "@aipack-ai/agent";
1483
+ function createStore() {
1484
+ return new FileApprovalStore2({
1485
+ baseDir: path5.join(defaultConfigDir(), "approvals")
1486
+ });
1487
+ }
1488
+ async function handleApprovalsCommand(args) {
1489
+ const [sub, ...rest] = args;
1490
+ if (!sub || sub === "help" || sub === "--help") {
1491
+ printUsage();
1492
+ return 0;
1493
+ }
1494
+ const store = createStore();
1495
+ if (sub === "list") {
1496
+ const pending = await store.load();
1497
+ if (pending.length === 0) {
1498
+ console.log(chalk5.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\u5355\uFF09"));
1499
+ return 0;
1500
+ }
1501
+ for (const p of pending) {
1502
+ printApproval(p);
1503
+ }
1504
+ return 0;
1505
+ }
1506
+ if (sub === "approve" || sub === "deny") {
1507
+ const id = rest[0];
1508
+ if (!id) {
1509
+ console.error(chalk5.red(`\u7528\u6CD5: aipack approvals ${sub} <id>`));
1510
+ return 1;
1511
+ }
1512
+ const manager = createApprovalManager2({ store });
1513
+ await manager.restore();
1514
+ const ok = manager.resolve(id, sub === "approve");
1515
+ manager.close();
1516
+ if (!ok) {
1517
+ console.error(chalk5.yellow(`\u5BA1\u6279\u5355 ${id} \u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97`));
1518
+ return 1;
1519
+ }
1520
+ console.log(chalk5.green(`\u5DF2${sub === "approve" ? "\u6279\u51C6" : "\u9A73\u56DE"} ${id}`));
1521
+ return 0;
1522
+ }
1523
+ printUsage();
1524
+ console.error(chalk5.red(`\u672A\u77E5\u5B50\u547D\u4EE4: ${sub}`));
1525
+ return 1;
1526
+ }
1527
+ function printApproval(p) {
1528
+ const created = new Date(p.createdAt).toLocaleString();
1529
+ const expires = p.expiresAt ? chalk5.dim(` \u8FC7\u671F ${new Date(p.expiresAt).toLocaleTimeString()}`) : "";
1530
+ console.log(`${chalk5.cyan(p.id)} ${chalk5.bold(p.toolName)} ${chalk5.dim(created)}${expires}`);
1531
+ if (p.permissions.length > 0) {
1532
+ console.log(chalk5.dim(` \u80FD\u529B: ${p.permissions.join(", ")}`));
1533
+ }
1534
+ const argsStr = JSON.stringify(p.args);
1535
+ if (argsStr && argsStr !== "{}") {
1536
+ console.log(chalk5.dim(` \u53C2\u6570: ${argsStr.length > 120 ? `${argsStr.slice(0, 120)}\u2026` : argsStr}`));
1537
+ }
1538
+ }
1539
+ function printUsage() {
1540
+ console.log(`\u7528\u6CD5:
1541
+ aipack approvals list \u5217\u51FA\u672A\u51B3\u5BA1\u6279\u5355
1542
+ aipack approvals approve <id> \u6279\u51C6
1543
+ aipack approvals deny <id> \u9A73\u56DE`);
1544
+ }
1545
+
1546
+ // src/commands/models.ts
1547
+ import chalk6 from "chalk";
1548
+ import { getBuiltinProviders as getBuiltinProviders2, getBuiltinModels as getBuiltinModels3, hasProviderConfigured as hasProviderConfigured2 } from "@aipack-ai/agent";
1549
+ function listModels(search) {
1550
+ const term = typeof search === "string" ? search.toLowerCase() : void 0;
1551
+ let total = 0;
1552
+ for (const provider of getBuiltinProviders2()) {
1553
+ const models = getBuiltinModels3(provider.id);
1554
+ const matched = term ? models.filter((m) => m.id.toLowerCase().includes(term) || m.name.toLowerCase().includes(term) || provider.id.includes(term)) : models;
1555
+ if (matched.length === 0) continue;
1556
+ const configured = hasProviderConfigured2(provider.id);
1557
+ const badge = configured ? chalk6.green("\u2713") : chalk6.dim("\xB7");
1558
+ console.log(`${badge} ${chalk6.bold(provider.name)} ${chalk6.dim(`(${provider.id})`)}`);
1559
+ for (const m of matched) {
1560
+ const flags = [
1561
+ m.reasoning ? chalk6.dim("\u63A8\u7406") : null,
1562
+ `${m.contextWindow / 1e3 | 0}k`
1563
+ ].filter(Boolean).join(" ");
1564
+ console.log(` ${m.id.padEnd(44)} ${chalk6.dim(flags)}`);
1565
+ total++;
1566
+ }
1567
+ }
1568
+ console.log(chalk6.dim(`
1569
+ \u5171 ${total} \u4E2A\u6A21\u578B\u3002\u2713 = \u5DF2\u914D\u7F6E API Key\uFF08${getEnvHint()}\uFF09`));
1570
+ return 0;
1571
+ }
1572
+ function getEnvHint() {
1573
+ const provider = getBuiltinProviders2().find((p) => hasProviderConfigured2(p.id));
1574
+ return provider ? `${provider.envVar} \u5DF2\u8BBE\u7F6E` : "\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 API Key";
1575
+ }
1576
+
1278
1577
  // src/cli.ts
1279
1578
  import { createRequest } from "@aipack-ai/agent";
1280
1579
  async function main(argv) {
@@ -1363,12 +1662,6 @@ async function main(argv) {
1363
1662
  }
1364
1663
  return process.exitCode === 1 ? 1 : 0;
1365
1664
  }
1366
- if (process.argv[1] && /cli\.(js|mjs|ts)$/.test(process.argv[1])) {
1367
- main(process.argv.slice(2)).then((code) => process.exit(code)).catch((err) => {
1368
- console.error(chalk7.red(`\u81F4\u547D\u9519\u8BEF: ${err instanceof Error ? err.stack ?? err.message : String(err)}`));
1369
- process.exit(1);
1370
- });
1371
- }
1372
1665
 
1373
1666
  export {
1374
1667
  APP_NAME,
@@ -1399,4 +1692,4 @@ export {
1399
1692
  createToolConfirmHandler,
1400
1693
  main
1401
1694
  };
1402
- //# sourceMappingURL=chunk-DWPSBSRO.js.map
1695
+ //# sourceMappingURL=chunk-TPMRQPLX.js.map