@tekmidian/pai 0.3.2 → 0.5.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/ARCHITECTURE.md +16 -10
- package/README.md +46 -6
- package/dist/{auto-route-JjW3f7pV.mjs → auto-route-B5MSUJZK.mjs} +3 -3
- package/dist/{auto-route-JjW3f7pV.mjs.map → auto-route-B5MSUJZK.mjs.map} +1 -1
- package/dist/cli/index.mjs +313 -43
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{config-DELNqq3Z.mjs → config-B4brrHHE.mjs} +1 -1
- package/dist/{config-DELNqq3Z.mjs.map → config-B4brrHHE.mjs.map} +1 -1
- package/dist/daemon/index.mjs +7 -7
- package/dist/daemon-mcp/index.mjs +11 -4
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{daemon-CeTX4NpF.mjs → daemon-s868Paua.mjs} +12 -12
- package/dist/{daemon-CeTX4NpF.mjs.map → daemon-s868Paua.mjs.map} +1 -1
- package/dist/{detect-D7gPV3fQ.mjs → detect-CdaA48EI.mjs} +1 -1
- package/dist/{detect-D7gPV3fQ.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
- package/dist/{detector-cYYhK2Mi.mjs → detector-Bp-2SM3x.mjs} +2 -2
- package/dist/{detector-cYYhK2Mi.mjs.map → detector-Bp-2SM3x.mjs.map} +1 -1
- package/dist/{factory-DZLvRf4m.mjs → factory-CeXQzlwn.mjs} +3 -3
- package/dist/{factory-DZLvRf4m.mjs.map → factory-CeXQzlwn.mjs.map} +1 -1
- package/dist/hooks/capture-all-events.mjs +238 -0
- package/dist/hooks/capture-all-events.mjs.map +7 -0
- package/dist/hooks/capture-session-summary.mjs +198 -0
- package/dist/hooks/capture-session-summary.mjs.map +7 -0
- package/dist/hooks/capture-tool-output.mjs +105 -0
- package/dist/hooks/capture-tool-output.mjs.map +7 -0
- package/dist/hooks/cleanup-session-files.mjs +129 -0
- package/dist/hooks/cleanup-session-files.mjs.map +7 -0
- package/dist/hooks/context-compression-hook.mjs +283 -0
- package/dist/hooks/context-compression-hook.mjs.map +7 -0
- package/dist/hooks/initialize-session.mjs +206 -0
- package/dist/hooks/initialize-session.mjs.map +7 -0
- package/dist/hooks/load-core-context.mjs +110 -0
- package/dist/hooks/load-core-context.mjs.map +7 -0
- package/dist/hooks/load-project-context.mjs +548 -0
- package/dist/hooks/load-project-context.mjs.map +7 -0
- package/dist/hooks/security-validator.mjs +159 -0
- package/dist/hooks/security-validator.mjs.map +7 -0
- package/dist/hooks/stop-hook.mjs +625 -0
- package/dist/hooks/stop-hook.mjs.map +7 -0
- package/dist/hooks/subagent-stop-hook.mjs +152 -0
- package/dist/hooks/subagent-stop-hook.mjs.map +7 -0
- package/dist/hooks/sync-todo-to-md.mjs +322 -0
- package/dist/hooks/sync-todo-to-md.mjs.map +7 -0
- package/dist/hooks/update-tab-on-action.mjs +90 -0
- package/dist/hooks/update-tab-on-action.mjs.map +7 -0
- package/dist/hooks/update-tab-titles.mjs +55 -0
- package/dist/hooks/update-tab-titles.mjs.map +7 -0
- package/dist/index.d.mts +29 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -3
- package/dist/{indexer-backend-BHztlJJg.mjs → indexer-backend-DQO-FqAI.mjs} +1 -1
- package/dist/{indexer-backend-BHztlJJg.mjs.map → indexer-backend-DQO-FqAI.mjs.map} +1 -1
- package/dist/{ipc-client-CLt2fNlC.mjs → ipc-client-CgSpwHDC.mjs} +1 -1
- package/dist/{ipc-client-CLt2fNlC.mjs.map → ipc-client-CgSpwHDC.mjs.map} +1 -1
- package/dist/mcp/index.mjs +15 -5
- package/dist/mcp/index.mjs.map +1 -1
- package/dist/{postgres-CRBe30Ag.mjs → postgres-CIxeqf_n.mjs} +1 -1
- package/dist/{postgres-CRBe30Ag.mjs.map → postgres-CIxeqf_n.mjs.map} +1 -1
- package/dist/reranker-D7bRAHi6.mjs +71 -0
- package/dist/reranker-D7bRAHi6.mjs.map +1 -0
- package/dist/{schemas-BY3Pjvje.mjs → schemas-BFIgGntb.mjs} +1 -1
- package/dist/{schemas-BY3Pjvje.mjs.map → schemas-BFIgGntb.mjs.map} +1 -1
- package/dist/{search-GK0ibTJy.mjs → search-_oHfguA5.mjs} +47 -4
- package/dist/search-_oHfguA5.mjs.map +1 -0
- package/dist/{sqlite-RyR8Up1v.mjs → sqlite-CymLKiDE.mjs} +2 -2
- package/dist/{sqlite-RyR8Up1v.mjs.map → sqlite-CymLKiDE.mjs.map} +1 -1
- package/dist/{tools-CUg0Lyg-.mjs → tools-Dx7GjOHd.mjs} +23 -14
- package/dist/tools-Dx7GjOHd.mjs.map +1 -0
- package/dist/{vault-indexer-Bo2aPSzP.mjs → vault-indexer-DXWs9pDn.mjs} +1 -1
- package/dist/{vault-indexer-Bo2aPSzP.mjs.map → vault-indexer-DXWs9pDn.mjs.map} +1 -1
- package/dist/{zettelkasten-Co-w0XSZ.mjs → zettelkasten-e-a4rW_6.mjs} +2 -2
- package/dist/{zettelkasten-Co-w0XSZ.mjs.map → zettelkasten-e-a4rW_6.mjs.map} +1 -1
- package/package.json +4 -2
- package/scripts/build-hooks.mjs +51 -0
- package/src/hooks/ts/capture-all-events.ts +179 -0
- package/src/hooks/ts/lib/detect-environment.ts +53 -0
- package/src/hooks/ts/lib/metadata-extraction.ts +144 -0
- package/src/hooks/ts/lib/pai-paths.ts +124 -0
- package/src/hooks/ts/lib/project-utils.ts +914 -0
- package/src/hooks/ts/post-tool-use/capture-tool-output.ts +78 -0
- package/src/hooks/ts/post-tool-use/sync-todo-to-md.ts +230 -0
- package/src/hooks/ts/post-tool-use/update-tab-on-action.ts +145 -0
- package/src/hooks/ts/pre-compact/context-compression-hook.ts +155 -0
- package/src/hooks/ts/pre-tool-use/security-validator.ts +258 -0
- package/src/hooks/ts/session-end/capture-session-summary.ts +185 -0
- package/src/hooks/ts/session-start/initialize-session.ts +155 -0
- package/src/hooks/ts/session-start/load-core-context.ts +104 -0
- package/src/hooks/ts/session-start/load-project-context.ts +394 -0
- package/src/hooks/ts/stop/stop-hook.ts +407 -0
- package/src/hooks/ts/subagent-stop/subagent-stop-hook.ts +212 -0
- package/src/hooks/ts/user-prompt/cleanup-session-files.ts +45 -0
- package/src/hooks/ts/user-prompt/update-tab-titles.ts +88 -0
- package/tab-color-command.sh +24 -0
- package/templates/skills/createskill-skill.template.md +78 -0
- package/templates/skills/history-system.template.md +371 -0
- package/templates/skills/hook-system.template.md +913 -0
- package/templates/skills/sessions-skill.template.md +102 -0
- package/templates/skills/skill-system.template.md +214 -0
- package/templates/skills/terminal-tabs.template.md +120 -0
- package/dist/search-GK0ibTJy.mjs.map +0 -1
- package/dist/tools-CUg0Lyg-.mjs.map +0 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -6,11 +6,11 @@ import { n as ensurePaiMarker, t as discoverPaiMarkers } from "../pai-marker-CXQ
|
|
|
6
6
|
import { n as openFederation } from "../db-Dp8VXIMR.mjs";
|
|
7
7
|
import { a as indexProject, n as embedChunks, r as indexAll } from "../indexer-CKQcgKsz.mjs";
|
|
8
8
|
import "../embeddings-DGRAPAYb.mjs";
|
|
9
|
-
import { n as populateSlugs, r as searchMemory } from "../search-
|
|
10
|
-
import { n as formatDetection, r as formatDetectionJson, t as detectProject } from "../detect-
|
|
11
|
-
import { t as PaiClient } from "../ipc-client-
|
|
12
|
-
import { a as expandHome, n as CONFIG_FILE$2, o as loadConfig$1, t as CONFIG_DIR } from "../config-
|
|
13
|
-
import { t as createStorageBackend } from "../factory-
|
|
9
|
+
import { n as populateSlugs, r as searchMemory } from "../search-_oHfguA5.mjs";
|
|
10
|
+
import { n as formatDetection, r as formatDetectionJson, t as detectProject } from "../detect-CdaA48EI.mjs";
|
|
11
|
+
import { t as PaiClient } from "../ipc-client-CgSpwHDC.mjs";
|
|
12
|
+
import { a as expandHome, n as CONFIG_FILE$2, o as loadConfig$1, t as CONFIG_DIR } from "../config-B4brrHHE.mjs";
|
|
13
|
+
import { t as createStorageBackend } from "../factory-CeXQzlwn.mjs";
|
|
14
14
|
import { appendFileSync, chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
15
15
|
import { homedir, tmpdir } from "node:os";
|
|
16
16
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
@@ -1809,10 +1809,10 @@ function cmdActive(db, opts) {
|
|
|
1809
1809
|
], rows));
|
|
1810
1810
|
}
|
|
1811
1811
|
async function cmdAutoRoute(opts) {
|
|
1812
|
-
const { autoRoute, formatAutoRoute, formatAutoRouteJson } = await import("../auto-route-
|
|
1812
|
+
const { autoRoute, formatAutoRoute, formatAutoRouteJson } = await import("../auto-route-B5MSUJZK.mjs");
|
|
1813
1813
|
const { openRegistry } = await import("../db-4lSqLFb8.mjs").then((n) => n.t);
|
|
1814
|
-
const { createStorageBackend } = await import("../factory-
|
|
1815
|
-
const { loadConfig } = await import("../config-
|
|
1814
|
+
const { createStorageBackend } = await import("../factory-CeXQzlwn.mjs").then((n) => n.n);
|
|
1815
|
+
const { loadConfig } = await import("../config-B4brrHHE.mjs").then((n) => n.r);
|
|
1816
1816
|
const config = loadConfig();
|
|
1817
1817
|
const registryDb = openRegistry();
|
|
1818
1818
|
const federation = await createStorageBackend(config);
|
|
@@ -2340,8 +2340,8 @@ async function displayDryRun(plans) {
|
|
|
2340
2340
|
async function countVectorDbPaths(oldPaths) {
|
|
2341
2341
|
if (oldPaths.length === 0) return 0;
|
|
2342
2342
|
try {
|
|
2343
|
-
const { loadConfig } = await import("../config-
|
|
2344
|
-
const { PostgresBackend } = await import("../postgres-
|
|
2343
|
+
const { loadConfig } = await import("../config-B4brrHHE.mjs").then((n) => n.r);
|
|
2344
|
+
const { PostgresBackend } = await import("../postgres-CIxeqf_n.mjs");
|
|
2345
2345
|
const config = loadConfig();
|
|
2346
2346
|
if (config.storageBackend !== "postgres") return 0;
|
|
2347
2347
|
const pgBackend = new PostgresBackend(config.postgres ?? {});
|
|
@@ -2367,8 +2367,8 @@ async function countVectorDbPaths(oldPaths) {
|
|
|
2367
2367
|
async function updateVectorDbPaths(moves) {
|
|
2368
2368
|
if (moves.length === 0) return 0;
|
|
2369
2369
|
try {
|
|
2370
|
-
const { loadConfig } = await import("../config-
|
|
2371
|
-
const { PostgresBackend } = await import("../postgres-
|
|
2370
|
+
const { loadConfig } = await import("../config-B4brrHHE.mjs").then((n) => n.r);
|
|
2371
|
+
const { PostgresBackend } = await import("../postgres-CIxeqf_n.mjs");
|
|
2372
2372
|
const config = loadConfig();
|
|
2373
2373
|
if (config.storageBackend !== "postgres") return 0;
|
|
2374
2374
|
const pgBackend = new PostgresBackend(config.postgres ?? {});
|
|
@@ -3110,7 +3110,7 @@ function registerMemoryCommands(memoryCmd, getDb) {
|
|
|
3110
3110
|
await runEmbed(federation, project.id, project.slug, parseInt(opts.batchSize ?? "50", 10));
|
|
3111
3111
|
} else await runEmbed(federation, void 0, void 0, parseInt(opts.batchSize ?? "50", 10));
|
|
3112
3112
|
});
|
|
3113
|
-
memoryCmd.command("search <query>").description("Search indexed memory (BM25 keyword, semantic, or hybrid)").option("--project <slug>", "Restrict search to a specific project").option("--source <source>", "Restrict to 'memory' or 'notes'").option("--limit <n>", "Maximum results to return", "10").option("--mode <mode>", "Search mode: keyword (default), semantic, hybrid", "keyword").action(async (query, opts) => {
|
|
3113
|
+
memoryCmd.command("search <query>").description("Search indexed memory (BM25 keyword, semantic, or hybrid)").option("--project <slug>", "Restrict search to a specific project").option("--source <source>", "Restrict to 'memory' or 'notes'").option("--limit <n>", "Maximum results to return", "10").option("--mode <mode>", "Search mode: keyword (default), semantic, hybrid", "keyword").option("--no-rerank", "Skip cross-encoder reranking (reranking is on by default)").option("--recency <days>", "Apply recency boost: score halves every N days. 0 = off (default)", "0").action(async (query, opts) => {
|
|
3114
3114
|
const registryDb = getDb();
|
|
3115
3115
|
let federation;
|
|
3116
3116
|
try {
|
|
@@ -3194,8 +3194,20 @@ function registerMemoryCommands(memoryCmd, getDb) {
|
|
|
3194
3194
|
console.log(dim(`No results found for: "${query}" (mode: ${mode})`));
|
|
3195
3195
|
return;
|
|
3196
3196
|
}
|
|
3197
|
+
if (opts.rerank !== false) {
|
|
3198
|
+
const { rerankResults } = await import("../reranker-D7bRAHi6.mjs").then((n) => n.r);
|
|
3199
|
+
console.log(dim("Reranking with cross-encoder..."));
|
|
3200
|
+
results = await rerankResults(query, results, { topK: maxResults });
|
|
3201
|
+
}
|
|
3202
|
+
const recencyDays = parseInt(opts.recency ?? "0", 10);
|
|
3203
|
+
if (recencyDays > 0) {
|
|
3204
|
+
const { applyRecencyBoost } = await import("../search-_oHfguA5.mjs").then((n) => n.o);
|
|
3205
|
+
console.log(dim(`Applying recency boost (half-life: ${recencyDays} days)...`));
|
|
3206
|
+
results = applyRecencyBoost(results, recencyDays);
|
|
3207
|
+
}
|
|
3197
3208
|
const withSlugs = populateSlugs(results, registryDb);
|
|
3198
|
-
const
|
|
3209
|
+
const rerankLabel = opts.rerank !== false ? " +rerank" : "";
|
|
3210
|
+
const modeLabel = mode !== "keyword" ? ` [${mode}${rerankLabel}]` : opts.rerank !== false ? ` [rerank]` : "";
|
|
3199
3211
|
console.log(`\n ${bold(`Search results for: "${query}"`)}${modeLabel} ${dim(`(${withSlugs.length} found)`)}\n`);
|
|
3200
3212
|
for (const result of withSlugs) {
|
|
3201
3213
|
const projectLabel = result.projectSlug ? chalk.cyan(result.projectSlug) : chalk.cyan(String(result.projectId));
|
|
@@ -3640,8 +3652,8 @@ function cmdLogs(opts) {
|
|
|
3640
3652
|
}
|
|
3641
3653
|
function registerDaemonCommands(daemonCmd) {
|
|
3642
3654
|
daemonCmd.command("serve").description("Start the PAI daemon in the foreground").action(async () => {
|
|
3643
|
-
const { serve } = await import("../daemon-
|
|
3644
|
-
const { loadConfig: lc, ensureConfigDir } = await import("../config-
|
|
3655
|
+
const { serve } = await import("../daemon-s868Paua.mjs").then((n) => n.t);
|
|
3656
|
+
const { loadConfig: lc, ensureConfigDir } = await import("../config-B4brrHHE.mjs").then((n) => n.r);
|
|
3645
3657
|
ensureConfigDir();
|
|
3646
3658
|
await serve(lc());
|
|
3647
3659
|
});
|
|
@@ -4099,6 +4111,42 @@ function mergeStatusLine(settings, incoming, report) {
|
|
|
4099
4111
|
return true;
|
|
4100
4112
|
}
|
|
4101
4113
|
/**
|
|
4114
|
+
* Merge permissions — append allow/deny entries, deduplicating.
|
|
4115
|
+
*/
|
|
4116
|
+
function mergePermissions(settings, incoming, report) {
|
|
4117
|
+
let changed = false;
|
|
4118
|
+
const perms = typeof settings["permissions"] === "object" && settings["permissions"] !== null ? settings["permissions"] : {};
|
|
4119
|
+
for (const list of ["allow", "deny"]) {
|
|
4120
|
+
const entries = incoming[list];
|
|
4121
|
+
if (!entries || entries.length === 0) continue;
|
|
4122
|
+
const existing = Array.isArray(perms[list]) ? perms[list] : [];
|
|
4123
|
+
const existingSet = new Set(existing);
|
|
4124
|
+
for (const entry of entries) if (existingSet.has(entry)) report.push(chalk.dim(` Skipped: permissions.${list} "${entry}" already present`));
|
|
4125
|
+
else {
|
|
4126
|
+
existing.push(entry);
|
|
4127
|
+
existingSet.add(entry);
|
|
4128
|
+
report.push(chalk.green(` Added permissions.${list}: ${entry}`));
|
|
4129
|
+
changed = true;
|
|
4130
|
+
}
|
|
4131
|
+
perms[list] = existing;
|
|
4132
|
+
}
|
|
4133
|
+
settings["permissions"] = perms;
|
|
4134
|
+
return changed;
|
|
4135
|
+
}
|
|
4136
|
+
/**
|
|
4137
|
+
* Merge flags — set keys only if not already present, never overwrite.
|
|
4138
|
+
*/
|
|
4139
|
+
function mergeFlags(settings, incoming, report) {
|
|
4140
|
+
let changed = false;
|
|
4141
|
+
for (const [key, value] of Object.entries(incoming)) if (Object.prototype.hasOwnProperty.call(settings, key)) report.push(chalk.dim(` Skipped: ${key} already set`));
|
|
4142
|
+
else {
|
|
4143
|
+
settings[key] = value;
|
|
4144
|
+
report.push(chalk.green(` Added flag: ${key}`));
|
|
4145
|
+
changed = true;
|
|
4146
|
+
}
|
|
4147
|
+
return changed;
|
|
4148
|
+
}
|
|
4149
|
+
/**
|
|
4102
4150
|
* Merge env vars, hooks, and/or a statusLine entry into ~/.claude/settings.json.
|
|
4103
4151
|
* Never overwrites existing values — only adds what is missing.
|
|
4104
4152
|
*
|
|
@@ -4117,6 +4165,12 @@ function mergeSettings(opts) {
|
|
|
4117
4165
|
if (opts.statusLine !== void 0) {
|
|
4118
4166
|
if (mergeStatusLine(settings, opts.statusLine, report)) changed = true;
|
|
4119
4167
|
}
|
|
4168
|
+
if (opts.permissions !== void 0) {
|
|
4169
|
+
if (mergePermissions(settings, opts.permissions, report)) changed = true;
|
|
4170
|
+
}
|
|
4171
|
+
if (opts.flags !== void 0 && Object.keys(opts.flags).length > 0) {
|
|
4172
|
+
if (mergeFlags(settings, opts.flags, report)) changed = true;
|
|
4173
|
+
}
|
|
4120
4174
|
if (changed) writeSettingsJson(settings);
|
|
4121
4175
|
return {
|
|
4122
4176
|
changed,
|
|
@@ -4231,7 +4285,7 @@ function getDockerDir() {
|
|
|
4231
4285
|
const candidates = [
|
|
4232
4286
|
join(process.cwd(), "docker"),
|
|
4233
4287
|
join(homedir(), "dev", "ai", "PAI", "docker"),
|
|
4234
|
-
join("/", "usr", "local", "lib", "node_modules", "@
|
|
4288
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "docker")
|
|
4235
4289
|
];
|
|
4236
4290
|
for (const c of candidates) if (existsSync(join(c, "docker-compose.yml"))) return c;
|
|
4237
4291
|
return join(process.cwd(), "docker");
|
|
@@ -4240,7 +4294,7 @@ function getTemplatesDir$1() {
|
|
|
4240
4294
|
const candidates = [
|
|
4241
4295
|
join(process.cwd(), "templates"),
|
|
4242
4296
|
join(homedir(), "dev", "ai", "PAI", "templates"),
|
|
4243
|
-
join("/", "usr", "local", "lib", "node_modules", "@
|
|
4297
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "templates")
|
|
4244
4298
|
];
|
|
4245
4299
|
for (const c of candidates) if (existsSync(join(c, "claude-md.template.md"))) return c;
|
|
4246
4300
|
return join(process.cwd(), "templates");
|
|
@@ -4254,6 +4308,18 @@ function getHooksDir() {
|
|
|
4254
4308
|
for (const c of candidates) if (existsSync(join(c, "session-stop.sh"))) return c;
|
|
4255
4309
|
return join(process.cwd(), "src", "hooks");
|
|
4256
4310
|
}
|
|
4311
|
+
function getDistHooksDir() {
|
|
4312
|
+
const moduleDir = new URL(".", import.meta.url).pathname;
|
|
4313
|
+
const fromModule = join(moduleDir, "..", "hooks");
|
|
4314
|
+
const candidates = [
|
|
4315
|
+
fromModule,
|
|
4316
|
+
join(process.cwd(), "dist", "hooks"),
|
|
4317
|
+
join(homedir(), "dev", "ai", "PAI", "dist", "hooks"),
|
|
4318
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "dist", "hooks")
|
|
4319
|
+
];
|
|
4320
|
+
for (const candidate of candidates) if (existsSync(join(candidate, "stop-hook.mjs"))) return candidate;
|
|
4321
|
+
return fromModule;
|
|
4322
|
+
}
|
|
4257
4323
|
function getStatuslineScript() {
|
|
4258
4324
|
const candidates = [
|
|
4259
4325
|
join(process.cwd(), "statusline-command.sh"),
|
|
@@ -4685,35 +4751,235 @@ async function stepHooks(rl) {
|
|
|
4685
4751
|
return anyInstalled;
|
|
4686
4752
|
}
|
|
4687
4753
|
/**
|
|
4688
|
-
* Step
|
|
4754
|
+
* Step 7b: Install compiled TypeScript hooks (.mjs) to ~/.claude/Hooks/
|
|
4755
|
+
*
|
|
4756
|
+
* Finds all .mjs files in the package's dist/hooks/ directory and copies them
|
|
4757
|
+
* to ~/.claude/Hooks/. Content is compared before copying — identical files are
|
|
4758
|
+
* skipped for idempotent re-runs. Each installed file gets chmod 755.
|
|
4759
|
+
*/
|
|
4760
|
+
async function stepTsHooks(rl) {
|
|
4761
|
+
section("Step 7b: TypeScript Hooks Installation");
|
|
4762
|
+
line$1();
|
|
4763
|
+
line$1(" PAI ships 14 compiled TypeScript hooks (.mjs) that fire on session events,");
|
|
4764
|
+
line$1(" tool use, and context compaction to capture context and update notes.");
|
|
4765
|
+
line$1();
|
|
4766
|
+
if (!await promptYesNo(rl, "Install PAI TypeScript hooks to ~/.claude/Hooks/?", true)) {
|
|
4767
|
+
console.log(c.dim(" Skipping TypeScript hooks installation."));
|
|
4768
|
+
return false;
|
|
4769
|
+
}
|
|
4770
|
+
const distHooksDir = getDistHooksDir();
|
|
4771
|
+
if (!existsSync(distHooksDir)) {
|
|
4772
|
+
console.log(c.warn(` dist/hooks/ directory not found at: ${distHooksDir}`));
|
|
4773
|
+
console.log(c.dim(" Build the package first: bun run build"));
|
|
4774
|
+
return false;
|
|
4775
|
+
}
|
|
4776
|
+
const hooksTarget = join(join(homedir(), ".claude"), "Hooks");
|
|
4777
|
+
if (!existsSync(hooksTarget)) mkdirSync(hooksTarget, { recursive: true });
|
|
4778
|
+
let allFiles;
|
|
4779
|
+
try {
|
|
4780
|
+
allFiles = readdirSync(distHooksDir).filter((f) => f.endsWith(".mjs"));
|
|
4781
|
+
} catch (e) {
|
|
4782
|
+
console.log(c.warn(` Could not read dist/hooks/: ${e}`));
|
|
4783
|
+
return false;
|
|
4784
|
+
}
|
|
4785
|
+
if (allFiles.length === 0) {
|
|
4786
|
+
console.log(c.warn(" No .mjs files found in dist/hooks/. Build first: bun run build"));
|
|
4787
|
+
return false;
|
|
4788
|
+
}
|
|
4789
|
+
line$1();
|
|
4790
|
+
let copiedCount = 0;
|
|
4791
|
+
let skippedCount = 0;
|
|
4792
|
+
for (const filename of allFiles) {
|
|
4793
|
+
const src = join(distHooksDir, filename);
|
|
4794
|
+
const dest = join(hooksTarget, filename);
|
|
4795
|
+
const srcContent = readFileSync(src, "utf-8");
|
|
4796
|
+
if (existsSync(dest)) {
|
|
4797
|
+
if (srcContent === readFileSync(dest, "utf-8")) {
|
|
4798
|
+
console.log(c.dim(` Unchanged: ${filename}`));
|
|
4799
|
+
skippedCount++;
|
|
4800
|
+
continue;
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
copyFileSync(src, dest);
|
|
4804
|
+
chmodSync(dest, 493);
|
|
4805
|
+
console.log(c.ok(`Installed: ${filename}`));
|
|
4806
|
+
copiedCount++;
|
|
4807
|
+
}
|
|
4808
|
+
line$1();
|
|
4809
|
+
if (copiedCount > 0) console.log(c.ok(`${copiedCount} hook(s) installed, ${skippedCount} unchanged.`));
|
|
4810
|
+
else console.log(c.dim(` All ${skippedCount} hook(s) already up-to-date.`));
|
|
4811
|
+
return copiedCount > 0;
|
|
4812
|
+
}
|
|
4813
|
+
/**
|
|
4814
|
+
* Step 8b: Prompt for the DA (Digital Assistant) name
|
|
4815
|
+
*
|
|
4816
|
+
* The name appears in tab titles, session notes, and hook output.
|
|
4817
|
+
* Stored in env.DA via settings merge.
|
|
4818
|
+
*/
|
|
4819
|
+
async function stepDaName(rl) {
|
|
4820
|
+
section("Step 8b: Assistant Name");
|
|
4821
|
+
line$1();
|
|
4822
|
+
line$1(" Choose a name for your AI assistant. This name appears in tab titles");
|
|
4823
|
+
line$1(" and session notes when hooks are active.");
|
|
4824
|
+
line$1();
|
|
4825
|
+
const daName = await prompt(rl, chalk.bold(" Assistant name [PAI]: ")) || "PAI";
|
|
4826
|
+
line$1();
|
|
4827
|
+
console.log(c.ok(`Assistant name set to: ${daName}`));
|
|
4828
|
+
return daName;
|
|
4829
|
+
}
|
|
4830
|
+
/**
|
|
4831
|
+
* Step 8: Patch ~/.claude/settings.json with PAI hooks, env vars, permissions, and flags
|
|
4832
|
+
*
|
|
4833
|
+
* Registers all 17 hook entries across 8 event types, adds env vars including DA name,
|
|
4834
|
+
* sets the statusline command, adds tool permissions (allow/deny), and sets flags.
|
|
4689
4835
|
*/
|
|
4690
|
-
async function stepSettings(rl) {
|
|
4836
|
+
async function stepSettings(rl, daName) {
|
|
4691
4837
|
section("Step 8: Settings Patch");
|
|
4692
4838
|
line$1();
|
|
4693
|
-
line$1(" PAI will add env vars, hook registrations, and
|
|
4839
|
+
line$1(" PAI will add env vars, all hook registrations, permissions, and flags");
|
|
4694
4840
|
line$1(" to ~/.claude/settings.json. Existing values are never overwritten.");
|
|
4695
4841
|
line$1();
|
|
4696
|
-
if (!await promptYesNo(rl, "Patch ~/.claude/settings.json with PAI hooks, env vars, and
|
|
4842
|
+
if (!await promptYesNo(rl, "Patch ~/.claude/settings.json with PAI hooks, env vars, and settings?", true)) {
|
|
4697
4843
|
console.log(c.dim(" Skipping settings patch."));
|
|
4698
4844
|
return false;
|
|
4699
4845
|
}
|
|
4700
4846
|
const result = mergeSettings({
|
|
4701
4847
|
env: {
|
|
4702
4848
|
PAI_DIR: join(homedir(), ".claude"),
|
|
4703
|
-
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "80"
|
|
4849
|
+
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "80",
|
|
4850
|
+
CLAUDE_CODE_MAX_OUTPUT_TOKENS: "64000",
|
|
4851
|
+
DA: daName
|
|
4704
4852
|
},
|
|
4705
|
-
hooks: [
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4853
|
+
hooks: [
|
|
4854
|
+
{
|
|
4855
|
+
hookType: "SessionStart",
|
|
4856
|
+
command: "${PAI_DIR}/Hooks/load-core-context.mjs"
|
|
4857
|
+
},
|
|
4858
|
+
{
|
|
4859
|
+
hookType: "SessionStart",
|
|
4860
|
+
command: "${PAI_DIR}/Hooks/load-project-context.mjs"
|
|
4861
|
+
},
|
|
4862
|
+
{
|
|
4863
|
+
hookType: "SessionStart",
|
|
4864
|
+
command: "${PAI_DIR}/Hooks/initialize-session.mjs"
|
|
4865
|
+
},
|
|
4866
|
+
{
|
|
4867
|
+
hookType: "SessionStart",
|
|
4868
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SessionStart"
|
|
4869
|
+
},
|
|
4870
|
+
{
|
|
4871
|
+
hookType: "UserPromptSubmit",
|
|
4872
|
+
command: "${PAI_DIR}/Hooks/cleanup-session-files.mjs"
|
|
4873
|
+
},
|
|
4874
|
+
{
|
|
4875
|
+
hookType: "UserPromptSubmit",
|
|
4876
|
+
command: "${PAI_DIR}/Hooks/update-tab-titles.mjs"
|
|
4877
|
+
},
|
|
4878
|
+
{
|
|
4879
|
+
hookType: "UserPromptSubmit",
|
|
4880
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type UserPromptSubmit"
|
|
4881
|
+
},
|
|
4882
|
+
{
|
|
4883
|
+
hookType: "PreToolUse",
|
|
4884
|
+
matcher: "Bash",
|
|
4885
|
+
command: "${PAI_DIR}/Hooks/security-validator.mjs"
|
|
4886
|
+
},
|
|
4887
|
+
{
|
|
4888
|
+
hookType: "PreToolUse",
|
|
4889
|
+
matcher: "*",
|
|
4890
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PreToolUse"
|
|
4891
|
+
},
|
|
4892
|
+
{
|
|
4893
|
+
hookType: "PostToolUse",
|
|
4894
|
+
matcher: "TodoWrite",
|
|
4895
|
+
command: "${PAI_DIR}/Hooks/sync-todo-to-md.mjs"
|
|
4896
|
+
},
|
|
4897
|
+
{
|
|
4898
|
+
hookType: "PostToolUse",
|
|
4899
|
+
matcher: "*",
|
|
4900
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PostToolUse"
|
|
4901
|
+
},
|
|
4902
|
+
{
|
|
4903
|
+
hookType: "PostToolUse",
|
|
4904
|
+
matcher: "*",
|
|
4905
|
+
command: "${PAI_DIR}/Hooks/capture-tool-output.mjs"
|
|
4906
|
+
},
|
|
4907
|
+
{
|
|
4908
|
+
hookType: "PostToolUse",
|
|
4909
|
+
matcher: "*",
|
|
4910
|
+
command: "${PAI_DIR}/Hooks/update-tab-on-action.mjs"
|
|
4911
|
+
},
|
|
4912
|
+
{
|
|
4913
|
+
hookType: "Stop",
|
|
4914
|
+
command: "${PAI_DIR}/Hooks/stop-hook.mjs"
|
|
4915
|
+
},
|
|
4916
|
+
{
|
|
4917
|
+
hookType: "Stop",
|
|
4918
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type Stop"
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
hookType: "Stop",
|
|
4922
|
+
command: "${PAI_DIR}/Hooks/pai-session-stop.sh"
|
|
4923
|
+
},
|
|
4924
|
+
{
|
|
4925
|
+
hookType: "SubagentStop",
|
|
4926
|
+
command: "${PAI_DIR}/Hooks/subagent-stop-hook.mjs"
|
|
4927
|
+
},
|
|
4928
|
+
{
|
|
4929
|
+
hookType: "SubagentStop",
|
|
4930
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SubagentStop"
|
|
4931
|
+
},
|
|
4932
|
+
{
|
|
4933
|
+
hookType: "SessionEnd",
|
|
4934
|
+
command: "${PAI_DIR}/Hooks/capture-session-summary.mjs"
|
|
4935
|
+
},
|
|
4936
|
+
{
|
|
4937
|
+
hookType: "SessionEnd",
|
|
4938
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SessionEnd"
|
|
4939
|
+
},
|
|
4940
|
+
{
|
|
4941
|
+
hookType: "PreCompact",
|
|
4942
|
+
command: "${PAI_DIR}/Hooks/context-compression-hook.mjs"
|
|
4943
|
+
},
|
|
4944
|
+
{
|
|
4945
|
+
hookType: "PreCompact",
|
|
4946
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PreCompact"
|
|
4947
|
+
},
|
|
4948
|
+
{
|
|
4949
|
+
hookType: "PreCompact",
|
|
4950
|
+
matcher: "",
|
|
4951
|
+
command: "${PAI_DIR}/Hooks/pai-pre-compact.sh"
|
|
4952
|
+
}
|
|
4953
|
+
],
|
|
4713
4954
|
statusLine: {
|
|
4714
4955
|
type: "command",
|
|
4715
4956
|
command: "bash ${PAI_DIR}/statusline-command.sh"
|
|
4716
|
-
}
|
|
4957
|
+
},
|
|
4958
|
+
permissions: {
|
|
4959
|
+
allow: [
|
|
4960
|
+
"Bash",
|
|
4961
|
+
"Read",
|
|
4962
|
+
"Write",
|
|
4963
|
+
"Edit",
|
|
4964
|
+
"Glob",
|
|
4965
|
+
"Grep",
|
|
4966
|
+
"WebFetch",
|
|
4967
|
+
"WebSearch",
|
|
4968
|
+
"NotebookEdit",
|
|
4969
|
+
"TodoWrite",
|
|
4970
|
+
"ExitPlanMode",
|
|
4971
|
+
"mcp__pai"
|
|
4972
|
+
],
|
|
4973
|
+
deny: [
|
|
4974
|
+
"Bash(rm -rf /)",
|
|
4975
|
+
"Bash(rm -rf /*)",
|
|
4976
|
+
"Bash(rm -rf ~)",
|
|
4977
|
+
"Bash(rm -rf $HOME)",
|
|
4978
|
+
"Bash(sudo rm -rf /)",
|
|
4979
|
+
"Bash(sudo rm -rf /*)"
|
|
4980
|
+
]
|
|
4981
|
+
},
|
|
4982
|
+
flags: { enableAllProjectMcpServers: true }
|
|
4717
4983
|
});
|
|
4718
4984
|
line$1();
|
|
4719
4985
|
for (const r of result.report) console.log(r);
|
|
@@ -4855,7 +5121,7 @@ async function stepInitialIndex(rl) {
|
|
|
4855
5121
|
/**
|
|
4856
5122
|
* Step 13: Summary and next steps
|
|
4857
5123
|
*/
|
|
4858
|
-
function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, settingsPatched, daemonInstalled, mcpRegistered) {
|
|
5124
|
+
function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered) {
|
|
4859
5125
|
section("Setup Complete");
|
|
4860
5126
|
line$1();
|
|
4861
5127
|
console.log(c.ok("PAI Knowledge OS is configured!"));
|
|
@@ -4869,8 +5135,10 @@ function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiStee
|
|
|
4869
5135
|
console.log(chalk.dim(" CLAUDE.md: ") + chalk.cyan(claudeMdGenerated ? "~/.claude/CLAUDE.md (generated)" : "(unchanged)"));
|
|
4870
5136
|
console.log(chalk.dim(" PAI skill: ") + chalk.cyan(paiSkillInstalled ? "~/.claude/skills/PAI/SKILL.md (installed)" : "(unchanged)"));
|
|
4871
5137
|
console.log(chalk.dim(" Steering rules: ") + chalk.cyan(aiSteeringRulesInstalled ? "~/.claude/skills/PAI/AI-STEERING-RULES.md (installed)" : "(unchanged)"));
|
|
4872
|
-
console.log(chalk.dim(" Hooks:
|
|
4873
|
-
console.log(chalk.dim("
|
|
5138
|
+
console.log(chalk.dim(" Hooks (shell): ") + chalk.cyan(hooksInstalled ? "pai-pre-compact.sh, pai-session-stop.sh (installed)" : "(unchanged)"));
|
|
5139
|
+
console.log(chalk.dim(" Hooks (TS): ") + chalk.cyan(tsHooksInstalled ? "14 .mjs hooks installed to ~/.claude/Hooks/" : "(unchanged)"));
|
|
5140
|
+
console.log(chalk.dim(" Assistant name: ") + chalk.cyan(daName));
|
|
5141
|
+
console.log(chalk.dim(" Settings: ") + chalk.cyan(settingsPatched ? "env vars, hooks, permissions, flags (patched)" : "(unchanged)"));
|
|
4874
5142
|
console.log(chalk.dim(" Daemon: ") + chalk.cyan(daemonInstalled ? "com.pai.pai-daemon (installed)" : "(unchanged)"));
|
|
4875
5143
|
console.log(chalk.dim(" MCP: ") + chalk.cyan(mcpRegistered ? "registered in ~/.claude.json" : "(unchanged)"));
|
|
4876
5144
|
line$1();
|
|
@@ -4928,7 +5196,9 @@ async function runSetup() {
|
|
|
4928
5196
|
const paiSkillInstalled = await stepPaiSkill(rl);
|
|
4929
5197
|
const aiSteeringRulesInstalled = await stepAiSteeringRules(rl);
|
|
4930
5198
|
const hooksInstalled = await stepHooks(rl);
|
|
4931
|
-
const
|
|
5199
|
+
const tsHooksInstalled = await stepTsHooks(rl);
|
|
5200
|
+
const daName = await stepDaName(rl);
|
|
5201
|
+
const settingsPatched = await stepSettings(rl, daName);
|
|
4932
5202
|
const daemonInstalled = await stepDaemon(rl);
|
|
4933
5203
|
const mcpRegistered = await stepMcp(rl);
|
|
4934
5204
|
await stepDirectories(rl);
|
|
@@ -4940,7 +5210,7 @@ async function runSetup() {
|
|
|
4940
5210
|
line$1();
|
|
4941
5211
|
console.log(c.ok("Configuration saved."));
|
|
4942
5212
|
await stepInitialIndex(rl);
|
|
4943
|
-
stepSummary(allUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, settingsPatched, daemonInstalled, mcpRegistered);
|
|
5213
|
+
stepSummary(allUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered);
|
|
4944
5214
|
} finally {
|
|
4945
5215
|
rl.close();
|
|
4946
5216
|
}
|
|
@@ -5829,7 +6099,7 @@ async function cmdExplore(note, opts) {
|
|
|
5829
6099
|
const depth = parseInt(opts.depth ?? "3", 10);
|
|
5830
6100
|
const direction = opts.direction ?? "both";
|
|
5831
6101
|
const mode = opts.mode ?? "all";
|
|
5832
|
-
const { zettelExplore } = await import("../zettelkasten-
|
|
6102
|
+
const { zettelExplore } = await import("../zettelkasten-e-a4rW_6.mjs");
|
|
5833
6103
|
const result = zettelExplore(getFedDb(), {
|
|
5834
6104
|
startNote: note,
|
|
5835
6105
|
depth,
|
|
@@ -5880,7 +6150,7 @@ async function cmdHealth(opts) {
|
|
|
5880
6150
|
const projectPath = opts.project;
|
|
5881
6151
|
const recentDays = parseInt(opts.days ?? "30", 10);
|
|
5882
6152
|
const includeTypes = opts.include ? opts.include.split(",").map((s) => s.trim()) : void 0;
|
|
5883
|
-
const { zettelHealth } = await import("../zettelkasten-
|
|
6153
|
+
const { zettelHealth } = await import("../zettelkasten-e-a4rW_6.mjs");
|
|
5884
6154
|
const result = zettelHealth(getFedDb(), {
|
|
5885
6155
|
scope,
|
|
5886
6156
|
projectPath,
|
|
@@ -5936,7 +6206,7 @@ async function cmdSurprise(note, opts) {
|
|
|
5936
6206
|
const limit = parseInt(opts.limit ?? "10", 10);
|
|
5937
6207
|
const minSimilarity = parseFloat(opts.minSimilarity ?? "0.3");
|
|
5938
6208
|
const minGraphDistance = parseInt(opts.minDistance ?? "3", 10);
|
|
5939
|
-
const { zettelSurprise } = await import("../zettelkasten-
|
|
6209
|
+
const { zettelSurprise } = await import("../zettelkasten-e-a4rW_6.mjs");
|
|
5940
6210
|
const db = getFedDb();
|
|
5941
6211
|
console.log();
|
|
5942
6212
|
console.log(header(" PAI Zettel Surprise"));
|
|
@@ -5976,7 +6246,7 @@ async function cmdSuggest(note, opts) {
|
|
|
5976
6246
|
const vaultProjectId = parseInt(opts.vaultProjectId, 10);
|
|
5977
6247
|
const limit = parseInt(opts.limit ?? "5", 10);
|
|
5978
6248
|
const excludeLinked = opts.excludeLinked !== false;
|
|
5979
|
-
const { zettelSuggest } = await import("../zettelkasten-
|
|
6249
|
+
const { zettelSuggest } = await import("../zettelkasten-e-a4rW_6.mjs");
|
|
5980
6250
|
const db = getFedDb();
|
|
5981
6251
|
console.log();
|
|
5982
6252
|
console.log(header(" PAI Zettel Suggest"));
|
|
@@ -6014,7 +6284,7 @@ async function cmdConverse(question, opts) {
|
|
|
6014
6284
|
const vaultProjectId = parseInt(opts.vaultProjectId, 10);
|
|
6015
6285
|
const depth = parseInt(opts.depth ?? "2", 10);
|
|
6016
6286
|
const limit = parseInt(opts.limit ?? "15", 10);
|
|
6017
|
-
const { zettelConverse } = await import("../zettelkasten-
|
|
6287
|
+
const { zettelConverse } = await import("../zettelkasten-e-a4rW_6.mjs");
|
|
6018
6288
|
const db = getFedDb();
|
|
6019
6289
|
console.log();
|
|
6020
6290
|
console.log(header(" PAI Zettel Converse"));
|
|
@@ -6062,7 +6332,7 @@ async function cmdThemes(opts) {
|
|
|
6062
6332
|
const minClusterSize = parseInt(opts.minSize ?? "3", 10);
|
|
6063
6333
|
const maxThemes = parseInt(opts.maxThemes ?? "10", 10);
|
|
6064
6334
|
const similarityThreshold = parseFloat(opts.threshold ?? "0.65");
|
|
6065
|
-
const { zettelThemes } = await import("../zettelkasten-
|
|
6335
|
+
const { zettelThemes } = await import("../zettelkasten-e-a4rW_6.mjs");
|
|
6066
6336
|
const db = getFedDb();
|
|
6067
6337
|
console.log();
|
|
6068
6338
|
console.log(header(" PAI Zettel Themes"));
|