@piut/cli 3.9.0 → 3.10.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/README.md +1 -1
- package/dist/cli.js +430 -231
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -28,9 +28,9 @@ __export(tree_prompt_exports, {
|
|
|
28
28
|
loadChildren: () => loadChildren,
|
|
29
29
|
shouldShowInTree: () => shouldShowInTree
|
|
30
30
|
});
|
|
31
|
-
import
|
|
32
|
-
import
|
|
33
|
-
import
|
|
31
|
+
import fs15 from "fs";
|
|
32
|
+
import path16 from "path";
|
|
33
|
+
import os9 from "os";
|
|
34
34
|
import {
|
|
35
35
|
createPrompt,
|
|
36
36
|
useState,
|
|
@@ -50,19 +50,19 @@ function shouldShowInTree(name) {
|
|
|
50
50
|
}
|
|
51
51
|
function shouldShowFile(name) {
|
|
52
52
|
if (name.startsWith(".")) return false;
|
|
53
|
-
const ext =
|
|
53
|
+
const ext = path16.extname(name).toLowerCase();
|
|
54
54
|
return !HIDDEN_FILE_EXTENSIONS.has(ext);
|
|
55
55
|
}
|
|
56
56
|
function loadChildren(parentPath, parentDepth, includeFiles = false) {
|
|
57
57
|
try {
|
|
58
|
-
const entries =
|
|
58
|
+
const entries = fs15.readdirSync(parentPath, { withFileTypes: true });
|
|
59
59
|
const dirs = [];
|
|
60
60
|
const files = [];
|
|
61
61
|
for (const entry of entries) {
|
|
62
62
|
if (entry.isDirectory()) {
|
|
63
63
|
if (!shouldShowInTree(entry.name)) continue;
|
|
64
64
|
dirs.push({
|
|
65
|
-
path:
|
|
65
|
+
path: path16.join(parentPath, entry.name),
|
|
66
66
|
name: entry.name,
|
|
67
67
|
depth: parentDepth + 1,
|
|
68
68
|
expanded: false,
|
|
@@ -72,7 +72,7 @@ function loadChildren(parentPath, parentDepth, includeFiles = false) {
|
|
|
72
72
|
} else if (includeFiles && entry.isFile()) {
|
|
73
73
|
if (!shouldShowFile(entry.name)) continue;
|
|
74
74
|
files.push({
|
|
75
|
-
path:
|
|
75
|
+
path: path16.join(parentPath, entry.name),
|
|
76
76
|
name: entry.name,
|
|
77
77
|
depth: parentDepth + 1,
|
|
78
78
|
expanded: false,
|
|
@@ -214,7 +214,7 @@ var init_tree_prompt = __esm({
|
|
|
214
214
|
".map"
|
|
215
215
|
]);
|
|
216
216
|
treePrompt = createPrompt((config, done) => {
|
|
217
|
-
const root = config.root ??
|
|
217
|
+
const root = config.root ?? os9.homedir();
|
|
218
218
|
const pageSize = config.pageSize ?? 15;
|
|
219
219
|
const mode = config.mode ?? "folders";
|
|
220
220
|
const includeFiles = mode === "files";
|
|
@@ -325,9 +325,9 @@ import { Command } from "commander";
|
|
|
325
325
|
|
|
326
326
|
// src/commands/setup.ts
|
|
327
327
|
init_esm_shims();
|
|
328
|
-
import
|
|
329
|
-
import
|
|
330
|
-
import { execSync } from "child_process";
|
|
328
|
+
import fs6 from "fs";
|
|
329
|
+
import path9 from "path";
|
|
330
|
+
import { execSync as execSync2 } from "child_process";
|
|
331
331
|
import { password, confirm, checkbox } from "@inquirer/prompts";
|
|
332
332
|
import chalk2 from "chalk";
|
|
333
333
|
|
|
@@ -641,7 +641,7 @@ var TOOLS = [
|
|
|
641
641
|
project: [".mcp.json"]
|
|
642
642
|
},
|
|
643
643
|
skillFilePath: "CLAUDE.md",
|
|
644
|
-
quickCommand: (slug, key) => `claude mcp add-json piut
|
|
644
|
+
quickCommand: (slug, key) => `claude mcp add-json piut '${JSON.stringify({
|
|
645
645
|
type: "http",
|
|
646
646
|
url: MCP_URL(slug),
|
|
647
647
|
headers: { ...AUTH_HEADER(key), ...machineHeaders("Claude Code") }
|
|
@@ -776,7 +776,7 @@ var TOOLS = [
|
|
|
776
776
|
win32: ["~/.mcporter/mcporter.json", "~/.openclaw/workspace/config/mcporter.json"],
|
|
777
777
|
linux: ["~/.mcporter/mcporter.json", "~/.openclaw/workspace/config/mcporter.json"]
|
|
778
778
|
},
|
|
779
|
-
quickCommand: (slug, key) => `npx mcporter config add piut
|
|
779
|
+
quickCommand: (slug, key) => `npx mcporter config add piut ${MCP_URL(slug)} --header "Authorization=Bearer ${key}"`,
|
|
780
780
|
generateConfig: (slug, key) => ({
|
|
781
781
|
url: MCP_URL(slug),
|
|
782
782
|
headers: { ...AUTH_HEADER(key), ...machineHeaders("OpenClaw") }
|
|
@@ -820,6 +820,8 @@ function resolveConfigPaths(tool) {
|
|
|
820
820
|
init_esm_shims();
|
|
821
821
|
import fs from "fs";
|
|
822
822
|
import path4 from "path";
|
|
823
|
+
var SERVER_KEY = "piut";
|
|
824
|
+
var LEGACY_SERVER_KEY = "piut-context";
|
|
823
825
|
function readConfig(filePath) {
|
|
824
826
|
let raw;
|
|
825
827
|
try {
|
|
@@ -867,12 +869,13 @@ function isPiutConfigured(filePath, configKey) {
|
|
|
867
869
|
const config = readConfig(filePath);
|
|
868
870
|
if (!config) return false;
|
|
869
871
|
const servers = resolveKeyPath(config, configKey);
|
|
870
|
-
return !!servers?.[
|
|
872
|
+
return !!(servers?.[SERVER_KEY] || servers?.[LEGACY_SERVER_KEY]);
|
|
871
873
|
}
|
|
872
874
|
function mergeConfig(filePath, configKey, serverConfig) {
|
|
873
875
|
const existing = readConfig(filePath) || {};
|
|
874
876
|
const servers = resolveKeyPath(existing, configKey) || {};
|
|
875
|
-
servers[
|
|
877
|
+
delete servers[LEGACY_SERVER_KEY];
|
|
878
|
+
servers[SERVER_KEY] = serverConfig;
|
|
876
879
|
setAtKeyPath(existing, configKey, servers);
|
|
877
880
|
writeConfig(filePath, existing);
|
|
878
881
|
}
|
|
@@ -880,7 +883,7 @@ function getPiutConfig(filePath, configKey) {
|
|
|
880
883
|
const config = readConfig(filePath);
|
|
881
884
|
if (!config) return null;
|
|
882
885
|
const servers = resolveKeyPath(config, configKey);
|
|
883
|
-
const piut = servers?.[
|
|
886
|
+
const piut = servers?.[SERVER_KEY] || servers?.[LEGACY_SERVER_KEY];
|
|
884
887
|
return piut ?? null;
|
|
885
888
|
}
|
|
886
889
|
function extractKeyFromConfig(piutConfig) {
|
|
@@ -932,8 +935,11 @@ function removeFromConfig(filePath, configKey) {
|
|
|
932
935
|
const config = readConfig(filePath);
|
|
933
936
|
if (!config) return false;
|
|
934
937
|
const servers = resolveKeyPath(config, configKey);
|
|
935
|
-
|
|
936
|
-
|
|
938
|
+
const hasNew = !!servers?.[SERVER_KEY];
|
|
939
|
+
const hasLegacy = !!servers?.[LEGACY_SERVER_KEY];
|
|
940
|
+
if (!hasNew && !hasLegacy) return false;
|
|
941
|
+
delete servers[SERVER_KEY];
|
|
942
|
+
delete servers[LEGACY_SERVER_KEY];
|
|
937
943
|
if (Object.keys(servers).length === 0 && !configKey.includes(".")) {
|
|
938
944
|
delete config[configKey];
|
|
939
945
|
}
|
|
@@ -945,7 +951,7 @@ function removeFromConfig(filePath, configKey) {
|
|
|
945
951
|
init_esm_shims();
|
|
946
952
|
import fs2 from "fs";
|
|
947
953
|
import path5 from "path";
|
|
948
|
-
var SKILL_SNIPPET = `## p\u0131ut Context (MCP Server: piut
|
|
954
|
+
var SKILL_SNIPPET = `## p\u0131ut Context (MCP Server: piut)
|
|
949
955
|
|
|
950
956
|
This project uses p\u0131ut for persistent personal context via MCP (Model Context Protocol).
|
|
951
957
|
p\u0131ut provides MCP tools \u2014 do NOT read local .piut/ files directly. Use the MCP tools.
|
|
@@ -965,7 +971,7 @@ p\u0131ut provides MCP tools \u2014 do NOT read local .piut/ files directly. Use
|
|
|
965
971
|
4. Never read .piut/config.json directly \u2014 always use the MCP tools
|
|
966
972
|
|
|
967
973
|
Skill reference: https://raw.githubusercontent.com/M-Flat-Inc/piut/main/skill.md`;
|
|
968
|
-
var PROJECT_SKILL_SNIPPET = `## p\u0131ut Context (MCP Server: piut
|
|
974
|
+
var PROJECT_SKILL_SNIPPET = `## p\u0131ut Context (MCP Server: piut)
|
|
969
975
|
|
|
970
976
|
This project uses p\u0131ut for persistent personal context via MCP (Model Context Protocol).
|
|
971
977
|
p\u0131ut provides MCP tools \u2014 do NOT read local .piut/ files directly. Use the MCP tools.
|
|
@@ -1114,6 +1120,42 @@ function hasPiutDir(projectPath) {
|
|
|
1114
1120
|
return fs3.existsSync(path6.join(piutDir(projectPath), CONFIG_FILE));
|
|
1115
1121
|
}
|
|
1116
1122
|
|
|
1123
|
+
// src/lib/global-install.ts
|
|
1124
|
+
init_esm_shims();
|
|
1125
|
+
import { execSync } from "child_process";
|
|
1126
|
+
import fs5 from "fs";
|
|
1127
|
+
import path8 from "path";
|
|
1128
|
+
import os5 from "os";
|
|
1129
|
+
|
|
1130
|
+
// src/lib/store.ts
|
|
1131
|
+
init_esm_shims();
|
|
1132
|
+
import fs4 from "fs";
|
|
1133
|
+
import path7 from "path";
|
|
1134
|
+
import os4 from "os";
|
|
1135
|
+
var CONFIG_DIR = path7.join(os4.homedir(), ".piut");
|
|
1136
|
+
var CONFIG_FILE2 = path7.join(CONFIG_DIR, "config.json");
|
|
1137
|
+
function readStore() {
|
|
1138
|
+
try {
|
|
1139
|
+
const raw = fs4.readFileSync(CONFIG_FILE2, "utf-8");
|
|
1140
|
+
return JSON.parse(raw);
|
|
1141
|
+
} catch {
|
|
1142
|
+
return {};
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
function updateStore(updates) {
|
|
1146
|
+
const config = readStore();
|
|
1147
|
+
const updated = { ...config, ...updates };
|
|
1148
|
+
fs4.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
1149
|
+
fs4.writeFileSync(CONFIG_FILE2, JSON.stringify(updated, null, 2) + "\n", "utf-8");
|
|
1150
|
+
return updated;
|
|
1151
|
+
}
|
|
1152
|
+
function clearStore() {
|
|
1153
|
+
try {
|
|
1154
|
+
fs4.unlinkSync(CONFIG_FILE2);
|
|
1155
|
+
} catch {
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1117
1159
|
// src/lib/ui.ts
|
|
1118
1160
|
init_esm_shims();
|
|
1119
1161
|
import chalk from "chalk";
|
|
@@ -1200,6 +1242,65 @@ var Spinner = class {
|
|
|
1200
1242
|
}
|
|
1201
1243
|
};
|
|
1202
1244
|
|
|
1245
|
+
// src/lib/global-install.ts
|
|
1246
|
+
function isPiutInPath() {
|
|
1247
|
+
try {
|
|
1248
|
+
execSync(process.platform === "win32" ? "where piut" : "which piut", { stdio: "pipe" });
|
|
1249
|
+
return true;
|
|
1250
|
+
} catch {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
function getShellProfile() {
|
|
1255
|
+
const shell = process.env.SHELL || "";
|
|
1256
|
+
const home2 = os5.homedir();
|
|
1257
|
+
if (shell.includes("zsh")) {
|
|
1258
|
+
return path8.join(home2, ".zshrc");
|
|
1259
|
+
}
|
|
1260
|
+
if (shell.includes("bash")) {
|
|
1261
|
+
const profile = path8.join(home2, ".bash_profile");
|
|
1262
|
+
if (process.platform === "darwin" && fs5.existsSync(profile)) {
|
|
1263
|
+
return profile;
|
|
1264
|
+
}
|
|
1265
|
+
return path8.join(home2, ".bashrc");
|
|
1266
|
+
}
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
function addShellAlias(profilePath) {
|
|
1270
|
+
try {
|
|
1271
|
+
const content = fs5.existsSync(profilePath) ? fs5.readFileSync(profilePath, "utf-8") : "";
|
|
1272
|
+
if (content.includes("alias piut=") || content.includes("piut()")) {
|
|
1273
|
+
return true;
|
|
1274
|
+
}
|
|
1275
|
+
const alias = '\n# p\u0131ut CLI shortcut\nalias piut="npx @piut/cli"\n';
|
|
1276
|
+
fs5.appendFileSync(profilePath, alias);
|
|
1277
|
+
return true;
|
|
1278
|
+
} catch {
|
|
1279
|
+
return false;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
async function offerGlobalInstall() {
|
|
1283
|
+
if (isPiutInPath()) return;
|
|
1284
|
+
const store = readStore();
|
|
1285
|
+
if (store.globalInstallOffered) return;
|
|
1286
|
+
updateStore({ globalInstallOffered: true });
|
|
1287
|
+
try {
|
|
1288
|
+
execSync("npm install -g @piut/cli", { stdio: "pipe", timeout: 3e4 });
|
|
1289
|
+
if (isPiutInPath()) {
|
|
1290
|
+
console.log(dim(" Installed `piut` command for quick access"));
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
} catch {
|
|
1294
|
+
}
|
|
1295
|
+
const profile = getShellProfile();
|
|
1296
|
+
if (profile) {
|
|
1297
|
+
if (addShellAlias(profile)) {
|
|
1298
|
+
console.log(dim(` Added \`piut\` shortcut to ${path8.basename(profile)}`));
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1203
1304
|
// src/types.ts
|
|
1204
1305
|
init_esm_shims();
|
|
1205
1306
|
var CliError = class extends Error {
|
|
@@ -1255,8 +1356,8 @@ async function setupCommand(options) {
|
|
|
1255
1356
|
if (tool.skillOnly) continue;
|
|
1256
1357
|
const paths = resolveConfigPaths(tool);
|
|
1257
1358
|
for (const { filePath, configKey } of paths) {
|
|
1258
|
-
const exists =
|
|
1259
|
-
const parentExists =
|
|
1359
|
+
const exists = fs6.existsSync(filePath);
|
|
1360
|
+
const parentExists = fs6.existsSync(path9.dirname(filePath));
|
|
1260
1361
|
if (exists || parentExists) {
|
|
1261
1362
|
const configured2 = exists && !!configKey && isPiutConfigured(filePath, configKey);
|
|
1262
1363
|
let staleKey = false;
|
|
@@ -1336,7 +1437,7 @@ async function setupCommand(options) {
|
|
|
1336
1437
|
if (tool.id === "claude-code" && tool.quickCommand && isCommandAvailable("claude")) {
|
|
1337
1438
|
let quickSuccess = false;
|
|
1338
1439
|
try {
|
|
1339
|
-
|
|
1440
|
+
execSync2(tool.quickCommand(slug, apiKey), { stdio: "pipe" });
|
|
1340
1441
|
const claudeJson = expandPath("~/.claude.json");
|
|
1341
1442
|
const written = tool.configKey ? getPiutConfig(claudeJson, tool.configKey) : null;
|
|
1342
1443
|
if (written) {
|
|
@@ -1346,7 +1447,7 @@ async function setupCommand(options) {
|
|
|
1346
1447
|
continue;
|
|
1347
1448
|
}
|
|
1348
1449
|
try {
|
|
1349
|
-
|
|
1450
|
+
execSync2(tool.quickCommand(slug, apiKey) + " --scope user", { stdio: "pipe" });
|
|
1350
1451
|
const retryCheck = tool.configKey ? getPiutConfig(claudeJson, tool.configKey) : null;
|
|
1351
1452
|
if (retryCheck) {
|
|
1352
1453
|
quickSuccess = true;
|
|
@@ -1396,7 +1497,7 @@ async function setupCommand(options) {
|
|
|
1396
1497
|
}
|
|
1397
1498
|
if (configured.length > 0) {
|
|
1398
1499
|
const cwd = process.cwd();
|
|
1399
|
-
const isProject2 =
|
|
1500
|
+
const isProject2 = fs6.existsSync(path9.join(cwd, ".git")) || fs6.existsSync(path9.join(cwd, "package.json"));
|
|
1400
1501
|
if (isProject2) {
|
|
1401
1502
|
const { serverUrl } = validationResult;
|
|
1402
1503
|
writePiutConfig(cwd, { slug, apiKey, serverUrl });
|
|
@@ -1438,6 +1539,7 @@ async function setupCommand(options) {
|
|
|
1438
1539
|
if (skipped.length > 0) {
|
|
1439
1540
|
console.log(dim(` Skipped: ${skipped.join(", ")}`));
|
|
1440
1541
|
}
|
|
1542
|
+
await offerGlobalInstall();
|
|
1441
1543
|
console.log();
|
|
1442
1544
|
console.log(dim(" Restart your AI tools for changes to take effect."));
|
|
1443
1545
|
console.log(dim(' Verify: ask any AI "What do you know about me from my context?"'));
|
|
@@ -1446,7 +1548,7 @@ async function setupCommand(options) {
|
|
|
1446
1548
|
}
|
|
1447
1549
|
function isCommandAvailable(cmd) {
|
|
1448
1550
|
try {
|
|
1449
|
-
|
|
1551
|
+
execSync2(process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`, { stdio: "pipe" });
|
|
1450
1552
|
return true;
|
|
1451
1553
|
} catch {
|
|
1452
1554
|
return false;
|
|
@@ -1455,16 +1557,16 @@ function isCommandAvailable(cmd) {
|
|
|
1455
1557
|
|
|
1456
1558
|
// src/commands/status.ts
|
|
1457
1559
|
init_esm_shims();
|
|
1458
|
-
import
|
|
1459
|
-
import
|
|
1460
|
-
import
|
|
1560
|
+
import fs8 from "fs";
|
|
1561
|
+
import os7 from "os";
|
|
1562
|
+
import path11 from "path";
|
|
1461
1563
|
import chalk3 from "chalk";
|
|
1462
1564
|
|
|
1463
1565
|
// src/lib/brain-scanner.ts
|
|
1464
1566
|
init_esm_shims();
|
|
1465
|
-
import
|
|
1466
|
-
import
|
|
1467
|
-
import
|
|
1567
|
+
import fs7 from "fs";
|
|
1568
|
+
import path10 from "path";
|
|
1569
|
+
import os6 from "os";
|
|
1468
1570
|
|
|
1469
1571
|
// src/lib/file-types.ts
|
|
1470
1572
|
init_esm_shims();
|
|
@@ -1483,7 +1585,7 @@ var AI_CONFIG_FILENAMES = /* @__PURE__ */ new Set([
|
|
|
1483
1585
|
]);
|
|
1484
1586
|
|
|
1485
1587
|
// src/lib/brain-scanner.ts
|
|
1486
|
-
var home =
|
|
1588
|
+
var home = os6.homedir();
|
|
1487
1589
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
1488
1590
|
"node_modules",
|
|
1489
1591
|
".git",
|
|
@@ -1547,22 +1649,22 @@ var INCLUDE_DOT_DIRS = /* @__PURE__ */ new Set([
|
|
|
1547
1649
|
function getDefaultScanDirs() {
|
|
1548
1650
|
const dirs = [];
|
|
1549
1651
|
try {
|
|
1550
|
-
const entries =
|
|
1652
|
+
const entries = fs7.readdirSync(home, { withFileTypes: true });
|
|
1551
1653
|
for (const entry of entries) {
|
|
1552
1654
|
if (!entry.isDirectory()) continue;
|
|
1553
1655
|
if (entry.name.startsWith(".") && !INCLUDE_DOT_DIRS.has(entry.name)) continue;
|
|
1554
1656
|
if (SKIP_HOME_DIRS.has(entry.name)) continue;
|
|
1555
|
-
dirs.push(
|
|
1657
|
+
dirs.push(path10.join(home, entry.name));
|
|
1556
1658
|
}
|
|
1557
1659
|
} catch {
|
|
1558
1660
|
}
|
|
1559
|
-
const cloudStorage =
|
|
1661
|
+
const cloudStorage = path10.join(home, "Library", "CloudStorage");
|
|
1560
1662
|
try {
|
|
1561
|
-
if (
|
|
1562
|
-
const entries =
|
|
1663
|
+
if (fs7.existsSync(cloudStorage) && fs7.statSync(cloudStorage).isDirectory()) {
|
|
1664
|
+
const entries = fs7.readdirSync(cloudStorage, { withFileTypes: true });
|
|
1563
1665
|
for (const entry of entries) {
|
|
1564
1666
|
if (!entry.isDirectory()) continue;
|
|
1565
|
-
const fullPath =
|
|
1667
|
+
const fullPath = path10.join(cloudStorage, entry.name);
|
|
1566
1668
|
if (!dirs.includes(fullPath)) {
|
|
1567
1669
|
dirs.push(fullPath);
|
|
1568
1670
|
}
|
|
@@ -1574,22 +1676,22 @@ function getDefaultScanDirs() {
|
|
|
1574
1676
|
return dirs;
|
|
1575
1677
|
}
|
|
1576
1678
|
function isProject(dirPath) {
|
|
1577
|
-
return
|
|
1679
|
+
return fs7.existsSync(path10.join(dirPath, ".git")) || fs7.existsSync(path10.join(dirPath, "package.json")) || fs7.existsSync(path10.join(dirPath, "Cargo.toml")) || fs7.existsSync(path10.join(dirPath, "pyproject.toml")) || fs7.existsSync(path10.join(dirPath, "go.mod"));
|
|
1578
1680
|
}
|
|
1579
1681
|
function buildProjectInfo(projectPath) {
|
|
1580
|
-
const hasPkgJson =
|
|
1682
|
+
const hasPkgJson = fs7.existsSync(path10.join(projectPath, "package.json"));
|
|
1581
1683
|
let description = "";
|
|
1582
1684
|
if (hasPkgJson) {
|
|
1583
1685
|
try {
|
|
1584
|
-
const pkg = JSON.parse(
|
|
1686
|
+
const pkg = JSON.parse(fs7.readFileSync(path10.join(projectPath, "package.json"), "utf-8"));
|
|
1585
1687
|
description = pkg.description || "";
|
|
1586
1688
|
} catch {
|
|
1587
1689
|
}
|
|
1588
1690
|
}
|
|
1589
|
-
const readmePath =
|
|
1590
|
-
if (!description &&
|
|
1691
|
+
const readmePath = path10.join(projectPath, "README.md");
|
|
1692
|
+
if (!description && fs7.existsSync(readmePath)) {
|
|
1591
1693
|
try {
|
|
1592
|
-
const content =
|
|
1694
|
+
const content = fs7.readFileSync(readmePath, "utf-8");
|
|
1593
1695
|
const lines = content.split("\n");
|
|
1594
1696
|
let foundHeading = false;
|
|
1595
1697
|
for (const line of lines) {
|
|
@@ -1606,15 +1708,15 @@ function buildProjectInfo(projectPath) {
|
|
|
1606
1708
|
}
|
|
1607
1709
|
}
|
|
1608
1710
|
return {
|
|
1609
|
-
name:
|
|
1711
|
+
name: path10.basename(projectPath),
|
|
1610
1712
|
path: projectPath,
|
|
1611
1713
|
description,
|
|
1612
|
-
hasClaudeMd:
|
|
1613
|
-
hasCursorRules:
|
|
1614
|
-
hasWindsurfRules:
|
|
1615
|
-
hasCopilotInstructions:
|
|
1616
|
-
hasConventionsMd:
|
|
1617
|
-
hasZedRules:
|
|
1714
|
+
hasClaudeMd: fs7.existsSync(path10.join(projectPath, "CLAUDE.md")) || fs7.existsSync(path10.join(projectPath, ".claude", "rules")),
|
|
1715
|
+
hasCursorRules: fs7.existsSync(path10.join(projectPath, ".cursorrules")) || fs7.existsSync(path10.join(projectPath, ".cursor", "rules")),
|
|
1716
|
+
hasWindsurfRules: fs7.existsSync(path10.join(projectPath, ".windsurfrules")) || fs7.existsSync(path10.join(projectPath, ".windsurf", "rules")),
|
|
1717
|
+
hasCopilotInstructions: fs7.existsSync(path10.join(projectPath, ".github", "copilot-instructions.md")) || fs7.existsSync(path10.join(projectPath, ".github", "instructions")),
|
|
1718
|
+
hasConventionsMd: fs7.existsSync(path10.join(projectPath, "CONVENTIONS.md")) || fs7.existsSync(path10.join(projectPath, ".amazonq", "rules")),
|
|
1719
|
+
hasZedRules: fs7.existsSync(path10.join(projectPath, ".rules"))
|
|
1618
1720
|
};
|
|
1619
1721
|
}
|
|
1620
1722
|
var MAX_PROJECT_DEPTH = 4;
|
|
@@ -1624,11 +1726,11 @@ function detectProjects(scanDirs, onProgress) {
|
|
|
1624
1726
|
function walk(dir, depth) {
|
|
1625
1727
|
if (depth > MAX_PROJECT_DEPTH) return;
|
|
1626
1728
|
try {
|
|
1627
|
-
const items =
|
|
1729
|
+
const items = fs7.readdirSync(dir, { withFileTypes: true });
|
|
1628
1730
|
for (const item of items) {
|
|
1629
1731
|
if (!item.isDirectory()) continue;
|
|
1630
1732
|
if (shouldSkipDir(item.name)) continue;
|
|
1631
|
-
const fullPath =
|
|
1733
|
+
const fullPath = path10.join(dir, item.name);
|
|
1632
1734
|
if (seen.has(fullPath)) continue;
|
|
1633
1735
|
seen.add(fullPath);
|
|
1634
1736
|
if (isProject(fullPath)) {
|
|
@@ -1652,20 +1754,20 @@ var MAX_BRAIN_INPUT_BYTES = 1e6;
|
|
|
1652
1754
|
function collectGlobalConfigFiles(onProgress) {
|
|
1653
1755
|
const configs = [];
|
|
1654
1756
|
const globalPaths = [
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1757
|
+
path10.join(home, ".claude", "MEMORY.md"),
|
|
1758
|
+
path10.join(home, ".claude", "CLAUDE.md"),
|
|
1759
|
+
path10.join(home, ".openclaw", "workspace", "SOUL.md"),
|
|
1760
|
+
path10.join(home, ".openclaw", "workspace", "MEMORY.md"),
|
|
1761
|
+
path10.join(home, ".gemini", "MEMORY.md"),
|
|
1762
|
+
path10.join(home, ".paperclip", "IDENTITY.md")
|
|
1661
1763
|
];
|
|
1662
1764
|
for (const gp of globalPaths) {
|
|
1663
1765
|
try {
|
|
1664
|
-
const stat =
|
|
1766
|
+
const stat = fs7.statSync(gp);
|
|
1665
1767
|
if (!stat.isFile() || stat.size > MAX_CONFIG_SIZE) continue;
|
|
1666
|
-
const content =
|
|
1768
|
+
const content = fs7.readFileSync(gp, "utf-8");
|
|
1667
1769
|
if (content.trim()) {
|
|
1668
|
-
const name =
|
|
1770
|
+
const name = path10.relative(home, gp);
|
|
1669
1771
|
configs.push({ name, content });
|
|
1670
1772
|
onProgress?.({ phase: "configs", message: name });
|
|
1671
1773
|
}
|
|
@@ -1678,11 +1780,11 @@ function collectProjectConfigFiles(projects, onProgress) {
|
|
|
1678
1780
|
const configs = [];
|
|
1679
1781
|
for (const project of projects) {
|
|
1680
1782
|
for (const fileName of AI_CONFIG_FILENAMES) {
|
|
1681
|
-
const filePath =
|
|
1783
|
+
const filePath = path10.join(project.path, fileName);
|
|
1682
1784
|
try {
|
|
1683
|
-
const stat =
|
|
1785
|
+
const stat = fs7.statSync(filePath);
|
|
1684
1786
|
if (!stat.isFile() || stat.size > MAX_CONFIG_SIZE) continue;
|
|
1685
|
-
const content =
|
|
1787
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
1686
1788
|
if (content.trim()) {
|
|
1687
1789
|
const name = `${project.name}/${fileName}`;
|
|
1688
1790
|
configs.push({ name, content });
|
|
@@ -1691,11 +1793,11 @@ function collectProjectConfigFiles(projects, onProgress) {
|
|
|
1691
1793
|
} catch {
|
|
1692
1794
|
}
|
|
1693
1795
|
}
|
|
1694
|
-
const pkgPath =
|
|
1796
|
+
const pkgPath = path10.join(project.path, "package.json");
|
|
1695
1797
|
try {
|
|
1696
|
-
const stat =
|
|
1798
|
+
const stat = fs7.statSync(pkgPath);
|
|
1697
1799
|
if (stat.isFile() && stat.size <= MAX_CONFIG_SIZE) {
|
|
1698
|
-
const pkg = JSON.parse(
|
|
1800
|
+
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
1699
1801
|
const summary = JSON.stringify({ name: pkg.name, description: pkg.description }, null, 2);
|
|
1700
1802
|
configs.push({ name: `${project.name}/package.json`, content: summary });
|
|
1701
1803
|
onProgress?.({ phase: "configs", message: `${project.name}/package.json` });
|
|
@@ -1715,35 +1817,6 @@ function formatSize(bytes) {
|
|
|
1715
1817
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1716
1818
|
}
|
|
1717
1819
|
|
|
1718
|
-
// src/lib/store.ts
|
|
1719
|
-
init_esm_shims();
|
|
1720
|
-
import fs6 from "fs";
|
|
1721
|
-
import path9 from "path";
|
|
1722
|
-
import os5 from "os";
|
|
1723
|
-
var CONFIG_DIR = path9.join(os5.homedir(), ".piut");
|
|
1724
|
-
var CONFIG_FILE2 = path9.join(CONFIG_DIR, "config.json");
|
|
1725
|
-
function readStore() {
|
|
1726
|
-
try {
|
|
1727
|
-
const raw = fs6.readFileSync(CONFIG_FILE2, "utf-8");
|
|
1728
|
-
return JSON.parse(raw);
|
|
1729
|
-
} catch {
|
|
1730
|
-
return {};
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
function updateStore(updates) {
|
|
1734
|
-
const config = readStore();
|
|
1735
|
-
const updated = { ...config, ...updates };
|
|
1736
|
-
fs6.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
1737
|
-
fs6.writeFileSync(CONFIG_FILE2, JSON.stringify(updated, null, 2) + "\n", "utf-8");
|
|
1738
|
-
return updated;
|
|
1739
|
-
}
|
|
1740
|
-
function clearStore() {
|
|
1741
|
-
try {
|
|
1742
|
-
fs6.unlinkSync(CONFIG_FILE2);
|
|
1743
|
-
} catch {
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
1820
|
// src/commands/status.ts
|
|
1748
1821
|
var API_BASE3 = process.env.PIUT_API_BASE || "https://piut.com";
|
|
1749
1822
|
var PIUT_FILES = [
|
|
@@ -1756,7 +1829,7 @@ var PIUT_FILES = [
|
|
|
1756
1829
|
];
|
|
1757
1830
|
function hasPiutReference(filePath) {
|
|
1758
1831
|
try {
|
|
1759
|
-
const content =
|
|
1832
|
+
const content = fs8.readFileSync(filePath, "utf-8");
|
|
1760
1833
|
return content.includes("p\u0131ut Context") || content.includes("piut Context");
|
|
1761
1834
|
} catch {
|
|
1762
1835
|
return false;
|
|
@@ -1808,7 +1881,7 @@ async function statusCommand(options = {}) {
|
|
|
1808
1881
|
await verifyStatus();
|
|
1809
1882
|
return;
|
|
1810
1883
|
}
|
|
1811
|
-
const thisHostname =
|
|
1884
|
+
const thisHostname = os7.hostname();
|
|
1812
1885
|
const thisMachineId = getMachineId2();
|
|
1813
1886
|
console.log(` AI tools on this machine ${dim(`(${thisHostname})`)}:`);
|
|
1814
1887
|
console.log();
|
|
@@ -1816,7 +1889,7 @@ async function statusCommand(options = {}) {
|
|
|
1816
1889
|
for (const tool of TOOLS) {
|
|
1817
1890
|
const paths = resolveConfigPaths(tool);
|
|
1818
1891
|
for (const { filePath, configKey } of paths) {
|
|
1819
|
-
if (!
|
|
1892
|
+
if (!fs8.existsSync(filePath)) continue;
|
|
1820
1893
|
foundAny = true;
|
|
1821
1894
|
const configured = isPiutConfigured(filePath, configKey);
|
|
1822
1895
|
if (configured) {
|
|
@@ -1839,8 +1912,8 @@ async function statusCommand(options = {}) {
|
|
|
1839
1912
|
for (const project of projects) {
|
|
1840
1913
|
const connectedFiles = [];
|
|
1841
1914
|
for (const file of PIUT_FILES) {
|
|
1842
|
-
const absPath =
|
|
1843
|
-
if (
|
|
1915
|
+
const absPath = path11.join(project.path, file);
|
|
1916
|
+
if (fs8.existsSync(absPath) && hasPiutReference(absPath)) {
|
|
1844
1917
|
connectedFiles.push(file);
|
|
1845
1918
|
}
|
|
1846
1919
|
}
|
|
@@ -1913,7 +1986,7 @@ async function verifyStatus() {
|
|
|
1913
1986
|
for (const tool of TOOLS) {
|
|
1914
1987
|
const paths = resolveConfigPaths(tool);
|
|
1915
1988
|
for (const { filePath, configKey } of paths) {
|
|
1916
|
-
if (!
|
|
1989
|
+
if (!fs8.existsSync(filePath)) continue;
|
|
1917
1990
|
const piutConfig = getPiutConfig(filePath, configKey);
|
|
1918
1991
|
if (!piutConfig) {
|
|
1919
1992
|
toolLine(tool.name, dim("installed, not connected"), "\u25CB");
|
|
@@ -1957,7 +2030,7 @@ async function verifyStatus() {
|
|
|
1957
2030
|
|
|
1958
2031
|
// src/commands/remove.ts
|
|
1959
2032
|
init_esm_shims();
|
|
1960
|
-
import
|
|
2033
|
+
import fs9 from "fs";
|
|
1961
2034
|
import { checkbox as checkbox2, confirm as confirm2 } from "@inquirer/prompts";
|
|
1962
2035
|
async function removeCommand() {
|
|
1963
2036
|
banner();
|
|
@@ -1966,7 +2039,7 @@ async function removeCommand() {
|
|
|
1966
2039
|
if (!tool.configKey) continue;
|
|
1967
2040
|
const paths = resolveConfigPaths(tool);
|
|
1968
2041
|
for (const { filePath, configKey } of paths) {
|
|
1969
|
-
if (
|
|
2042
|
+
if (fs9.existsSync(filePath) && isPiutConfigured(filePath, configKey)) {
|
|
1970
2043
|
configured.push({ tool, configPath: filePath, resolvedConfigKey: configKey });
|
|
1971
2044
|
break;
|
|
1972
2045
|
}
|
|
@@ -2020,7 +2093,7 @@ async function removeCommand() {
|
|
|
2020
2093
|
init_esm_shims();
|
|
2021
2094
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
2022
2095
|
import chalk5 from "chalk";
|
|
2023
|
-
import
|
|
2096
|
+
import os8 from "os";
|
|
2024
2097
|
|
|
2025
2098
|
// src/lib/auth.ts
|
|
2026
2099
|
init_esm_shims();
|
|
@@ -2224,10 +2297,95 @@ async function resolveApiKeyWithResult(keyOption) {
|
|
|
2224
2297
|
}
|
|
2225
2298
|
}
|
|
2226
2299
|
|
|
2300
|
+
// src/lib/sync.ts
|
|
2301
|
+
init_esm_shims();
|
|
2302
|
+
import fs10 from "fs";
|
|
2303
|
+
import path12 from "path";
|
|
2304
|
+
function syncStaleConfigs(slug, apiKey, serverUrl) {
|
|
2305
|
+
const updated = [];
|
|
2306
|
+
for (const tool of TOOLS) {
|
|
2307
|
+
if (tool.skillOnly || !tool.generateConfig || !tool.configKey) continue;
|
|
2308
|
+
const paths = resolveConfigPaths(tool);
|
|
2309
|
+
for (const { filePath, configKey } of paths) {
|
|
2310
|
+
if (!fs10.existsSync(filePath)) continue;
|
|
2311
|
+
const piutConfig = getPiutConfig(filePath, configKey);
|
|
2312
|
+
if (!piutConfig) continue;
|
|
2313
|
+
const existingKey = extractKeyFromConfig(piutConfig);
|
|
2314
|
+
const existingSlug = extractSlugFromConfig(piutConfig);
|
|
2315
|
+
const keyStale = !!existingKey && existingKey !== apiKey;
|
|
2316
|
+
const slugStale = !!existingSlug && existingSlug !== slug;
|
|
2317
|
+
if (keyStale || slugStale) {
|
|
2318
|
+
const newConfig = tool.generateConfig(slug, apiKey);
|
|
2319
|
+
mergeConfig(filePath, configKey, newConfig);
|
|
2320
|
+
updated.push(tool.name);
|
|
2321
|
+
}
|
|
2322
|
+
break;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
const cwd = process.cwd();
|
|
2326
|
+
const existing = readPiutConfig(cwd);
|
|
2327
|
+
if (existing && (existing.apiKey !== apiKey || existing.slug !== slug)) {
|
|
2328
|
+
writePiutConfig(cwd, { slug, apiKey, serverUrl });
|
|
2329
|
+
updated.push(".piut/config.json");
|
|
2330
|
+
}
|
|
2331
|
+
return updated;
|
|
2332
|
+
}
|
|
2333
|
+
function getConfiguredToolNames() {
|
|
2334
|
+
const names = [];
|
|
2335
|
+
for (const tool of TOOLS) {
|
|
2336
|
+
if (tool.skillOnly || !tool.configKey) continue;
|
|
2337
|
+
const paths = resolveConfigPaths(tool);
|
|
2338
|
+
for (const { filePath, configKey } of paths) {
|
|
2339
|
+
if (!fs10.existsSync(filePath)) continue;
|
|
2340
|
+
if (getPiutConfig(filePath, configKey)) {
|
|
2341
|
+
names.push(tool.name);
|
|
2342
|
+
break;
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
return names;
|
|
2347
|
+
}
|
|
2348
|
+
async function cycleConfigEntry(filePath, configKey, freshConfig) {
|
|
2349
|
+
removeFromConfig(filePath, configKey);
|
|
2350
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2351
|
+
mergeConfig(filePath, configKey, freshConfig);
|
|
2352
|
+
}
|
|
2353
|
+
async function cycleMcpConfigs(slug, apiKey) {
|
|
2354
|
+
for (const tool of TOOLS) {
|
|
2355
|
+
if (tool.skillOnly || !tool.generateConfig || !tool.configKey) continue;
|
|
2356
|
+
const paths = resolveConfigPaths(tool);
|
|
2357
|
+
for (const { filePath, configKey } of paths) {
|
|
2358
|
+
if (!fs10.existsSync(filePath)) continue;
|
|
2359
|
+
if (!getPiutConfig(filePath, configKey)) continue;
|
|
2360
|
+
await cycleConfigEntry(filePath, configKey, tool.generateConfig(slug, apiKey));
|
|
2361
|
+
break;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
async function cycleProjectConfigs(slug, apiKey, serverUrl) {
|
|
2366
|
+
const projects = scanForProjects();
|
|
2367
|
+
const refreshed = [];
|
|
2368
|
+
const vscodeTool = TOOLS.find((t) => t.id === "vscode");
|
|
2369
|
+
for (const project of projects) {
|
|
2370
|
+
if (!hasPiutDir(project.path)) continue;
|
|
2371
|
+
const projectName = path12.basename(project.path);
|
|
2372
|
+
writePiutConfig(project.path, { slug, apiKey, serverUrl });
|
|
2373
|
+
await writePiutSkill(project.path, slug, apiKey);
|
|
2374
|
+
if (vscodeTool?.generateConfig && vscodeTool.configKey) {
|
|
2375
|
+
const vscodeMcpPath = path12.join(project.path, ".vscode", "mcp.json");
|
|
2376
|
+
if (fs10.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
|
|
2377
|
+
await cycleConfigEntry(vscodeMcpPath, "servers", vscodeTool.generateConfig(slug, apiKey));
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
refreshed.push(projectName);
|
|
2381
|
+
}
|
|
2382
|
+
return refreshed;
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2227
2385
|
// src/commands/build.ts
|
|
2228
2386
|
async function buildCommand(options) {
|
|
2229
2387
|
banner();
|
|
2230
|
-
const { apiKey, serverUrl } = await resolveApiKeyWithResult(options.key);
|
|
2388
|
+
const { apiKey, serverUrl, slug } = await resolveApiKeyWithResult(options.key);
|
|
2231
2389
|
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"));
|
|
2232
2390
|
console.log();
|
|
2233
2391
|
console.log(dim(" Scanning for AI config files..."));
|
|
@@ -2289,7 +2447,7 @@ async function buildCommand(options) {
|
|
|
2289
2447
|
return;
|
|
2290
2448
|
}
|
|
2291
2449
|
}
|
|
2292
|
-
const home2 =
|
|
2450
|
+
const home2 = os8.homedir();
|
|
2293
2451
|
const brainInput = {
|
|
2294
2452
|
summary: {
|
|
2295
2453
|
projects: projects.map((p) => ({
|
|
@@ -2300,9 +2458,9 @@ async function buildCommand(options) {
|
|
|
2300
2458
|
configFiles: allConfigs
|
|
2301
2459
|
}
|
|
2302
2460
|
};
|
|
2303
|
-
await streamBuild(apiKey, serverUrl, brainInput, options);
|
|
2461
|
+
await streamBuild(apiKey, serverUrl, slug, brainInput, options);
|
|
2304
2462
|
}
|
|
2305
|
-
async function streamBuild(apiKey, serverUrl, brainInput, options) {
|
|
2463
|
+
async function streamBuild(apiKey, serverUrl, slug, brainInput, options) {
|
|
2306
2464
|
const spinner = new Spinner();
|
|
2307
2465
|
spinner.start("Generating brain...");
|
|
2308
2466
|
try {
|
|
@@ -2381,6 +2539,7 @@ async function streamBuild(apiKey, serverUrl, brainInput, options) {
|
|
|
2381
2539
|
console.log(` ${brand(serverUrl)}`);
|
|
2382
2540
|
console.log(dim(" (accessible only with secure authentication)"));
|
|
2383
2541
|
console.log();
|
|
2542
|
+
await cycleMcpConfigs(slug, apiKey);
|
|
2384
2543
|
} catch (err) {
|
|
2385
2544
|
console.log();
|
|
2386
2545
|
const msg = err.message;
|
|
@@ -2427,6 +2586,7 @@ async function deployCommand(options) {
|
|
|
2427
2586
|
console.log(` ${brand(serverUrl)}`);
|
|
2428
2587
|
console.log(dim(" (securely accessible only with authentication)"));
|
|
2429
2588
|
console.log();
|
|
2589
|
+
await cycleMcpConfigs(slug, apiKey);
|
|
2430
2590
|
console.log(dim(" Next: run ") + brand("piut connect") + dim(" to add brain references to your projects."));
|
|
2431
2591
|
console.log();
|
|
2432
2592
|
} catch (err) {
|
|
@@ -2447,33 +2607,33 @@ async function deployCommand(options) {
|
|
|
2447
2607
|
|
|
2448
2608
|
// src/commands/connect.ts
|
|
2449
2609
|
init_esm_shims();
|
|
2450
|
-
import
|
|
2451
|
-
import
|
|
2610
|
+
import fs11 from "fs";
|
|
2611
|
+
import path13 from "path";
|
|
2452
2612
|
import { checkbox as checkbox3 } from "@inquirer/prompts";
|
|
2453
2613
|
var RULE_FILES = [
|
|
2454
2614
|
{
|
|
2455
2615
|
tool: "Claude Code",
|
|
2456
2616
|
filePath: "CLAUDE.md",
|
|
2457
2617
|
strategy: "append",
|
|
2458
|
-
detect: (p) => p.hasClaudeMd ||
|
|
2618
|
+
detect: (p) => p.hasClaudeMd || fs11.existsSync(path13.join(p.path, ".claude"))
|
|
2459
2619
|
},
|
|
2460
2620
|
{
|
|
2461
2621
|
tool: "Cursor",
|
|
2462
2622
|
filePath: ".cursor/rules/piut.mdc",
|
|
2463
2623
|
strategy: "create",
|
|
2464
|
-
detect: (p) => p.hasCursorRules ||
|
|
2624
|
+
detect: (p) => p.hasCursorRules || fs11.existsSync(path13.join(p.path, ".cursor"))
|
|
2465
2625
|
},
|
|
2466
2626
|
{
|
|
2467
2627
|
tool: "Windsurf",
|
|
2468
2628
|
filePath: ".windsurf/rules/piut.md",
|
|
2469
2629
|
strategy: "create",
|
|
2470
|
-
detect: (p) => p.hasWindsurfRules ||
|
|
2630
|
+
detect: (p) => p.hasWindsurfRules || fs11.existsSync(path13.join(p.path, ".windsurf"))
|
|
2471
2631
|
},
|
|
2472
2632
|
{
|
|
2473
2633
|
tool: "VS Code",
|
|
2474
2634
|
filePath: ".github/copilot-instructions.md",
|
|
2475
2635
|
strategy: "append",
|
|
2476
|
-
detect: (p) => p.hasCopilotInstructions ||
|
|
2636
|
+
detect: (p) => p.hasCopilotInstructions || fs11.existsSync(path13.join(p.path, ".github"))
|
|
2477
2637
|
},
|
|
2478
2638
|
{
|
|
2479
2639
|
tool: "Amazon Q",
|
|
@@ -2485,22 +2645,22 @@ var RULE_FILES = [
|
|
|
2485
2645
|
tool: "Zed",
|
|
2486
2646
|
filePath: ".zed/rules.md",
|
|
2487
2647
|
strategy: "create",
|
|
2488
|
-
detect: (p) => p.hasZedRules ||
|
|
2648
|
+
detect: (p) => p.hasZedRules || fs11.existsSync(path13.join(p.path, ".zed"))
|
|
2489
2649
|
},
|
|
2490
2650
|
{
|
|
2491
2651
|
tool: "Gemini CLI",
|
|
2492
2652
|
filePath: "GEMINI.md",
|
|
2493
2653
|
strategy: "append",
|
|
2494
|
-
detect: (p) =>
|
|
2654
|
+
detect: (p) => fs11.existsSync(path13.join(p.path, ".gemini"))
|
|
2495
2655
|
},
|
|
2496
2656
|
{
|
|
2497
2657
|
tool: "Paperclip",
|
|
2498
2658
|
filePath: "AGENTS.md",
|
|
2499
2659
|
strategy: "append",
|
|
2500
|
-
detect: (p) =>
|
|
2660
|
+
detect: (p) => fs11.existsSync(path13.join(p.path, ".paperclip"))
|
|
2501
2661
|
}
|
|
2502
2662
|
];
|
|
2503
|
-
var DEDICATED_FILE_CONTENT = `## p\u0131ut Context (MCP Server: piut
|
|
2663
|
+
var DEDICATED_FILE_CONTENT = `## p\u0131ut Context (MCP Server: piut)
|
|
2504
2664
|
|
|
2505
2665
|
This project uses p\u0131ut for persistent personal context via MCP (Model Context Protocol).
|
|
2506
2666
|
p\u0131ut provides MCP tools \u2014 do NOT read local .piut/ files directly. Use the MCP tools.
|
|
@@ -2523,7 +2683,7 @@ Full skill reference: .piut/skill.md
|
|
|
2523
2683
|
`;
|
|
2524
2684
|
var APPEND_SECTION = `
|
|
2525
2685
|
|
|
2526
|
-
## p\u0131ut Context (MCP Server: piut
|
|
2686
|
+
## p\u0131ut Context (MCP Server: piut)
|
|
2527
2687
|
|
|
2528
2688
|
p\u0131ut provides MCP tools for persistent personal context. Do NOT read local .piut/ files.
|
|
2529
2689
|
Available tools: \`get_context\`, \`get_section\`, \`search_brain\`, \`append_brain\`, \`update_brain\`, \`prompt_brain\`
|
|
@@ -2532,7 +2692,7 @@ Full skill reference: .piut/skill.md
|
|
|
2532
2692
|
`;
|
|
2533
2693
|
function hasPiutReference2(filePath) {
|
|
2534
2694
|
try {
|
|
2535
|
-
const content =
|
|
2695
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
2536
2696
|
return content.includes("p\u0131ut Context") || content.includes("piut Context");
|
|
2537
2697
|
} catch {
|
|
2538
2698
|
return false;
|
|
@@ -2572,20 +2732,20 @@ async function connectCommand(options) {
|
|
|
2572
2732
|
for (const project of projects) {
|
|
2573
2733
|
for (const rule of RULE_FILES) {
|
|
2574
2734
|
if (!rule.detect(project)) continue;
|
|
2575
|
-
const absPath =
|
|
2576
|
-
if (
|
|
2735
|
+
const absPath = path13.join(project.path, rule.filePath);
|
|
2736
|
+
if (fs11.existsSync(absPath) && hasPiutReference2(absPath)) continue;
|
|
2577
2737
|
actions.push({
|
|
2578
2738
|
project,
|
|
2579
2739
|
tool: rule.tool,
|
|
2580
2740
|
filePath: rule.filePath,
|
|
2581
2741
|
absPath,
|
|
2582
|
-
action: rule.strategy === "create" || !
|
|
2742
|
+
action: rule.strategy === "create" || !fs11.existsSync(absPath) ? "create" : "append"
|
|
2583
2743
|
});
|
|
2584
2744
|
}
|
|
2585
2745
|
const hasAnyAction = actions.some((a) => a.project === project);
|
|
2586
2746
|
if (!hasAnyAction) {
|
|
2587
|
-
const claudeMdPath =
|
|
2588
|
-
if (!
|
|
2747
|
+
const claudeMdPath = path13.join(project.path, "CLAUDE.md");
|
|
2748
|
+
if (!fs11.existsSync(claudeMdPath)) {
|
|
2589
2749
|
actions.push({
|
|
2590
2750
|
project,
|
|
2591
2751
|
tool: "Claude Code",
|
|
@@ -2625,7 +2785,7 @@ async function connectCommand(options) {
|
|
|
2625
2785
|
console.log();
|
|
2626
2786
|
const projectChoices = [];
|
|
2627
2787
|
for (const [projectPath, projectActions] of byProject) {
|
|
2628
|
-
const projectName =
|
|
2788
|
+
const projectName = path13.basename(projectPath);
|
|
2629
2789
|
const desc = projectActions.map((a) => {
|
|
2630
2790
|
const verb = a.action === "create" ? "will create" : "will append to";
|
|
2631
2791
|
return `${verb} ${a.filePath}`;
|
|
@@ -2654,15 +2814,15 @@ async function connectCommand(options) {
|
|
|
2654
2814
|
const vscodeTool = TOOLS.find((t) => t.id === "vscode");
|
|
2655
2815
|
for (const projectPath of selectedPaths) {
|
|
2656
2816
|
const projectActions = byProject.get(projectPath) || [];
|
|
2657
|
-
const projectName =
|
|
2817
|
+
const projectName = path13.basename(projectPath);
|
|
2658
2818
|
writePiutConfig(projectPath, { slug, apiKey, serverUrl });
|
|
2659
2819
|
await writePiutSkill(projectPath, slug, apiKey);
|
|
2660
2820
|
ensureGitignored(projectPath);
|
|
2661
2821
|
console.log(success(` \u2713 ${projectName}/.piut/`) + dim(" \u2014 credentials + skill"));
|
|
2662
2822
|
if (vscodeTool) {
|
|
2663
|
-
const hasVscode =
|
|
2823
|
+
const hasVscode = fs11.existsSync(path13.join(projectPath, ".github", "copilot-instructions.md")) || fs11.existsSync(path13.join(projectPath, ".github"));
|
|
2664
2824
|
if (hasVscode) {
|
|
2665
|
-
const vscodeMcpPath =
|
|
2825
|
+
const vscodeMcpPath = path13.join(projectPath, ".vscode", "mcp.json");
|
|
2666
2826
|
const serverConfig = vscodeTool.generateConfig(slug, apiKey);
|
|
2667
2827
|
mergeConfig(vscodeMcpPath, vscodeTool.configKey, serverConfig);
|
|
2668
2828
|
console.log(success(` \u2713 ${projectName}/.vscode/mcp.json`) + dim(" \u2014 VS Code MCP"));
|
|
@@ -2672,11 +2832,11 @@ async function connectCommand(options) {
|
|
|
2672
2832
|
if (action.action === "create") {
|
|
2673
2833
|
const isAppendType = RULE_FILES.find((r) => r.filePath === action.filePath)?.strategy === "append";
|
|
2674
2834
|
const content = isAppendType ? PROJECT_SKILL_SNIPPET + "\n" : DEDICATED_FILE_CONTENT;
|
|
2675
|
-
|
|
2676
|
-
|
|
2835
|
+
fs11.mkdirSync(path13.dirname(action.absPath), { recursive: true });
|
|
2836
|
+
fs11.writeFileSync(action.absPath, content, "utf-8");
|
|
2677
2837
|
console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 created"));
|
|
2678
2838
|
} else {
|
|
2679
|
-
|
|
2839
|
+
fs11.appendFileSync(action.absPath, APPEND_SECTION);
|
|
2680
2840
|
console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 appended"));
|
|
2681
2841
|
}
|
|
2682
2842
|
connected++;
|
|
@@ -2686,7 +2846,7 @@ async function connectCommand(options) {
|
|
|
2686
2846
|
const hostname = getHostname();
|
|
2687
2847
|
for (const projectPath of selectedPaths) {
|
|
2688
2848
|
const projectActions = byProject.get(projectPath) || [];
|
|
2689
|
-
const projectName =
|
|
2849
|
+
const projectName = path13.basename(projectPath);
|
|
2690
2850
|
const toolsDetected = [...new Set(projectActions.map((a) => a.tool))];
|
|
2691
2851
|
const configFilesWritten = projectActions.map((a) => a.filePath);
|
|
2692
2852
|
registerProject(apiKey, {
|
|
@@ -2706,8 +2866,8 @@ async function connectCommand(options) {
|
|
|
2706
2866
|
|
|
2707
2867
|
// src/commands/disconnect.ts
|
|
2708
2868
|
init_esm_shims();
|
|
2709
|
-
import
|
|
2710
|
-
import
|
|
2869
|
+
import fs12 from "fs";
|
|
2870
|
+
import path14 from "path";
|
|
2711
2871
|
import { checkbox as checkbox4, confirm as confirm5 } from "@inquirer/prompts";
|
|
2712
2872
|
var DEDICATED_FILES = /* @__PURE__ */ new Set([
|
|
2713
2873
|
".cursor/rules/piut.mdc",
|
|
@@ -2723,7 +2883,7 @@ var APPEND_FILES = [
|
|
|
2723
2883
|
];
|
|
2724
2884
|
function hasPiutReference3(filePath) {
|
|
2725
2885
|
try {
|
|
2726
|
-
const content =
|
|
2886
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
2727
2887
|
return content.includes("p\u0131ut Context") || content.includes("piut Context");
|
|
2728
2888
|
} catch {
|
|
2729
2889
|
return false;
|
|
@@ -2731,7 +2891,7 @@ function hasPiutReference3(filePath) {
|
|
|
2731
2891
|
}
|
|
2732
2892
|
function removePiutSection(filePath) {
|
|
2733
2893
|
try {
|
|
2734
|
-
let content =
|
|
2894
|
+
let content = fs12.readFileSync(filePath, "utf-8");
|
|
2735
2895
|
const patterns = [
|
|
2736
2896
|
/\n*## p[ıi]ut Context[\s\S]*?(?=\n## |\n---\n|$)/g
|
|
2737
2897
|
];
|
|
@@ -2745,7 +2905,7 @@ function removePiutSection(filePath) {
|
|
|
2745
2905
|
}
|
|
2746
2906
|
if (changed) {
|
|
2747
2907
|
content = content.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
2748
|
-
|
|
2908
|
+
fs12.writeFileSync(filePath, content, "utf-8");
|
|
2749
2909
|
}
|
|
2750
2910
|
return changed;
|
|
2751
2911
|
} catch {
|
|
@@ -2762,10 +2922,10 @@ async function disconnectCommand(options) {
|
|
|
2762
2922
|
const projects = scanForProjects(scanFolders);
|
|
2763
2923
|
const actions = [];
|
|
2764
2924
|
for (const project of projects) {
|
|
2765
|
-
const projectName =
|
|
2925
|
+
const projectName = path14.basename(project.path);
|
|
2766
2926
|
for (const dedicatedFile of DEDICATED_FILES) {
|
|
2767
|
-
const absPath =
|
|
2768
|
-
if (
|
|
2927
|
+
const absPath = path14.join(project.path, dedicatedFile);
|
|
2928
|
+
if (fs12.existsSync(absPath) && hasPiutReference3(absPath)) {
|
|
2769
2929
|
actions.push({
|
|
2770
2930
|
projectPath: project.path,
|
|
2771
2931
|
projectName,
|
|
@@ -2776,8 +2936,8 @@ async function disconnectCommand(options) {
|
|
|
2776
2936
|
}
|
|
2777
2937
|
}
|
|
2778
2938
|
for (const appendFile of APPEND_FILES) {
|
|
2779
|
-
const absPath =
|
|
2780
|
-
if (
|
|
2939
|
+
const absPath = path14.join(project.path, appendFile);
|
|
2940
|
+
if (fs12.existsSync(absPath) && hasPiutReference3(absPath)) {
|
|
2781
2941
|
actions.push({
|
|
2782
2942
|
projectPath: project.path,
|
|
2783
2943
|
projectName,
|
|
@@ -2792,12 +2952,12 @@ async function disconnectCommand(options) {
|
|
|
2792
2952
|
projectPath: project.path,
|
|
2793
2953
|
projectName,
|
|
2794
2954
|
filePath: ".piut/",
|
|
2795
|
-
absPath:
|
|
2955
|
+
absPath: path14.join(project.path, ".piut"),
|
|
2796
2956
|
action: "remove-dir"
|
|
2797
2957
|
});
|
|
2798
2958
|
}
|
|
2799
|
-
const vscodeMcpPath =
|
|
2800
|
-
if (
|
|
2959
|
+
const vscodeMcpPath = path14.join(project.path, ".vscode", "mcp.json");
|
|
2960
|
+
if (fs12.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
|
|
2801
2961
|
actions.push({
|
|
2802
2962
|
projectPath: project.path,
|
|
2803
2963
|
projectName,
|
|
@@ -2819,7 +2979,7 @@ async function disconnectCommand(options) {
|
|
|
2819
2979
|
}
|
|
2820
2980
|
console.log();
|
|
2821
2981
|
const projectChoices = Array.from(byProject.entries()).map(([projectPath, projectActions]) => {
|
|
2822
|
-
const name =
|
|
2982
|
+
const name = path14.basename(projectPath);
|
|
2823
2983
|
const files = projectActions.map((a) => a.filePath).join(", ");
|
|
2824
2984
|
return {
|
|
2825
2985
|
name: `${name} ${dim(`(${files})`)}`,
|
|
@@ -2848,11 +3008,11 @@ async function disconnectCommand(options) {
|
|
|
2848
3008
|
let disconnected = 0;
|
|
2849
3009
|
for (const projectPath of selectedPaths) {
|
|
2850
3010
|
const projectActions = byProject.get(projectPath) || [];
|
|
2851
|
-
const projectName =
|
|
3011
|
+
const projectName = path14.basename(projectPath);
|
|
2852
3012
|
for (const action of projectActions) {
|
|
2853
3013
|
if (action.action === "delete") {
|
|
2854
3014
|
try {
|
|
2855
|
-
|
|
3015
|
+
fs12.unlinkSync(action.absPath);
|
|
2856
3016
|
console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 deleted"));
|
|
2857
3017
|
disconnected++;
|
|
2858
3018
|
} catch {
|
|
@@ -2866,7 +3026,7 @@ async function disconnectCommand(options) {
|
|
|
2866
3026
|
} else if (action.action === "remove-mcp") {
|
|
2867
3027
|
try {
|
|
2868
3028
|
removeFromConfig(action.absPath, "servers");
|
|
2869
|
-
console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 piut
|
|
3029
|
+
console.log(success(` \u2713 ${projectName}/${action.filePath}`) + dim(" \u2014 piut removed"));
|
|
2870
3030
|
disconnected++;
|
|
2871
3031
|
} catch {
|
|
2872
3032
|
console.log(warning(` \u2717 ${projectName}/${action.filePath}`) + dim(" \u2014 could not update"));
|
|
@@ -3033,7 +3193,7 @@ async function updateCommand(currentVersion) {
|
|
|
3033
3193
|
|
|
3034
3194
|
// src/commands/doctor.ts
|
|
3035
3195
|
init_esm_shims();
|
|
3036
|
-
import
|
|
3196
|
+
import fs13 from "fs";
|
|
3037
3197
|
import chalk10 from "chalk";
|
|
3038
3198
|
async function doctorCommand(options) {
|
|
3039
3199
|
if (!options.json) banner();
|
|
@@ -3085,7 +3245,7 @@ async function doctorCommand(options) {
|
|
|
3085
3245
|
for (const tool of TOOLS) {
|
|
3086
3246
|
const paths = resolveConfigPaths(tool);
|
|
3087
3247
|
for (const { filePath: configPath, configKey: resolvedKey } of paths) {
|
|
3088
|
-
if (!
|
|
3248
|
+
if (!fs13.existsSync(configPath)) continue;
|
|
3089
3249
|
const piutConfig = getPiutConfig(configPath, resolvedKey);
|
|
3090
3250
|
if (!piutConfig) {
|
|
3091
3251
|
result.tools.push({
|
|
@@ -3185,6 +3345,12 @@ async function doctorCommand(options) {
|
|
|
3185
3345
|
}
|
|
3186
3346
|
if (result.issues === 0) {
|
|
3187
3347
|
console.log(success(" All checks passed."));
|
|
3348
|
+
if (result.mcp.ok && result.tools.some((t) => t.configured)) {
|
|
3349
|
+
console.log();
|
|
3350
|
+
console.log(dim(" Tip: If your AI tool can't access your brain but everything"));
|
|
3351
|
+
console.log(dim(" checks out here, try toggling the MCP server off and on in"));
|
|
3352
|
+
console.log(dim(" your tool's settings. MCP connections can go stale."));
|
|
3353
|
+
}
|
|
3188
3354
|
} else {
|
|
3189
3355
|
console.log(warning(` ${result.issues} issue(s) found.`));
|
|
3190
3356
|
const staleTools = result.tools.filter((t) => t.keyMatch === "stale" && !t.fixed);
|
|
@@ -3200,10 +3366,49 @@ async function doctorCommand(options) {
|
|
|
3200
3366
|
if (result.issues > 0) throw new CliError(`${result.issues} issue(s) found`);
|
|
3201
3367
|
}
|
|
3202
3368
|
|
|
3369
|
+
// src/commands/refresh.ts
|
|
3370
|
+
init_esm_shims();
|
|
3371
|
+
async function refreshCommand(options) {
|
|
3372
|
+
banner();
|
|
3373
|
+
const { apiKey, slug, serverUrl, status } = await resolveApiKeyWithResult(options.key);
|
|
3374
|
+
const configuredTools = getConfiguredToolNames();
|
|
3375
|
+
const isDeployed = status === "active";
|
|
3376
|
+
if (configuredTools.length === 0 && !isDeployed) {
|
|
3377
|
+
console.log();
|
|
3378
|
+
console.log(warning(" Nothing to refresh."));
|
|
3379
|
+
console.log(dim(" Run ") + brand("piut setup") + dim(" first to configure your AI tools."));
|
|
3380
|
+
console.log();
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
console.log(dim(" Refreshing..."));
|
|
3384
|
+
if (isDeployed) {
|
|
3385
|
+
try {
|
|
3386
|
+
await publishServer(apiKey);
|
|
3387
|
+
console.log(success(" \u2713 Server republished"));
|
|
3388
|
+
} catch {
|
|
3389
|
+
console.log(warning(" \u2717 Could not republish server"));
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
if (configuredTools.length > 0) {
|
|
3393
|
+
await cycleMcpConfigs(slug, apiKey);
|
|
3394
|
+
console.log(success(" \u2713 Refreshed MCP connections"));
|
|
3395
|
+
console.log(dim(` Cycled: ${configuredTools.join(", ")}`));
|
|
3396
|
+
}
|
|
3397
|
+
const refreshedProjects = await cycleProjectConfigs(slug, apiKey, serverUrl);
|
|
3398
|
+
if (refreshedProjects.length > 0) {
|
|
3399
|
+
console.log(success(" \u2713 Refreshed connected projects"));
|
|
3400
|
+
console.log(dim(` Updated: ${refreshedProjects.join(", ")}`));
|
|
3401
|
+
}
|
|
3402
|
+
console.log();
|
|
3403
|
+
console.log(dim(" Tools that watch config files will reconnect automatically."));
|
|
3404
|
+
console.log(dim(" If a tool doesn't refresh, restart it manually."));
|
|
3405
|
+
console.log();
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3203
3408
|
// src/commands/vault.ts
|
|
3204
3409
|
init_esm_shims();
|
|
3205
|
-
import
|
|
3206
|
-
import
|
|
3410
|
+
import fs14 from "fs";
|
|
3411
|
+
import path15 from "path";
|
|
3207
3412
|
import chalk11 from "chalk";
|
|
3208
3413
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
3209
3414
|
var DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -3256,26 +3461,26 @@ async function vaultListCommand(options) {
|
|
|
3256
3461
|
}
|
|
3257
3462
|
async function vaultUploadCommand(filePath, options) {
|
|
3258
3463
|
const key = resolveApiKey(options);
|
|
3259
|
-
const resolved =
|
|
3260
|
-
if (!
|
|
3464
|
+
const resolved = path15.resolve(filePath);
|
|
3465
|
+
if (!fs14.existsSync(resolved)) {
|
|
3261
3466
|
console.log(chalk11.red(` File not found: ${filePath}`));
|
|
3262
3467
|
throw new CliError();
|
|
3263
3468
|
}
|
|
3264
|
-
const stat =
|
|
3469
|
+
const stat = fs14.statSync(resolved);
|
|
3265
3470
|
if (!stat.isFile()) {
|
|
3266
3471
|
console.log(chalk11.red(` Not a file: ${filePath}`));
|
|
3267
3472
|
throw new CliError();
|
|
3268
3473
|
}
|
|
3269
|
-
const filename =
|
|
3474
|
+
const filename = path15.basename(resolved);
|
|
3270
3475
|
const ext = filename.includes(".") ? filename.split(".").pop()?.toLowerCase() || "" : "";
|
|
3271
3476
|
const isDocument = DOCUMENT_EXTENSIONS.has(ext);
|
|
3272
3477
|
let content;
|
|
3273
3478
|
let encoding;
|
|
3274
3479
|
if (isDocument) {
|
|
3275
|
-
content =
|
|
3480
|
+
content = fs14.readFileSync(resolved).toString("base64");
|
|
3276
3481
|
encoding = "base64";
|
|
3277
3482
|
} else {
|
|
3278
|
-
content =
|
|
3483
|
+
content = fs14.readFileSync(resolved, "utf-8");
|
|
3279
3484
|
}
|
|
3280
3485
|
const spinner = new Spinner();
|
|
3281
3486
|
spinner.start(`Uploading ${filename}...`);
|
|
@@ -3298,8 +3503,8 @@ async function vaultReadCommand(filename, options) {
|
|
|
3298
3503
|
try {
|
|
3299
3504
|
const file = await readVaultFile(key, filename);
|
|
3300
3505
|
if (options.output) {
|
|
3301
|
-
const outPath =
|
|
3302
|
-
|
|
3506
|
+
const outPath = path15.resolve(options.output);
|
|
3507
|
+
fs14.writeFileSync(outPath, file.content, "utf-8");
|
|
3303
3508
|
console.log(success(` Saved to ${outPath}`));
|
|
3304
3509
|
console.log();
|
|
3305
3510
|
} else {
|
|
@@ -3333,45 +3538,10 @@ async function vaultDeleteCommand(filename, options) {
|
|
|
3333
3538
|
// src/commands/interactive.ts
|
|
3334
3539
|
init_esm_shims();
|
|
3335
3540
|
import { select as select2, confirm as confirm8, checkbox as checkbox5, Separator } from "@inquirer/prompts";
|
|
3336
|
-
import
|
|
3337
|
-
import
|
|
3541
|
+
import fs16 from "fs";
|
|
3542
|
+
import path17 from "path";
|
|
3338
3543
|
import { exec as exec2 } from "child_process";
|
|
3339
3544
|
import chalk13 from "chalk";
|
|
3340
|
-
|
|
3341
|
-
// src/lib/sync.ts
|
|
3342
|
-
init_esm_shims();
|
|
3343
|
-
import fs13 from "fs";
|
|
3344
|
-
function syncStaleConfigs(slug, apiKey, serverUrl) {
|
|
3345
|
-
const updated = [];
|
|
3346
|
-
for (const tool of TOOLS) {
|
|
3347
|
-
if (tool.skillOnly || !tool.generateConfig || !tool.configKey) continue;
|
|
3348
|
-
const paths = resolveConfigPaths(tool);
|
|
3349
|
-
for (const { filePath, configKey } of paths) {
|
|
3350
|
-
if (!fs13.existsSync(filePath)) continue;
|
|
3351
|
-
const piutConfig = getPiutConfig(filePath, configKey);
|
|
3352
|
-
if (!piutConfig) continue;
|
|
3353
|
-
const existingKey = extractKeyFromConfig(piutConfig);
|
|
3354
|
-
const existingSlug = extractSlugFromConfig(piutConfig);
|
|
3355
|
-
const keyStale = !!existingKey && existingKey !== apiKey;
|
|
3356
|
-
const slugStale = !!existingSlug && existingSlug !== slug;
|
|
3357
|
-
if (keyStale || slugStale) {
|
|
3358
|
-
const newConfig = tool.generateConfig(slug, apiKey);
|
|
3359
|
-
mergeConfig(filePath, configKey, newConfig);
|
|
3360
|
-
updated.push(tool.name);
|
|
3361
|
-
}
|
|
3362
|
-
break;
|
|
3363
|
-
}
|
|
3364
|
-
}
|
|
3365
|
-
const cwd = process.cwd();
|
|
3366
|
-
const existing = readPiutConfig(cwd);
|
|
3367
|
-
if (existing && (existing.apiKey !== apiKey || existing.slug !== slug)) {
|
|
3368
|
-
writePiutConfig(cwd, { slug, apiKey, serverUrl });
|
|
3369
|
-
updated.push(".piut/config.json");
|
|
3370
|
-
}
|
|
3371
|
-
return updated;
|
|
3372
|
-
}
|
|
3373
|
-
|
|
3374
|
-
// src/commands/interactive.ts
|
|
3375
3545
|
var DOCUMENT_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
3376
3546
|
"pdf",
|
|
3377
3547
|
"docx",
|
|
@@ -3426,6 +3596,34 @@ async function interactiveMenu() {
|
|
|
3426
3596
|
if (synced.length > 0) {
|
|
3427
3597
|
console.log(dim(` Updated ${synced.length} stale config(s): ${synced.join(", ")}`));
|
|
3428
3598
|
}
|
|
3599
|
+
await offerGlobalInstall();
|
|
3600
|
+
const configuredTools = getConfiguredToolNames();
|
|
3601
|
+
const isDeployed = currentValidation.status === "active";
|
|
3602
|
+
if (configuredTools.length > 0 || isDeployed) {
|
|
3603
|
+
const parts = [];
|
|
3604
|
+
if (isDeployed) {
|
|
3605
|
+
try {
|
|
3606
|
+
await publishServer(apiKey);
|
|
3607
|
+
parts.push("server");
|
|
3608
|
+
} catch {
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
if (configuredTools.length > 0) {
|
|
3612
|
+
await cycleMcpConfigs(currentValidation.slug, apiKey);
|
|
3613
|
+
parts.push(`${configuredTools.length} tool(s)`);
|
|
3614
|
+
}
|
|
3615
|
+
const refreshedProjects = await cycleProjectConfigs(
|
|
3616
|
+
currentValidation.slug,
|
|
3617
|
+
apiKey,
|
|
3618
|
+
currentValidation.serverUrl
|
|
3619
|
+
);
|
|
3620
|
+
if (refreshedProjects.length > 0) {
|
|
3621
|
+
parts.push(`${refreshedProjects.length} project(s)`);
|
|
3622
|
+
}
|
|
3623
|
+
if (parts.length > 0) {
|
|
3624
|
+
console.log(dim(` Refreshed: ${parts.join(", ")}`));
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3429
3627
|
console.log();
|
|
3430
3628
|
if (currentValidation.status === "no_brain") {
|
|
3431
3629
|
console.log(warning(" You haven\u2019t built a brain yet."));
|
|
@@ -3461,7 +3659,7 @@ async function interactiveMenu() {
|
|
|
3461
3659
|
}
|
|
3462
3660
|
while (true) {
|
|
3463
3661
|
const hasBrain = currentValidation.status !== "no_brain";
|
|
3464
|
-
const
|
|
3662
|
+
const isDeployed2 = currentValidation.status === "active";
|
|
3465
3663
|
let action;
|
|
3466
3664
|
try {
|
|
3467
3665
|
action = await select2({
|
|
@@ -3487,22 +3685,22 @@ async function interactiveMenu() {
|
|
|
3487
3685
|
},
|
|
3488
3686
|
new Separator(),
|
|
3489
3687
|
{
|
|
3490
|
-
name:
|
|
3688
|
+
name: isDeployed2 ? "Undeploy Brain" : "Deploy Brain",
|
|
3491
3689
|
value: "deploy",
|
|
3492
|
-
description:
|
|
3690
|
+
description: isDeployed2 ? "Take your MCP server offline" : "Publish your MCP server (requires paid account)"
|
|
3493
3691
|
},
|
|
3494
3692
|
new Separator(),
|
|
3495
3693
|
{
|
|
3496
3694
|
name: "Connect Tools",
|
|
3497
3695
|
value: "connect-tools",
|
|
3498
3696
|
description: "Manage which AI tools use your MCP server",
|
|
3499
|
-
disabled: !
|
|
3697
|
+
disabled: !isDeployed2 && "(deploy brain first)"
|
|
3500
3698
|
},
|
|
3501
3699
|
{
|
|
3502
3700
|
name: "Connect Projects",
|
|
3503
3701
|
value: "connect-projects",
|
|
3504
3702
|
description: "Manage brain references in project config files",
|
|
3505
|
-
disabled: !
|
|
3703
|
+
disabled: !isDeployed2 && "(deploy brain first)"
|
|
3506
3704
|
},
|
|
3507
3705
|
new Separator(),
|
|
3508
3706
|
{
|
|
@@ -3549,7 +3747,7 @@ async function interactiveMenu() {
|
|
|
3549
3747
|
handleEditBrain();
|
|
3550
3748
|
break;
|
|
3551
3749
|
case "deploy":
|
|
3552
|
-
if (
|
|
3750
|
+
if (isDeployed2) {
|
|
3553
3751
|
await handleUndeploy(apiKey);
|
|
3554
3752
|
} else {
|
|
3555
3753
|
await deployCommand({ key: apiKey });
|
|
@@ -3620,8 +3818,8 @@ async function handleConnectTools(apiKey, validation) {
|
|
|
3620
3818
|
for (const tool of TOOLS) {
|
|
3621
3819
|
const paths = resolveConfigPaths(tool);
|
|
3622
3820
|
for (const { filePath, configKey } of paths) {
|
|
3623
|
-
const exists =
|
|
3624
|
-
const parentExists =
|
|
3821
|
+
const exists = fs16.existsSync(filePath);
|
|
3822
|
+
const parentExists = fs16.existsSync(path17.dirname(filePath));
|
|
3625
3823
|
if (exists || parentExists) {
|
|
3626
3824
|
const connected = exists && !!configKey && isPiutConfigured(filePath, configKey);
|
|
3627
3825
|
detected.push({ tool, configPath: filePath, resolvedConfigKey: configKey, connected });
|
|
@@ -3744,29 +3942,29 @@ async function handleManageProjects(apiKey, validation) {
|
|
|
3744
3942
|
console.log();
|
|
3745
3943
|
const copilotTool = TOOLS.find((t) => t.id === "copilot");
|
|
3746
3944
|
for (const { project } of toConnect) {
|
|
3747
|
-
const projectName =
|
|
3945
|
+
const projectName = path17.basename(project.path);
|
|
3748
3946
|
writePiutConfig(project.path, { slug, apiKey, serverUrl });
|
|
3749
3947
|
await writePiutSkill(project.path, slug, apiKey);
|
|
3750
3948
|
ensureGitignored(project.path);
|
|
3751
3949
|
if (copilotTool) {
|
|
3752
|
-
const hasCopilot =
|
|
3950
|
+
const hasCopilot = fs16.existsSync(path17.join(project.path, ".github", "copilot-instructions.md")) || fs16.existsSync(path17.join(project.path, ".github"));
|
|
3753
3951
|
if (hasCopilot) {
|
|
3754
|
-
const vscodeMcpPath =
|
|
3952
|
+
const vscodeMcpPath = path17.join(project.path, ".vscode", "mcp.json");
|
|
3755
3953
|
const serverConfig = copilotTool.generateConfig(slug, apiKey);
|
|
3756
3954
|
mergeConfig(vscodeMcpPath, copilotTool.configKey, serverConfig);
|
|
3757
3955
|
}
|
|
3758
3956
|
}
|
|
3759
3957
|
for (const rule of RULE_FILES) {
|
|
3760
3958
|
if (!rule.detect(project)) continue;
|
|
3761
|
-
const absPath =
|
|
3762
|
-
if (
|
|
3763
|
-
if (rule.strategy === "create" || !
|
|
3959
|
+
const absPath = path17.join(project.path, rule.filePath);
|
|
3960
|
+
if (fs16.existsSync(absPath) && hasPiutReference2(absPath)) continue;
|
|
3961
|
+
if (rule.strategy === "create" || !fs16.existsSync(absPath)) {
|
|
3764
3962
|
const isAppendType = rule.strategy === "append";
|
|
3765
3963
|
const content = isAppendType ? PROJECT_SKILL_SNIPPET + "\n" : DEDICATED_FILE_CONTENT;
|
|
3766
|
-
|
|
3767
|
-
|
|
3964
|
+
fs16.mkdirSync(path17.dirname(absPath), { recursive: true });
|
|
3965
|
+
fs16.writeFileSync(absPath, content, "utf-8");
|
|
3768
3966
|
} else {
|
|
3769
|
-
|
|
3967
|
+
fs16.appendFileSync(absPath, APPEND_SECTION);
|
|
3770
3968
|
}
|
|
3771
3969
|
}
|
|
3772
3970
|
toolLine(projectName, success("connected"), "\u2714");
|
|
@@ -3782,24 +3980,24 @@ async function handleManageProjects(apiKey, validation) {
|
|
|
3782
3980
|
});
|
|
3783
3981
|
}
|
|
3784
3982
|
for (const { project } of toDisconnect) {
|
|
3785
|
-
const projectName =
|
|
3983
|
+
const projectName = path17.basename(project.path);
|
|
3786
3984
|
for (const dedicatedFile of DEDICATED_FILES) {
|
|
3787
|
-
const absPath =
|
|
3788
|
-
if (
|
|
3985
|
+
const absPath = path17.join(project.path, dedicatedFile);
|
|
3986
|
+
if (fs16.existsSync(absPath) && hasPiutReference2(absPath)) {
|
|
3789
3987
|
try {
|
|
3790
|
-
|
|
3988
|
+
fs16.unlinkSync(absPath);
|
|
3791
3989
|
} catch {
|
|
3792
3990
|
}
|
|
3793
3991
|
}
|
|
3794
3992
|
}
|
|
3795
3993
|
for (const appendFile of APPEND_FILES) {
|
|
3796
|
-
const absPath =
|
|
3797
|
-
if (
|
|
3994
|
+
const absPath = path17.join(project.path, appendFile);
|
|
3995
|
+
if (fs16.existsSync(absPath) && hasPiutReference2(absPath)) {
|
|
3798
3996
|
removePiutSection(absPath);
|
|
3799
3997
|
}
|
|
3800
3998
|
}
|
|
3801
|
-
const vscodeMcpPath =
|
|
3802
|
-
if (
|
|
3999
|
+
const vscodeMcpPath = path17.join(project.path, ".vscode", "mcp.json");
|
|
4000
|
+
if (fs16.existsSync(vscodeMcpPath) && isPiutConfigured(vscodeMcpPath, "servers")) {
|
|
3803
4001
|
removeFromConfig(vscodeMcpPath, "servers");
|
|
3804
4002
|
}
|
|
3805
4003
|
removePiutDir(project.path);
|
|
@@ -3891,16 +4089,16 @@ async function handleVaultUpload(apiKey) {
|
|
|
3891
4089
|
console.log();
|
|
3892
4090
|
let uploaded = 0;
|
|
3893
4091
|
for (const filePath of files) {
|
|
3894
|
-
const filename =
|
|
4092
|
+
const filename = path17.basename(filePath);
|
|
3895
4093
|
const ext = filename.includes(".") ? filename.split(".").pop()?.toLowerCase() || "" : "";
|
|
3896
4094
|
const isDocument = DOCUMENT_EXTENSIONS2.has(ext);
|
|
3897
4095
|
let content;
|
|
3898
4096
|
let encoding;
|
|
3899
4097
|
if (isDocument) {
|
|
3900
|
-
content =
|
|
4098
|
+
content = fs16.readFileSync(filePath).toString("base64");
|
|
3901
4099
|
encoding = "base64";
|
|
3902
4100
|
} else {
|
|
3903
|
-
content =
|
|
4101
|
+
content = fs16.readFileSync(filePath, "utf-8");
|
|
3904
4102
|
}
|
|
3905
4103
|
const spinner = new Spinner();
|
|
3906
4104
|
spinner.start(`Uploading ${filename}...`);
|
|
@@ -3976,7 +4174,7 @@ async function handleViewBrain(apiKey) {
|
|
|
3976
4174
|
}
|
|
3977
4175
|
|
|
3978
4176
|
// src/cli.ts
|
|
3979
|
-
var VERSION = "3.
|
|
4177
|
+
var VERSION = "3.10.0";
|
|
3980
4178
|
function withExit(fn) {
|
|
3981
4179
|
return async (...args2) => {
|
|
3982
4180
|
try {
|
|
@@ -4002,6 +4200,7 @@ program.command("remove").description("Remove all p\u0131ut configurations").act
|
|
|
4002
4200
|
program.command("login").description("Authenticate with p\u0131ut (email, browser, or API key)").action(withExit(loginCommand));
|
|
4003
4201
|
program.command("logout").description("Remove saved API key").action(logoutCommand);
|
|
4004
4202
|
program.command("doctor").description("Diagnose and fix connection issues").option("-k, --key <key>", "API key to verify against").option("--fix", "Auto-fix stale configurations").option("--json", "Output results as JSON").action(withExit(doctorCommand));
|
|
4203
|
+
program.command("refresh").description("Force all configured tools to reconnect to your MCP server").option("-k, --key <key>", "API key").action(withExit(refreshCommand));
|
|
4005
4204
|
var vault = program.command("vault").description("Manage your file vault (upload, list, read, delete)");
|
|
4006
4205
|
vault.command("list").description("List all files in your vault").option("-k, --key <key>", "API key").action(withExit(vaultListCommand));
|
|
4007
4206
|
vault.command("upload <file>").description("Upload a file to your vault").option("-k, --key <key>", "API key").action(withExit(vaultUploadCommand));
|