@piut/cli 3.7.0 → 3.8.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.
Files changed (2) hide show
  1. package/dist/cli.js +777 -886
  2. package/package.json +3 -6
package/dist/cli.js CHANGED
@@ -1,16 +1,338 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // node_modules/tsup/assets/esm_shims.js
13
+ import path from "path";
14
+ import { fileURLToPath } from "url";
15
+ var init_esm_shims = __esm({
16
+ "node_modules/tsup/assets/esm_shims.js"() {
17
+ "use strict";
18
+ }
19
+ });
20
+
21
+ // src/lib/tree-prompt.ts
22
+ var tree_prompt_exports = {};
23
+ __export(tree_prompt_exports, {
24
+ collapseNode: () => collapseNode,
25
+ default: () => tree_prompt_default,
26
+ expandNode: () => expandNode,
27
+ getParentIndex: () => getParentIndex,
28
+ loadChildren: () => loadChildren,
29
+ shouldShowInTree: () => shouldShowInTree
30
+ });
31
+ import fs13 from "fs";
32
+ import path14 from "path";
33
+ import os8 from "os";
34
+ import {
35
+ createPrompt,
36
+ useState,
37
+ useKeypress,
38
+ usePagination,
39
+ useRef,
40
+ isUpKey,
41
+ isDownKey,
42
+ isSpaceKey,
43
+ isEnterKey
44
+ } from "@inquirer/core";
45
+ import chalk12 from "chalk";
46
+ function shouldShowInTree(name) {
47
+ if (TREE_SKIP.has(name)) return false;
48
+ if (name.startsWith(".") && !TREE_INCLUDE_DOT_DIRS.has(name)) return false;
49
+ return true;
50
+ }
51
+ function shouldShowFile(name) {
52
+ if (name.startsWith(".")) return false;
53
+ const ext = path14.extname(name).toLowerCase();
54
+ return !HIDDEN_FILE_EXTENSIONS.has(ext);
55
+ }
56
+ function loadChildren(parentPath, parentDepth, includeFiles = false) {
57
+ try {
58
+ const entries = fs13.readdirSync(parentPath, { withFileTypes: true });
59
+ const dirs = [];
60
+ const files = [];
61
+ for (const entry of entries) {
62
+ if (entry.isDirectory()) {
63
+ if (!shouldShowInTree(entry.name)) continue;
64
+ dirs.push({
65
+ path: path14.join(parentPath, entry.name),
66
+ name: entry.name,
67
+ depth: parentDepth + 1,
68
+ expanded: false,
69
+ selected: false,
70
+ children: null
71
+ });
72
+ } else if (includeFiles && entry.isFile()) {
73
+ if (!shouldShowFile(entry.name)) continue;
74
+ files.push({
75
+ path: path14.join(parentPath, entry.name),
76
+ name: entry.name,
77
+ depth: parentDepth + 1,
78
+ expanded: false,
79
+ selected: false,
80
+ children: null,
81
+ isFile: true
82
+ });
83
+ }
84
+ }
85
+ dirs.sort((a, b) => a.name.localeCompare(b.name));
86
+ files.sort((a, b) => a.name.localeCompare(b.name));
87
+ return [...dirs, ...files];
88
+ } catch {
89
+ return [];
90
+ }
91
+ }
92
+ function expandNode(items, index, children) {
93
+ const result = [...items];
94
+ result[index] = { ...result[index], expanded: true, children, empty: children.length === 0 };
95
+ result.splice(index + 1, 0, ...children);
96
+ return result;
97
+ }
98
+ function collapseNode(items, index) {
99
+ const node = items[index];
100
+ const result = [...items];
101
+ result[index] = { ...result[index], expanded: false };
102
+ let removeCount = 0;
103
+ for (let i = index + 1; i < result.length; i++) {
104
+ if (result[i].depth > node.depth) {
105
+ removeCount++;
106
+ } else {
107
+ break;
108
+ }
109
+ }
110
+ if (removeCount > 0) {
111
+ result.splice(index + 1, removeCount);
112
+ }
113
+ return result;
114
+ }
115
+ function getParentIndex(items, index) {
116
+ const targetDepth = items[index].depth - 1;
117
+ for (let i = index - 1; i >= 0; i--) {
118
+ if (items[i].depth === targetDepth) return i;
119
+ }
120
+ return index;
121
+ }
122
+ var TREE_SKIP, TREE_INCLUDE_DOT_DIRS, HIDDEN_FILE_EXTENSIONS, treePrompt, tree_prompt_default;
123
+ var init_tree_prompt = __esm({
124
+ "src/lib/tree-prompt.ts"() {
125
+ "use strict";
126
+ init_esm_shims();
127
+ TREE_SKIP = /* @__PURE__ */ new Set([
128
+ "node_modules",
129
+ ".git",
130
+ "__pycache__",
131
+ ".venv",
132
+ "venv",
133
+ "dist",
134
+ "build",
135
+ ".next",
136
+ ".nuxt",
137
+ ".output",
138
+ ".Trash",
139
+ "Library",
140
+ ".cache",
141
+ ".npm",
142
+ ".yarn",
143
+ ".pnpm-store",
144
+ "Caches",
145
+ "Cache",
146
+ ".piut",
147
+ "Applications",
148
+ "Public",
149
+ "Movies",
150
+ "Music",
151
+ "Pictures",
152
+ "Templates"
153
+ ]);
154
+ TREE_INCLUDE_DOT_DIRS = /* @__PURE__ */ new Set([
155
+ ".cursor",
156
+ ".windsurf",
157
+ ".openclaw",
158
+ ".zed",
159
+ ".github",
160
+ ".amazonq",
161
+ ".gemini",
162
+ ".mcporter",
163
+ ".paperclip",
164
+ ".vscode"
165
+ ]);
166
+ HIDDEN_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
167
+ ".png",
168
+ ".jpg",
169
+ ".jpeg",
170
+ ".gif",
171
+ ".svg",
172
+ ".ico",
173
+ ".webp",
174
+ ".bmp",
175
+ ".tiff",
176
+ ".heic",
177
+ ".mp3",
178
+ ".mp4",
179
+ ".wav",
180
+ ".aac",
181
+ ".flac",
182
+ ".ogg",
183
+ ".avi",
184
+ ".mov",
185
+ ".mkv",
186
+ ".wmv",
187
+ ".webm",
188
+ ".zip",
189
+ ".tar",
190
+ ".gz",
191
+ ".bz2",
192
+ ".xz",
193
+ ".7z",
194
+ ".rar",
195
+ ".dmg",
196
+ ".iso",
197
+ ".exe",
198
+ ".dll",
199
+ ".so",
200
+ ".dylib",
201
+ ".o",
202
+ ".a",
203
+ ".wasm",
204
+ ".class",
205
+ ".jar",
206
+ ".pyc",
207
+ ".pyo",
208
+ ".ttf",
209
+ ".otf",
210
+ ".woff",
211
+ ".woff2",
212
+ ".eot",
213
+ ".lock",
214
+ ".map"
215
+ ]);
216
+ treePrompt = createPrompt((config, done) => {
217
+ const root = config.root ?? os8.homedir();
218
+ const pageSize = config.pageSize ?? 15;
219
+ const mode = config.mode ?? "folders";
220
+ const includeFiles = mode === "files";
221
+ const prefix = chalk12.green("?");
222
+ const childrenCache = useRef(/* @__PURE__ */ new Map()).current;
223
+ const [items, setItems] = useState(() => {
224
+ const rootChildren = loadChildren(root, -1, includeFiles);
225
+ childrenCache.set(root, rootChildren);
226
+ return rootChildren;
227
+ });
228
+ const [active, setActive] = useState(0);
229
+ const [done_, setDone] = useState(false);
230
+ useKeypress((event) => {
231
+ if (done_) return;
232
+ if (isEnterKey(event)) {
233
+ const selected = items.filter((n) => n.selected).map((n) => n.path);
234
+ setDone(true);
235
+ done(selected);
236
+ return;
237
+ }
238
+ if (isUpKey(event)) {
239
+ setActive(Math.max(0, active - 1));
240
+ return;
241
+ }
242
+ if (isDownKey(event)) {
243
+ setActive(Math.min(items.length - 1, active + 1));
244
+ return;
245
+ }
246
+ if (isSpaceKey(event)) {
247
+ const node = items[active];
248
+ if (includeFiles && !node.isFile) return;
249
+ if (!includeFiles && node.isFile) return;
250
+ const updated = [...items];
251
+ updated[active] = { ...updated[active], selected: !updated[active].selected };
252
+ setItems(updated);
253
+ return;
254
+ }
255
+ if (event.name === "right") {
256
+ const node = items[active];
257
+ if (node.isFile) return;
258
+ if (node.expanded) return;
259
+ let children;
260
+ if (childrenCache.has(node.path)) {
261
+ children = childrenCache.get(node.path);
262
+ } else {
263
+ children = loadChildren(node.path, node.depth, includeFiles);
264
+ childrenCache.set(node.path, children);
265
+ }
266
+ setItems(expandNode(items, active, children));
267
+ return;
268
+ }
269
+ if (event.name === "left") {
270
+ const node = items[active];
271
+ if (!node.isFile && node.expanded) {
272
+ setItems(collapseNode(items, active));
273
+ } else {
274
+ const parentIdx = getParentIndex(items, active);
275
+ setActive(parentIdx);
276
+ }
277
+ return;
278
+ }
279
+ });
280
+ if (done_) {
281
+ const selected = items.filter((n) => n.selected);
282
+ const label = includeFiles ? "file" : "folder";
283
+ const summary = selected.length === 0 ? chalk12.dim(`no ${label}s selected`) : selected.map((n) => n.isFile ? n.name : n.path).join(", ");
284
+ return `${prefix} ${config.message} ${chalk12.cyan(summary)}`;
285
+ }
286
+ const page = usePagination({
287
+ items,
288
+ active,
289
+ pageSize,
290
+ loop: false,
291
+ renderItem({ item, isActive }) {
292
+ const indent = " ".repeat(item.depth + 1);
293
+ if (item.isFile) {
294
+ const marker2 = item.selected ? chalk12.green("\u25CF ") : "\u25CB ";
295
+ const line2 = `${indent} ${marker2}${item.name}`;
296
+ return isActive ? chalk12.cyan(line2) : line2;
297
+ }
298
+ const icon = item.expanded ? "\u25BE" : "\u25B8";
299
+ const name = `${item.name}/`;
300
+ const suffix = item.error ? chalk12.dim(" (permission denied)") : item.empty ? chalk12.dim(" (empty)") : "";
301
+ if (includeFiles) {
302
+ const line2 = `${indent}${icon} ${name}${suffix}`;
303
+ return isActive ? chalk12.cyan(line2) : chalk12.dim(line2);
304
+ }
305
+ const marker = item.selected ? chalk12.green("\u25CF ") : "\u25CB ";
306
+ const line = `${indent}${icon} ${marker}${name}${suffix}`;
307
+ return isActive ? chalk12.cyan(line) : line;
308
+ }
309
+ });
310
+ const selectHint = includeFiles ? "space select file" : "space select";
311
+ const help = chalk12.dim(` \u2191\u2193 navigate \u2192 expand \u2190 collapse ${selectHint} enter done`);
312
+ const header = chalk12.dim(` ${root}`);
313
+ return `${prefix} ${config.message}
314
+ ${help}
315
+ ${header}
316
+ ${page}`;
317
+ });
318
+ tree_prompt_default = treePrompt;
319
+ }
320
+ });
2
321
 
3
322
  // src/cli.ts
323
+ init_esm_shims();
4
324
  import { Command } from "commander";
5
325
 
6
326
  // src/commands/setup.ts
327
+ init_esm_shims();
7
328
  import fs4 from "fs";
8
- import path6 from "path";
329
+ import path7 from "path";
9
330
  import { execSync } from "child_process";
10
331
  import { password, confirm, checkbox } from "@inquirer/prompts";
11
332
  import chalk2 from "chalk";
12
333
 
13
334
  // src/lib/api.ts
335
+ init_esm_shims();
14
336
  import os from "os";
15
337
  import crypto from "crypto";
16
338
  var API_BASE = process.env.PIUT_API_BASE || "https://piut.com";
@@ -36,7 +358,7 @@ async function loginWithEmail(email, password3) {
36
358
  }
37
359
  return res.json();
38
360
  }
39
- async function* buildBrainStreaming(key, input3) {
361
+ async function* buildBrainStreaming(key, input2) {
40
362
  const res = await fetch(`${API_BASE}/api/cli/build-brain`, {
41
363
  method: "POST",
42
364
  headers: {
@@ -44,7 +366,7 @@ async function* buildBrainStreaming(key, input3) {
44
366
  "Content-Type": "application/json",
45
367
  Accept: "text/event-stream"
46
368
  },
47
- body: JSON.stringify(input3)
369
+ body: JSON.stringify(input2)
48
370
  });
49
371
  if (!res.ok) {
50
372
  const body = await res.json().catch(() => ({ error: "Unknown error" }));
@@ -240,14 +562,16 @@ async function listVaultFiles(key) {
240
562
  }
241
563
  return res.json();
242
564
  }
243
- async function uploadVaultFile(key, filename, content) {
565
+ async function uploadVaultFile(key, filename, content, encoding) {
566
+ const payload = { filename, content };
567
+ if (encoding) payload.encoding = encoding;
244
568
  const res = await fetch(`${API_BASE}/api/cli/vault/upload`, {
245
569
  method: "POST",
246
570
  headers: {
247
571
  Authorization: `Bearer ${key}`,
248
572
  "Content-Type": "application/json"
249
573
  },
250
- body: JSON.stringify({ filename, content })
574
+ body: JSON.stringify(payload)
251
575
  });
252
576
  if (!res.ok) {
253
577
  const body = await res.json().catch(() => ({ error: "Unknown error" }));
@@ -282,8 +606,9 @@ async function deleteVaultFile(key, filename) {
282
606
  }
283
607
 
284
608
  // src/lib/tools.ts
609
+ init_esm_shims();
285
610
  import os2 from "os";
286
- import path from "path";
611
+ import path2 from "path";
287
612
  import crypto2 from "crypto";
288
613
  var MCP_URL = (slug) => `https://piut.com/api/mcp/${slug}`;
289
614
  var AUTH_HEADER = (key) => ({ Authorization: `Bearer ${key}` });
@@ -298,7 +623,7 @@ function machineHeaders(toolName) {
298
623
  };
299
624
  }
300
625
  function appData() {
301
- return process.env.APPDATA || path.join(os2.homedir(), "AppData", "Roaming");
626
+ return process.env.APPDATA || path2.join(os2.homedir(), "AppData", "Roaming");
302
627
  }
303
628
  var TOOLS = [
304
629
  {
@@ -329,7 +654,7 @@ var TOOLS = [
329
654
  configKey: "mcpServers",
330
655
  configPaths: {
331
656
  darwin: ["~/Library/Application Support/Claude/claude_desktop_config.json"],
332
- win32: [path.join(appData(), "Claude", "claude_desktop_config.json")],
657
+ win32: [path2.join(appData(), "Claude", "claude_desktop_config.json")],
333
658
  linux: ["~/.config/Claude/claude_desktop_config.json"]
334
659
  },
335
660
  generateConfig: (slug, key) => ({
@@ -378,7 +703,11 @@ var TOOLS = [
378
703
  id: "copilot",
379
704
  name: "GitHub Copilot",
380
705
  configKey: "servers",
706
+ globalConfigKey: "mcp.servers",
381
707
  configPaths: {
708
+ darwin: ["~/Library/Application Support/Code/User/settings.json"],
709
+ win32: [path2.join(appData(), "Code", "User", "settings.json")],
710
+ linux: ["~/.config/Code/User/settings.json"],
382
711
  project: [".vscode/mcp.json"]
383
712
  },
384
713
  skillFilePath: ".github/copilot-instructions.md",
@@ -463,28 +792,31 @@ var TOOLS = [
463
792
  ];
464
793
 
465
794
  // src/lib/paths.ts
795
+ init_esm_shims();
466
796
  import os3 from "os";
467
- import path2 from "path";
797
+ import path3 from "path";
468
798
  function expandPath(p) {
469
799
  return p.replace(/^~/, os3.homedir());
470
800
  }
471
- function resolveConfigPaths(configPaths) {
801
+ function resolveConfigPaths(tool) {
472
802
  const resolved = [];
803
+ const configKey = tool.configKey || "";
473
804
  const platformKey = process.platform;
474
- const globalPaths = configPaths[platformKey] || [];
805
+ const globalPaths = tool.configPaths[platformKey] || [];
475
806
  for (const p of globalPaths) {
476
- resolved.push(expandPath(p));
807
+ resolved.push({ filePath: expandPath(p), configKey: tool.globalConfigKey || configKey });
477
808
  }
478
- const projectPaths = configPaths.project || [];
809
+ const projectPaths = tool.configPaths.project || [];
479
810
  for (const p of projectPaths) {
480
- resolved.push(path2.resolve(process.cwd(), p));
811
+ resolved.push({ filePath: path3.resolve(process.cwd(), p), configKey });
481
812
  }
482
813
  return resolved;
483
814
  }
484
815
 
485
816
  // src/lib/config.ts
817
+ init_esm_shims();
486
818
  import fs from "fs";
487
- import path3 from "path";
819
+ import path4 from "path";
488
820
  function readConfig(filePath) {
489
821
  let raw;
490
822
  try {
@@ -505,26 +837,46 @@ function readConfig(filePath) {
505
837
  }
506
838
  }
507
839
  function writeConfig(filePath, data) {
508
- fs.mkdirSync(path3.dirname(filePath), { recursive: true });
840
+ fs.mkdirSync(path4.dirname(filePath), { recursive: true });
509
841
  fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
510
842
  }
843
+ function resolveKeyPath(config, keyPath) {
844
+ const parts = keyPath.split(".");
845
+ let current = config;
846
+ for (const part of parts) {
847
+ if (current === void 0 || current === null || typeof current !== "object") return void 0;
848
+ current = current[part];
849
+ }
850
+ return current;
851
+ }
852
+ function setAtKeyPath(config, keyPath, value) {
853
+ const parts = keyPath.split(".");
854
+ let current = config;
855
+ for (let i = 0; i < parts.length - 1; i++) {
856
+ if (!current[parts[i]] || typeof current[parts[i]] !== "object") {
857
+ current[parts[i]] = {};
858
+ }
859
+ current = current[parts[i]];
860
+ }
861
+ current[parts[parts.length - 1]] = value;
862
+ }
511
863
  function isPiutConfigured(filePath, configKey) {
512
864
  const config = readConfig(filePath);
513
865
  if (!config) return false;
514
- const servers = config[configKey];
866
+ const servers = resolveKeyPath(config, configKey);
515
867
  return !!servers?.["piut-context"];
516
868
  }
517
869
  function mergeConfig(filePath, configKey, serverConfig) {
518
870
  const existing = readConfig(filePath) || {};
519
- const servers = existing[configKey] || {};
871
+ const servers = resolveKeyPath(existing, configKey) || {};
520
872
  servers["piut-context"] = serverConfig;
521
- existing[configKey] = servers;
873
+ setAtKeyPath(existing, configKey, servers);
522
874
  writeConfig(filePath, existing);
523
875
  }
524
876
  function getPiutConfig(filePath, configKey) {
525
877
  const config = readConfig(filePath);
526
878
  if (!config) return null;
527
- const servers = config[configKey];
879
+ const servers = resolveKeyPath(config, configKey);
528
880
  const piut = servers?.["piut-context"];
529
881
  return piut ?? null;
530
882
  }
@@ -576,10 +928,10 @@ function extractSlugFromConfig(piutConfig) {
576
928
  function removeFromConfig(filePath, configKey) {
577
929
  const config = readConfig(filePath);
578
930
  if (!config) return false;
579
- const servers = config[configKey];
931
+ const servers = resolveKeyPath(config, configKey);
580
932
  if (!servers?.["piut-context"]) return false;
581
933
  delete servers["piut-context"];
582
- if (Object.keys(servers).length === 0) {
934
+ if (Object.keys(servers).length === 0 && !configKey.includes(".")) {
583
935
  delete config[configKey];
584
936
  }
585
937
  writeConfig(filePath, config);
@@ -587,8 +939,9 @@ function removeFromConfig(filePath, configKey) {
587
939
  }
588
940
 
589
941
  // src/lib/skill.ts
942
+ init_esm_shims();
590
943
  import fs2 from "fs";
591
- import path4 from "path";
944
+ import path5 from "path";
592
945
  var SKILL_SNIPPET = `## p\u0131ut Context (MCP Server: piut-context)
593
946
 
594
947
  This project uses p\u0131ut for persistent personal context via MCP (Model Context Protocol).
@@ -631,7 +984,7 @@ p\u0131ut provides MCP tools \u2014 do NOT read local .piut/ files directly. Use
631
984
  Full skill reference: .piut/skill.md`;
632
985
  var SEPARATOR = "\n\n---\n\n";
633
986
  function placeSkillFile(filePath) {
634
- const absPath = path4.isAbsolute(filePath) ? filePath : path4.resolve(process.cwd(), filePath);
987
+ const absPath = path5.isAbsolute(filePath) ? filePath : path5.resolve(process.cwd(), filePath);
635
988
  try {
636
989
  const existing = fs2.readFileSync(absPath, "utf-8");
637
990
  if (existing.includes("p\u0131ut Context")) {
@@ -641,7 +994,7 @@ function placeSkillFile(filePath) {
641
994
  return { created: false, appended: true };
642
995
  } catch (err) {
643
996
  if (err.code === "ENOENT") {
644
- fs2.mkdirSync(path4.dirname(absPath), { recursive: true });
997
+ fs2.mkdirSync(path5.dirname(absPath), { recursive: true });
645
998
  fs2.writeFileSync(absPath, SKILL_SNIPPET + "\n", "utf-8");
646
999
  return { created: true, appended: false };
647
1000
  }
@@ -650,8 +1003,9 @@ function placeSkillFile(filePath) {
650
1003
  }
651
1004
 
652
1005
  // src/lib/piut-dir.ts
1006
+ init_esm_shims();
653
1007
  import fs3 from "fs";
654
- import path5 from "path";
1008
+ import path6 from "path";
655
1009
  var API_BASE2 = process.env.PIUT_API_BASE || "https://piut.com";
656
1010
  var PIUT_DIR = ".piut";
657
1011
  var CONFIG_FILE = "config.json";
@@ -693,13 +1047,13 @@ Protocol: JSON-RPC 2.0 over HTTPS
693
1047
  4. Use \`append_brain\` for quick notes and facts
694
1048
  `;
695
1049
  function piutDir(projectPath) {
696
- return path5.join(projectPath, PIUT_DIR);
1050
+ return path6.join(projectPath, PIUT_DIR);
697
1051
  }
698
1052
  function writePiutConfig(projectPath, config) {
699
1053
  const dir = piutDir(projectPath);
700
1054
  fs3.mkdirSync(dir, { recursive: true });
701
1055
  fs3.writeFileSync(
702
- path5.join(dir, CONFIG_FILE),
1056
+ path6.join(dir, CONFIG_FILE),
703
1057
  JSON.stringify(config, null, 2) + "\n",
704
1058
  "utf-8"
705
1059
  );
@@ -716,10 +1070,10 @@ async function writePiutSkill(projectPath, slug, apiKey) {
716
1070
  content = MINIMAL_SKILL_CONTENT;
717
1071
  }
718
1072
  content = content.replaceAll("{{slug}}", slug).replaceAll("{{key}}", apiKey);
719
- fs3.writeFileSync(path5.join(dir, SKILL_FILE), content, "utf-8");
1073
+ fs3.writeFileSync(path6.join(dir, SKILL_FILE), content, "utf-8");
720
1074
  }
721
1075
  function ensureGitignored(projectPath) {
722
- const gitignorePath = path5.join(projectPath, ".gitignore");
1076
+ const gitignorePath = path6.join(projectPath, ".gitignore");
723
1077
  let content = "";
724
1078
  try {
725
1079
  content = fs3.readFileSync(gitignorePath, "utf-8");
@@ -744,10 +1098,11 @@ function removePiutDir(projectPath) {
744
1098
  return true;
745
1099
  }
746
1100
  function hasPiutDir(projectPath) {
747
- return fs3.existsSync(path5.join(piutDir(projectPath), CONFIG_FILE));
1101
+ return fs3.existsSync(path6.join(piutDir(projectPath), CONFIG_FILE));
748
1102
  }
749
1103
 
750
1104
  // src/lib/ui.ts
1105
+ init_esm_shims();
751
1106
  import chalk from "chalk";
752
1107
  var brand = chalk.hex("#8B5CF6");
753
1108
  var success = chalk.green;
@@ -833,6 +1188,7 @@ var Spinner = class {
833
1188
  };
834
1189
 
835
1190
  // src/types.ts
1191
+ init_esm_shims();
836
1192
  var CliError = class extends Error {
837
1193
  constructor(message) {
838
1194
  super(message || "");
@@ -884,15 +1240,15 @@ async function setupCommand(options) {
884
1240
  for (const tool of TOOLS) {
885
1241
  if (toolFilter && tool.id !== toolFilter) continue;
886
1242
  if (tool.skillOnly) continue;
887
- const paths = resolveConfigPaths(tool.configPaths);
888
- for (const configPath of paths) {
889
- const exists = fs4.existsSync(configPath);
890
- const parentExists = fs4.existsSync(path6.dirname(configPath));
1243
+ const paths = resolveConfigPaths(tool);
1244
+ for (const { filePath, configKey } of paths) {
1245
+ const exists = fs4.existsSync(filePath);
1246
+ const parentExists = fs4.existsSync(path7.dirname(filePath));
891
1247
  if (exists || parentExists) {
892
- const configured2 = exists && !!tool.configKey && isPiutConfigured(configPath, tool.configKey);
1248
+ const configured2 = exists && !!configKey && isPiutConfigured(filePath, configKey);
893
1249
  let staleKey = false;
894
- if (configured2 && tool.configKey) {
895
- const piutConfig = getPiutConfig(configPath, tool.configKey);
1250
+ if (configured2 && configKey) {
1251
+ const piutConfig = getPiutConfig(filePath, configKey);
896
1252
  if (piutConfig) {
897
1253
  const existingKey = extractKeyFromConfig(piutConfig);
898
1254
  if (existingKey && existingKey !== apiKey) {
@@ -906,7 +1262,8 @@ async function setupCommand(options) {
906
1262
  }
907
1263
  detected.push({
908
1264
  tool,
909
- configPath,
1265
+ configPath: filePath,
1266
+ resolvedConfigKey: configKey,
910
1267
  exists,
911
1268
  alreadyConfigured: configured2 && !staleKey,
912
1269
  staleKey
@@ -996,9 +1353,9 @@ async function setupCommand(options) {
996
1353
  }
997
1354
  if (quickSuccess) continue;
998
1355
  }
999
- if (tool.generateConfig && tool.configKey) {
1356
+ if (tool.generateConfig && det.resolvedConfigKey) {
1000
1357
  const serverConfig = tool.generateConfig(slug, apiKey);
1001
- mergeConfig(configPath, tool.configKey, serverConfig);
1358
+ mergeConfig(configPath, det.resolvedConfigKey, serverConfig);
1002
1359
  configured.push(tool.name);
1003
1360
  toolLine(tool.name, success("configured"), "\u2714");
1004
1361
  }
@@ -1026,7 +1383,7 @@ async function setupCommand(options) {
1026
1383
  }
1027
1384
  if (configured.length > 0) {
1028
1385
  const cwd = process.cwd();
1029
- const isProject2 = fs4.existsSync(path6.join(cwd, ".git")) || fs4.existsSync(path6.join(cwd, "package.json"));
1386
+ const isProject2 = fs4.existsSync(path7.join(cwd, ".git")) || fs4.existsSync(path7.join(cwd, "package.json"));
1030
1387
  if (isProject2) {
1031
1388
  const { serverUrl } = validationResult;
1032
1389
  writePiutConfig(cwd, { slug, apiKey, serverUrl });
@@ -1042,8 +1399,8 @@ async function setupCommand(options) {
1042
1399
  console.log(dim(" Verifying..."));
1043
1400
  for (const det of selected) {
1044
1401
  if (!configured.includes(det.tool.name)) continue;
1045
- if (!det.tool.configKey) continue;
1046
- const piutConfig = getPiutConfig(det.configPath, det.tool.configKey);
1402
+ if (!det.resolvedConfigKey) continue;
1403
+ const piutConfig = getPiutConfig(det.configPath, det.resolvedConfigKey);
1047
1404
  if (piutConfig) {
1048
1405
  toolLine(det.tool.name, success("config verified"), "\u2714");
1049
1406
  } else {
@@ -1084,51 +1441,20 @@ function isCommandAvailable(cmd) {
1084
1441
  }
1085
1442
 
1086
1443
  // src/commands/status.ts
1087
- import fs9 from "fs";
1088
- import os7 from "os";
1089
- import path12 from "path";
1444
+ init_esm_shims();
1445
+ import fs7 from "fs";
1446
+ import os6 from "os";
1447
+ import path10 from "path";
1090
1448
  import chalk3 from "chalk";
1091
1449
 
1092
1450
  // src/lib/brain-scanner.ts
1093
- import fs7 from "fs";
1094
- import path10 from "path";
1095
- import os5 from "os";
1451
+ init_esm_shims();
1452
+ import fs5 from "fs";
1453
+ import path8 from "path";
1454
+ import os4 from "os";
1096
1455
 
1097
1456
  // src/lib/file-types.ts
1098
- import path7 from "path";
1099
- var DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
1100
- ".pdf",
1101
- ".docx",
1102
- ".doc",
1103
- ".pptx",
1104
- ".pages",
1105
- ".key",
1106
- ".rtf",
1107
- ".odt",
1108
- ".odp",
1109
- ".eml",
1110
- ".mbox"
1111
- ]);
1112
- var PLAIN_TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
1113
- ".md",
1114
- ".markdown",
1115
- ".txt",
1116
- ".csv",
1117
- ".xml",
1118
- ".html",
1119
- ".htm",
1120
- ".json",
1121
- ".yaml",
1122
- ".yml",
1123
- ".toml",
1124
- ".rst",
1125
- ".adoc",
1126
- ".tex",
1127
- ".ini",
1128
- ".cfg",
1129
- ".conf",
1130
- ".log"
1131
- ]);
1457
+ init_esm_shims();
1132
1458
  var AI_CONFIG_FILENAMES = /* @__PURE__ */ new Set([
1133
1459
  "CLAUDE.md",
1134
1460
  ".cursorrules",
@@ -1142,350 +1468,46 @@ var AI_CONFIG_FILENAMES = /* @__PURE__ */ new Set([
1142
1468
  "IDENTITY.md",
1143
1469
  "copilot-instructions.md"
1144
1470
  ]);
1145
- var PARSEABLE_EXTENSIONS = /* @__PURE__ */ new Set([
1146
- ...DOCUMENT_EXTENSIONS,
1147
- ...PLAIN_TEXT_EXTENSIONS
1148
- ]);
1149
- var EXCLUDED_EXTENSIONS = /* @__PURE__ */ new Set([
1150
- ".js",
1151
- ".ts",
1152
- ".jsx",
1153
- ".tsx",
1154
- ".mjs",
1155
- ".cjs",
1156
- ".py",
1157
- ".pyw",
1158
- ".pyi",
1159
- ".rs",
1160
- ".go",
1161
- ".java",
1162
- ".kt",
1163
- ".scala",
1164
- ".clj",
1165
- ".c",
1166
- ".cpp",
1167
- ".cc",
1168
- ".h",
1169
- ".hpp",
1170
- ".cs",
1171
- ".rb",
1172
- ".php",
1173
- ".swift",
1174
- ".m",
1175
- ".mm",
1176
- ".lua",
1177
- ".r",
1178
- ".jl",
1179
- ".zig",
1180
- ".nim",
1181
- ".v",
1182
- ".sh",
1183
- ".bash",
1184
- ".zsh",
1185
- ".fish",
1186
- ".ps1",
1187
- ".bat",
1188
- ".cmd",
1189
- ".sql",
1190
- ".graphql",
1191
- ".gql",
1192
- ".proto",
1193
- ".css",
1194
- ".scss",
1195
- ".sass",
1196
- ".less",
1197
- ".styl",
1198
- ".xls",
1199
- ".xlsx",
1200
- ".numbers",
1201
- ".sqlite",
1202
- ".db",
1203
- ".dat",
1204
- ".parquet",
1205
- ".avro",
1206
- ".png",
1207
- ".jpg",
1208
- ".jpeg",
1209
- ".gif",
1210
- ".svg",
1211
- ".ico",
1212
- ".webp",
1213
- ".bmp",
1214
- ".tiff",
1215
- ".heic",
1216
- ".mp3",
1217
- ".mp4",
1218
- ".wav",
1219
- ".aac",
1220
- ".flac",
1221
- ".ogg",
1222
- ".avi",
1223
- ".mov",
1224
- ".mkv",
1225
- ".wmv",
1226
- ".webm",
1227
- ".zip",
1228
- ".tar",
1229
- ".gz",
1230
- ".bz2",
1231
- ".xz",
1232
- ".7z",
1233
- ".rar",
1234
- ".dmg",
1235
- ".iso",
1236
- ".exe",
1237
- ".dll",
1238
- ".so",
1239
- ".dylib",
1240
- ".o",
1241
- ".a",
1242
- ".wasm",
1243
- ".class",
1244
- ".jar",
1245
- ".pyc",
1246
- ".pyo",
1247
- ".ttf",
1248
- ".otf",
1249
- ".woff",
1250
- ".woff2",
1251
- ".eot",
1252
- ".lock",
1253
- ".map",
1254
- ".min.js",
1255
- ".min.css"
1256
- ]);
1257
- function canParse(filename) {
1258
- return PARSEABLE_EXTENSIONS.has(path7.extname(filename).toLowerCase());
1259
- }
1260
- function isAiConfigFile(filename) {
1261
- return AI_CONFIG_FILENAMES.has(path7.basename(filename));
1262
- }
1263
- function getFileCategory(filename) {
1264
- const base = path7.basename(filename);
1265
- if (AI_CONFIG_FILENAMES.has(base)) return "config";
1266
- const ext = path7.extname(filename).toLowerCase();
1267
- if (DOCUMENT_EXTENSIONS.has(ext)) return "document";
1268
- if (PLAIN_TEXT_EXTENSIONS.has(ext)) return "text";
1269
- if (EXCLUDED_EXTENSIONS.has(ext)) return "excluded";
1270
- return "unknown";
1271
- }
1272
1471
 
1273
- // src/lib/file-parsers.ts
1274
- import fs5 from "fs";
1275
- import path8 from "path";
1276
- var MAX_RAW_SIZE = 500 * 1024;
1277
- var MAX_EXTRACTED_TEXT = 100 * 1024;
1278
- function truncate(text) {
1279
- if (text.length <= MAX_EXTRACTED_TEXT) return text;
1280
- return text.slice(0, MAX_EXTRACTED_TEXT);
1281
- }
1282
- function stripHtml(html) {
1283
- return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<\/div>/gi, "\n").replace(/<\/li>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/\n{3,}/g, "\n\n").trim();
1284
- }
1285
- async function parsePdf(buffer) {
1286
- const { PDFParse } = await import("pdf-parse");
1287
- const parser = new PDFParse({ data: new Uint8Array(buffer) });
1288
- const result = await parser.getText();
1289
- return result.text;
1290
- }
1291
- async function parseDocx(buffer) {
1292
- const { extractRawText } = await import("mammoth");
1293
- const result = await extractRawText({ buffer });
1294
- return result.value;
1295
- }
1296
- async function parsePptx(buffer) {
1297
- const JSZip = (await import("jszip")).default;
1298
- const zip = await JSZip.loadAsync(buffer);
1299
- const texts = [];
1300
- const slideFiles = Object.keys(zip.files).filter((name) => /^ppt\/slides\/slide\d+\.xml$/i.test(name)).sort((a, b) => {
1301
- const numA = parseInt(a.match(/slide(\d+)/)?.[1] || "0");
1302
- const numB = parseInt(b.match(/slide(\d+)/)?.[1] || "0");
1303
- return numA - numB;
1304
- });
1305
- for (const slidePath of slideFiles) {
1306
- const xml = await zip.files[slidePath].async("string");
1307
- const matches = xml.match(/<a:t[^>]*>([^<]*)<\/a:t>/g);
1308
- if (matches) {
1309
- texts.push(matches.map((m) => m.replace(/<[^>]+>/g, "")).join(" "));
1310
- }
1311
- }
1312
- return texts.join("\n\n");
1313
- }
1314
- async function parseAppleDoc(buffer) {
1315
- const JSZip = (await import("jszip")).default;
1316
- const zip = await JSZip.loadAsync(buffer);
1317
- if (zip.files["preview.pdf"]) {
1318
- const pdfBuf = await zip.files["preview.pdf"].async("nodebuffer");
1319
- try {
1320
- return await parsePdf(pdfBuf);
1321
- } catch {
1322
- }
1323
- }
1324
- const texts = [];
1325
- for (const [name, file] of Object.entries(zip.files)) {
1326
- if (name.endsWith(".iwa") && !file.dir) {
1327
- try {
1328
- const buf = await file.async("nodebuffer");
1329
- const str = buf.toString("utf-8");
1330
- const readable = str.match(/[\x20-\x7E\xC0-\xFF]{4,}/g);
1331
- if (readable) {
1332
- texts.push(...readable.filter((s) => s.length > 10));
1333
- }
1334
- } catch {
1335
- }
1336
- }
1337
- }
1338
- return texts.join("\n\n");
1339
- }
1340
- async function parseRtf(buffer) {
1341
- const { fromString } = await import("@iarna/rtf-to-html");
1342
- return new Promise((resolve, reject) => {
1343
- fromString(buffer.toString("utf-8"), (err, html) => {
1344
- if (err) {
1345
- reject(err);
1346
- return;
1347
- }
1348
- resolve(stripHtml(html));
1349
- });
1350
- });
1351
- }
1352
- async function parseOpenDocument(buffer) {
1353
- const JSZip = (await import("jszip")).default;
1354
- const zip = await JSZip.loadAsync(buffer);
1355
- const contentXml = zip.files["content.xml"];
1356
- if (!contentXml) return "";
1357
- return stripHtml(await contentXml.async("string"));
1358
- }
1359
- function parseEml(buffer) {
1360
- const content = buffer.toString("utf-8");
1361
- const boundaryMatch = content.match(/boundary="?([^\s"]+)"?/i);
1362
- if (boundaryMatch) {
1363
- const parts = content.split(`--${boundaryMatch[1]}`);
1364
- for (const part of parts) {
1365
- if (/content-type:\s*text\/plain/i.test(part)) {
1366
- const bodyStart = part.indexOf("\n\n");
1367
- if (bodyStart !== -1) return part.slice(bodyStart + 2).trim();
1368
- }
1369
- }
1370
- }
1371
- const headerEnd = content.indexOf("\n\n");
1372
- if (headerEnd !== -1) {
1373
- const body = content.slice(headerEnd + 2);
1374
- if (!/<html/i.test(body.slice(0, 200))) return body.trim();
1375
- return stripHtml(body);
1376
- }
1377
- return content.trim();
1378
- }
1379
- function parseMbox(buffer) {
1380
- const content = buffer.toString("utf-8");
1381
- const messages = content.split(/^From /m).filter(Boolean);
1382
- const texts = [];
1383
- for (const msg of messages.slice(0, 50)) {
1384
- const headerEnd = msg.indexOf("\n\n");
1385
- if (headerEnd !== -1) {
1386
- const body = msg.slice(headerEnd + 2);
1387
- texts.push(!/<html/i.test(body.slice(0, 200)) ? body.trim() : stripHtml(body));
1388
- }
1389
- }
1390
- return texts.join("\n\n---\n\n");
1391
- }
1392
- async function extractTextFromFile(filePath) {
1393
- const ext = path8.extname(filePath).toLowerCase();
1394
- try {
1395
- const stat = fs5.statSync(filePath);
1396
- if (!stat.isFile()) return null;
1397
- if (stat.size > MAX_RAW_SIZE) return null;
1398
- } catch {
1399
- return null;
1400
- }
1401
- if (PLAIN_TEXT_EXTENSIONS.has(ext)) {
1402
- try {
1403
- return truncate(fs5.readFileSync(filePath, "utf-8"));
1404
- } catch {
1405
- return null;
1406
- }
1407
- }
1408
- if (!DOCUMENT_EXTENSIONS.has(ext)) return null;
1409
- try {
1410
- const buffer = fs5.readFileSync(filePath);
1411
- let text;
1412
- switch (ext) {
1413
- case ".pdf":
1414
- text = await parsePdf(buffer);
1415
- break;
1416
- case ".docx":
1417
- case ".doc":
1418
- text = await parseDocx(buffer);
1419
- break;
1420
- case ".pptx":
1421
- text = await parsePptx(buffer);
1422
- break;
1423
- case ".pages":
1424
- case ".key":
1425
- text = await parseAppleDoc(buffer);
1426
- break;
1427
- case ".rtf":
1428
- text = await parseRtf(buffer);
1429
- break;
1430
- case ".odt":
1431
- case ".odp":
1432
- text = await parseOpenDocument(buffer);
1433
- break;
1434
- case ".eml":
1435
- text = parseEml(buffer);
1436
- break;
1437
- case ".mbox":
1438
- text = parseMbox(buffer);
1439
- break;
1440
- default:
1441
- return null;
1442
- }
1443
- return truncate(text);
1444
- } catch {
1445
- return null;
1446
- }
1447
- }
1448
- function formatSize(bytes) {
1449
- if (bytes < 1024) return `${bytes} B`;
1450
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1451
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1452
- }
1453
-
1454
- // src/lib/folder-tree.ts
1455
- import fs6 from "fs";
1456
- import path9 from "path";
1457
- import os4 from "os";
1472
+ // src/lib/brain-scanner.ts
1458
1473
  var home = os4.homedir();
1459
- function displayPath(p) {
1460
- return p.startsWith(home) ? "~" + p.slice(home.length) : p;
1461
- }
1462
- function groupFilesByFolder(files) {
1463
- const map = /* @__PURE__ */ new Map();
1464
- for (const file of files) {
1465
- const folder = file.folder;
1466
- if (!map.has(folder)) map.set(folder, []);
1467
- map.get(folder).push(file);
1468
- }
1469
- const results = [];
1470
- for (const [folderPath, folderFiles] of map) {
1471
- results.push({
1472
- path: folderPath,
1473
- displayPath: displayPath(folderPath),
1474
- files: folderFiles,
1475
- fileCount: folderFiles.length,
1476
- totalBytes: folderFiles.reduce((sum, f) => sum + f.sizeBytes, 0)
1477
- });
1478
- }
1479
- results.sort((a, b) => a.displayPath.localeCompare(b.displayPath));
1480
- return results;
1481
- }
1482
- function formatFolderChoice(folder) {
1483
- return `${folder.displayPath} \u2014 ${folder.fileCount} file${folder.fileCount === 1 ? "" : "s"} (${formatSize(folder.totalBytes)})`;
1484
- }
1485
- function formatSelectionSummary(folders) {
1486
- const totalFiles = folders.reduce((sum, f) => sum + f.fileCount, 0);
1487
- const totalBytes = folders.reduce((sum, f) => sum + f.totalBytes, 0);
1488
- return `${folders.length} folder${folders.length === 1 ? "" : "s"} selected (${totalFiles} file${totalFiles === 1 ? "" : "s"}, ${formatSize(totalBytes)})`;
1474
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
1475
+ "node_modules",
1476
+ ".git",
1477
+ "__pycache__",
1478
+ ".venv",
1479
+ "venv",
1480
+ "dist",
1481
+ "build",
1482
+ ".next",
1483
+ ".nuxt",
1484
+ ".output",
1485
+ ".Trash",
1486
+ "Library",
1487
+ ".cache",
1488
+ ".npm",
1489
+ ".yarn",
1490
+ ".pnpm-store",
1491
+ "Caches",
1492
+ "Cache",
1493
+ ".piut"
1494
+ ]);
1495
+ var SCAN_DOT_DIRS = /* @__PURE__ */ new Set([
1496
+ ".cursor",
1497
+ ".windsurf",
1498
+ ".github",
1499
+ ".zed",
1500
+ ".amazonq",
1501
+ ".vscode",
1502
+ ".gemini",
1503
+ ".openclaw",
1504
+ ".mcporter",
1505
+ ".paperclip"
1506
+ // .claude intentionally excluded — useful files collected by collectGlobalConfigFiles()
1507
+ ]);
1508
+ function shouldSkipDir(name) {
1509
+ if (name.startsWith(".") && !SCAN_DOT_DIRS.has(name)) return true;
1510
+ return SKIP_DIRS.has(name);
1489
1511
  }
1490
1512
  var SKIP_HOME_DIRS = /* @__PURE__ */ new Set([
1491
1513
  "Library",
@@ -1498,7 +1520,6 @@ var SKIP_HOME_DIRS = /* @__PURE__ */ new Set([
1498
1520
  ".Trash"
1499
1521
  ]);
1500
1522
  var INCLUDE_DOT_DIRS = /* @__PURE__ */ new Set([
1501
- ".claude",
1502
1523
  ".cursor",
1503
1524
  ".windsurf",
1504
1525
  ".openclaw",
@@ -1508,26 +1529,27 @@ var INCLUDE_DOT_DIRS = /* @__PURE__ */ new Set([
1508
1529
  ".gemini",
1509
1530
  ".mcporter",
1510
1531
  ".paperclip"
1532
+ // .claude excluded — useful files collected by collectGlobalConfigFiles()
1511
1533
  ]);
1512
1534
  function getDefaultScanDirs() {
1513
1535
  const dirs = [];
1514
1536
  try {
1515
- const entries = fs6.readdirSync(home, { withFileTypes: true });
1537
+ const entries = fs5.readdirSync(home, { withFileTypes: true });
1516
1538
  for (const entry of entries) {
1517
1539
  if (!entry.isDirectory()) continue;
1518
1540
  if (entry.name.startsWith(".") && !INCLUDE_DOT_DIRS.has(entry.name)) continue;
1519
1541
  if (SKIP_HOME_DIRS.has(entry.name)) continue;
1520
- dirs.push(path9.join(home, entry.name));
1542
+ dirs.push(path8.join(home, entry.name));
1521
1543
  }
1522
1544
  } catch {
1523
1545
  }
1524
- const cloudStorage = path9.join(home, "Library", "CloudStorage");
1546
+ const cloudStorage = path8.join(home, "Library", "CloudStorage");
1525
1547
  try {
1526
- if (fs6.existsSync(cloudStorage) && fs6.statSync(cloudStorage).isDirectory()) {
1527
- const entries = fs6.readdirSync(cloudStorage, { withFileTypes: true });
1548
+ if (fs5.existsSync(cloudStorage) && fs5.statSync(cloudStorage).isDirectory()) {
1549
+ const entries = fs5.readdirSync(cloudStorage, { withFileTypes: true });
1528
1550
  for (const entry of entries) {
1529
1551
  if (!entry.isDirectory()) continue;
1530
- const fullPath = path9.join(cloudStorage, entry.name);
1552
+ const fullPath = path8.join(cloudStorage, entry.name);
1531
1553
  if (!dirs.includes(fullPath)) {
1532
1554
  dirs.push(fullPath);
1533
1555
  }
@@ -1538,64 +1560,23 @@ function getDefaultScanDirs() {
1538
1560
  if (dirs.length === 0) dirs.push(home);
1539
1561
  return dirs;
1540
1562
  }
1541
-
1542
- // src/lib/brain-scanner.ts
1543
- var home2 = os5.homedir();
1544
- var SKIP_DIRS = /* @__PURE__ */ new Set([
1545
- "node_modules",
1546
- ".git",
1547
- "__pycache__",
1548
- ".venv",
1549
- "venv",
1550
- "dist",
1551
- "build",
1552
- ".next",
1553
- ".nuxt",
1554
- ".output",
1555
- ".Trash",
1556
- "Library",
1557
- ".cache",
1558
- ".npm",
1559
- ".yarn",
1560
- ".pnpm-store",
1561
- "Caches",
1562
- "Cache",
1563
- ".piut"
1564
- ]);
1565
- var SCAN_DOT_DIRS = /* @__PURE__ */ new Set([
1566
- ".claude",
1567
- ".cursor",
1568
- ".windsurf",
1569
- ".github",
1570
- ".zed",
1571
- ".amazonq",
1572
- ".vscode",
1573
- ".gemini",
1574
- ".openclaw",
1575
- ".mcporter",
1576
- ".paperclip"
1577
- ]);
1578
- function shouldSkipDir(name) {
1579
- if (name.startsWith(".") && !SCAN_DOT_DIRS.has(name)) return true;
1580
- return SKIP_DIRS.has(name);
1581
- }
1582
1563
  function isProject(dirPath) {
1583
- return fs7.existsSync(path10.join(dirPath, ".git")) || fs7.existsSync(path10.join(dirPath, "package.json")) || fs7.existsSync(path10.join(dirPath, "Cargo.toml")) || fs7.existsSync(path10.join(dirPath, "pyproject.toml")) || fs7.existsSync(path10.join(dirPath, "go.mod"));
1564
+ return fs5.existsSync(path8.join(dirPath, ".git")) || fs5.existsSync(path8.join(dirPath, "package.json")) || fs5.existsSync(path8.join(dirPath, "Cargo.toml")) || fs5.existsSync(path8.join(dirPath, "pyproject.toml")) || fs5.existsSync(path8.join(dirPath, "go.mod"));
1584
1565
  }
1585
1566
  function buildProjectInfo(projectPath) {
1586
- const hasPkgJson = fs7.existsSync(path10.join(projectPath, "package.json"));
1567
+ const hasPkgJson = fs5.existsSync(path8.join(projectPath, "package.json"));
1587
1568
  let description = "";
1588
1569
  if (hasPkgJson) {
1589
1570
  try {
1590
- const pkg = JSON.parse(fs7.readFileSync(path10.join(projectPath, "package.json"), "utf-8"));
1571
+ const pkg = JSON.parse(fs5.readFileSync(path8.join(projectPath, "package.json"), "utf-8"));
1591
1572
  description = pkg.description || "";
1592
1573
  } catch {
1593
1574
  }
1594
1575
  }
1595
- const readmePath = path10.join(projectPath, "README.md");
1596
- if (!description && fs7.existsSync(readmePath)) {
1576
+ const readmePath = path8.join(projectPath, "README.md");
1577
+ if (!description && fs5.existsSync(readmePath)) {
1597
1578
  try {
1598
- const content = fs7.readFileSync(readmePath, "utf-8");
1579
+ const content = fs5.readFileSync(readmePath, "utf-8");
1599
1580
  const lines = content.split("\n");
1600
1581
  let foundHeading = false;
1601
1582
  for (const line of lines) {
@@ -1612,15 +1593,15 @@ function buildProjectInfo(projectPath) {
1612
1593
  }
1613
1594
  }
1614
1595
  return {
1615
- name: path10.basename(projectPath),
1596
+ name: path8.basename(projectPath),
1616
1597
  path: projectPath,
1617
1598
  description,
1618
- hasClaudeMd: fs7.existsSync(path10.join(projectPath, "CLAUDE.md")) || fs7.existsSync(path10.join(projectPath, ".claude", "rules")),
1619
- hasCursorRules: fs7.existsSync(path10.join(projectPath, ".cursorrules")) || fs7.existsSync(path10.join(projectPath, ".cursor", "rules")),
1620
- hasWindsurfRules: fs7.existsSync(path10.join(projectPath, ".windsurfrules")) || fs7.existsSync(path10.join(projectPath, ".windsurf", "rules")),
1621
- hasCopilotInstructions: fs7.existsSync(path10.join(projectPath, ".github", "copilot-instructions.md")) || fs7.existsSync(path10.join(projectPath, ".github", "instructions")),
1622
- hasConventionsMd: fs7.existsSync(path10.join(projectPath, "CONVENTIONS.md")) || fs7.existsSync(path10.join(projectPath, ".amazonq", "rules")),
1623
- hasZedRules: fs7.existsSync(path10.join(projectPath, ".rules"))
1599
+ hasClaudeMd: fs5.existsSync(path8.join(projectPath, "CLAUDE.md")) || fs5.existsSync(path8.join(projectPath, ".claude", "rules")),
1600
+ hasCursorRules: fs5.existsSync(path8.join(projectPath, ".cursorrules")) || fs5.existsSync(path8.join(projectPath, ".cursor", "rules")),
1601
+ hasWindsurfRules: fs5.existsSync(path8.join(projectPath, ".windsurfrules")) || fs5.existsSync(path8.join(projectPath, ".windsurf", "rules")),
1602
+ hasCopilotInstructions: fs5.existsSync(path8.join(projectPath, ".github", "copilot-instructions.md")) || fs5.existsSync(path8.join(projectPath, ".github", "instructions")),
1603
+ hasConventionsMd: fs5.existsSync(path8.join(projectPath, "CONVENTIONS.md")) || fs5.existsSync(path8.join(projectPath, ".amazonq", "rules")),
1604
+ hasZedRules: fs5.existsSync(path8.join(projectPath, ".rules"))
1624
1605
  };
1625
1606
  }
1626
1607
  var MAX_PROJECT_DEPTH = 4;
@@ -1630,17 +1611,17 @@ function detectProjects(scanDirs, onProgress) {
1630
1611
  function walk(dir, depth) {
1631
1612
  if (depth > MAX_PROJECT_DEPTH) return;
1632
1613
  try {
1633
- const items = fs7.readdirSync(dir, { withFileTypes: true });
1614
+ const items = fs5.readdirSync(dir, { withFileTypes: true });
1634
1615
  for (const item of items) {
1635
1616
  if (!item.isDirectory()) continue;
1636
1617
  if (shouldSkipDir(item.name)) continue;
1637
- const fullPath = path10.join(dir, item.name);
1618
+ const fullPath = path8.join(dir, item.name);
1638
1619
  if (seen.has(fullPath)) continue;
1639
1620
  seen.add(fullPath);
1640
1621
  if (isProject(fullPath)) {
1641
1622
  const info = buildProjectInfo(fullPath);
1642
1623
  projects.push(info);
1643
- onProgress?.({ phase: "projects", message: `${info.name} (${fullPath.replace(home2, "~")})` });
1624
+ onProgress?.({ phase: "projects", message: `${info.name} (${fullPath})` });
1644
1625
  } else {
1645
1626
  walk(fullPath, depth + 1);
1646
1627
  }
@@ -1654,36 +1635,41 @@ function detectProjects(scanDirs, onProgress) {
1654
1635
  return projects;
1655
1636
  }
1656
1637
  var MAX_CONFIG_SIZE = 100 * 1024;
1657
- function collectConfigFiles(projects, onProgress) {
1638
+ var MAX_BRAIN_INPUT_BYTES = 1e6;
1639
+ function collectGlobalConfigFiles(onProgress) {
1658
1640
  const configs = [];
1659
1641
  const globalPaths = [
1660
- path10.join(home2, ".claude", "MEMORY.md"),
1661
- path10.join(home2, ".claude", "CLAUDE.md"),
1662
- path10.join(home2, ".openclaw", "workspace", "SOUL.md"),
1663
- path10.join(home2, ".openclaw", "workspace", "MEMORY.md"),
1664
- path10.join(home2, ".gemini", "MEMORY.md"),
1665
- path10.join(home2, ".paperclip", "IDENTITY.md")
1642
+ path8.join(home, ".claude", "MEMORY.md"),
1643
+ path8.join(home, ".claude", "CLAUDE.md"),
1644
+ path8.join(home, ".openclaw", "workspace", "SOUL.md"),
1645
+ path8.join(home, ".openclaw", "workspace", "MEMORY.md"),
1646
+ path8.join(home, ".gemini", "MEMORY.md"),
1647
+ path8.join(home, ".paperclip", "IDENTITY.md")
1666
1648
  ];
1667
1649
  for (const gp of globalPaths) {
1668
1650
  try {
1669
- const stat = fs7.statSync(gp);
1651
+ const stat = fs5.statSync(gp);
1670
1652
  if (!stat.isFile() || stat.size > MAX_CONFIG_SIZE) continue;
1671
- const content = fs7.readFileSync(gp, "utf-8");
1653
+ const content = fs5.readFileSync(gp, "utf-8");
1672
1654
  if (content.trim()) {
1673
- const name = `~/${path10.relative(home2, gp)}`;
1655
+ const name = path8.relative(home, gp);
1674
1656
  configs.push({ name, content });
1675
1657
  onProgress?.({ phase: "configs", message: name });
1676
1658
  }
1677
1659
  } catch {
1678
1660
  }
1679
1661
  }
1662
+ return configs;
1663
+ }
1664
+ function collectProjectConfigFiles(projects, onProgress) {
1665
+ const configs = [];
1680
1666
  for (const project of projects) {
1681
1667
  for (const fileName of AI_CONFIG_FILENAMES) {
1682
- const filePath = path10.join(project.path, fileName);
1668
+ const filePath = path8.join(project.path, fileName);
1683
1669
  try {
1684
- const stat = fs7.statSync(filePath);
1670
+ const stat = fs5.statSync(filePath);
1685
1671
  if (!stat.isFile() || stat.size > MAX_CONFIG_SIZE) continue;
1686
- const content = fs7.readFileSync(filePath, "utf-8");
1672
+ const content = fs5.readFileSync(filePath, "utf-8");
1687
1673
  if (content.trim()) {
1688
1674
  const name = `${project.name}/${fileName}`;
1689
1675
  configs.push({ name, content });
@@ -1692,11 +1678,11 @@ function collectConfigFiles(projects, onProgress) {
1692
1678
  } catch {
1693
1679
  }
1694
1680
  }
1695
- const pkgPath = path10.join(project.path, "package.json");
1681
+ const pkgPath = path8.join(project.path, "package.json");
1696
1682
  try {
1697
- const stat = fs7.statSync(pkgPath);
1683
+ const stat = fs5.statSync(pkgPath);
1698
1684
  if (stat.isFile() && stat.size <= MAX_CONFIG_SIZE) {
1699
- const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
1685
+ const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
1700
1686
  const summary = JSON.stringify({ name: pkg.name, description: pkg.description }, null, 2);
1701
1687
  configs.push({ name: `${project.name}/package.json`, content: summary });
1702
1688
  onProgress?.({ phase: "configs", message: `${project.name}/package.json` });
@@ -1706,114 +1692,26 @@ function collectConfigFiles(projects, onProgress) {
1706
1692
  }
1707
1693
  return configs;
1708
1694
  }
1709
- var MAX_SCAN_DEPTH = 6;
1710
- var MAX_FILES = 500;
1711
- async function scanFilesInDirs(dirs, onProgress) {
1712
- const files = [];
1713
- const seen = /* @__PURE__ */ new Set();
1714
- function walk(dir, depth) {
1715
- if (depth > MAX_SCAN_DEPTH) return [];
1716
- const found = [];
1717
- try {
1718
- const items = fs7.readdirSync(dir, { withFileTypes: true });
1719
- for (const item of items) {
1720
- if (item.isDirectory()) {
1721
- if (!shouldSkipDir(item.name)) {
1722
- found.push(...walk(path10.join(dir, item.name), depth + 1));
1723
- }
1724
- } else if (item.isFile()) {
1725
- if (canParse(item.name) && !isAiConfigFile(item.name)) {
1726
- const fullPath = path10.join(dir, item.name);
1727
- if (!seen.has(fullPath)) {
1728
- seen.add(fullPath);
1729
- found.push(fullPath);
1730
- }
1731
- }
1732
- }
1733
- }
1734
- } catch {
1735
- }
1736
- return found;
1737
- }
1738
- const allPaths = [];
1739
- for (const dir of dirs) {
1740
- onProgress?.({ phase: "scanning", message: displayPath(dir) });
1741
- allPaths.push(...walk(dir, 0));
1742
- if (allPaths.length > MAX_FILES) break;
1743
- }
1744
- const pathsToProcess = allPaths.slice(0, MAX_FILES);
1745
- for (const filePath of pathsToProcess) {
1746
- try {
1747
- const stat = fs7.statSync(filePath);
1748
- onProgress?.({ phase: "parsing", message: displayPath(filePath) });
1749
- const content = await extractTextFromFile(filePath);
1750
- if (content && content.trim()) {
1751
- const category = getFileCategory(filePath);
1752
- files.push({
1753
- path: filePath,
1754
- displayPath: displayPath(filePath),
1755
- content,
1756
- format: category === "document" ? path10.extname(filePath).slice(1) : "text",
1757
- sizeBytes: stat.size,
1758
- folder: path10.dirname(filePath)
1759
- });
1760
- }
1761
- } catch {
1762
- }
1763
- }
1764
- return files;
1765
- }
1766
- async function scanFolders(dirs, onProgress) {
1767
- const allFiles = await scanFilesInDirs(dirs, onProgress);
1768
- const folders = groupFilesByFolder(allFiles);
1769
- const projects = detectProjects(dirs, onProgress);
1770
- const configFiles = collectConfigFiles(projects, onProgress);
1771
- const totalFiles = allFiles.length;
1772
- const totalBytes = allFiles.reduce((sum, f) => sum + f.sizeBytes, 0);
1773
- return { folders, configFiles, projects, allFiles, totalFiles, totalBytes };
1774
- }
1775
- function buildBrainInput(scanResult, selectedFolderPaths) {
1776
- const selectedSet = new Set(selectedFolderPaths);
1777
- const selectedFiles = scanResult.allFiles.filter((f) => selectedSet.has(f.folder));
1778
- const folderTree = [];
1779
- for (const folder of scanResult.folders) {
1780
- if (selectedSet.has(folder.path)) {
1781
- folderTree.push(`${folder.displayPath}/ (${folder.fileCount} files)`);
1782
- }
1783
- }
1784
- const personalDocuments = selectedFiles.map((f) => ({
1785
- name: f.displayPath,
1786
- content: f.content,
1787
- format: f.format
1788
- }));
1789
- return {
1790
- summary: {
1791
- folders: folderTree,
1792
- projects: scanResult.projects.map((p) => ({
1793
- name: p.name,
1794
- path: p.path.replace(home2, "~"),
1795
- description: p.description
1796
- })),
1797
- configFiles: scanResult.configFiles,
1798
- recentDocuments: [],
1799
- personalDocuments
1800
- }
1801
- };
1802
- }
1803
1695
  function scanForProjects(folders) {
1804
1696
  const scanDirs = folders || getDefaultScanDirs();
1805
1697
  return detectProjects(scanDirs);
1806
1698
  }
1699
+ function formatSize(bytes) {
1700
+ if (bytes < 1024) return `${bytes} B`;
1701
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1702
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1703
+ }
1807
1704
 
1808
1705
  // src/lib/store.ts
1809
- import fs8 from "fs";
1810
- import path11 from "path";
1811
- import os6 from "os";
1812
- var CONFIG_DIR = path11.join(os6.homedir(), ".piut");
1813
- var CONFIG_FILE2 = path11.join(CONFIG_DIR, "config.json");
1706
+ init_esm_shims();
1707
+ import fs6 from "fs";
1708
+ import path9 from "path";
1709
+ import os5 from "os";
1710
+ var CONFIG_DIR = path9.join(os5.homedir(), ".piut");
1711
+ var CONFIG_FILE2 = path9.join(CONFIG_DIR, "config.json");
1814
1712
  function readStore() {
1815
1713
  try {
1816
- const raw = fs8.readFileSync(CONFIG_FILE2, "utf-8");
1714
+ const raw = fs6.readFileSync(CONFIG_FILE2, "utf-8");
1817
1715
  return JSON.parse(raw);
1818
1716
  } catch {
1819
1717
  return {};
@@ -1822,13 +1720,13 @@ function readStore() {
1822
1720
  function updateStore(updates) {
1823
1721
  const config = readStore();
1824
1722
  const updated = { ...config, ...updates };
1825
- fs8.mkdirSync(CONFIG_DIR, { recursive: true });
1826
- fs8.writeFileSync(CONFIG_FILE2, JSON.stringify(updated, null, 2) + "\n", "utf-8");
1723
+ fs6.mkdirSync(CONFIG_DIR, { recursive: true });
1724
+ fs6.writeFileSync(CONFIG_FILE2, JSON.stringify(updated, null, 2) + "\n", "utf-8");
1827
1725
  return updated;
1828
1726
  }
1829
1727
  function clearStore() {
1830
1728
  try {
1831
- fs8.unlinkSync(CONFIG_FILE2);
1729
+ fs6.unlinkSync(CONFIG_FILE2);
1832
1730
  } catch {
1833
1731
  }
1834
1732
  }
@@ -1845,7 +1743,7 @@ var PIUT_FILES = [
1845
1743
  ];
1846
1744
  function hasPiutReference(filePath) {
1847
1745
  try {
1848
- const content = fs9.readFileSync(filePath, "utf-8");
1746
+ const content = fs7.readFileSync(filePath, "utf-8");
1849
1747
  return content.includes("p\u0131ut Context") || content.includes("piut Context");
1850
1748
  } catch {
1851
1749
  return false;
@@ -1897,17 +1795,17 @@ async function statusCommand(options = {}) {
1897
1795
  await verifyStatus();
1898
1796
  return;
1899
1797
  }
1900
- const thisHostname = os7.hostname();
1798
+ const thisHostname = os6.hostname();
1901
1799
  const thisMachineId = getMachineId2();
1902
1800
  console.log(` AI tools on this machine ${dim(`(${thisHostname})`)}:`);
1903
1801
  console.log();
1904
1802
  let foundAny = false;
1905
1803
  for (const tool of TOOLS) {
1906
- const paths = resolveConfigPaths(tool.configPaths);
1907
- for (const configPath of paths) {
1908
- if (!fs9.existsSync(configPath)) continue;
1804
+ const paths = resolveConfigPaths(tool);
1805
+ for (const { filePath, configKey } of paths) {
1806
+ if (!fs7.existsSync(filePath)) continue;
1909
1807
  foundAny = true;
1910
- const configured = isPiutConfigured(configPath, tool.configKey);
1808
+ const configured = isPiutConfigured(filePath, configKey);
1911
1809
  if (configured) {
1912
1810
  toolLine(tool.name, success("connected"), "\u2714");
1913
1811
  } else {
@@ -1928,8 +1826,8 @@ async function statusCommand(options = {}) {
1928
1826
  for (const project of projects) {
1929
1827
  const connectedFiles = [];
1930
1828
  for (const file of PIUT_FILES) {
1931
- const absPath = path12.join(project.path, file);
1932
- if (fs9.existsSync(absPath) && hasPiutReference(absPath)) {
1829
+ const absPath = path10.join(project.path, file);
1830
+ if (fs7.existsSync(absPath) && hasPiutReference(absPath)) {
1933
1831
  connectedFiles.push(file);
1934
1832
  }
1935
1833
  }
@@ -2000,19 +1898,19 @@ async function verifyStatus() {
2000
1898
  console.log();
2001
1899
  console.log(" Tool Configurations");
2002
1900
  for (const tool of TOOLS) {
2003
- const paths = resolveConfigPaths(tool.configPaths);
2004
- for (const configPath of paths) {
2005
- if (!fs9.existsSync(configPath)) continue;
2006
- const piutConfig = getPiutConfig(configPath, tool.configKey);
1901
+ const paths = resolveConfigPaths(tool);
1902
+ for (const { filePath, configKey } of paths) {
1903
+ if (!fs7.existsSync(filePath)) continue;
1904
+ const piutConfig = getPiutConfig(filePath, configKey);
2007
1905
  if (!piutConfig) {
2008
1906
  toolLine(tool.name, dim("installed, not connected"), "\u25CB");
2009
1907
  break;
2010
1908
  }
2011
- const configKey = extractKeyFromConfig(piutConfig);
2012
- if (configKey && configKey === store.apiKey) {
1909
+ const extractedKey = extractKeyFromConfig(piutConfig);
1910
+ if (extractedKey && extractedKey === store.apiKey) {
2013
1911
  toolLine(tool.name, success("key matches"), "\u2714");
2014
- } else if (configKey) {
2015
- const masked = configKey.slice(0, 6) + "...";
1912
+ } else if (extractedKey) {
1913
+ const masked = extractedKey.slice(0, 6) + "...";
2016
1914
  toolLine(tool.name, chalk3.red(`key STALE (${masked})`), "\u2717");
2017
1915
  issues++;
2018
1916
  } else {
@@ -2045,17 +1943,18 @@ async function verifyStatus() {
2045
1943
  }
2046
1944
 
2047
1945
  // src/commands/remove.ts
2048
- import fs10 from "fs";
1946
+ init_esm_shims();
1947
+ import fs8 from "fs";
2049
1948
  import { checkbox as checkbox2, confirm as confirm2 } from "@inquirer/prompts";
2050
1949
  async function removeCommand() {
2051
1950
  banner();
2052
1951
  const configured = [];
2053
1952
  for (const tool of TOOLS) {
2054
1953
  if (!tool.configKey) continue;
2055
- const paths = resolveConfigPaths(tool.configPaths);
2056
- for (const configPath of paths) {
2057
- if (fs10.existsSync(configPath) && isPiutConfigured(configPath, tool.configKey)) {
2058
- configured.push({ tool, configPath });
1954
+ const paths = resolveConfigPaths(tool);
1955
+ for (const { filePath, configKey } of paths) {
1956
+ if (fs8.existsSync(filePath) && isPiutConfigured(filePath, configKey)) {
1957
+ configured.push({ tool, configPath: filePath, resolvedConfigKey: configKey });
2059
1958
  break;
2060
1959
  }
2061
1960
  }
@@ -2084,9 +1983,9 @@ async function removeCommand() {
2084
1983
  if (!proceed) return;
2085
1984
  console.log();
2086
1985
  const removedNames = [];
2087
- for (const { tool, configPath } of selected) {
2088
- if (!tool.configKey) continue;
2089
- const removed = removeFromConfig(configPath, tool.configKey);
1986
+ for (const { tool, configPath, resolvedConfigKey } of selected) {
1987
+ if (!resolvedConfigKey) continue;
1988
+ const removed = removeFromConfig(configPath, resolvedConfigKey);
2090
1989
  if (removed) {
2091
1990
  removedNames.push(tool.name);
2092
1991
  toolLine(tool.name, success("removed"), "\u2714");
@@ -2105,11 +2004,13 @@ async function removeCommand() {
2105
2004
  }
2106
2005
 
2107
2006
  // src/commands/build.ts
2108
- import { select as select2, checkbox as checkbox3, input as input2, confirm as confirm3 } from "@inquirer/prompts";
2007
+ init_esm_shims();
2008
+ import { confirm as confirm3 } from "@inquirer/prompts";
2109
2009
  import chalk5 from "chalk";
2110
- import os8 from "os";
2010
+ import os7 from "os";
2111
2011
 
2112
2012
  // src/lib/auth.ts
2013
+ init_esm_shims();
2113
2014
  import { select, input, password as password2 } from "@inquirer/prompts";
2114
2015
  import { exec } from "child_process";
2115
2016
  import chalk4 from "chalk";
@@ -2222,66 +2123,53 @@ async function resolveApiKeyWithResult(keyOption) {
2222
2123
  async function buildCommand(options) {
2223
2124
  banner();
2224
2125
  const { apiKey, serverUrl } = await resolveApiKeyWithResult(options.key);
2225
- let scanDirs;
2226
- if (options.folders) {
2227
- scanDirs = options.folders.split(",").map((f) => expandPath(f.trim()));
2228
- } else {
2229
- console.log(dim(" \u2501\u2501\u2501 BUILD YOUR BRAIN \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
2230
- console.log();
2231
- console.log(dim(" This is a local scan only \u2014 no files leave your machine"));
2232
- console.log(dim(" until you review and explicitly approve."));
2233
- console.log();
2234
- scanDirs = await selectFolders();
2235
- }
2236
- if (scanDirs.length === 0) {
2237
- console.log(chalk5.yellow(" No folders selected."));
2238
- return;
2239
- }
2126
+ console.log(dim(" \u2501\u2501\u2501 BUILD YOUR BRAIN \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
2240
2127
  console.log();
2241
- console.log(dim(" Scanning locally \u2014 no data is shared..."));
2128
+ console.log(dim(" Scanning for AI config files..."));
2242
2129
  console.log();
2243
- let fileCount = 0;
2130
+ const cwd = process.cwd();
2131
+ const homeDirs = getDefaultScanDirs();
2132
+ const allScanDirs = [cwd, ...homeDirs.filter((d) => !d.startsWith(cwd) && !cwd.startsWith(d))];
2244
2133
  const onProgress = (progress) => {
2245
- if (progress.phase === "scanning") {
2246
- console.log(dim(` ${progress.message}`));
2247
- } else if (progress.phase === "parsing") {
2248
- fileCount++;
2249
- console.log(dim(` [${fileCount}] ${progress.message}`));
2250
- } else if (progress.phase === "projects") {
2134
+ if (progress.phase === "projects") {
2251
2135
  console.log(dim(` [project] ${progress.message}`));
2252
2136
  } else if (progress.phase === "configs") {
2253
2137
  console.log(dim(` [config] ${progress.message}`));
2254
2138
  }
2255
2139
  };
2256
- const scanResult = await scanFolders(scanDirs, onProgress);
2140
+ const projects = detectProjects(allScanDirs, onProgress);
2141
+ const globalConfigs = collectGlobalConfigFiles(onProgress);
2142
+ const projectConfigs = collectProjectConfigFiles(projects, onProgress);
2143
+ const allConfigs = [...globalConfigs, ...projectConfigs];
2257
2144
  console.log();
2258
- console.log(success(` \u2713 Scan complete: ${scanResult.totalFiles} files found across ${scanResult.folders.length} folders (local only)`));
2259
- console.log();
2260
- if (scanResult.totalFiles === 0 && scanResult.configFiles.length === 0) {
2261
- console.log(chalk5.yellow(" No parseable files found in the selected folders."));
2262
- console.log(dim(" Try scanning a different directory, or use --folders to specify paths."));
2145
+ if (allConfigs.length > 0) {
2146
+ console.log(success(` \u2713 Found ${allConfigs.length} config file${allConfigs.length === 1 ? "" : "s"} in ${projects.length} project${projects.length === 1 ? "" : "s"}`));
2147
+ } else {
2148
+ console.log(dim(" No AI config files found."));
2149
+ }
2150
+ const totalBytes = allConfigs.reduce((sum, c) => sum + Buffer.byteLength(c.content, "utf-8"), 0);
2151
+ const totalFiles = allConfigs.length;
2152
+ if (totalFiles === 0) {
2153
+ console.log();
2154
+ console.log(chalk5.yellow(" No config files found to build your brain."));
2155
+ console.log(dim(" Add AI config files (CLAUDE.md, .cursorrules, etc.) to your projects,"));
2156
+ console.log(dim(" or upload documents via: piut vault upload <file>"));
2263
2157
  console.log();
2264
2158
  return;
2265
2159
  }
2266
- let selectedFolderPaths;
2267
- if (options.yes || scanResult.folders.length === 0) {
2268
- selectedFolderPaths = scanResult.folders.map((f) => f.path);
2269
- } else {
2270
- selectedFolderPaths = await reviewFolders(scanResult);
2271
- }
2272
- if (selectedFolderPaths.length === 0 && scanResult.configFiles.length === 0) {
2273
- console.log(chalk5.yellow(" No folders selected."));
2160
+ if (totalBytes > MAX_BRAIN_INPUT_BYTES) {
2161
+ console.log();
2162
+ console.log(chalk5.yellow(` Total data: ${formatSize(totalBytes)} exceeds the 1MB limit.`));
2163
+ console.log();
2274
2164
  return;
2275
2165
  }
2276
- const selectedFolders = scanResult.folders.filter((f) => selectedFolderPaths.includes(f.path));
2277
- const totalSelectedFiles = selectedFolders.reduce((sum, f) => sum + f.fileCount, 0) + scanResult.configFiles.length;
2278
2166
  if (!options.yes) {
2279
2167
  console.log();
2280
2168
  console.log(dim(" \u2501\u2501\u2501 READY TO BUILD \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
2281
2169
  console.log();
2282
- console.log(dim(` ${totalSelectedFiles} files will be sent to p\u0131ut and processed by Claude`));
2283
- console.log(dim(" Sonnet to design your brain. File contents are used for"));
2284
- console.log(dim(" brain generation only and are not retained."));
2170
+ console.log(dim(` ${totalFiles} file${totalFiles === 1 ? "" : "s"} (${formatSize(totalBytes)}) will be processed by Claude Sonnet to design your brain.`));
2171
+ console.log(dim(" File contents are used for brain generation only and"));
2172
+ console.log(dim(` are not retained by p\u0131ut.`));
2285
2173
  console.log();
2286
2174
  console.log(dim(` Privacy policy: ${brand("https://piut.com/privacy")}`));
2287
2175
  console.log();
@@ -2296,7 +2184,20 @@ async function buildCommand(options) {
2296
2184
  return;
2297
2185
  }
2298
2186
  }
2299
- const brainInput = buildBrainInput(scanResult, selectedFolderPaths);
2187
+ const home2 = os7.homedir();
2188
+ const brainInput = {
2189
+ summary: {
2190
+ projects: projects.map((p) => ({
2191
+ name: p.name,
2192
+ path: p.path.replace(home2, "~"),
2193
+ description: p.description
2194
+ })),
2195
+ configFiles: allConfigs
2196
+ }
2197
+ };
2198
+ await streamBuild(apiKey, serverUrl, brainInput, options);
2199
+ }
2200
+ async function streamBuild(apiKey, serverUrl, brainInput, options) {
2300
2201
  const spinner = new Spinner();
2301
2202
  spinner.start("Generating brain...");
2302
2203
  try {
@@ -2396,85 +2297,13 @@ async function buildCommand(options) {
2396
2297
  spinner.stop();
2397
2298
  if (err instanceof CliError) throw err;
2398
2299
  const msg = err.message || "Unknown error";
2399
- const hint = msg === "terminated" || msg.includes("network") || msg.includes("fetch") ? "The build was interrupted. This can happen if your scan data is very large. Try using --folders to limit which directories are scanned." : msg;
2400
- console.log(chalk5.red(` \u2717 ${hint}`));
2401
- throw new CliError(hint);
2402
- }
2403
- }
2404
- async function selectFolders() {
2405
- const defaults = getDefaultScanDirs();
2406
- const homeDir = os8.homedir();
2407
- const ALL_VALUE = "__all__";
2408
- const CUSTOM_VALUE = "__custom__";
2409
- const choices = [
2410
- { name: `All home folders (~) ${chalk5.dim("(Recommended)")}`, value: ALL_VALUE },
2411
- { name: chalk5.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), value: "__sep__", disabled: true },
2412
- ...defaults.map((d) => ({ name: displayPath(d), value: d })),
2413
- { name: chalk5.dim("Browse to a folder..."), value: CUSTOM_VALUE }
2414
- ];
2415
- const selected = await checkbox3({
2416
- message: "Select folders to scan:",
2417
- choices,
2418
- required: true
2419
- });
2420
- let scanDirs;
2421
- if (selected.includes(ALL_VALUE)) {
2422
- scanDirs = defaults;
2423
- } else {
2424
- scanDirs = selected.filter((v) => v !== CUSTOM_VALUE);
2425
- if (selected.includes(CUSTOM_VALUE)) {
2426
- const custom = await input2({
2427
- message: "Enter folder path(s), comma-separated:"
2428
- });
2429
- const customPaths = custom.split(",").map((f) => expandPath(f.trim())).filter(Boolean);
2430
- scanDirs = [...scanDirs, ...customPaths];
2431
- }
2300
+ console.log(chalk5.red(` \u2717 ${msg}`));
2301
+ throw new CliError(msg);
2432
2302
  }
2433
- if (scanDirs.length > 0 && !selected.includes(ALL_VALUE)) {
2434
- console.log();
2435
- console.log(dim(" Selected:"));
2436
- for (const d of scanDirs) {
2437
- console.log(dim(` ${displayPath(d)}`));
2438
- }
2439
- const addMore = await select2({
2440
- message: "Add more folders or continue?",
2441
- choices: [
2442
- { name: "Continue with scan", value: "continue" },
2443
- { name: "Add another folder...", value: "add" }
2444
- ]
2445
- });
2446
- if (addMore === "add") {
2447
- const extra = await input2({
2448
- message: "Enter folder path(s), comma-separated:"
2449
- });
2450
- const extraPaths = extra.split(",").map((f) => expandPath(f.trim())).filter(Boolean);
2451
- scanDirs = [...scanDirs, ...extraPaths];
2452
- }
2453
- }
2454
- return scanDirs;
2455
- }
2456
- async function reviewFolders(scanResult) {
2457
- if (scanResult.folders.length === 0) return [];
2458
- console.log(dim(" \u2501\u2501\u2501 REVIEW SCANNED FOLDERS \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
2459
- console.log();
2460
- console.log(dim(" All folders selected by default. Deselect any you want to exclude."));
2461
- console.log();
2462
- const choices = scanResult.folders.map((folder) => ({
2463
- name: formatFolderChoice(folder),
2464
- value: folder.path,
2465
- checked: true
2466
- }));
2467
- const selected = await checkbox3({
2468
- message: "Select folders to include in your brain:",
2469
- choices
2470
- });
2471
- const selectedFolders = scanResult.folders.filter((f) => selected.includes(f.path));
2472
- console.log();
2473
- console.log(dim(` ${formatSelectionSummary(selectedFolders)}`));
2474
- return selected;
2475
2303
  }
2476
2304
 
2477
2305
  // src/commands/deploy.ts
2306
+ init_esm_shims();
2478
2307
  import chalk6 from "chalk";
2479
2308
  async function deployCommand(options) {
2480
2309
  banner();
@@ -2512,33 +2341,34 @@ async function deployCommand(options) {
2512
2341
  }
2513
2342
 
2514
2343
  // src/commands/connect.ts
2515
- import fs11 from "fs";
2516
- import path13 from "path";
2517
- import { checkbox as checkbox4 } from "@inquirer/prompts";
2344
+ init_esm_shims();
2345
+ import fs9 from "fs";
2346
+ import path11 from "path";
2347
+ import { checkbox as checkbox3 } from "@inquirer/prompts";
2518
2348
  var RULE_FILES = [
2519
2349
  {
2520
2350
  tool: "Claude Code",
2521
2351
  filePath: "CLAUDE.md",
2522
2352
  strategy: "append",
2523
- detect: (p) => p.hasClaudeMd || fs11.existsSync(path13.join(p.path, ".claude"))
2353
+ detect: (p) => p.hasClaudeMd || fs9.existsSync(path11.join(p.path, ".claude"))
2524
2354
  },
2525
2355
  {
2526
2356
  tool: "Cursor",
2527
2357
  filePath: ".cursor/rules/piut.mdc",
2528
2358
  strategy: "create",
2529
- detect: (p) => p.hasCursorRules || fs11.existsSync(path13.join(p.path, ".cursor"))
2359
+ detect: (p) => p.hasCursorRules || fs9.existsSync(path11.join(p.path, ".cursor"))
2530
2360
  },
2531
2361
  {
2532
2362
  tool: "Windsurf",
2533
2363
  filePath: ".windsurf/rules/piut.md",
2534
2364
  strategy: "create",
2535
- detect: (p) => p.hasWindsurfRules || fs11.existsSync(path13.join(p.path, ".windsurf"))
2365
+ detect: (p) => p.hasWindsurfRules || fs9.existsSync(path11.join(p.path, ".windsurf"))
2536
2366
  },
2537
2367
  {
2538
2368
  tool: "GitHub Copilot",
2539
2369
  filePath: ".github/copilot-instructions.md",
2540
2370
  strategy: "append",
2541
- detect: (p) => p.hasCopilotInstructions || fs11.existsSync(path13.join(p.path, ".github"))
2371
+ detect: (p) => p.hasCopilotInstructions || fs9.existsSync(path11.join(p.path, ".github"))
2542
2372
  },
2543
2373
  {
2544
2374
  tool: "Amazon Q",
@@ -2550,19 +2380,19 @@ var RULE_FILES = [
2550
2380
  tool: "Zed",
2551
2381
  filePath: ".zed/rules.md",
2552
2382
  strategy: "create",
2553
- detect: (p) => p.hasZedRules || fs11.existsSync(path13.join(p.path, ".zed"))
2383
+ detect: (p) => p.hasZedRules || fs9.existsSync(path11.join(p.path, ".zed"))
2554
2384
  },
2555
2385
  {
2556
2386
  tool: "Gemini CLI",
2557
2387
  filePath: "GEMINI.md",
2558
2388
  strategy: "append",
2559
- detect: (p) => fs11.existsSync(path13.join(p.path, ".gemini"))
2389
+ detect: (p) => fs9.existsSync(path11.join(p.path, ".gemini"))
2560
2390
  },
2561
2391
  {
2562
2392
  tool: "Paperclip",
2563
2393
  filePath: "AGENTS.md",
2564
2394
  strategy: "append",
2565
- detect: (p) => fs11.existsSync(path13.join(p.path, ".paperclip"))
2395
+ detect: (p) => fs9.existsSync(path11.join(p.path, ".paperclip"))
2566
2396
  }
2567
2397
  ];
2568
2398
  var DEDICATED_FILE_CONTENT = `## p\u0131ut Context (MCP Server: piut-context)
@@ -2597,7 +2427,7 @@ Full skill reference: .piut/skill.md
2597
2427
  `;
2598
2428
  function hasPiutReference2(filePath) {
2599
2429
  try {
2600
- const content = fs11.readFileSync(filePath, "utf-8");
2430
+ const content = fs9.readFileSync(filePath, "utf-8");
2601
2431
  return content.includes("p\u0131ut Context") || content.includes("piut Context");
2602
2432
  } catch {
2603
2433
  return false;
@@ -2620,13 +2450,13 @@ async function connectCommand(options) {
2620
2450
  console.log();
2621
2451
  return;
2622
2452
  }
2623
- let scanFolders2;
2453
+ let scanFolders;
2624
2454
  if (options.folders) {
2625
- scanFolders2 = options.folders.split(",").map((f) => expandPath(f.trim()));
2455
+ scanFolders = options.folders.split(",").map((f) => expandPath(f.trim()));
2626
2456
  }
2627
2457
  console.log();
2628
2458
  console.log(dim(" Scanning for projects..."));
2629
- const projects = scanForProjects(scanFolders2);
2459
+ const projects = scanForProjects(scanFolders);
2630
2460
  if (projects.length === 0) {
2631
2461
  console.log(warning(" No projects found."));
2632
2462
  console.log(dim(" Try running from a directory with your projects, or use --folders."));
@@ -2637,20 +2467,20 @@ async function connectCommand(options) {
2637
2467
  for (const project of projects) {
2638
2468
  for (const rule of RULE_FILES) {
2639
2469
  if (!rule.detect(project)) continue;
2640
- const absPath = path13.join(project.path, rule.filePath);
2641
- if (fs11.existsSync(absPath) && hasPiutReference2(absPath)) continue;
2470
+ const absPath = path11.join(project.path, rule.filePath);
2471
+ if (fs9.existsSync(absPath) && hasPiutReference2(absPath)) continue;
2642
2472
  actions.push({
2643
2473
  project,
2644
2474
  tool: rule.tool,
2645
2475
  filePath: rule.filePath,
2646
2476
  absPath,
2647
- action: rule.strategy === "create" || !fs11.existsSync(absPath) ? "create" : "append"
2477
+ action: rule.strategy === "create" || !fs9.existsSync(absPath) ? "create" : "append"
2648
2478
  });
2649
2479
  }
2650
2480
  const hasAnyAction = actions.some((a) => a.project === project);
2651
2481
  if (!hasAnyAction) {
2652
- const claudeMdPath = path13.join(project.path, "CLAUDE.md");
2653
- if (!fs11.existsSync(claudeMdPath)) {
2482
+ const claudeMdPath = path11.join(project.path, "CLAUDE.md");
2483
+ if (!fs9.existsSync(claudeMdPath)) {
2654
2484
  actions.push({
2655
2485
  project,
2656
2486
  tool: "Claude Code",
@@ -2690,7 +2520,7 @@ async function connectCommand(options) {
2690
2520
  console.log();
2691
2521
  const projectChoices = [];
2692
2522
  for (const [projectPath, projectActions] of byProject) {
2693
- const projectName = path13.basename(projectPath);
2523
+ const projectName = path11.basename(projectPath);
2694
2524
  const desc = projectActions.map((a) => {
2695
2525
  const verb = a.action === "create" ? "will create" : "will append to";
2696
2526
  return `${verb} ${a.filePath}`;
@@ -2705,7 +2535,7 @@ async function connectCommand(options) {
2705
2535
  if (options.yes) {
2706
2536
  selectedPaths = Array.from(byProject.keys());
2707
2537
  } else {
2708
- selectedPaths = await checkbox4({
2538
+ selectedPaths = await checkbox3({
2709
2539
  message: "Select projects to connect:",
2710
2540
  choices: projectChoices
2711
2541
  });
@@ -2719,15 +2549,15 @@ async function connectCommand(options) {
2719
2549
  const copilotTool = TOOLS.find((t) => t.id === "copilot");
2720
2550
  for (const projectPath of selectedPaths) {
2721
2551
  const projectActions = byProject.get(projectPath) || [];
2722
- const projectName = path13.basename(projectPath);
2552
+ const projectName = path11.basename(projectPath);
2723
2553
  writePiutConfig(projectPath, { slug, apiKey, serverUrl });
2724
2554
  await writePiutSkill(projectPath, slug, apiKey);
2725
2555
  ensureGitignored(projectPath);
2726
2556
  console.log(success(` \u2713 ${projectName}/.piut/`) + dim(" \u2014 credentials + skill"));
2727
2557
  if (copilotTool) {
2728
- const hasCopilot = fs11.existsSync(path13.join(projectPath, ".github", "copilot-instructions.md")) || fs11.existsSync(path13.join(projectPath, ".github"));
2558
+ const hasCopilot = fs9.existsSync(path11.join(projectPath, ".github", "copilot-instructions.md")) || fs9.existsSync(path11.join(projectPath, ".github"));
2729
2559
  if (hasCopilot) {
2730
- const vscodeMcpPath = path13.join(projectPath, ".vscode", "mcp.json");
2560
+ const vscodeMcpPath = path11.join(projectPath, ".vscode", "mcp.json");
2731
2561
  const serverConfig = copilotTool.generateConfig(slug, apiKey);
2732
2562
  mergeConfig(vscodeMcpPath, copilotTool.configKey, serverConfig);
2733
2563
  console.log(success(` \u2713 ${projectName}/.vscode/mcp.json`) + dim(" \u2014 Copilot MCP"));
@@ -2737,11 +2567,11 @@ async function connectCommand(options) {
2737
2567
  if (action.action === "create") {
2738
2568
  const isAppendType = RULE_FILES.find((r) => r.filePath === action.filePath)?.strategy === "append";
2739
2569
  const content = isAppendType ? PROJECT_SKILL_SNIPPET + "\n" : DEDICATED_FILE_CONTENT;
2740
- fs11.mkdirSync(path13.dirname(action.absPath), { recursive: true });
2741
- fs11.writeFileSync(action.absPath, content, "utf-8");
2570
+ fs9.mkdirSync(path11.dirname(action.absPath), { recursive: true });
2571
+ fs9.writeFileSync(action.absPath, content, "utf-8");
2742
2572
  console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 created"));
2743
2573
  } else {
2744
- fs11.appendFileSync(action.absPath, APPEND_SECTION);
2574
+ fs9.appendFileSync(action.absPath, APPEND_SECTION);
2745
2575
  console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 appended"));
2746
2576
  }
2747
2577
  connected++;
@@ -2751,7 +2581,7 @@ async function connectCommand(options) {
2751
2581
  const hostname = getHostname();
2752
2582
  for (const projectPath of selectedPaths) {
2753
2583
  const projectActions = byProject.get(projectPath) || [];
2754
- const projectName = path13.basename(projectPath);
2584
+ const projectName = path11.basename(projectPath);
2755
2585
  const toolsDetected = [...new Set(projectActions.map((a) => a.tool))];
2756
2586
  const configFilesWritten = projectActions.map((a) => a.filePath);
2757
2587
  registerProject(apiKey, {
@@ -2770,9 +2600,10 @@ async function connectCommand(options) {
2770
2600
  }
2771
2601
 
2772
2602
  // src/commands/disconnect.ts
2773
- import fs12 from "fs";
2774
- import path14 from "path";
2775
- import { checkbox as checkbox5, confirm as confirm5 } from "@inquirer/prompts";
2603
+ init_esm_shims();
2604
+ import fs10 from "fs";
2605
+ import path12 from "path";
2606
+ import { checkbox as checkbox4, confirm as confirm5 } from "@inquirer/prompts";
2776
2607
  var DEDICATED_FILES = /* @__PURE__ */ new Set([
2777
2608
  ".cursor/rules/piut.mdc",
2778
2609
  ".windsurf/rules/piut.md",
@@ -2787,7 +2618,7 @@ var APPEND_FILES = [
2787
2618
  ];
2788
2619
  function hasPiutReference3(filePath) {
2789
2620
  try {
2790
- const content = fs12.readFileSync(filePath, "utf-8");
2621
+ const content = fs10.readFileSync(filePath, "utf-8");
2791
2622
  return content.includes("p\u0131ut Context") || content.includes("piut Context");
2792
2623
  } catch {
2793
2624
  return false;
@@ -2795,7 +2626,7 @@ function hasPiutReference3(filePath) {
2795
2626
  }
2796
2627
  function removePiutSection(filePath) {
2797
2628
  try {
2798
- let content = fs12.readFileSync(filePath, "utf-8");
2629
+ let content = fs10.readFileSync(filePath, "utf-8");
2799
2630
  const patterns = [
2800
2631
  /\n*## p[ıi]ut Context[\s\S]*?(?=\n## |\n---\n|$)/g
2801
2632
  ];
@@ -2809,7 +2640,7 @@ function removePiutSection(filePath) {
2809
2640
  }
2810
2641
  if (changed) {
2811
2642
  content = content.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
2812
- fs12.writeFileSync(filePath, content, "utf-8");
2643
+ fs10.writeFileSync(filePath, content, "utf-8");
2813
2644
  }
2814
2645
  return changed;
2815
2646
  } catch {
@@ -2818,18 +2649,18 @@ function removePiutSection(filePath) {
2818
2649
  }
2819
2650
  async function disconnectCommand(options) {
2820
2651
  banner();
2821
- let scanFolders2;
2652
+ let scanFolders;
2822
2653
  if (options.folders) {
2823
- scanFolders2 = options.folders.split(",").map((f) => expandPath(f.trim()));
2654
+ scanFolders = options.folders.split(",").map((f) => expandPath(f.trim()));
2824
2655
  }
2825
2656
  console.log(dim(" Scanning for connected projects..."));
2826
- const projects = scanForProjects(scanFolders2);
2657
+ const projects = scanForProjects(scanFolders);
2827
2658
  const actions = [];
2828
2659
  for (const project of projects) {
2829
- const projectName = path14.basename(project.path);
2660
+ const projectName = path12.basename(project.path);
2830
2661
  for (const dedicatedFile of DEDICATED_FILES) {
2831
- const absPath = path14.join(project.path, dedicatedFile);
2832
- if (fs12.existsSync(absPath) && hasPiutReference3(absPath)) {
2662
+ const absPath = path12.join(project.path, dedicatedFile);
2663
+ if (fs10.existsSync(absPath) && hasPiutReference3(absPath)) {
2833
2664
  actions.push({
2834
2665
  projectPath: project.path,
2835
2666
  projectName,
@@ -2840,8 +2671,8 @@ async function disconnectCommand(options) {
2840
2671
  }
2841
2672
  }
2842
2673
  for (const appendFile of APPEND_FILES) {
2843
- const absPath = path14.join(project.path, appendFile);
2844
- if (fs12.existsSync(absPath) && hasPiutReference3(absPath)) {
2674
+ const absPath = path12.join(project.path, appendFile);
2675
+ if (fs10.existsSync(absPath) && hasPiutReference3(absPath)) {
2845
2676
  actions.push({
2846
2677
  projectPath: project.path,
2847
2678
  projectName,
@@ -2856,12 +2687,12 @@ async function disconnectCommand(options) {
2856
2687
  projectPath: project.path,
2857
2688
  projectName,
2858
2689
  filePath: ".piut/",
2859
- absPath: path14.join(project.path, ".piut"),
2690
+ absPath: path12.join(project.path, ".piut"),
2860
2691
  action: "remove-dir"
2861
2692
  });
2862
2693
  }
2863
- const vscodeMcpPath = path14.join(project.path, ".vscode", "mcp.json");
2864
- if (fs12.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
2694
+ const vscodeMcpPath = path12.join(project.path, ".vscode", "mcp.json");
2695
+ if (fs10.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
2865
2696
  actions.push({
2866
2697
  projectPath: project.path,
2867
2698
  projectName,
@@ -2883,7 +2714,7 @@ async function disconnectCommand(options) {
2883
2714
  }
2884
2715
  console.log();
2885
2716
  const projectChoices = Array.from(byProject.entries()).map(([projectPath, projectActions]) => {
2886
- const name = path14.basename(projectPath);
2717
+ const name = path12.basename(projectPath);
2887
2718
  const files = projectActions.map((a) => a.filePath).join(", ");
2888
2719
  return {
2889
2720
  name: `${name} ${dim(`(${files})`)}`,
@@ -2894,7 +2725,7 @@ async function disconnectCommand(options) {
2894
2725
  if (options.yes) {
2895
2726
  selectedPaths = Array.from(byProject.keys());
2896
2727
  } else {
2897
- selectedPaths = await checkbox5({
2728
+ selectedPaths = await checkbox4({
2898
2729
  message: "Select projects to disconnect:",
2899
2730
  choices: projectChoices
2900
2731
  });
@@ -2912,11 +2743,11 @@ async function disconnectCommand(options) {
2912
2743
  let disconnected = 0;
2913
2744
  for (const projectPath of selectedPaths) {
2914
2745
  const projectActions = byProject.get(projectPath) || [];
2915
- const projectName = path14.basename(projectPath);
2746
+ const projectName = path12.basename(projectPath);
2916
2747
  for (const action of projectActions) {
2917
2748
  if (action.action === "delete") {
2918
2749
  try {
2919
- fs12.unlinkSync(action.absPath);
2750
+ fs10.unlinkSync(action.absPath);
2920
2751
  console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 deleted"));
2921
2752
  disconnected++;
2922
2753
  } catch {
@@ -2960,6 +2791,7 @@ async function disconnectCommand(options) {
2960
2791
  }
2961
2792
 
2962
2793
  // src/commands/login.ts
2794
+ init_esm_shims();
2963
2795
  import chalk7 from "chalk";
2964
2796
  async function loginCommand() {
2965
2797
  try {
@@ -2975,6 +2807,7 @@ async function loginCommand() {
2975
2807
  }
2976
2808
 
2977
2809
  // src/commands/logout.ts
2810
+ init_esm_shims();
2978
2811
  async function logoutCommand() {
2979
2812
  banner();
2980
2813
  const config = readStore();
@@ -2991,9 +2824,11 @@ async function logoutCommand() {
2991
2824
  }
2992
2825
 
2993
2826
  // src/commands/update.ts
2827
+ init_esm_shims();
2994
2828
  import chalk9 from "chalk";
2995
2829
 
2996
2830
  // src/lib/update-check.ts
2831
+ init_esm_shims();
2997
2832
  import { execFile } from "child_process";
2998
2833
  import chalk8 from "chalk";
2999
2834
  import { confirm as confirm6 } from "@inquirer/prompts";
@@ -3092,7 +2927,8 @@ async function updateCommand(currentVersion) {
3092
2927
  }
3093
2928
 
3094
2929
  // src/commands/doctor.ts
3095
- import fs13 from "fs";
2930
+ init_esm_shims();
2931
+ import fs11 from "fs";
3096
2932
  import chalk10 from "chalk";
3097
2933
  async function doctorCommand(options) {
3098
2934
  if (!options.json) banner();
@@ -3142,10 +2978,10 @@ async function doctorCommand(options) {
3142
2978
  }
3143
2979
  let toolsFixed = 0;
3144
2980
  for (const tool of TOOLS) {
3145
- const paths = resolveConfigPaths(tool.configPaths);
3146
- for (const configPath of paths) {
3147
- if (!fs13.existsSync(configPath)) continue;
3148
- const piutConfig = getPiutConfig(configPath, tool.configKey);
2981
+ const paths = resolveConfigPaths(tool);
2982
+ for (const { filePath: configPath, configKey: resolvedKey } of paths) {
2983
+ if (!fs11.existsSync(configPath)) continue;
2984
+ const piutConfig = getPiutConfig(configPath, resolvedKey);
3149
2985
  if (!piutConfig) {
3150
2986
  result.tools.push({
3151
2987
  name: tool.name,
@@ -3160,13 +2996,13 @@ async function doctorCommand(options) {
3160
2996
  }
3161
2997
  break;
3162
2998
  }
3163
- const configKey = extractKeyFromConfig(piutConfig);
3164
- const configPrefix = configKey ? configKey.slice(0, 7) + "..." : "(none)";
2999
+ const extractedKey = extractKeyFromConfig(piutConfig);
3000
+ const configPrefix = extractedKey ? extractedKey.slice(0, 7) + "..." : "(none)";
3165
3001
  let keyMatch = "missing";
3166
- if (!configKey) {
3002
+ if (!extractedKey) {
3167
3003
  keyMatch = "missing";
3168
3004
  result.issues++;
3169
- } else if (apiKey && configKey === apiKey) {
3005
+ } else if (apiKey && extractedKey === apiKey) {
3170
3006
  keyMatch = "match";
3171
3007
  } else {
3172
3008
  keyMatch = "stale";
@@ -3184,7 +3020,7 @@ async function doctorCommand(options) {
3184
3020
  };
3185
3021
  if (keyMatch === "stale" && options.fix && apiKey && result.key.valid && result.key.slug) {
3186
3022
  const serverConfig = tool.generateConfig(result.key.slug, apiKey);
3187
- mergeConfig(configPath, tool.configKey, serverConfig);
3023
+ mergeConfig(configPath, resolvedKey, serverConfig);
3188
3024
  toolResult.fixed = true;
3189
3025
  toolResult.keyMatch = "match";
3190
3026
  result.issues--;
@@ -3260,10 +3096,24 @@ async function doctorCommand(options) {
3260
3096
  }
3261
3097
 
3262
3098
  // src/commands/vault.ts
3263
- import fs14 from "fs";
3264
- import path15 from "path";
3099
+ init_esm_shims();
3100
+ import fs12 from "fs";
3101
+ import path13 from "path";
3265
3102
  import chalk11 from "chalk";
3266
3103
  import { confirm as confirm7 } from "@inquirer/prompts";
3104
+ var DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
3105
+ "pdf",
3106
+ "docx",
3107
+ "doc",
3108
+ "pptx",
3109
+ "pages",
3110
+ "key",
3111
+ "rtf",
3112
+ "odt",
3113
+ "odp",
3114
+ "eml",
3115
+ "mbox"
3116
+ ]);
3267
3117
  function formatSize2(bytes) {
3268
3118
  if (bytes < 1024) return `${bytes} B`;
3269
3119
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -3301,22 +3151,31 @@ async function vaultListCommand(options) {
3301
3151
  }
3302
3152
  async function vaultUploadCommand(filePath, options) {
3303
3153
  const key = resolveApiKey(options);
3304
- const resolved = path15.resolve(filePath);
3305
- if (!fs14.existsSync(resolved)) {
3154
+ const resolved = path13.resolve(filePath);
3155
+ if (!fs12.existsSync(resolved)) {
3306
3156
  console.log(chalk11.red(` File not found: ${filePath}`));
3307
3157
  throw new CliError();
3308
3158
  }
3309
- const stat = fs14.statSync(resolved);
3159
+ const stat = fs12.statSync(resolved);
3310
3160
  if (!stat.isFile()) {
3311
3161
  console.log(chalk11.red(` Not a file: ${filePath}`));
3312
3162
  throw new CliError();
3313
3163
  }
3314
- const filename = path15.basename(resolved);
3315
- const content = fs14.readFileSync(resolved, "utf-8");
3164
+ const filename = path13.basename(resolved);
3165
+ const ext = filename.includes(".") ? filename.split(".").pop()?.toLowerCase() || "" : "";
3166
+ const isDocument = DOCUMENT_EXTENSIONS.has(ext);
3167
+ let content;
3168
+ let encoding;
3169
+ if (isDocument) {
3170
+ content = fs12.readFileSync(resolved).toString("base64");
3171
+ encoding = "base64";
3172
+ } else {
3173
+ content = fs12.readFileSync(resolved, "utf-8");
3174
+ }
3316
3175
  const spinner = new Spinner();
3317
3176
  spinner.start(`Uploading ${filename}...`);
3318
3177
  try {
3319
- const result = await uploadVaultFile(key, filename, content);
3178
+ const result = await uploadVaultFile(key, filename, content, encoding);
3320
3179
  spinner.stop();
3321
3180
  console.log(success(` Uploaded ${result.filename}`) + dim(` (${formatSize2(result.sizeBytes)})`));
3322
3181
  if (result.summary) {
@@ -3334,8 +3193,8 @@ async function vaultReadCommand(filename, options) {
3334
3193
  try {
3335
3194
  const file = await readVaultFile(key, filename);
3336
3195
  if (options.output) {
3337
- const outPath = path15.resolve(options.output);
3338
- fs14.writeFileSync(outPath, file.content, "utf-8");
3196
+ const outPath = path13.resolve(options.output);
3197
+ fs12.writeFileSync(outPath, file.content, "utf-8");
3339
3198
  console.log(success(` Saved to ${outPath}`));
3340
3199
  console.log();
3341
3200
  } else {
@@ -3367,11 +3226,25 @@ async function vaultDeleteCommand(filename, options) {
3367
3226
  }
3368
3227
 
3369
3228
  // src/commands/interactive.ts
3370
- import { select as select3, confirm as confirm8, checkbox as checkbox6, Separator } from "@inquirer/prompts";
3371
- import fs15 from "fs";
3372
- import path16 from "path";
3229
+ init_esm_shims();
3230
+ import { select as select2, confirm as confirm8, checkbox as checkbox5, Separator } from "@inquirer/prompts";
3231
+ import fs14 from "fs";
3232
+ import path15 from "path";
3373
3233
  import { exec as exec2 } from "child_process";
3374
- import chalk12 from "chalk";
3234
+ import chalk13 from "chalk";
3235
+ var DOCUMENT_EXTENSIONS2 = /* @__PURE__ */ new Set([
3236
+ "pdf",
3237
+ "docx",
3238
+ "doc",
3239
+ "pptx",
3240
+ "pages",
3241
+ "key",
3242
+ "rtf",
3243
+ "odt",
3244
+ "odp",
3245
+ "eml",
3246
+ "mbox"
3247
+ ]);
3375
3248
  async function authenticate() {
3376
3249
  const config = readStore();
3377
3250
  const apiKey = config.apiKey;
@@ -3443,7 +3316,7 @@ async function interactiveMenu() {
3443
3316
  const isDeployed = currentValidation.status === "active";
3444
3317
  let action;
3445
3318
  try {
3446
- action = await select3({
3319
+ action = await select2({
3447
3320
  message: "What would you like to do?",
3448
3321
  loop: false,
3449
3322
  choices: [
@@ -3567,7 +3440,7 @@ async function interactiveMenu() {
3567
3440
  } else if (err instanceof CliError) {
3568
3441
  console.log();
3569
3442
  } else {
3570
- console.log(chalk12.red(` Error: ${err.message}`));
3443
+ console.log(chalk13.red(` Error: ${err.message}`));
3571
3444
  console.log();
3572
3445
  }
3573
3446
  }
@@ -3590,20 +3463,20 @@ async function handleUndeploy(apiKey) {
3590
3463
  console.log(dim(" Run ") + brand("piut deploy") + dim(" to re-deploy anytime."));
3591
3464
  console.log();
3592
3465
  } catch (err) {
3593
- console.log(chalk12.red(` \u2717 ${err.message}`));
3466
+ console.log(chalk13.red(` \u2717 ${err.message}`));
3594
3467
  }
3595
3468
  }
3596
3469
  async function handleConnectTools(apiKey, validation) {
3597
3470
  const { slug } = validation;
3598
3471
  const detected = [];
3599
3472
  for (const tool of TOOLS) {
3600
- const paths = resolveConfigPaths(tool.configPaths);
3601
- for (const configPath of paths) {
3602
- const exists = fs15.existsSync(configPath);
3603
- const parentExists = fs15.existsSync(path16.dirname(configPath));
3473
+ const paths = resolveConfigPaths(tool);
3474
+ for (const { filePath, configKey } of paths) {
3475
+ const exists = fs14.existsSync(filePath);
3476
+ const parentExists = fs14.existsSync(path15.dirname(filePath));
3604
3477
  if (exists || parentExists) {
3605
- const connected = exists && !!tool.configKey && isPiutConfigured(configPath, tool.configKey);
3606
- detected.push({ tool, configPath, connected });
3478
+ const connected = exists && !!configKey && isPiutConfigured(filePath, configKey);
3479
+ detected.push({ tool, configPath: filePath, resolvedConfigKey: configKey, connected });
3607
3480
  break;
3608
3481
  }
3609
3482
  }
@@ -3639,7 +3512,7 @@ async function handleConnectTools(apiKey, validation) {
3639
3512
  value: d,
3640
3513
  checked: d.connected
3641
3514
  }));
3642
- const selected = await checkbox6({
3515
+ const selected = await checkbox5({
3643
3516
  message: "Select tools to keep connected (toggle with space):",
3644
3517
  choices
3645
3518
  });
@@ -3651,17 +3524,17 @@ async function handleConnectTools(apiKey, validation) {
3651
3524
  return;
3652
3525
  }
3653
3526
  console.log();
3654
- for (const { tool, configPath } of toConnect) {
3655
- if (tool.generateConfig && tool.configKey) {
3527
+ for (const { tool, configPath, resolvedConfigKey } of toConnect) {
3528
+ if (tool.generateConfig && resolvedConfigKey) {
3656
3529
  const serverConfig = tool.generateConfig(slug, apiKey);
3657
- mergeConfig(configPath, tool.configKey, serverConfig);
3530
+ mergeConfig(configPath, resolvedConfigKey, serverConfig);
3658
3531
  toolLine(tool.name, success("connected"), "\u2714");
3659
3532
  }
3660
3533
  }
3661
3534
  const removedNames = [];
3662
- for (const { tool, configPath } of toDisconnect) {
3663
- if (!tool.configKey) continue;
3664
- const removed = removeFromConfig(configPath, tool.configKey);
3535
+ for (const { tool, configPath, resolvedConfigKey } of toDisconnect) {
3536
+ if (!resolvedConfigKey) continue;
3537
+ const removed = removeFromConfig(configPath, resolvedConfigKey);
3665
3538
  if (removed) {
3666
3539
  removedNames.push(tool.name);
3667
3540
  toolLine(tool.name, warning("disconnected"), "\u2714");
@@ -3709,7 +3582,7 @@ async function handleManageProjects(apiKey, validation) {
3709
3582
  value: i,
3710
3583
  checked: i.connected
3711
3584
  }));
3712
- const selected = await checkbox6({
3585
+ const selected = await checkbox5({
3713
3586
  message: "Select projects to keep connected (toggle with space):",
3714
3587
  choices
3715
3588
  });
@@ -3723,29 +3596,29 @@ async function handleManageProjects(apiKey, validation) {
3723
3596
  console.log();
3724
3597
  const copilotTool = TOOLS.find((t) => t.id === "copilot");
3725
3598
  for (const { project } of toConnect) {
3726
- const projectName = path16.basename(project.path);
3599
+ const projectName = path15.basename(project.path);
3727
3600
  writePiutConfig(project.path, { slug, apiKey, serverUrl });
3728
3601
  await writePiutSkill(project.path, slug, apiKey);
3729
3602
  ensureGitignored(project.path);
3730
3603
  if (copilotTool) {
3731
- const hasCopilot = fs15.existsSync(path16.join(project.path, ".github", "copilot-instructions.md")) || fs15.existsSync(path16.join(project.path, ".github"));
3604
+ const hasCopilot = fs14.existsSync(path15.join(project.path, ".github", "copilot-instructions.md")) || fs14.existsSync(path15.join(project.path, ".github"));
3732
3605
  if (hasCopilot) {
3733
- const vscodeMcpPath = path16.join(project.path, ".vscode", "mcp.json");
3606
+ const vscodeMcpPath = path15.join(project.path, ".vscode", "mcp.json");
3734
3607
  const serverConfig = copilotTool.generateConfig(slug, apiKey);
3735
3608
  mergeConfig(vscodeMcpPath, copilotTool.configKey, serverConfig);
3736
3609
  }
3737
3610
  }
3738
3611
  for (const rule of RULE_FILES) {
3739
3612
  if (!rule.detect(project)) continue;
3740
- const absPath = path16.join(project.path, rule.filePath);
3741
- if (fs15.existsSync(absPath) && hasPiutReference2(absPath)) continue;
3742
- if (rule.strategy === "create" || !fs15.existsSync(absPath)) {
3613
+ const absPath = path15.join(project.path, rule.filePath);
3614
+ if (fs14.existsSync(absPath) && hasPiutReference2(absPath)) continue;
3615
+ if (rule.strategy === "create" || !fs14.existsSync(absPath)) {
3743
3616
  const isAppendType = rule.strategy === "append";
3744
3617
  const content = isAppendType ? PROJECT_SKILL_SNIPPET + "\n" : DEDICATED_FILE_CONTENT;
3745
- fs15.mkdirSync(path16.dirname(absPath), { recursive: true });
3746
- fs15.writeFileSync(absPath, content, "utf-8");
3618
+ fs14.mkdirSync(path15.dirname(absPath), { recursive: true });
3619
+ fs14.writeFileSync(absPath, content, "utf-8");
3747
3620
  } else {
3748
- fs15.appendFileSync(absPath, APPEND_SECTION);
3621
+ fs14.appendFileSync(absPath, APPEND_SECTION);
3749
3622
  }
3750
3623
  }
3751
3624
  toolLine(projectName, success("connected"), "\u2714");
@@ -3761,24 +3634,24 @@ async function handleManageProjects(apiKey, validation) {
3761
3634
  });
3762
3635
  }
3763
3636
  for (const { project } of toDisconnect) {
3764
- const projectName = path16.basename(project.path);
3637
+ const projectName = path15.basename(project.path);
3765
3638
  for (const dedicatedFile of DEDICATED_FILES) {
3766
- const absPath = path16.join(project.path, dedicatedFile);
3767
- if (fs15.existsSync(absPath) && hasPiutReference2(absPath)) {
3639
+ const absPath = path15.join(project.path, dedicatedFile);
3640
+ if (fs14.existsSync(absPath) && hasPiutReference2(absPath)) {
3768
3641
  try {
3769
- fs15.unlinkSync(absPath);
3642
+ fs14.unlinkSync(absPath);
3770
3643
  } catch {
3771
3644
  }
3772
3645
  }
3773
3646
  }
3774
3647
  for (const appendFile of APPEND_FILES) {
3775
- const absPath = path16.join(project.path, appendFile);
3776
- if (fs15.existsSync(absPath) && hasPiutReference2(absPath)) {
3648
+ const absPath = path15.join(project.path, appendFile);
3649
+ if (fs14.existsSync(absPath) && hasPiutReference2(absPath)) {
3777
3650
  removePiutSection(absPath);
3778
3651
  }
3779
3652
  }
3780
- const vscodeMcpPath = path16.join(project.path, ".vscode", "mcp.json");
3781
- if (fs15.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
3653
+ const vscodeMcpPath = path15.join(project.path, ".vscode", "mcp.json");
3654
+ if (fs14.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
3782
3655
  removeFromConfig(vscodeMcpPath, "servers");
3783
3656
  }
3784
3657
  removePiutDir(project.path);
@@ -3823,7 +3696,7 @@ async function handleVaultView(apiKey) {
3823
3696
  console.log();
3824
3697
  console.log(dim(` ${data.usage.fileCount} file(s), ${formatSize3(data.usage.totalBytes)} / ${formatSize3(data.usage.maxBytes)} used`));
3825
3698
  console.log();
3826
- const action = await select3({
3699
+ const action = await select2({
3827
3700
  message: "Actions:",
3828
3701
  choices: [
3829
3702
  { name: "Delete a file", value: "delete" },
@@ -3836,7 +3709,7 @@ async function handleVaultView(apiKey) {
3836
3709
  name: `${f.filename} ${dim(`(${formatSize3(f.sizeBytes)})`)}`,
3837
3710
  value: f.filename
3838
3711
  }));
3839
- const filename = await select3({
3712
+ const filename = await select2({
3840
3713
  message: "Which file to delete?",
3841
3714
  choices: fileChoices
3842
3715
  });
@@ -3850,37 +3723,55 @@ async function handleVaultView(apiKey) {
3850
3723
  console.log(success(` Deleted ${filename}`));
3851
3724
  console.log();
3852
3725
  } catch (err) {
3853
- console.log(chalk12.red(` ${err.message}`));
3726
+ console.log(chalk13.red(` ${err.message}`));
3854
3727
  console.log();
3855
3728
  }
3856
3729
  }
3857
3730
  }
3858
3731
  }
3859
3732
  async function handleVaultUpload(apiKey) {
3860
- const { input: input3 } = await import("@inquirer/prompts");
3861
- const filePath = await input3({ message: "File path:" });
3862
- if (!filePath.trim()) return;
3863
- const resolved = path16.resolve(filePath);
3864
- if (!fs15.existsSync(resolved) || !fs15.statSync(resolved).isFile()) {
3865
- console.log(chalk12.red(` File not found: ${filePath}`));
3733
+ const treePrompt2 = (await Promise.resolve().then(() => (init_tree_prompt(), tree_prompt_exports))).default;
3734
+ const files = await treePrompt2({
3735
+ message: "Select files to upload:",
3736
+ mode: "files"
3737
+ });
3738
+ if (files.length === 0) {
3739
+ console.log(dim(" No files selected."));
3866
3740
  console.log();
3867
3741
  return;
3868
3742
  }
3869
- const filename = path16.basename(resolved);
3870
- const content = fs15.readFileSync(resolved, "utf-8");
3871
- const spinner = new Spinner();
3872
- spinner.start(`Uploading ${filename}...`);
3873
- try {
3874
- const result = await uploadVaultFile(apiKey, filename, content);
3875
- spinner.stop();
3876
- console.log(success(` Uploaded ${result.filename}`) + dim(` (${formatSize3(result.sizeBytes)})`));
3877
- if (result.summary) console.log(dim(` ${result.summary}`));
3878
- console.log();
3879
- } catch (err) {
3880
- spinner.stop();
3881
- console.log(chalk12.red(` ${err.message}`));
3743
+ console.log();
3744
+ let uploaded = 0;
3745
+ for (const filePath of files) {
3746
+ const filename = path15.basename(filePath);
3747
+ const ext = filename.includes(".") ? filename.split(".").pop()?.toLowerCase() || "" : "";
3748
+ const isDocument = DOCUMENT_EXTENSIONS2.has(ext);
3749
+ let content;
3750
+ let encoding;
3751
+ if (isDocument) {
3752
+ content = fs14.readFileSync(filePath).toString("base64");
3753
+ encoding = "base64";
3754
+ } else {
3755
+ content = fs14.readFileSync(filePath, "utf-8");
3756
+ }
3757
+ const spinner = new Spinner();
3758
+ spinner.start(`Uploading ${filename}...`);
3759
+ try {
3760
+ const result = await uploadVaultFile(apiKey, filename, content, encoding);
3761
+ spinner.stop();
3762
+ console.log(success(` Uploaded ${result.filename}`) + dim(` (${formatSize3(result.sizeBytes)})`));
3763
+ if (result.summary) console.log(dim(` ${result.summary}`));
3764
+ uploaded++;
3765
+ } catch (err) {
3766
+ spinner.stop();
3767
+ console.log(chalk13.red(` ${err.message}`));
3768
+ }
3769
+ }
3770
+ if (uploaded > 0) {
3882
3771
  console.log();
3772
+ console.log(success(` ${uploaded} file${uploaded === 1 ? "" : "s"} uploaded to vault.`));
3883
3773
  }
3774
+ console.log();
3884
3775
  }
3885
3776
  async function handleViewBrain(apiKey) {
3886
3777
  console.log(dim(" Loading brain..."));
@@ -3924,11 +3815,11 @@ async function handleViewBrain(apiKey) {
3924
3815
  console.log();
3925
3816
  const msg = err.message;
3926
3817
  if (msg === "REQUIRES_SUBSCRIPTION") {
3927
- console.log(chalk12.yellow(" Deploy requires an active subscription ($10/mo)."));
3818
+ console.log(chalk13.yellow(" Deploy requires an active subscription ($10/mo)."));
3928
3819
  console.log(` Subscribe at: ${brand("https://piut.com/dashboard/billing")}`);
3929
3820
  console.log(dim(" 14-day free trial included."));
3930
3821
  } else {
3931
- console.log(chalk12.red(` \u2717 ${msg}`));
3822
+ console.log(chalk13.red(` \u2717 ${msg}`));
3932
3823
  }
3933
3824
  console.log();
3934
3825
  }
@@ -3937,7 +3828,7 @@ async function handleViewBrain(apiKey) {
3937
3828
  }
3938
3829
 
3939
3830
  // src/cli.ts
3940
- var VERSION = "3.7.0";
3831
+ var VERSION = "3.8.0";
3941
3832
  function withExit(fn) {
3942
3833
  return async (...args2) => {
3943
3834
  try {
@@ -3953,7 +3844,7 @@ program.name("piut").description("Build your AI brain instantly. Deploy it as an
3953
3844
  if (actionCommand.name() === "update") return;
3954
3845
  return checkForUpdate(VERSION);
3955
3846
  }).action(interactiveMenu);
3956
- program.command("build").description("Build or rebuild your brain from your files").option("-k, --key <key>", "API key").option("--folders <paths>", "Comma-separated folder paths to scan").option("-y, --yes", "Auto-publish after build").option("--no-publish", "Skip publish prompt after build").action(withExit(buildCommand));
3847
+ program.command("build").description("Build or rebuild your brain from your AI config files").option("-k, --key <key>", "API key").option("-y, --yes", "Auto-publish after build").option("--no-publish", "Skip publish prompt after build").action(withExit(buildCommand));
3957
3848
  program.command("deploy").description("Publish your MCP server (requires paid account)").option("-k, --key <key>", "API key").action(withExit(deployCommand));
3958
3849
  program.command("connect").description("Add brain references to project config files").option("-k, --key <key>", "API key").option("-y, --yes", "Skip interactive prompts").option("--folders <paths>", "Comma-separated folder paths to scan").action(withExit(connectCommand));
3959
3850
  program.command("disconnect").description("Remove brain references from project config files").option("-y, --yes", "Skip interactive prompts").option("--folders <paths>", "Comma-separated folder paths to scan").action(withExit(disconnectCommand));