@tekmidian/pai 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.mjs +352 -33
- package/dist/cli/index.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/package.json +4 -2
- package/scripts/build-hooks.mjs +51 -0
- package/src/hooks/pre-compact.sh +4 -0
- package/src/hooks/session-stop.sh +4 -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/ai-steering-rules.template.md +58 -0
- package/templates/pai-skill.template.md +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/cli/index.mjs
CHANGED
|
@@ -4099,6 +4099,42 @@ function mergeStatusLine(settings, incoming, report) {
|
|
|
4099
4099
|
return true;
|
|
4100
4100
|
}
|
|
4101
4101
|
/**
|
|
4102
|
+
* Merge permissions — append allow/deny entries, deduplicating.
|
|
4103
|
+
*/
|
|
4104
|
+
function mergePermissions(settings, incoming, report) {
|
|
4105
|
+
let changed = false;
|
|
4106
|
+
const perms = typeof settings["permissions"] === "object" && settings["permissions"] !== null ? settings["permissions"] : {};
|
|
4107
|
+
for (const list of ["allow", "deny"]) {
|
|
4108
|
+
const entries = incoming[list];
|
|
4109
|
+
if (!entries || entries.length === 0) continue;
|
|
4110
|
+
const existing = Array.isArray(perms[list]) ? perms[list] : [];
|
|
4111
|
+
const existingSet = new Set(existing);
|
|
4112
|
+
for (const entry of entries) if (existingSet.has(entry)) report.push(chalk.dim(` Skipped: permissions.${list} "${entry}" already present`));
|
|
4113
|
+
else {
|
|
4114
|
+
existing.push(entry);
|
|
4115
|
+
existingSet.add(entry);
|
|
4116
|
+
report.push(chalk.green(` Added permissions.${list}: ${entry}`));
|
|
4117
|
+
changed = true;
|
|
4118
|
+
}
|
|
4119
|
+
perms[list] = existing;
|
|
4120
|
+
}
|
|
4121
|
+
settings["permissions"] = perms;
|
|
4122
|
+
return changed;
|
|
4123
|
+
}
|
|
4124
|
+
/**
|
|
4125
|
+
* Merge flags — set keys only if not already present, never overwrite.
|
|
4126
|
+
*/
|
|
4127
|
+
function mergeFlags(settings, incoming, report) {
|
|
4128
|
+
let changed = false;
|
|
4129
|
+
for (const [key, value] of Object.entries(incoming)) if (Object.prototype.hasOwnProperty.call(settings, key)) report.push(chalk.dim(` Skipped: ${key} already set`));
|
|
4130
|
+
else {
|
|
4131
|
+
settings[key] = value;
|
|
4132
|
+
report.push(chalk.green(` Added flag: ${key}`));
|
|
4133
|
+
changed = true;
|
|
4134
|
+
}
|
|
4135
|
+
return changed;
|
|
4136
|
+
}
|
|
4137
|
+
/**
|
|
4102
4138
|
* Merge env vars, hooks, and/or a statusLine entry into ~/.claude/settings.json.
|
|
4103
4139
|
* Never overwrites existing values — only adds what is missing.
|
|
4104
4140
|
*
|
|
@@ -4117,6 +4153,12 @@ function mergeSettings(opts) {
|
|
|
4117
4153
|
if (opts.statusLine !== void 0) {
|
|
4118
4154
|
if (mergeStatusLine(settings, opts.statusLine, report)) changed = true;
|
|
4119
4155
|
}
|
|
4156
|
+
if (opts.permissions !== void 0) {
|
|
4157
|
+
if (mergePermissions(settings, opts.permissions, report)) changed = true;
|
|
4158
|
+
}
|
|
4159
|
+
if (opts.flags !== void 0 && Object.keys(opts.flags).length > 0) {
|
|
4160
|
+
if (mergeFlags(settings, opts.flags, report)) changed = true;
|
|
4161
|
+
}
|
|
4120
4162
|
if (changed) writeSettingsJson(settings);
|
|
4121
4163
|
return {
|
|
4122
4164
|
changed,
|
|
@@ -4231,7 +4273,7 @@ function getDockerDir() {
|
|
|
4231
4273
|
const candidates = [
|
|
4232
4274
|
join(process.cwd(), "docker"),
|
|
4233
4275
|
join(homedir(), "dev", "ai", "PAI", "docker"),
|
|
4234
|
-
join("/", "usr", "local", "lib", "node_modules", "@
|
|
4276
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "docker")
|
|
4235
4277
|
];
|
|
4236
4278
|
for (const c of candidates) if (existsSync(join(c, "docker-compose.yml"))) return c;
|
|
4237
4279
|
return join(process.cwd(), "docker");
|
|
@@ -4240,7 +4282,7 @@ function getTemplatesDir$1() {
|
|
|
4240
4282
|
const candidates = [
|
|
4241
4283
|
join(process.cwd(), "templates"),
|
|
4242
4284
|
join(homedir(), "dev", "ai", "PAI", "templates"),
|
|
4243
|
-
join("/", "usr", "local", "lib", "node_modules", "@
|
|
4285
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "templates")
|
|
4244
4286
|
];
|
|
4245
4287
|
for (const c of candidates) if (existsSync(join(c, "claude-md.template.md"))) return c;
|
|
4246
4288
|
return join(process.cwd(), "templates");
|
|
@@ -4254,6 +4296,18 @@ function getHooksDir() {
|
|
|
4254
4296
|
for (const c of candidates) if (existsSync(join(c, "session-stop.sh"))) return c;
|
|
4255
4297
|
return join(process.cwd(), "src", "hooks");
|
|
4256
4298
|
}
|
|
4299
|
+
function getDistHooksDir() {
|
|
4300
|
+
const moduleDir = new URL(".", import.meta.url).pathname;
|
|
4301
|
+
const fromModule = join(moduleDir, "..", "hooks");
|
|
4302
|
+
const candidates = [
|
|
4303
|
+
fromModule,
|
|
4304
|
+
join(process.cwd(), "dist", "hooks"),
|
|
4305
|
+
join(homedir(), "dev", "ai", "PAI", "dist", "hooks"),
|
|
4306
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "dist", "hooks")
|
|
4307
|
+
];
|
|
4308
|
+
for (const candidate of candidates) if (existsSync(join(candidate, "stop-hook.mjs"))) return candidate;
|
|
4309
|
+
return fromModule;
|
|
4310
|
+
}
|
|
4257
4311
|
function getStatuslineScript() {
|
|
4258
4312
|
const candidates = [
|
|
4259
4313
|
join(process.cwd(), "statusline-command.sh"),
|
|
@@ -4263,6 +4317,15 @@ function getStatuslineScript() {
|
|
|
4263
4317
|
for (const c of candidates) if (existsSync(c)) return c;
|
|
4264
4318
|
return null;
|
|
4265
4319
|
}
|
|
4320
|
+
function getTabColorScript() {
|
|
4321
|
+
const candidates = [
|
|
4322
|
+
join(process.cwd(), "tab-color-command.sh"),
|
|
4323
|
+
join(homedir(), "dev", "ai", "PAI", "tab-color-command.sh"),
|
|
4324
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "tab-color-command.sh")
|
|
4325
|
+
];
|
|
4326
|
+
for (const c of candidates) if (existsSync(c)) return c;
|
|
4327
|
+
return null;
|
|
4328
|
+
}
|
|
4266
4329
|
async function startDocker(rl) {
|
|
4267
4330
|
const dockerDir = getDockerDir();
|
|
4268
4331
|
if (!existsSync(join(dockerDir, "docker-compose.yml"))) {
|
|
@@ -4583,10 +4646,57 @@ async function stepPaiSkill(rl) {
|
|
|
4583
4646
|
return true;
|
|
4584
4647
|
}
|
|
4585
4648
|
/**
|
|
4586
|
-
* Step 6:
|
|
4649
|
+
* Step 6: AI Steering Rules installation (~/.claude/skills/PAI/AI-STEERING-RULES.md)
|
|
4650
|
+
*/
|
|
4651
|
+
async function stepAiSteeringRules(rl) {
|
|
4652
|
+
section("Step 6: AI Steering Rules");
|
|
4653
|
+
line$1();
|
|
4654
|
+
line$1(" PAI ships a set of universal behavioral rules for AI assistants:");
|
|
4655
|
+
line$1(" surgical fixes, verification before assertion, root cause analysis,");
|
|
4656
|
+
line$1(" and honest failure modes. These rules load at startup as a skill.");
|
|
4657
|
+
line$1();
|
|
4658
|
+
const templatePath = join(getTemplatesDir$1(), "ai-steering-rules.template.md");
|
|
4659
|
+
if (!existsSync(templatePath)) {
|
|
4660
|
+
console.log(c.warn("AI steering rules template not found: " + templatePath));
|
|
4661
|
+
console.log(c.dim(" Skipping AI steering rules installation."));
|
|
4662
|
+
return false;
|
|
4663
|
+
}
|
|
4664
|
+
const skillDir = join(homedir(), ".claude", "skills", "PAI");
|
|
4665
|
+
const skillFile = join(skillDir, "AI-STEERING-RULES.md");
|
|
4666
|
+
if (existsSync(skillFile)) {
|
|
4667
|
+
const content = readFileSync(skillFile, "utf-8");
|
|
4668
|
+
const isGenerated = content.includes("Generated by PAI Setup");
|
|
4669
|
+
if (isGenerated) console.log(c.dim(" Found existing PAI-generated AI-STEERING-RULES.md."));
|
|
4670
|
+
else {
|
|
4671
|
+
console.log(c.yellow(" Found existing AI-STEERING-RULES.md (not PAI-generated)."));
|
|
4672
|
+
console.log(c.dim(" A backup will be created before overwriting."));
|
|
4673
|
+
}
|
|
4674
|
+
line$1();
|
|
4675
|
+
if (!await promptYesNo(rl, "Update ~/.claude/skills/PAI/AI-STEERING-RULES.md with the latest rules?", isGenerated)) {
|
|
4676
|
+
console.log(c.dim(" Keeping existing AI-STEERING-RULES.md unchanged."));
|
|
4677
|
+
return false;
|
|
4678
|
+
}
|
|
4679
|
+
if (!isGenerated) {
|
|
4680
|
+
const backupPath = skillFile + ".backup";
|
|
4681
|
+
writeFileSync(backupPath, content, "utf-8");
|
|
4682
|
+
console.log(c.ok(`Backed up existing AI-STEERING-RULES.md to ${backupPath}`));
|
|
4683
|
+
}
|
|
4684
|
+
} else if (!await promptYesNo(rl, "Install AI steering rules to ~/.claude/skills/PAI/AI-STEERING-RULES.md?", true)) {
|
|
4685
|
+
console.log(c.dim(" Skipping AI steering rules installation."));
|
|
4686
|
+
return false;
|
|
4687
|
+
}
|
|
4688
|
+
const template = readFileSync(templatePath, "utf-8");
|
|
4689
|
+
if (!existsSync(skillDir)) mkdirSync(skillDir, { recursive: true });
|
|
4690
|
+
writeFileSync(skillFile, template, "utf-8");
|
|
4691
|
+
line$1();
|
|
4692
|
+
console.log(c.ok("Installed ~/.claude/skills/PAI/AI-STEERING-RULES.md"));
|
|
4693
|
+
return true;
|
|
4694
|
+
}
|
|
4695
|
+
/**
|
|
4696
|
+
* Step 7: Hook scripts (pre-compact, session-stop, statusline)
|
|
4587
4697
|
*/
|
|
4588
4698
|
async function stepHooks(rl) {
|
|
4589
|
-
section("Step
|
|
4699
|
+
section("Step 7: Lifecycle Hooks");
|
|
4590
4700
|
line$1();
|
|
4591
4701
|
line$1(" PAI hooks fire on session stop and context compaction to save state,");
|
|
4592
4702
|
line$1(" update notes, and display live statusline information.");
|
|
@@ -4597,6 +4707,7 @@ async function stepHooks(rl) {
|
|
|
4597
4707
|
}
|
|
4598
4708
|
const hooksDir = getHooksDir();
|
|
4599
4709
|
const statuslineSrc = getStatuslineScript();
|
|
4710
|
+
const tabColorSrc = getTabColorScript();
|
|
4600
4711
|
const claudeDir = join(homedir(), ".claude");
|
|
4601
4712
|
const hooksTarget = join(claudeDir, "Hooks");
|
|
4602
4713
|
if (!existsSync(hooksTarget)) mkdirSync(hooksTarget, { recursive: true });
|
|
@@ -4623,38 +4734,240 @@ async function stepHooks(rl) {
|
|
|
4623
4734
|
installFile(join(hooksDir, "session-stop.sh"), join(hooksTarget, "pai-session-stop.sh"), "pai-session-stop.sh");
|
|
4624
4735
|
if (statuslineSrc) installFile(statuslineSrc, join(claudeDir, "statusline-command.sh"), "statusline-command.sh");
|
|
4625
4736
|
else console.log(c.warn(" statusline-command.sh not found — skipping statusline."));
|
|
4737
|
+
if (tabColorSrc) installFile(tabColorSrc, join(claudeDir, "tab-color-command.sh"), "tab-color-command.sh");
|
|
4738
|
+
else console.log(c.warn(" tab-color-command.sh not found — skipping tab color."));
|
|
4626
4739
|
return anyInstalled;
|
|
4627
4740
|
}
|
|
4628
4741
|
/**
|
|
4629
|
-
* Step
|
|
4742
|
+
* Step 7b: Install compiled TypeScript hooks (.mjs) to ~/.claude/Hooks/
|
|
4743
|
+
*
|
|
4744
|
+
* Finds all .mjs files in the package's dist/hooks/ directory and copies them
|
|
4745
|
+
* to ~/.claude/Hooks/. Content is compared before copying — identical files are
|
|
4746
|
+
* skipped for idempotent re-runs. Each installed file gets chmod 755.
|
|
4630
4747
|
*/
|
|
4631
|
-
async function
|
|
4632
|
-
section("Step
|
|
4748
|
+
async function stepTsHooks(rl) {
|
|
4749
|
+
section("Step 7b: TypeScript Hooks Installation");
|
|
4750
|
+
line$1();
|
|
4751
|
+
line$1(" PAI ships 14 compiled TypeScript hooks (.mjs) that fire on session events,");
|
|
4752
|
+
line$1(" tool use, and context compaction to capture context and update notes.");
|
|
4753
|
+
line$1();
|
|
4754
|
+
if (!await promptYesNo(rl, "Install PAI TypeScript hooks to ~/.claude/Hooks/?", true)) {
|
|
4755
|
+
console.log(c.dim(" Skipping TypeScript hooks installation."));
|
|
4756
|
+
return false;
|
|
4757
|
+
}
|
|
4758
|
+
const distHooksDir = getDistHooksDir();
|
|
4759
|
+
if (!existsSync(distHooksDir)) {
|
|
4760
|
+
console.log(c.warn(` dist/hooks/ directory not found at: ${distHooksDir}`));
|
|
4761
|
+
console.log(c.dim(" Build the package first: bun run build"));
|
|
4762
|
+
return false;
|
|
4763
|
+
}
|
|
4764
|
+
const hooksTarget = join(join(homedir(), ".claude"), "Hooks");
|
|
4765
|
+
if (!existsSync(hooksTarget)) mkdirSync(hooksTarget, { recursive: true });
|
|
4766
|
+
let allFiles;
|
|
4767
|
+
try {
|
|
4768
|
+
allFiles = readdirSync(distHooksDir).filter((f) => f.endsWith(".mjs"));
|
|
4769
|
+
} catch (e) {
|
|
4770
|
+
console.log(c.warn(` Could not read dist/hooks/: ${e}`));
|
|
4771
|
+
return false;
|
|
4772
|
+
}
|
|
4773
|
+
if (allFiles.length === 0) {
|
|
4774
|
+
console.log(c.warn(" No .mjs files found in dist/hooks/. Build first: bun run build"));
|
|
4775
|
+
return false;
|
|
4776
|
+
}
|
|
4633
4777
|
line$1();
|
|
4634
|
-
|
|
4778
|
+
let copiedCount = 0;
|
|
4779
|
+
let skippedCount = 0;
|
|
4780
|
+
for (const filename of allFiles) {
|
|
4781
|
+
const src = join(distHooksDir, filename);
|
|
4782
|
+
const dest = join(hooksTarget, filename);
|
|
4783
|
+
const srcContent = readFileSync(src, "utf-8");
|
|
4784
|
+
if (existsSync(dest)) {
|
|
4785
|
+
if (srcContent === readFileSync(dest, "utf-8")) {
|
|
4786
|
+
console.log(c.dim(` Unchanged: ${filename}`));
|
|
4787
|
+
skippedCount++;
|
|
4788
|
+
continue;
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
copyFileSync(src, dest);
|
|
4792
|
+
chmodSync(dest, 493);
|
|
4793
|
+
console.log(c.ok(`Installed: ${filename}`));
|
|
4794
|
+
copiedCount++;
|
|
4795
|
+
}
|
|
4796
|
+
line$1();
|
|
4797
|
+
if (copiedCount > 0) console.log(c.ok(`${copiedCount} hook(s) installed, ${skippedCount} unchanged.`));
|
|
4798
|
+
else console.log(c.dim(` All ${skippedCount} hook(s) already up-to-date.`));
|
|
4799
|
+
return copiedCount > 0;
|
|
4800
|
+
}
|
|
4801
|
+
/**
|
|
4802
|
+
* Step 8b: Prompt for the DA (Digital Assistant) name
|
|
4803
|
+
*
|
|
4804
|
+
* The name appears in tab titles, session notes, and hook output.
|
|
4805
|
+
* Stored in env.DA via settings merge.
|
|
4806
|
+
*/
|
|
4807
|
+
async function stepDaName(rl) {
|
|
4808
|
+
section("Step 8b: Assistant Name");
|
|
4809
|
+
line$1();
|
|
4810
|
+
line$1(" Choose a name for your AI assistant. This name appears in tab titles");
|
|
4811
|
+
line$1(" and session notes when hooks are active.");
|
|
4812
|
+
line$1();
|
|
4813
|
+
const daName = await prompt(rl, chalk.bold(" Assistant name [PAI]: ")) || "PAI";
|
|
4814
|
+
line$1();
|
|
4815
|
+
console.log(c.ok(`Assistant name set to: ${daName}`));
|
|
4816
|
+
return daName;
|
|
4817
|
+
}
|
|
4818
|
+
/**
|
|
4819
|
+
* Step 8: Patch ~/.claude/settings.json with PAI hooks, env vars, permissions, and flags
|
|
4820
|
+
*
|
|
4821
|
+
* Registers all 17 hook entries across 8 event types, adds env vars including DA name,
|
|
4822
|
+
* sets the statusline command, adds tool permissions (allow/deny), and sets flags.
|
|
4823
|
+
*/
|
|
4824
|
+
async function stepSettings(rl, daName) {
|
|
4825
|
+
section("Step 8: Settings Patch");
|
|
4826
|
+
line$1();
|
|
4827
|
+
line$1(" PAI will add env vars, all hook registrations, permissions, and flags");
|
|
4635
4828
|
line$1(" to ~/.claude/settings.json. Existing values are never overwritten.");
|
|
4636
4829
|
line$1();
|
|
4637
|
-
if (!await promptYesNo(rl, "Patch ~/.claude/settings.json with PAI hooks, env vars, and
|
|
4830
|
+
if (!await promptYesNo(rl, "Patch ~/.claude/settings.json with PAI hooks, env vars, and settings?", true)) {
|
|
4638
4831
|
console.log(c.dim(" Skipping settings patch."));
|
|
4639
4832
|
return false;
|
|
4640
4833
|
}
|
|
4641
4834
|
const result = mergeSettings({
|
|
4642
4835
|
env: {
|
|
4643
4836
|
PAI_DIR: join(homedir(), ".claude"),
|
|
4644
|
-
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "80"
|
|
4837
|
+
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "80",
|
|
4838
|
+
CLAUDE_CODE_MAX_OUTPUT_TOKENS: "64000",
|
|
4839
|
+
DA: daName
|
|
4645
4840
|
},
|
|
4646
|
-
hooks: [
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4841
|
+
hooks: [
|
|
4842
|
+
{
|
|
4843
|
+
hookType: "SessionStart",
|
|
4844
|
+
command: "${PAI_DIR}/Hooks/load-core-context.mjs"
|
|
4845
|
+
},
|
|
4846
|
+
{
|
|
4847
|
+
hookType: "SessionStart",
|
|
4848
|
+
command: "${PAI_DIR}/Hooks/load-project-context.mjs"
|
|
4849
|
+
},
|
|
4850
|
+
{
|
|
4851
|
+
hookType: "SessionStart",
|
|
4852
|
+
command: "${PAI_DIR}/Hooks/initialize-session.mjs"
|
|
4853
|
+
},
|
|
4854
|
+
{
|
|
4855
|
+
hookType: "SessionStart",
|
|
4856
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SessionStart"
|
|
4857
|
+
},
|
|
4858
|
+
{
|
|
4859
|
+
hookType: "UserPromptSubmit",
|
|
4860
|
+
command: "${PAI_DIR}/Hooks/cleanup-session-files.mjs"
|
|
4861
|
+
},
|
|
4862
|
+
{
|
|
4863
|
+
hookType: "UserPromptSubmit",
|
|
4864
|
+
command: "${PAI_DIR}/Hooks/update-tab-titles.mjs"
|
|
4865
|
+
},
|
|
4866
|
+
{
|
|
4867
|
+
hookType: "UserPromptSubmit",
|
|
4868
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type UserPromptSubmit"
|
|
4869
|
+
},
|
|
4870
|
+
{
|
|
4871
|
+
hookType: "PreToolUse",
|
|
4872
|
+
matcher: "Bash",
|
|
4873
|
+
command: "${PAI_DIR}/Hooks/security-validator.mjs"
|
|
4874
|
+
},
|
|
4875
|
+
{
|
|
4876
|
+
hookType: "PreToolUse",
|
|
4877
|
+
matcher: "*",
|
|
4878
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PreToolUse"
|
|
4879
|
+
},
|
|
4880
|
+
{
|
|
4881
|
+
hookType: "PostToolUse",
|
|
4882
|
+
matcher: "TodoWrite",
|
|
4883
|
+
command: "${PAI_DIR}/Hooks/sync-todo-to-md.mjs"
|
|
4884
|
+
},
|
|
4885
|
+
{
|
|
4886
|
+
hookType: "PostToolUse",
|
|
4887
|
+
matcher: "*",
|
|
4888
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PostToolUse"
|
|
4889
|
+
},
|
|
4890
|
+
{
|
|
4891
|
+
hookType: "PostToolUse",
|
|
4892
|
+
matcher: "*",
|
|
4893
|
+
command: "${PAI_DIR}/Hooks/capture-tool-output.mjs"
|
|
4894
|
+
},
|
|
4895
|
+
{
|
|
4896
|
+
hookType: "PostToolUse",
|
|
4897
|
+
matcher: "*",
|
|
4898
|
+
command: "${PAI_DIR}/Hooks/update-tab-on-action.mjs"
|
|
4899
|
+
},
|
|
4900
|
+
{
|
|
4901
|
+
hookType: "Stop",
|
|
4902
|
+
command: "${PAI_DIR}/Hooks/stop-hook.mjs"
|
|
4903
|
+
},
|
|
4904
|
+
{
|
|
4905
|
+
hookType: "Stop",
|
|
4906
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type Stop"
|
|
4907
|
+
},
|
|
4908
|
+
{
|
|
4909
|
+
hookType: "Stop",
|
|
4910
|
+
command: "${PAI_DIR}/Hooks/pai-session-stop.sh"
|
|
4911
|
+
},
|
|
4912
|
+
{
|
|
4913
|
+
hookType: "SubagentStop",
|
|
4914
|
+
command: "${PAI_DIR}/Hooks/subagent-stop-hook.mjs"
|
|
4915
|
+
},
|
|
4916
|
+
{
|
|
4917
|
+
hookType: "SubagentStop",
|
|
4918
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SubagentStop"
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
hookType: "SessionEnd",
|
|
4922
|
+
command: "${PAI_DIR}/Hooks/capture-session-summary.mjs"
|
|
4923
|
+
},
|
|
4924
|
+
{
|
|
4925
|
+
hookType: "SessionEnd",
|
|
4926
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SessionEnd"
|
|
4927
|
+
},
|
|
4928
|
+
{
|
|
4929
|
+
hookType: "PreCompact",
|
|
4930
|
+
command: "${PAI_DIR}/Hooks/context-compression-hook.mjs"
|
|
4931
|
+
},
|
|
4932
|
+
{
|
|
4933
|
+
hookType: "PreCompact",
|
|
4934
|
+
command: "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PreCompact"
|
|
4935
|
+
},
|
|
4936
|
+
{
|
|
4937
|
+
hookType: "PreCompact",
|
|
4938
|
+
matcher: "",
|
|
4939
|
+
command: "${PAI_DIR}/Hooks/pai-pre-compact.sh"
|
|
4940
|
+
}
|
|
4941
|
+
],
|
|
4654
4942
|
statusLine: {
|
|
4655
4943
|
type: "command",
|
|
4656
4944
|
command: "bash ${PAI_DIR}/statusline-command.sh"
|
|
4657
|
-
}
|
|
4945
|
+
},
|
|
4946
|
+
permissions: {
|
|
4947
|
+
allow: [
|
|
4948
|
+
"Bash",
|
|
4949
|
+
"Read",
|
|
4950
|
+
"Write",
|
|
4951
|
+
"Edit",
|
|
4952
|
+
"Glob",
|
|
4953
|
+
"Grep",
|
|
4954
|
+
"WebFetch",
|
|
4955
|
+
"WebSearch",
|
|
4956
|
+
"NotebookEdit",
|
|
4957
|
+
"TodoWrite",
|
|
4958
|
+
"ExitPlanMode",
|
|
4959
|
+
"mcp__pai"
|
|
4960
|
+
],
|
|
4961
|
+
deny: [
|
|
4962
|
+
"Bash(rm -rf /)",
|
|
4963
|
+
"Bash(rm -rf /*)",
|
|
4964
|
+
"Bash(rm -rf ~)",
|
|
4965
|
+
"Bash(rm -rf $HOME)",
|
|
4966
|
+
"Bash(sudo rm -rf /)",
|
|
4967
|
+
"Bash(sudo rm -rf /*)"
|
|
4968
|
+
]
|
|
4969
|
+
},
|
|
4970
|
+
flags: { enableAllProjectMcpServers: true }
|
|
4658
4971
|
});
|
|
4659
4972
|
line$1();
|
|
4660
4973
|
for (const r of result.report) console.log(r);
|
|
@@ -4662,10 +4975,10 @@ async function stepSettings(rl) {
|
|
|
4662
4975
|
return result.changed;
|
|
4663
4976
|
}
|
|
4664
4977
|
/**
|
|
4665
|
-
* Step
|
|
4978
|
+
* Step 9: Daemon install (launchd plist)
|
|
4666
4979
|
*/
|
|
4667
4980
|
async function stepDaemon(rl) {
|
|
4668
|
-
section("Step
|
|
4981
|
+
section("Step 9: Daemon Install");
|
|
4669
4982
|
line$1();
|
|
4670
4983
|
line$1(" The PAI daemon indexes your projects every 5 minutes in the background.");
|
|
4671
4984
|
line$1();
|
|
@@ -4689,10 +5002,10 @@ async function stepDaemon(rl) {
|
|
|
4689
5002
|
return true;
|
|
4690
5003
|
}
|
|
4691
5004
|
/**
|
|
4692
|
-
* Step
|
|
5005
|
+
* Step 10: MCP registration in ~/.claude.json
|
|
4693
5006
|
*/
|
|
4694
5007
|
async function stepMcp(rl) {
|
|
4695
|
-
section("Step
|
|
5008
|
+
section("Step 10: MCP Registration");
|
|
4696
5009
|
line$1();
|
|
4697
5010
|
line$1(" Registering the PAI MCP server lets Claude Code call PAI tools directly.");
|
|
4698
5011
|
line$1();
|
|
@@ -4719,10 +5032,10 @@ async function stepMcp(rl) {
|
|
|
4719
5032
|
return true;
|
|
4720
5033
|
}
|
|
4721
5034
|
/**
|
|
4722
|
-
* Step
|
|
5035
|
+
* Step 11: Directory scanning configuration
|
|
4723
5036
|
*/
|
|
4724
5037
|
async function stepDirectories(rl) {
|
|
4725
|
-
section("Step
|
|
5038
|
+
section("Step 11: Directories to Index");
|
|
4726
5039
|
line$1();
|
|
4727
5040
|
line$1(" PAI indexes files in your registered projects. You can register projects");
|
|
4728
5041
|
line$1(" individually with `pai project add <path>`, or let the registry scanner");
|
|
@@ -4749,10 +5062,10 @@ async function stepDirectories(rl) {
|
|
|
4749
5062
|
stepDirectories._runScan = runScan;
|
|
4750
5063
|
}
|
|
4751
5064
|
/**
|
|
4752
|
-
* Step
|
|
5065
|
+
* Step 12: Initial index
|
|
4753
5066
|
*/
|
|
4754
5067
|
async function stepInitialIndex(rl) {
|
|
4755
|
-
section("Step
|
|
5068
|
+
section("Step 12: Initial Index");
|
|
4756
5069
|
line$1();
|
|
4757
5070
|
line$1(" Indexing scans your registered projects and builds the search index.");
|
|
4758
5071
|
line$1(" The daemon runs indexing automatically every 5 minutes once started.");
|
|
@@ -4794,9 +5107,9 @@ async function stepInitialIndex(rl) {
|
|
|
4794
5107
|
}
|
|
4795
5108
|
}
|
|
4796
5109
|
/**
|
|
4797
|
-
* Step
|
|
5110
|
+
* Step 13: Summary and next steps
|
|
4798
5111
|
*/
|
|
4799
|
-
function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, hooksInstalled, settingsPatched, daemonInstalled, mcpRegistered) {
|
|
5112
|
+
function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered) {
|
|
4800
5113
|
section("Setup Complete");
|
|
4801
5114
|
line$1();
|
|
4802
5115
|
console.log(c.ok("PAI Knowledge OS is configured!"));
|
|
@@ -4809,8 +5122,11 @@ function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, hooksI
|
|
|
4809
5122
|
console.log(chalk.dim(" Embedding model: ") + chalk.cyan(model && model !== "none" ? model : "(none — keyword search only)"));
|
|
4810
5123
|
console.log(chalk.dim(" CLAUDE.md: ") + chalk.cyan(claudeMdGenerated ? "~/.claude/CLAUDE.md (generated)" : "(unchanged)"));
|
|
4811
5124
|
console.log(chalk.dim(" PAI skill: ") + chalk.cyan(paiSkillInstalled ? "~/.claude/skills/PAI/SKILL.md (installed)" : "(unchanged)"));
|
|
4812
|
-
console.log(chalk.dim("
|
|
4813
|
-
console.log(chalk.dim("
|
|
5125
|
+
console.log(chalk.dim(" Steering rules: ") + chalk.cyan(aiSteeringRulesInstalled ? "~/.claude/skills/PAI/AI-STEERING-RULES.md (installed)" : "(unchanged)"));
|
|
5126
|
+
console.log(chalk.dim(" Hooks (shell): ") + chalk.cyan(hooksInstalled ? "pai-pre-compact.sh, pai-session-stop.sh (installed)" : "(unchanged)"));
|
|
5127
|
+
console.log(chalk.dim(" Hooks (TS): ") + chalk.cyan(tsHooksInstalled ? "14 .mjs hooks installed to ~/.claude/Hooks/" : "(unchanged)"));
|
|
5128
|
+
console.log(chalk.dim(" Assistant name: ") + chalk.cyan(daName));
|
|
5129
|
+
console.log(chalk.dim(" Settings: ") + chalk.cyan(settingsPatched ? "env vars, hooks, permissions, flags (patched)" : "(unchanged)"));
|
|
4814
5130
|
console.log(chalk.dim(" Daemon: ") + chalk.cyan(daemonInstalled ? "com.pai.pai-daemon (installed)" : "(unchanged)"));
|
|
4815
5131
|
console.log(chalk.dim(" MCP: ") + chalk.cyan(mcpRegistered ? "registered in ~/.claude.json" : "(unchanged)"));
|
|
4816
5132
|
line$1();
|
|
@@ -4866,8 +5182,11 @@ async function runSetup() {
|
|
|
4866
5182
|
const embeddingConfig = await stepEmbedding(rl);
|
|
4867
5183
|
const claudeMdGenerated = await stepClaudeMd(rl);
|
|
4868
5184
|
const paiSkillInstalled = await stepPaiSkill(rl);
|
|
5185
|
+
const aiSteeringRulesInstalled = await stepAiSteeringRules(rl);
|
|
4869
5186
|
const hooksInstalled = await stepHooks(rl);
|
|
4870
|
-
const
|
|
5187
|
+
const tsHooksInstalled = await stepTsHooks(rl);
|
|
5188
|
+
const daName = await stepDaName(rl);
|
|
5189
|
+
const settingsPatched = await stepSettings(rl, daName);
|
|
4871
5190
|
const daemonInstalled = await stepDaemon(rl);
|
|
4872
5191
|
const mcpRegistered = await stepMcp(rl);
|
|
4873
5192
|
await stepDirectories(rl);
|
|
@@ -4879,7 +5198,7 @@ async function runSetup() {
|
|
|
4879
5198
|
line$1();
|
|
4880
5199
|
console.log(c.ok("Configuration saved."));
|
|
4881
5200
|
await stepInitialIndex(rl);
|
|
4882
|
-
stepSummary(allUpdates, claudeMdGenerated, paiSkillInstalled, hooksInstalled, settingsPatched, daemonInstalled, mcpRegistered);
|
|
5201
|
+
stepSummary(allUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered);
|
|
4883
5202
|
} finally {
|
|
4884
5203
|
rl.close();
|
|
4885
5204
|
}
|