@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.
- package/dist/cli.js +777 -886
- 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
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
|
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 ||
|
|
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: [
|
|
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
|
|
797
|
+
import path3 from "path";
|
|
468
798
|
function expandPath(p) {
|
|
469
799
|
return p.replace(/^~/, os3.homedir());
|
|
470
800
|
}
|
|
471
|
-
function resolveConfigPaths(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
871
|
+
const servers = resolveKeyPath(existing, configKey) || {};
|
|
520
872
|
servers["piut-context"] = serverConfig;
|
|
521
|
-
existing
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
1073
|
+
fs3.writeFileSync(path6.join(dir, SKILL_FILE), content, "utf-8");
|
|
720
1074
|
}
|
|
721
1075
|
function ensureGitignored(projectPath) {
|
|
722
|
-
const gitignorePath =
|
|
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(
|
|
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
|
|
888
|
-
for (const
|
|
889
|
-
const exists = fs4.existsSync(
|
|
890
|
-
const parentExists = fs4.existsSync(
|
|
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 && !!
|
|
1248
|
+
const configured2 = exists && !!configKey && isPiutConfigured(filePath, configKey);
|
|
893
1249
|
let staleKey = false;
|
|
894
|
-
if (configured2 &&
|
|
895
|
-
const piutConfig = getPiutConfig(
|
|
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 &&
|
|
1356
|
+
if (tool.generateConfig && det.resolvedConfigKey) {
|
|
1000
1357
|
const serverConfig = tool.generateConfig(slug, apiKey);
|
|
1001
|
-
mergeConfig(configPath,
|
|
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(
|
|
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.
|
|
1046
|
-
const piutConfig = getPiutConfig(det.configPath, det.
|
|
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
|
-
|
|
1088
|
-
import
|
|
1089
|
-
import
|
|
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
|
-
|
|
1094
|
-
import
|
|
1095
|
-
import
|
|
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
|
-
|
|
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/
|
|
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(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /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
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
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 =
|
|
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(
|
|
1542
|
+
dirs.push(path8.join(home, entry.name));
|
|
1521
1543
|
}
|
|
1522
1544
|
} catch {
|
|
1523
1545
|
}
|
|
1524
|
-
const cloudStorage =
|
|
1546
|
+
const cloudStorage = path8.join(home, "Library", "CloudStorage");
|
|
1525
1547
|
try {
|
|
1526
|
-
if (
|
|
1527
|
-
const entries =
|
|
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 =
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
1596
|
-
if (!description &&
|
|
1576
|
+
const readmePath = path8.join(projectPath, "README.md");
|
|
1577
|
+
if (!description && fs5.existsSync(readmePath)) {
|
|
1597
1578
|
try {
|
|
1598
|
-
const content =
|
|
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:
|
|
1596
|
+
name: path8.basename(projectPath),
|
|
1616
1597
|
path: projectPath,
|
|
1617
1598
|
description,
|
|
1618
|
-
hasClaudeMd:
|
|
1619
|
-
hasCursorRules:
|
|
1620
|
-
hasWindsurfRules:
|
|
1621
|
-
hasCopilotInstructions:
|
|
1622
|
-
hasConventionsMd:
|
|
1623
|
-
hasZedRules:
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
1638
|
+
var MAX_BRAIN_INPUT_BYTES = 1e6;
|
|
1639
|
+
function collectGlobalConfigFiles(onProgress) {
|
|
1658
1640
|
const configs = [];
|
|
1659
1641
|
const globalPaths = [
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
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 =
|
|
1651
|
+
const stat = fs5.statSync(gp);
|
|
1670
1652
|
if (!stat.isFile() || stat.size > MAX_CONFIG_SIZE) continue;
|
|
1671
|
-
const content =
|
|
1653
|
+
const content = fs5.readFileSync(gp, "utf-8");
|
|
1672
1654
|
if (content.trim()) {
|
|
1673
|
-
const name =
|
|
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 =
|
|
1668
|
+
const filePath = path8.join(project.path, fileName);
|
|
1683
1669
|
try {
|
|
1684
|
-
const stat =
|
|
1670
|
+
const stat = fs5.statSync(filePath);
|
|
1685
1671
|
if (!stat.isFile() || stat.size > MAX_CONFIG_SIZE) continue;
|
|
1686
|
-
const content =
|
|
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 =
|
|
1681
|
+
const pkgPath = path8.join(project.path, "package.json");
|
|
1696
1682
|
try {
|
|
1697
|
-
const stat =
|
|
1683
|
+
const stat = fs5.statSync(pkgPath);
|
|
1698
1684
|
if (stat.isFile() && stat.size <= MAX_CONFIG_SIZE) {
|
|
1699
|
-
const pkg = JSON.parse(
|
|
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
|
-
|
|
1810
|
-
import
|
|
1811
|
-
import
|
|
1812
|
-
|
|
1813
|
-
var
|
|
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 =
|
|
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
|
-
|
|
1826
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
1907
|
-
for (const
|
|
1908
|
-
if (!
|
|
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(
|
|
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 =
|
|
1932
|
-
if (
|
|
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
|
|
2004
|
-
for (const
|
|
2005
|
-
if (!
|
|
2006
|
-
const piutConfig = getPiutConfig(
|
|
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
|
|
2012
|
-
if (
|
|
1909
|
+
const extractedKey = extractKeyFromConfig(piutConfig);
|
|
1910
|
+
if (extractedKey && extractedKey === store.apiKey) {
|
|
2013
1911
|
toolLine(tool.name, success("key matches"), "\u2714");
|
|
2014
|
-
} else if (
|
|
2015
|
-
const masked =
|
|
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
|
-
|
|
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
|
|
2056
|
-
for (const
|
|
2057
|
-
if (
|
|
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 (!
|
|
2089
|
-
const removed = removeFromConfig(configPath,
|
|
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
|
-
|
|
2007
|
+
init_esm_shims();
|
|
2008
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
2109
2009
|
import chalk5 from "chalk";
|
|
2110
|
-
import
|
|
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
|
-
|
|
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
|
|
2128
|
+
console.log(dim(" Scanning for AI config files..."));
|
|
2242
2129
|
console.log();
|
|
2243
|
-
|
|
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 === "
|
|
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
|
|
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
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
console.log(
|
|
2262
|
-
|
|
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
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
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(` ${
|
|
2283
|
-
console.log(dim("
|
|
2284
|
-
console.log(dim(
|
|
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
|
|
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
|
-
|
|
2400
|
-
|
|
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
|
-
|
|
2516
|
-
import
|
|
2517
|
-
import
|
|
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 ||
|
|
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 ||
|
|
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 ||
|
|
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 ||
|
|
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 ||
|
|
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) =>
|
|
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) =>
|
|
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 =
|
|
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
|
|
2453
|
+
let scanFolders;
|
|
2624
2454
|
if (options.folders) {
|
|
2625
|
-
|
|
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(
|
|
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 =
|
|
2641
|
-
if (
|
|
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" || !
|
|
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 =
|
|
2653
|
-
if (!
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
2741
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
2774
|
-
import
|
|
2775
|
-
import
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
2652
|
+
let scanFolders;
|
|
2822
2653
|
if (options.folders) {
|
|
2823
|
-
|
|
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(
|
|
2657
|
+
const projects = scanForProjects(scanFolders);
|
|
2827
2658
|
const actions = [];
|
|
2828
2659
|
for (const project of projects) {
|
|
2829
|
-
const projectName =
|
|
2660
|
+
const projectName = path12.basename(project.path);
|
|
2830
2661
|
for (const dedicatedFile of DEDICATED_FILES) {
|
|
2831
|
-
const absPath =
|
|
2832
|
-
if (
|
|
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 =
|
|
2844
|
-
if (
|
|
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:
|
|
2690
|
+
absPath: path12.join(project.path, ".piut"),
|
|
2860
2691
|
action: "remove-dir"
|
|
2861
2692
|
});
|
|
2862
2693
|
}
|
|
2863
|
-
const vscodeMcpPath =
|
|
2864
|
-
if (
|
|
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 =
|
|
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
|
|
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 =
|
|
2746
|
+
const projectName = path12.basename(projectPath);
|
|
2916
2747
|
for (const action of projectActions) {
|
|
2917
2748
|
if (action.action === "delete") {
|
|
2918
2749
|
try {
|
|
2919
|
-
|
|
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
|
-
|
|
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
|
|
3146
|
-
for (const configPath of paths) {
|
|
3147
|
-
if (!
|
|
3148
|
-
const piutConfig = getPiutConfig(configPath,
|
|
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
|
|
3164
|
-
const configPrefix =
|
|
2999
|
+
const extractedKey = extractKeyFromConfig(piutConfig);
|
|
3000
|
+
const configPrefix = extractedKey ? extractedKey.slice(0, 7) + "..." : "(none)";
|
|
3165
3001
|
let keyMatch = "missing";
|
|
3166
|
-
if (!
|
|
3002
|
+
if (!extractedKey) {
|
|
3167
3003
|
keyMatch = "missing";
|
|
3168
3004
|
result.issues++;
|
|
3169
|
-
} else if (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,
|
|
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
|
-
|
|
3264
|
-
import
|
|
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 =
|
|
3305
|
-
if (!
|
|
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 =
|
|
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 =
|
|
3315
|
-
const
|
|
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 =
|
|
3338
|
-
|
|
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
|
-
|
|
3371
|
-
import
|
|
3372
|
-
import
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
3601
|
-
for (const
|
|
3602
|
-
const exists =
|
|
3603
|
-
const parentExists =
|
|
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 && !!
|
|
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
|
|
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 &&
|
|
3527
|
+
for (const { tool, configPath, resolvedConfigKey } of toConnect) {
|
|
3528
|
+
if (tool.generateConfig && resolvedConfigKey) {
|
|
3656
3529
|
const serverConfig = tool.generateConfig(slug, apiKey);
|
|
3657
|
-
mergeConfig(configPath,
|
|
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 (!
|
|
3664
|
-
const removed = removeFromConfig(configPath,
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3741
|
-
if (
|
|
3742
|
-
if (rule.strategy === "create" || !
|
|
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
|
-
|
|
3746
|
-
|
|
3618
|
+
fs14.mkdirSync(path15.dirname(absPath), { recursive: true });
|
|
3619
|
+
fs14.writeFileSync(absPath, content, "utf-8");
|
|
3747
3620
|
} else {
|
|
3748
|
-
|
|
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 =
|
|
3637
|
+
const projectName = path15.basename(project.path);
|
|
3765
3638
|
for (const dedicatedFile of DEDICATED_FILES) {
|
|
3766
|
-
const absPath =
|
|
3767
|
-
if (
|
|
3639
|
+
const absPath = path15.join(project.path, dedicatedFile);
|
|
3640
|
+
if (fs14.existsSync(absPath) && hasPiutReference2(absPath)) {
|
|
3768
3641
|
try {
|
|
3769
|
-
|
|
3642
|
+
fs14.unlinkSync(absPath);
|
|
3770
3643
|
} catch {
|
|
3771
3644
|
}
|
|
3772
3645
|
}
|
|
3773
3646
|
}
|
|
3774
3647
|
for (const appendFile of APPEND_FILES) {
|
|
3775
|
-
const absPath =
|
|
3776
|
-
if (
|
|
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 =
|
|
3781
|
-
if (
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
3861
|
-
const
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
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
|
-
|
|
3870
|
-
|
|
3871
|
-
const
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
const
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
if (
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
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(
|
|
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(
|
|
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.
|
|
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("
|
|
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));
|