@tekmidian/pai 0.6.0 → 0.6.2
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 +201 -56
- package/FEATURE.md +2 -2
- package/dist/cli/index.mjs +100 -3
- package/dist/cli/index.mjs.map +1 -1
- package/dist/daemon-mcp/index.mjs +37 -6
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/skills/Art/SKILL.md +32 -0
- package/dist/skills/Createskill/SKILL.md +23 -0
- package/dist/skills/Journal/SKILL.md +34 -0
- package/dist/skills/Name/SKILL.md +12 -0
- package/dist/skills/Observability/SKILL.md +25 -0
- package/dist/skills/Plan/SKILL.md +28 -0
- package/dist/skills/Research/SKILL.md +30 -0
- package/dist/skills/Review/SKILL.md +58 -0
- package/dist/skills/Route/SKILL.md +14 -0
- package/dist/skills/SearchHistory/SKILL.md +31 -0
- package/dist/skills/Sessions/SKILL.md +28 -0
- package/dist/skills/Share/SKILL.md +35 -0
- package/dist/skills/StoryExplanation/SKILL.md +21 -0
- package/dist/skills/VaultConnect/SKILL.md +10 -0
- package/dist/skills/VaultContext/SKILL.md +12 -0
- package/dist/skills/VaultEmerge/SKILL.md +10 -0
- package/dist/skills/VaultOrphans/SKILL.md +10 -0
- package/dist/skills/VaultTrace/SKILL.md +10 -0
- package/package.json +3 -2
- package/scripts/build-skill-stubs.mjs +202 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -95,15 +95,23 @@ docker run -d \
|
|
|
95
95
|
pai setup
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
The interactive wizard walks through
|
|
98
|
+
The interactive wizard walks through 14 steps:
|
|
99
99
|
|
|
100
|
-
1.
|
|
101
|
-
2.
|
|
102
|
-
3.
|
|
100
|
+
1. Welcome and version check
|
|
101
|
+
2. Storage backend selection (SQLite or PostgreSQL)
|
|
102
|
+
3. Embedding model configuration
|
|
103
103
|
4. CLAUDE.md template installation
|
|
104
|
-
5.
|
|
105
|
-
6.
|
|
106
|
-
7. MCP
|
|
104
|
+
5. PAI skill installation
|
|
105
|
+
6. Steering rules installation
|
|
106
|
+
7. MCP skill stub symlinks
|
|
107
|
+
8. Hook system deployment
|
|
108
|
+
9. TypeScript hook compilation
|
|
109
|
+
10. Claude Code settings configuration
|
|
110
|
+
11. Daemon installation
|
|
111
|
+
12. MCP server registration
|
|
112
|
+
13. Directory creation
|
|
113
|
+
14. Initial indexing
|
|
114
|
+
15. Verification
|
|
107
115
|
|
|
108
116
|
### 4. Install the Daemon
|
|
109
117
|
|
|
@@ -143,7 +151,7 @@ If both commands return healthy output, PAI is running. Open a new Claude Code s
|
|
|
143
151
|
|
|
144
152
|
## MCP Server
|
|
145
153
|
|
|
146
|
-
PAI exposes
|
|
154
|
+
PAI exposes 9 tools, 18 on-demand prompts (skills), and 11 reference resources to Claude Code via a daemon-backed MCP shim. The shim speaks stdio (what Claude Code expects) and proxies each request to the background daemon over NDJSON on a Unix socket.
|
|
147
155
|
|
|
148
156
|
```
|
|
149
157
|
Claude Code (stdio)
|
|
@@ -164,14 +172,8 @@ Claude Code (stdio)
|
|
|
164
172
|
| `session_list` | List session notes, optionally filtered by project |
|
|
165
173
|
| `registry_search` | Search project metadata (names, paths, tags) |
|
|
166
174
|
| `project_detect` | Identify which project a given path belongs to |
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `zettel_explore` | BFS traversal of wikilink graph from a seed note |
|
|
170
|
-
| `zettel_surprise` | Find semantically distant but graph-close notes |
|
|
171
|
-
| `zettel_converse` | Hybrid search with graph expansion and cross-domain connections |
|
|
172
|
-
| `zettel_themes` | Cluster vault notes into thematic groups by embedding similarity |
|
|
173
|
-
| `zettel_health` | Audit vault for broken links, orphans, and isolated clusters |
|
|
174
|
-
| `zettel_suggest` | Suggest link targets weighted by semantics, tags, and graph neighborhood |
|
|
175
|
+
| `project_health` | Audit all registered paths for moved or deleted directories |
|
|
176
|
+
| `project_todo` | Read a project's TODO.md and continuation prompt |
|
|
175
177
|
|
|
176
178
|
### Tool Reference
|
|
177
179
|
|
|
@@ -189,21 +191,52 @@ Claude Code (stdio)
|
|
|
189
191
|
|
|
190
192
|
**`project_detect(path?)`** — Given a filesystem path (defaults to CWD), returns the matching project.
|
|
191
193
|
|
|
192
|
-
**`
|
|
194
|
+
**`project_health(category?)`** — Audits all registered projects to find moved or deleted directories. Categorizes each as `active` (path exists), `stale` (path missing but candidate found nearby), or `dead` (path missing, no candidate). Also reports TODO.md presence and continuation prompts.
|
|
193
195
|
|
|
194
|
-
**`
|
|
196
|
+
**`project_todo(project?)`** — Reads a project's TODO.md without needing the exact file path. Searches Notes/TODO.md, .claude/Notes/TODO.md, tasks/todo.md, and project-root TODO.md in order. Surfaces any `## Continue` section at the top for quick context recovery.
|
|
195
197
|
|
|
196
|
-
|
|
198
|
+
### On-Demand Prompts (Skills)
|
|
197
199
|
|
|
198
|
-
|
|
200
|
+
The MCP server registers 18 prompts that Claude can invoke as on-demand skills. Each prompt provides a focused workflow with instructions, examples, and constraints — loaded only when needed to conserve context.
|
|
199
201
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
| Prompt | Purpose |
|
|
203
|
+
|--------|---------|
|
|
204
|
+
| `art` | Visual art direction and creative guidance |
|
|
205
|
+
| `createskill` | Scaffold new PAI skills |
|
|
206
|
+
| `journal` | Structured journaling workflow |
|
|
207
|
+
| `name` | Session and project naming conventions |
|
|
208
|
+
| `observability` | Observation system usage and querying |
|
|
209
|
+
| `plan` | Forward-looking planning from TODOs and recent activity |
|
|
210
|
+
| `research` | Structured research methodology |
|
|
211
|
+
| `review` | Retrospective review of work over a time period |
|
|
212
|
+
| `route` | Session note routing across projects |
|
|
213
|
+
| `search-history` | Search history analysis and patterns |
|
|
214
|
+
| `sessions` | Session lifecycle management |
|
|
215
|
+
| `share` | Generate social media posts from recent work |
|
|
216
|
+
| `story-explanation` | Narrative explanations of technical concepts |
|
|
217
|
+
| `vault-connect` | Suggest and create vault connections |
|
|
218
|
+
| `vault-context` | Use vault as conversational context |
|
|
219
|
+
| `vault-emerge` | Detect emerging themes in the vault |
|
|
220
|
+
| `vault-orphans` | Find and fix orphaned vault notes |
|
|
221
|
+
| `vault-trace` | Trace idea lineage through vault links |
|
|
222
|
+
|
|
223
|
+
### Reference Resources
|
|
224
|
+
|
|
225
|
+
11 resources available via `pai://` URIs. Claude reads these on demand for reference documentation.
|
|
226
|
+
|
|
227
|
+
| URI | Content |
|
|
228
|
+
|-----|---------|
|
|
229
|
+
| `pai://aesthetic` | Visual and output style guidelines |
|
|
230
|
+
| `pai://constitution` | Core philosophy and principles |
|
|
231
|
+
| `pai://history-system` | Search history tracking system |
|
|
232
|
+
| `pai://hook-system` | Hook architecture and development guide |
|
|
233
|
+
| `pai://mcp-dev-guide` | MCP server development patterns |
|
|
234
|
+
| `pai://prompting` | Prompt engineering best practices |
|
|
235
|
+
| `pai://prosody-agent-template` | Voice agent template |
|
|
236
|
+
| `pai://prosody-guide` | Voice and prosody guidelines |
|
|
237
|
+
| `pai://skill-system` | Skill authoring reference |
|
|
238
|
+
| `pai://terminal-tabs` | Terminal tab management |
|
|
239
|
+
| `pai://voice` | Voice configuration reference |
|
|
207
240
|
|
|
208
241
|
### Installation
|
|
209
242
|
|
|
@@ -418,7 +451,7 @@ pai observation stats
|
|
|
418
451
|
```bash
|
|
419
452
|
pai backup # Backup registry, config, and Postgres
|
|
420
453
|
pai restore <path> # Restore from backup (--no-postgres to skip DB)
|
|
421
|
-
pai setup # Interactive
|
|
454
|
+
pai setup # Interactive 14-step setup wizard
|
|
422
455
|
pai search "query" # Quick full-text search shortcut
|
|
423
456
|
```
|
|
424
457
|
|
|
@@ -610,6 +643,68 @@ The build script compiles each `.ts` hook to a self-contained `.mjs` module usin
|
|
|
610
643
|
|
|
611
644
|
---
|
|
612
645
|
|
|
646
|
+
## Skill Stub System
|
|
647
|
+
|
|
648
|
+
PAI's 18 MCP prompts are exposed to Claude Code as discoverable skills via auto-generated SKILL.md files. This bridges the gap between MCP prompts (protocol-level, invoked via `prompts/get`) and Claude Code's skill scanner (filesystem-based, scans `~/.claude/skills/`).
|
|
649
|
+
|
|
650
|
+
### How It Works
|
|
651
|
+
|
|
652
|
+
```
|
|
653
|
+
Source (TypeScript) Build Claude Code
|
|
654
|
+
───────────────── ───── ──────────
|
|
655
|
+
src/daemon-mcp/prompts/*.ts → dist/skills/<Name>/ → ~/.claude/skills/<Name>/
|
|
656
|
+
src/daemon-mcp/prompts/ SKILL.md (symlink)
|
|
657
|
+
custom/*.ts (gitignored)
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
1. **Source of truth**: TypeScript files in `src/daemon-mcp/prompts/`. Each exports `{ description, content }`.
|
|
661
|
+
2. **Build**: `node scripts/build-skill-stubs.mjs --sync` extracts content and generates `dist/skills/<TitleCase>/SKILL.md` with YAML frontmatter.
|
|
662
|
+
3. **Sync**: The `--sync` flag creates/updates symlinks in `~/.claude/skills/`. Runs automatically on every `bun run build`.
|
|
663
|
+
4. **Discovery**: Claude Code scans `~/.claude/skills/<Name>/SKILL.md` at session start, loads descriptions, and auto-invokes matching skills.
|
|
664
|
+
|
|
665
|
+
**Important**: Skills MUST be at `~/.claude/skills/<Name>/SKILL.md` (one level deep). Subdirectories like `~/.claude/skills/user/<Name>/` are NOT discovered by Claude Code's scanner.
|
|
666
|
+
|
|
667
|
+
### Adding a New Skill
|
|
668
|
+
|
|
669
|
+
**Built-in (shipped with PAI):**
|
|
670
|
+
|
|
671
|
+
1. Create `src/daemon-mcp/prompts/my-skill.ts`:
|
|
672
|
+
```typescript
|
|
673
|
+
export const mySkill = {
|
|
674
|
+
description: "What the skill does",
|
|
675
|
+
content: `## My Skill
|
|
676
|
+
|
|
677
|
+
USE WHEN user says 'trigger phrase', 'another trigger', ...
|
|
678
|
+
|
|
679
|
+
### Instructions
|
|
680
|
+
...your skill content here...`,
|
|
681
|
+
};
|
|
682
|
+
```
|
|
683
|
+
2. Add export to `src/daemon-mcp/prompts/index.ts`:
|
|
684
|
+
```typescript
|
|
685
|
+
export { mySkill } from "./my-skill.js";
|
|
686
|
+
```
|
|
687
|
+
3. Run `bun run build` — generates the stub AND syncs the symlink.
|
|
688
|
+
|
|
689
|
+
**Custom (user-created, survives `git pull`):**
|
|
690
|
+
|
|
691
|
+
1. Create `src/daemon-mcp/prompts/custom/my-local-skill.ts` (same format as above).
|
|
692
|
+
2. Run `bun run build` — custom prompts are picked up automatically.
|
|
693
|
+
|
|
694
|
+
The `custom/` directory is gitignored (only `.gitkeep` is tracked), so your local skills survive PAI updates.
|
|
695
|
+
|
|
696
|
+
### Updating After Changes
|
|
697
|
+
|
|
698
|
+
Symlinks point to `dist/skills/`, so any `bun run build` automatically updates what Claude Code sees. No manual steps needed.
|
|
699
|
+
|
|
700
|
+
If you reorganize prompts (rename, delete, add), the build script regenerates all stubs and the `--sync` flag updates symlinks accordingly. Stale symlinks pointing to removed stubs are cleaned up automatically.
|
|
701
|
+
|
|
702
|
+
### Setup Integration
|
|
703
|
+
|
|
704
|
+
`pai setup` (Step 7) runs the same symlink logic interactively, asking before creating symlinks. It also cleans up legacy symlinks from the old `~/.claude/skills/user/` location.
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
613
708
|
## Templates
|
|
614
709
|
|
|
615
710
|
PAI ships three templates used during setup and customizable for your workflow.
|
|
@@ -819,41 +914,91 @@ bun run lint # tsc --noEmit
|
|
|
819
914
|
| Output | Purpose |
|
|
820
915
|
|--------|---------|
|
|
821
916
|
| `dist/cli/index.mjs` | `pai` CLI |
|
|
822
|
-
| `dist/mcp/index.mjs` | Direct MCP server (legacy) |
|
|
823
917
|
| `dist/daemon/index.mjs` | Daemon server |
|
|
824
918
|
| `dist/daemon-mcp/index.mjs` | MCP shim (stdio → daemon socket) |
|
|
919
|
+
| `dist/hooks/*.mjs` | Compiled lifecycle hooks |
|
|
920
|
+
| `dist/skills/<Name>/SKILL.md` | Generated skill stubs (symlinked to ~/.claude/skills/) |
|
|
825
921
|
|
|
826
922
|
### Source Structure
|
|
827
923
|
|
|
828
924
|
```
|
|
829
925
|
src/
|
|
830
|
-
├── cli/
|
|
831
|
-
│
|
|
832
|
-
├──
|
|
833
|
-
├── daemon
|
|
834
|
-
├──
|
|
835
|
-
├──
|
|
836
|
-
├──
|
|
837
|
-
├──
|
|
838
|
-
│ ├──
|
|
839
|
-
│
|
|
840
|
-
├──
|
|
841
|
-
│ ├──
|
|
842
|
-
│
|
|
843
|
-
│ └──
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
├──
|
|
847
|
-
├──
|
|
848
|
-
├──
|
|
849
|
-
└──
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
926
|
+
├── cli/
|
|
927
|
+
│ ├── commands/ # CLI command modules
|
|
928
|
+
│ │ ├── backup.ts
|
|
929
|
+
│ │ ├── daemon.ts
|
|
930
|
+
│ │ ├── memory.ts
|
|
931
|
+
│ │ ├── observation.ts
|
|
932
|
+
│ │ ├── obsidian.ts
|
|
933
|
+
│ │ ├── project.ts
|
|
934
|
+
│ │ ├── registry.ts
|
|
935
|
+
│ │ ├── session.ts
|
|
936
|
+
│ │ ├── setup/ # 14-step interactive wizard
|
|
937
|
+
│ │ │ ├── steps/ # 01-welcome through 15-verify
|
|
938
|
+
│ │ │ └── index.ts
|
|
939
|
+
│ │ └── zettel.ts
|
|
940
|
+
│ └── index.ts # CLI entry point
|
|
941
|
+
├── daemon/
|
|
942
|
+
│ ├── daemon/ # Daemon server internals
|
|
943
|
+
│ │ ├── dispatcher.ts # Tool dispatch (zettel, observation, memory)
|
|
944
|
+
│ │ ├── handler.ts # NDJSON request handler
|
|
945
|
+
│ │ └── server.ts # Socket server
|
|
946
|
+
│ ├── indexer/ # Background index scheduler
|
|
947
|
+
│ ├── config.ts # Runtime configuration
|
|
948
|
+
│ └── index.ts # Daemon entry point
|
|
949
|
+
├── daemon-mcp/
|
|
950
|
+
│ ├── instructions.ts # MCP server instructions (~1.5KB routing table)
|
|
951
|
+
│ ├── prompts/ # 18 on-demand skill prompts
|
|
952
|
+
│ │ └── custom/ # User-created prompts (gitignored)
|
|
953
|
+
│ ├── resources/ # 11 reference resources (pai:// URIs)
|
|
954
|
+
│ └── index.ts # MCP shim entry point (stdio → socket)
|
|
955
|
+
├── hooks/
|
|
956
|
+
│ └── ts/ # TypeScript hook sources by event
|
|
957
|
+
│ ├── PreCompact/
|
|
958
|
+
│ ├── PreToolUse/
|
|
959
|
+
│ ├── PostToolUse/
|
|
960
|
+
│ ├── SessionStart/
|
|
961
|
+
│ ├── Stop/
|
|
962
|
+
│ └── UserPromptSubmit/
|
|
963
|
+
├── mcp/
|
|
964
|
+
│ └── tools/ # Shared tool implementations
|
|
965
|
+
│ ├── memory.ts
|
|
966
|
+
│ ├── observations.ts
|
|
967
|
+
│ ├── projects.ts
|
|
968
|
+
│ ├── registry.ts
|
|
969
|
+
│ ├── sessions.ts
|
|
970
|
+
│ └── zettel.ts
|
|
971
|
+
├── memory/
|
|
972
|
+
│ ├── chunker/ # Text chunking strategies
|
|
973
|
+
│ ├── embeddings.ts # Snowflake Arctic embedding generation
|
|
974
|
+
│ ├── indexer.ts # File indexer with change detection
|
|
975
|
+
│ ├── reranker.ts # Cross-encoder reranking (ms-marco-MiniLM)
|
|
976
|
+
│ ├── search.ts # Multi-mode search (keyword/semantic/hybrid)
|
|
977
|
+
│ └── vault-indexer.ts # Obsidian vault indexing
|
|
978
|
+
├── observations/ # Automatic observation capture
|
|
979
|
+
│ ├── classifier.ts # Rule-based tool call classifier
|
|
980
|
+
│ ├── store.ts # PostgreSQL persistence with deduplication
|
|
981
|
+
│ └── schema.sql # DDL for observation tables
|
|
982
|
+
├── obsidian/ # Obsidian vault bridge
|
|
983
|
+
│ └── vault-fixer.ts # Repairs broken wikilinks and orphans
|
|
984
|
+
├── registry/ # SQLite registry queries and migrations
|
|
985
|
+
├── session/ # Session slug generator
|
|
986
|
+
├── storage/ # Pluggable storage backend
|
|
987
|
+
│ ├── factory.ts # Backend selection (SQLite/PostgreSQL)
|
|
988
|
+
│ ├── interface.ts # StorageInterface contract
|
|
989
|
+
│ ├── postgres.ts # PostgreSQL + pgvector backend
|
|
990
|
+
│ └── sqlite.ts # SQLite backend
|
|
991
|
+
├── utils/ # Shared utilities
|
|
992
|
+
│ ├── hash.ts # SHA-256 hashing
|
|
993
|
+
│ └── stop-words.ts # Stop word lists for search
|
|
994
|
+
├── zettelkasten/ # Luhmann-inspired operations
|
|
995
|
+
│ ├── explore.ts # BFS traversal
|
|
996
|
+
│ ├── surprise.ts # Serendipitous bridge discovery
|
|
997
|
+
│ ├── converse.ts # Hybrid search + graph expansion
|
|
998
|
+
│ ├── themes.ts # Embedding clustering
|
|
999
|
+
│ ├── health.ts # Vault structural audit
|
|
1000
|
+
│ └── suggest.ts # Weighted link suggestions
|
|
1001
|
+
└── index.ts # Package entry point
|
|
857
1002
|
```
|
|
858
1003
|
|
|
859
1004
|
### Important Notes
|
package/FEATURE.md
CHANGED
|
@@ -28,13 +28,13 @@ different direction: persistent memory, session continuity, and deep Claude Code
|
|
|
28
28
|
| **Persistent session memory** | No | Yes — auto-indexed, 449K+ chunks |
|
|
29
29
|
| **Session registry** | No | Yes — SQLite, tracks 77+ projects |
|
|
30
30
|
| **Background daemon** | No | Yes — launchd, IPC via Unix socket |
|
|
31
|
-
| **MCP server** | No | Yes —
|
|
31
|
+
| **MCP server** | No | Yes — 9 tools, 18 prompts, 11 resources exposed to Claude Code |
|
|
32
32
|
| **Keyword search (BM25)** | No | Yes — GIN full-text index, PostgreSQL |
|
|
33
33
|
| **Semantic search (vector)** | No | Yes — pgvector HNSW, Snowflake Arctic 768-dim |
|
|
34
34
|
| **Multi-backend storage** | No | Yes — SQLite (simple) or PostgreSQL (full) |
|
|
35
35
|
| **Obsidian vault bridge** | No | Yes — symlinks + auto-generated topic pages |
|
|
36
36
|
| **Project lifecycle** | No | Yes — promote, archive, move, detect from cwd |
|
|
37
|
-
| **Setup wizard** | No | Yes — idempotent
|
|
37
|
+
| **Setup wizard** | No | Yes — idempotent 14-step interactive wizard |
|
|
38
38
|
| **Hook system** | No | Yes — pre-compact, session-stop, auto-cleanup |
|
|
39
39
|
| **Backup / restore** | No | Yes — timestamped pg_dump + registry export |
|
|
40
40
|
| **Multi-session concurrency** | n/a | Yes — daemon multiplexes Claude sessions |
|
package/dist/cli/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import { t as PaiClient } from "../ipc-client-CoyUHPod.mjs";
|
|
|
15
15
|
import { a as expandHome, i as ensureConfigDir, n as CONFIG_FILE$2, o as loadConfig, t as CONFIG_DIR } from "../config-BuhHWyOK.mjs";
|
|
16
16
|
import { t as createStorageBackend } from "../factory-Ygqe_bVZ.mjs";
|
|
17
17
|
import { appendFileSync, chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
18
|
-
import { homedir, tmpdir } from "node:os";
|
|
18
|
+
import { homedir, platform, tmpdir } from "node:os";
|
|
19
19
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
20
20
|
import chalk from "chalk";
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -4310,6 +4310,18 @@ function getDistHooksDir() {
|
|
|
4310
4310
|
for (const candidate of candidates) if (existsSync(join(candidate, "stop-hook.mjs"))) return candidate;
|
|
4311
4311
|
return fromModule;
|
|
4312
4312
|
}
|
|
4313
|
+
function getDistDir() {
|
|
4314
|
+
const moduleDir = new URL(".", import.meta.url).pathname;
|
|
4315
|
+
const fromModule = join(moduleDir, "..", "..", "..");
|
|
4316
|
+
const candidates = [
|
|
4317
|
+
fromModule,
|
|
4318
|
+
join(process.cwd(), "dist"),
|
|
4319
|
+
join(homedir(), "dev", "ai", "PAI", "dist"),
|
|
4320
|
+
join("/", "usr", "local", "lib", "node_modules", "@tekmidian", "pai", "dist")
|
|
4321
|
+
];
|
|
4322
|
+
for (const candidate of candidates) if (existsSync(join(candidate, "skills"))) return candidate;
|
|
4323
|
+
return fromModule;
|
|
4324
|
+
}
|
|
4313
4325
|
function getStatuslineScript() {
|
|
4314
4326
|
const candidates = [
|
|
4315
4327
|
join(process.cwd(), "statusline-command.sh"),
|
|
@@ -4685,6 +4697,89 @@ async function stepAiSteeringRules(rl) {
|
|
|
4685
4697
|
return true;
|
|
4686
4698
|
}
|
|
4687
4699
|
|
|
4700
|
+
//#endregion
|
|
4701
|
+
//#region src/cli/commands/setup/steps/07-skill-stubs.ts
|
|
4702
|
+
/**
|
|
4703
|
+
* Step 7: Install PAI MCP skill stubs to ~/.claude/skills/.
|
|
4704
|
+
*
|
|
4705
|
+
* Each PAI MCP prompt has a SKILL.md stub generated at build time
|
|
4706
|
+
* (dist/skills/<Name>/SKILL.md). This step symlinks (macOS/Linux) or
|
|
4707
|
+
* copies (Windows) them into Claude Code's skill discovery directory.
|
|
4708
|
+
*
|
|
4709
|
+
* Skills MUST live at ~/.claude/skills/<Name>/SKILL.md (top level),
|
|
4710
|
+
* NOT under a user/ subdirectory — Claude Code only scans one level deep.
|
|
4711
|
+
*
|
|
4712
|
+
* Symlinks keep the stubs in sync — rebuilding PAI updates them automatically.
|
|
4713
|
+
* Existing non-symlink directories with the same name are never overwritten.
|
|
4714
|
+
*/
|
|
4715
|
+
async function stepSkillStubs(rl) {
|
|
4716
|
+
section("Step 7: MCP Skill Stubs");
|
|
4717
|
+
line$1();
|
|
4718
|
+
line$1(" PAI MCP prompts need SKILL.md stubs so Claude Code can discover them.");
|
|
4719
|
+
line$1(" Stubs are symlinked from dist/skills/ — rebuilding PAI keeps them in sync.");
|
|
4720
|
+
line$1();
|
|
4721
|
+
const distSkills = join(getDistDir(), "skills");
|
|
4722
|
+
if (!existsSync(distSkills)) {
|
|
4723
|
+
console.log(c.warn("dist/skills/ not found — run `bun run build` first."));
|
|
4724
|
+
return false;
|
|
4725
|
+
}
|
|
4726
|
+
const skillNames = readdirSync(distSkills).filter((name) => {
|
|
4727
|
+
return existsSync(join(join(distSkills, name), "SKILL.md"));
|
|
4728
|
+
});
|
|
4729
|
+
if (skillNames.length === 0) {
|
|
4730
|
+
console.log(c.warn("No skill stubs found in dist/skills/."));
|
|
4731
|
+
return false;
|
|
4732
|
+
}
|
|
4733
|
+
console.log(c.dim(` Found ${skillNames.length} skill stubs to install.`));
|
|
4734
|
+
line$1();
|
|
4735
|
+
if (!await promptYesNo(rl, `Symlink ${skillNames.length} PAI skill stubs to ~/.claude/skills/?`, true)) {
|
|
4736
|
+
console.log(c.dim(" Skipping skill stub installation."));
|
|
4737
|
+
return false;
|
|
4738
|
+
}
|
|
4739
|
+
const targetBase = join(homedir(), ".claude", "skills");
|
|
4740
|
+
mkdirSync(targetBase, { recursive: true });
|
|
4741
|
+
const oldUserBase = join(targetBase, "user");
|
|
4742
|
+
if (existsSync(oldUserBase)) for (const name of skillNames) {
|
|
4743
|
+
const oldTarget = join(oldUserBase, name);
|
|
4744
|
+
if (existsSync(oldTarget) && lstatSync(oldTarget).isSymbolicLink()) unlinkSync(oldTarget);
|
|
4745
|
+
}
|
|
4746
|
+
const useSymlinks = platform() !== "win32";
|
|
4747
|
+
let installed = 0;
|
|
4748
|
+
let skipped = 0;
|
|
4749
|
+
let updated = 0;
|
|
4750
|
+
for (const name of skillNames) {
|
|
4751
|
+
const source = resolve(join(distSkills, name));
|
|
4752
|
+
const target = join(targetBase, name);
|
|
4753
|
+
if (existsSync(target) && !lstatSync(target).isSymbolicLink()) {
|
|
4754
|
+
console.log(c.dim(` SKIP ${name} (existing user skill, not a symlink)`));
|
|
4755
|
+
skipped++;
|
|
4756
|
+
continue;
|
|
4757
|
+
}
|
|
4758
|
+
if (existsSync(target) && lstatSync(target).isSymbolicLink()) {
|
|
4759
|
+
if (resolve(readlinkSync(target)) === source) {
|
|
4760
|
+
installed++;
|
|
4761
|
+
continue;
|
|
4762
|
+
}
|
|
4763
|
+
unlinkSync(target);
|
|
4764
|
+
updated++;
|
|
4765
|
+
}
|
|
4766
|
+
if (useSymlinks) symlinkSync(source, target);
|
|
4767
|
+
else {
|
|
4768
|
+
mkdirSync(target, { recursive: true });
|
|
4769
|
+
copyFileSync(join(source, "SKILL.md"), join(target, "SKILL.md"));
|
|
4770
|
+
}
|
|
4771
|
+
installed++;
|
|
4772
|
+
}
|
|
4773
|
+
line$1();
|
|
4774
|
+
const method = useSymlinks ? "symlinked" : "copied";
|
|
4775
|
+
if (updated > 0) console.log(c.ok(`${installed} stubs ${method}, ${updated} updated, ${skipped} skipped (user skills).`));
|
|
4776
|
+
else {
|
|
4777
|
+
console.log(c.ok(`${installed} skill stubs ${method} to ~/.claude/skills/.`));
|
|
4778
|
+
if (skipped > 0) console.log(c.dim(` ${skipped} skipped (existing user skills not managed by PAI).`));
|
|
4779
|
+
}
|
|
4780
|
+
return true;
|
|
4781
|
+
}
|
|
4782
|
+
|
|
4688
4783
|
//#endregion
|
|
4689
4784
|
//#region src/cli/commands/setup/steps/08-hooks.ts
|
|
4690
4785
|
/** Step 7: Shell lifecycle hooks installation (pre-compact, session-stop, statusline). */
|
|
@@ -5317,7 +5412,7 @@ async function stepInitialIndex(rl) {
|
|
|
5317
5412
|
//#endregion
|
|
5318
5413
|
//#region src/cli/commands/setup/steps/15-verify.ts
|
|
5319
5414
|
/** Step 13: Setup summary — displays all configuration choices made during setup. */
|
|
5320
|
-
function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered) {
|
|
5415
|
+
function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, skillStubsInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered) {
|
|
5321
5416
|
section("Setup Complete");
|
|
5322
5417
|
line$1();
|
|
5323
5418
|
console.log(chalk.green(" PAI Knowledge OS is configured!"));
|
|
@@ -5331,6 +5426,7 @@ function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiStee
|
|
|
5331
5426
|
console.log(chalk.dim(" CLAUDE.md: ") + chalk.cyan(claudeMdGenerated ? "~/.claude/CLAUDE.md (generated)" : "(unchanged)"));
|
|
5332
5427
|
console.log(chalk.dim(" PAI skill: ") + chalk.cyan(paiSkillInstalled ? "~/.claude/skills/PAI/SKILL.md (installed)" : "(unchanged)"));
|
|
5333
5428
|
console.log(chalk.dim(" Steering rules: ") + chalk.cyan(aiSteeringRulesInstalled ? "~/.claude/skills/PAI/AI-STEERING-RULES.md (installed)" : "(unchanged)"));
|
|
5429
|
+
console.log(chalk.dim(" Skill stubs: ") + chalk.cyan(skillStubsInstalled ? "18 MCP prompt stubs symlinked to ~/.claude/skills/" : "(unchanged)"));
|
|
5334
5430
|
console.log(chalk.dim(" Hooks (shell): ") + chalk.cyan(hooksInstalled ? "pai-pre-compact.sh, pai-session-stop.sh (installed)" : "(unchanged)"));
|
|
5335
5431
|
console.log(chalk.dim(" Hooks (TS): ") + chalk.cyan(tsHooksInstalled ? "14 .mjs hooks installed to ~/.claude/Hooks/" : "(unchanged)"));
|
|
5336
5432
|
console.log(chalk.dim(" Assistant name: ") + chalk.cyan(daName));
|
|
@@ -5394,6 +5490,7 @@ async function runSetup() {
|
|
|
5394
5490
|
const claudeMdGenerated = await stepClaudeMd(rl);
|
|
5395
5491
|
const paiSkillInstalled = await stepPaiSkill(rl);
|
|
5396
5492
|
const aiSteeringRulesInstalled = await stepAiSteeringRules(rl);
|
|
5493
|
+
const skillStubsInstalled = await stepSkillStubs(rl);
|
|
5397
5494
|
const hooksInstalled = await stepHooks(rl);
|
|
5398
5495
|
const tsHooksInstalled = await stepTsHooks(rl);
|
|
5399
5496
|
const daName = await stepDaName(rl);
|
|
@@ -5409,7 +5506,7 @@ async function runSetup() {
|
|
|
5409
5506
|
line$1();
|
|
5410
5507
|
console.log(chalk.green(" Configuration saved."));
|
|
5411
5508
|
await stepInitialIndex(rl);
|
|
5412
|
-
stepSummary(allUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered);
|
|
5509
|
+
stepSummary(allUpdates, claudeMdGenerated, paiSkillInstalled, aiSteeringRulesInstalled, skillStubsInstalled, hooksInstalled, tsHooksInstalled, settingsPatched, daName, daemonInstalled, mcpRegistered);
|
|
5413
5510
|
} finally {
|
|
5414
5511
|
rl.close();
|
|
5415
5512
|
}
|