@tekmidian/pai 0.6.6 → 0.7.1
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/.claude-plugin/plugin.json +50 -0
- package/PLUGIN-ARCHITECTURE.md +365 -0
- package/dist/cli/index.mjs +1 -1
- package/dist/daemon/index.mjs +1 -1
- package/dist/{daemon-D3hYb5_C.mjs → daemon-DJoesjez.mjs} +847 -4
- package/dist/daemon-DJoesjez.mjs.map +1 -0
- package/dist/hooks/context-compression-hook.mjs.map +2 -2
- package/dist/hooks/load-project-context.mjs +4 -23
- package/dist/hooks/load-project-context.mjs.map +2 -2
- package/dist/hooks/stop-hook.mjs +206 -125
- package/dist/hooks/stop-hook.mjs.map +3 -3
- package/dist/hooks/sync-todo-to-md.mjs.map +1 -1
- package/gemini-extension.json +26 -0
- package/package.json +8 -2
- package/pai-plugin.json +212 -0
- package/plugins/context-preservation/hooks/hooks.json +23 -0
- package/plugins/context-preservation/plugin.json +10 -0
- package/plugins/core/hooks/hooks.json +37 -0
- package/plugins/core/plugin.json +10 -0
- package/plugins/creative/plugin.json +10 -0
- package/plugins/observability/hooks/hooks.json +75 -0
- package/plugins/observability/plugin.json +11 -0
- package/plugins/productivity/hooks/hooks.json +17 -0
- package/plugins/productivity/plugin.json +11 -0
- package/plugins/semantic-search/plugin.json +21 -0
- package/plugins/ui/hooks/hooks.json +17 -0
- package/plugins/ui/plugin.json +11 -0
- package/plugins/zettelkasten/plugin.json +19 -0
- package/src/hooks/ts/lib/project-utils/session-notes.ts +24 -5
- package/src/hooks/ts/session-start/load-project-context.ts +9 -25
- package/src/hooks/ts/stop/stop-hook.ts +259 -199
- package/user-extensions/README.md +87 -0
- package/user-extensions/hooks/.gitkeep +0 -0
- package/user-extensions/skills/.gitkeep +0 -0
- package/dist/daemon-D3hYb5_C.mjs.map +0 -1
package/pai-plugin.json
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://pai.dev/schemas/plugin-manifest-v1.json",
|
|
3
|
+
"name": "@tekmidian/pai",
|
|
4
|
+
"displayName": "PAI Knowledge OS",
|
|
5
|
+
"description": "Personal AI Infrastructure — persistent memory, session continuity, and knowledge graph",
|
|
6
|
+
"version": "0.7.0",
|
|
7
|
+
"author": "Matthias Nott",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"homepage": "https://github.com/mnott/PAI",
|
|
10
|
+
"repository": "https://github.com/mnott/PAI",
|
|
11
|
+
|
|
12
|
+
"modules": {
|
|
13
|
+
"core": {
|
|
14
|
+
"description": "Core memory engine, session management, project registry",
|
|
15
|
+
"tier": "free",
|
|
16
|
+
"required": true,
|
|
17
|
+
"hooks": "plugins/core/hooks/hooks.json",
|
|
18
|
+
"skills": ["Sessions", "Route", "Name"],
|
|
19
|
+
"mcp": {
|
|
20
|
+
"server": "dist/daemon-mcp/index.mjs",
|
|
21
|
+
"daemon": "dist/daemon/index.mjs",
|
|
22
|
+
"tools": [
|
|
23
|
+
"memory_search",
|
|
24
|
+
"memory_get",
|
|
25
|
+
"project_info",
|
|
26
|
+
"project_list",
|
|
27
|
+
"session_list",
|
|
28
|
+
"registry_search",
|
|
29
|
+
"project_detect",
|
|
30
|
+
"project_health",
|
|
31
|
+
"project_todo"
|
|
32
|
+
],
|
|
33
|
+
"resources": [
|
|
34
|
+
"pai://constitution",
|
|
35
|
+
"pai://skill-system",
|
|
36
|
+
"pai://hook-system",
|
|
37
|
+
"pai://mcp-dev-guide",
|
|
38
|
+
"pai://terminal-tabs"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"templates": [
|
|
42
|
+
"templates/claude-md.template.md",
|
|
43
|
+
"templates/pai-skill.template.md",
|
|
44
|
+
"templates/pai-project.template.md"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
"productivity": {
|
|
49
|
+
"description": "Planning, journaling, reviewing, research, and sharing workflows",
|
|
50
|
+
"tier": "free",
|
|
51
|
+
"required": false,
|
|
52
|
+
"depends": ["core"],
|
|
53
|
+
"hooks": "plugins/productivity/hooks/hooks.json",
|
|
54
|
+
"skills": ["Plan", "Review", "Journal", "Research", "Share", "Createskill"],
|
|
55
|
+
"templates": [
|
|
56
|
+
"templates/agent-prefs.example.md"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
"ui": {
|
|
61
|
+
"description": "Terminal tab titles, statusline, tab coloring, and visual customization",
|
|
62
|
+
"tier": "free",
|
|
63
|
+
"required": false,
|
|
64
|
+
"depends": ["core"],
|
|
65
|
+
"hooks": "plugins/ui/hooks/hooks.json",
|
|
66
|
+
"scripts": [
|
|
67
|
+
"statusline-command.sh",
|
|
68
|
+
"tab-color-command.sh"
|
|
69
|
+
],
|
|
70
|
+
"templates": [
|
|
71
|
+
"templates/ai-steering-rules.template.md"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
"context-preservation": {
|
|
76
|
+
"description": "Context compression and relay across compaction cycles",
|
|
77
|
+
"tier": "free",
|
|
78
|
+
"required": false,
|
|
79
|
+
"depends": ["core"],
|
|
80
|
+
"hooks": "plugins/context-preservation/hooks/hooks.json"
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
"semantic-search": {
|
|
84
|
+
"description": "Vector search with pgvector, cross-encoder reranking, hybrid mode, recency boost",
|
|
85
|
+
"tier": "pro",
|
|
86
|
+
"required": false,
|
|
87
|
+
"depends": ["core"],
|
|
88
|
+
"features": [
|
|
89
|
+
"semantic_search_mode",
|
|
90
|
+
"hybrid_search_mode",
|
|
91
|
+
"cross_encoder_reranking",
|
|
92
|
+
"recency_boost",
|
|
93
|
+
"pgvector_storage"
|
|
94
|
+
],
|
|
95
|
+
"requirements": {
|
|
96
|
+
"docker": true,
|
|
97
|
+
"postgresql": ">=15",
|
|
98
|
+
"pgvector": ">=0.5.0"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
"observability": {
|
|
103
|
+
"description": "Automatic observation capture, classification, session summaries, and search history",
|
|
104
|
+
"tier": "pro",
|
|
105
|
+
"required": false,
|
|
106
|
+
"depends": ["core"],
|
|
107
|
+
"hooks": "plugins/observability/hooks/hooks.json",
|
|
108
|
+
"skills": ["Observability", "SearchHistory"],
|
|
109
|
+
"mcp": {
|
|
110
|
+
"resources": [
|
|
111
|
+
"pai://history-system"
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
"zettelkasten": {
|
|
117
|
+
"description": "Luhmann-inspired vault intelligence — explore, surprise, converse, themes, health, suggest",
|
|
118
|
+
"tier": "enterprise",
|
|
119
|
+
"required": false,
|
|
120
|
+
"depends": ["core", "semantic-search"],
|
|
121
|
+
"skills": ["VaultConnect", "VaultContext", "VaultEmerge", "VaultOrphans", "VaultTrace"],
|
|
122
|
+
"features": [
|
|
123
|
+
"vault_indexer",
|
|
124
|
+
"zettel_explore",
|
|
125
|
+
"zettel_surprise",
|
|
126
|
+
"zettel_converse",
|
|
127
|
+
"zettel_themes",
|
|
128
|
+
"zettel_health",
|
|
129
|
+
"zettel_suggest"
|
|
130
|
+
],
|
|
131
|
+
"requirements": {
|
|
132
|
+
"obsidian": true
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
"creative": {
|
|
137
|
+
"description": "Art direction, story explanation, voice/prosody configuration",
|
|
138
|
+
"tier": "enterprise",
|
|
139
|
+
"required": false,
|
|
140
|
+
"depends": ["core"],
|
|
141
|
+
"skills": ["Art", "StoryExplanation"],
|
|
142
|
+
"mcp": {
|
|
143
|
+
"resources": [
|
|
144
|
+
"pai://aesthetic",
|
|
145
|
+
"pai://prosody-guide",
|
|
146
|
+
"pai://prosody-agent-template",
|
|
147
|
+
"pai://voice",
|
|
148
|
+
"pai://prompting"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"templates": [
|
|
152
|
+
"templates/voices.example.json"
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
"tiers": {
|
|
158
|
+
"free": {
|
|
159
|
+
"description": "Core memory engine with keyword search, essential hooks, and productivity skills",
|
|
160
|
+
"price": 0,
|
|
161
|
+
"modules": ["core", "productivity", "ui", "context-preservation"]
|
|
162
|
+
},
|
|
163
|
+
"pro": {
|
|
164
|
+
"description": "Semantic search, observability suite, and advanced memory features",
|
|
165
|
+
"price": {
|
|
166
|
+
"monthly": 9,
|
|
167
|
+
"yearly": 79
|
|
168
|
+
},
|
|
169
|
+
"modules": ["core", "productivity", "ui", "context-preservation", "semantic-search", "observability"]
|
|
170
|
+
},
|
|
171
|
+
"enterprise": {
|
|
172
|
+
"description": "Full PAI — zettelkasten intelligence, creative studio, and all features",
|
|
173
|
+
"price": {
|
|
174
|
+
"monthly": 29,
|
|
175
|
+
"yearly": 249
|
|
176
|
+
},
|
|
177
|
+
"modules": ["core", "productivity", "ui", "context-preservation", "semantic-search", "observability", "zettelkasten", "creative"]
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
"userExtensions": {
|
|
182
|
+
"hooks": "user-extensions/hooks/",
|
|
183
|
+
"skills": "user-extensions/skills/",
|
|
184
|
+
"prompts": "src/daemon-mcp/prompts/custom/"
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
"platforms": {
|
|
188
|
+
"claude-code": {
|
|
189
|
+
"manifest": ".claude-plugin/plugin.json",
|
|
190
|
+
"hooks": true,
|
|
191
|
+
"skills": true,
|
|
192
|
+
"mcp": true,
|
|
193
|
+
"resources": true
|
|
194
|
+
},
|
|
195
|
+
"cursor": {
|
|
196
|
+
"manifest": ".cursor/plugin.json",
|
|
197
|
+
"hooks": false,
|
|
198
|
+
"skills": false,
|
|
199
|
+
"mcp": true,
|
|
200
|
+
"resources": false,
|
|
201
|
+
"notes": "Cursor supports MCP but not Claude Code hooks/skills"
|
|
202
|
+
},
|
|
203
|
+
"gemini-cli": {
|
|
204
|
+
"manifest": "gemini-extension.json",
|
|
205
|
+
"hooks": false,
|
|
206
|
+
"skills": false,
|
|
207
|
+
"mcp": true,
|
|
208
|
+
"resources": false,
|
|
209
|
+
"notes": "Gemini CLI supports MCP servers via extensions"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"module": "context-preservation",
|
|
3
|
+
"description": "Context compression and relay across compaction cycles",
|
|
4
|
+
"hooks": [
|
|
5
|
+
{
|
|
6
|
+
"event": "PreCompact",
|
|
7
|
+
"command": "${PAI_DIR}/Hooks/context-compression-hook.mjs",
|
|
8
|
+
"description": "Extract session state, save checkpoint, write temp file for relay to post-compact"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"event": "PreCompact",
|
|
12
|
+
"matcher": "",
|
|
13
|
+
"command": "${PAI_DIR}/Hooks/pai-pre-compact.sh",
|
|
14
|
+
"description": "Shell-level pre-compact processing"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"event": "SessionStart",
|
|
18
|
+
"matcher": "compact",
|
|
19
|
+
"command": "${PAI_DIR}/Hooks/post-compact-inject.mjs",
|
|
20
|
+
"description": "Read saved state from temp file and inject into post-compaction context"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-context-preservation",
|
|
3
|
+
"displayName": "PAI Context Preservation",
|
|
4
|
+
"description": "Context compression and relay across compaction cycles",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "free",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core"],
|
|
9
|
+
"hooks": "hooks/hooks.json"
|
|
10
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"module": "core",
|
|
3
|
+
"description": "Essential lifecycle hooks for session management, context loading, and security",
|
|
4
|
+
"hooks": [
|
|
5
|
+
{
|
|
6
|
+
"event": "SessionStart",
|
|
7
|
+
"command": "${PAI_DIR}/Hooks/load-core-context.mjs",
|
|
8
|
+
"description": "Load PAI skill system and core configuration into session context"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"event": "SessionStart",
|
|
12
|
+
"command": "${PAI_DIR}/Hooks/load-project-context.mjs",
|
|
13
|
+
"description": "Detect project from CWD, load notes directory, TODO.md, and session note"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"event": "SessionStart",
|
|
17
|
+
"command": "${PAI_DIR}/Hooks/initialize-session.mjs",
|
|
18
|
+
"description": "Create numbered session note and register in PAI registry"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"event": "PreToolUse",
|
|
22
|
+
"matcher": "Bash",
|
|
23
|
+
"command": "${PAI_DIR}/Hooks/security-validator.mjs",
|
|
24
|
+
"description": "Validate shell commands against security rules before execution"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"event": "Stop",
|
|
28
|
+
"command": "${PAI_DIR}/Hooks/stop-hook.mjs",
|
|
29
|
+
"description": "Write work items and summary to session note, send notification"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"event": "Stop",
|
|
33
|
+
"command": "${PAI_DIR}/Hooks/pai-session-stop.sh",
|
|
34
|
+
"description": "Shell-level session cleanup on stop"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-core",
|
|
3
|
+
"displayName": "PAI Core",
|
|
4
|
+
"description": "Core memory engine, session management, and project registry",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "free",
|
|
7
|
+
"required": true,
|
|
8
|
+
"hooks": "hooks/hooks.json",
|
|
9
|
+
"skills": ["Sessions", "Route", "Name"]
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-creative",
|
|
3
|
+
"displayName": "PAI Creative Studio",
|
|
4
|
+
"description": "Art direction, story explanation, voice/prosody configuration",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "enterprise",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core"],
|
|
9
|
+
"skills": ["Art", "StoryExplanation"]
|
|
10
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"module": "observability",
|
|
3
|
+
"description": "Automatic observation capture, event logging, tool output recording, and session summaries",
|
|
4
|
+
"hooks": [
|
|
5
|
+
{
|
|
6
|
+
"event": "SessionStart",
|
|
7
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SessionStart",
|
|
8
|
+
"description": "Log SessionStart event to session timeline"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"event": "SessionStart",
|
|
12
|
+
"command": "${PAI_DIR}/Hooks/inject-observations.mjs",
|
|
13
|
+
"description": "Inject recent observation context (compact index + timeline)"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"event": "UserPromptSubmit",
|
|
17
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type UserPromptSubmit",
|
|
18
|
+
"description": "Log UserPromptSubmit event to session timeline"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"event": "PreToolUse",
|
|
22
|
+
"matcher": "*",
|
|
23
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PreToolUse",
|
|
24
|
+
"description": "Log PreToolUse event to session timeline"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"event": "PostToolUse",
|
|
28
|
+
"matcher": "*",
|
|
29
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PostToolUse",
|
|
30
|
+
"description": "Log PostToolUse event to session timeline"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"event": "PostToolUse",
|
|
34
|
+
"matcher": "*",
|
|
35
|
+
"command": "${PAI_DIR}/Hooks/observe.mjs",
|
|
36
|
+
"description": "Classify tool calls into typed observations (decision/bugfix/feature/refactor/discovery/change)"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"event": "PostToolUse",
|
|
40
|
+
"matcher": "*",
|
|
41
|
+
"command": "${PAI_DIR}/Hooks/capture-tool-output.mjs",
|
|
42
|
+
"description": "Record tool inputs/outputs for observability dashboard"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"event": "Stop",
|
|
46
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type Stop",
|
|
47
|
+
"description": "Log Stop event to session timeline"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"event": "SubagentStop",
|
|
51
|
+
"command": "${PAI_DIR}/Hooks/subagent-stop-hook.mjs",
|
|
52
|
+
"description": "Capture sub-agent completion for observability"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"event": "SubagentStop",
|
|
56
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SubagentStop",
|
|
57
|
+
"description": "Log SubagentStop event to session timeline"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"event": "SessionEnd",
|
|
61
|
+
"command": "${PAI_DIR}/Hooks/capture-session-summary.mjs",
|
|
62
|
+
"description": "Generate final session summary and write to session note"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"event": "SessionEnd",
|
|
66
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type SessionEnd",
|
|
67
|
+
"description": "Log SessionEnd event to session timeline"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"event": "PreCompact",
|
|
71
|
+
"command": "${PAI_DIR}/Hooks/capture-all-events.mjs --event-type PreCompact",
|
|
72
|
+
"description": "Log PreCompact event to session timeline"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-observability",
|
|
3
|
+
"displayName": "PAI Observability Suite",
|
|
4
|
+
"description": "Automatic observation capture, classification, session summaries, and search history",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "pro",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core"],
|
|
9
|
+
"hooks": "hooks/hooks.json",
|
|
10
|
+
"skills": ["Observability", "SearchHistory"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"module": "productivity",
|
|
3
|
+
"description": "Hooks for TODO sync, session cleanup, and productivity workflows",
|
|
4
|
+
"hooks": [
|
|
5
|
+
{
|
|
6
|
+
"event": "PostToolUse",
|
|
7
|
+
"matcher": "TodoWrite",
|
|
8
|
+
"command": "${PAI_DIR}/Hooks/sync-todo-to-md.mjs",
|
|
9
|
+
"description": "Sync Claude's internal TODO list to Notes/TODO.md on every TodoWrite"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"event": "UserPromptSubmit",
|
|
13
|
+
"command": "${PAI_DIR}/Hooks/cleanup-session-files.mjs",
|
|
14
|
+
"description": "Clean up stale temp files between user prompts"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-productivity",
|
|
3
|
+
"displayName": "PAI Productivity",
|
|
4
|
+
"description": "Planning, journaling, reviewing, research, and sharing workflows",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "free",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core"],
|
|
9
|
+
"hooks": "hooks/hooks.json",
|
|
10
|
+
"skills": ["Plan", "Review", "Journal", "Research", "Share", "Createskill"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-semantic-search",
|
|
3
|
+
"displayName": "PAI Semantic Search",
|
|
4
|
+
"description": "Vector search with pgvector, cross-encoder reranking, hybrid mode, recency boost",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "pro",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core"],
|
|
9
|
+
"features": [
|
|
10
|
+
"semantic_search_mode",
|
|
11
|
+
"hybrid_search_mode",
|
|
12
|
+
"cross_encoder_reranking",
|
|
13
|
+
"recency_boost",
|
|
14
|
+
"pgvector_storage"
|
|
15
|
+
],
|
|
16
|
+
"requirements": {
|
|
17
|
+
"docker": true,
|
|
18
|
+
"postgresql": ">=15",
|
|
19
|
+
"pgvector": ">=0.5.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"module": "ui",
|
|
3
|
+
"description": "Terminal tab titles, statusline updates, and visual feedback hooks",
|
|
4
|
+
"hooks": [
|
|
5
|
+
{
|
|
6
|
+
"event": "UserPromptSubmit",
|
|
7
|
+
"command": "${PAI_DIR}/Hooks/update-tab-titles.mjs",
|
|
8
|
+
"description": "Set terminal tab title from session context"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"event": "PostToolUse",
|
|
12
|
+
"matcher": "*",
|
|
13
|
+
"command": "${PAI_DIR}/Hooks/update-tab-on-action.mjs",
|
|
14
|
+
"description": "Update terminal tab title based on current tool activity"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-ui",
|
|
3
|
+
"displayName": "PAI UI Customization",
|
|
4
|
+
"description": "Terminal tab titles, statusline, tab coloring, and visual customization",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "free",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core"],
|
|
9
|
+
"hooks": "hooks/hooks.json",
|
|
10
|
+
"scripts": ["statusline-command.sh", "tab-color-command.sh"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pai-zettelkasten",
|
|
3
|
+
"displayName": "PAI Zettelkasten Intelligence",
|
|
4
|
+
"description": "Luhmann-inspired vault intelligence with graph operations and Obsidian integration",
|
|
5
|
+
"version": "0.7.0",
|
|
6
|
+
"tier": "enterprise",
|
|
7
|
+
"required": false,
|
|
8
|
+
"depends": ["core", "semantic-search"],
|
|
9
|
+
"skills": ["VaultConnect", "VaultContext", "VaultEmerge", "VaultOrphans", "VaultTrace"],
|
|
10
|
+
"features": [
|
|
11
|
+
"vault_indexer",
|
|
12
|
+
"zettel_explore",
|
|
13
|
+
"zettel_surprise",
|
|
14
|
+
"zettel_converse",
|
|
15
|
+
"zettel_themes",
|
|
16
|
+
"zettel_health",
|
|
17
|
+
"zettel_suggest"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -215,6 +215,21 @@ export function sanitizeForFilename(str: string): string {
|
|
|
215
215
|
.substring(0, 50);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Return true if the candidate string should be rejected as a meaningful name.
|
|
220
|
+
* Rejects file paths, shebangs, timestamps, and "[object Object]" artifacts.
|
|
221
|
+
*/
|
|
222
|
+
function isMeaninglessCandidate(text: string): boolean {
|
|
223
|
+
const t = text.trim();
|
|
224
|
+
if (!t) return true;
|
|
225
|
+
if (t.startsWith('/')) return true; // file path
|
|
226
|
+
if (t.startsWith('#!')) return true; // shebang
|
|
227
|
+
if (t.includes('[object Object]')) return true; // serialization artifact
|
|
228
|
+
if (/^\d{4}-\d{2}-\d{2}(T[\d:.Z+-]+)?$/.test(t)) return true; // ISO timestamp
|
|
229
|
+
if (/^\d{1,2}:\d{2}(:\d{2})?(\s*(AM|PM))?$/i.test(t)) return true; // time-only
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
|
|
218
233
|
/**
|
|
219
234
|
* Extract a meaningful name from session note content and summary.
|
|
220
235
|
* Looks at Work Done section headers, bold text, and summary.
|
|
@@ -228,7 +243,7 @@ export function extractMeaningfulName(noteContent: string, summary: string): str
|
|
|
228
243
|
const subheadings = workDoneSection.match(/### ([^\n]+)/g);
|
|
229
244
|
if (subheadings && subheadings.length > 0) {
|
|
230
245
|
const firstHeading = subheadings[0].replace('### ', '').trim();
|
|
231
|
-
if (firstHeading.length > 5 && firstHeading.length < 60) {
|
|
246
|
+
if (!isMeaninglessCandidate(firstHeading) && firstHeading.length > 5 && firstHeading.length < 60) {
|
|
232
247
|
return sanitizeForFilename(firstHeading);
|
|
233
248
|
}
|
|
234
249
|
}
|
|
@@ -236,23 +251,27 @@ export function extractMeaningfulName(noteContent: string, summary: string): str
|
|
|
236
251
|
const boldMatches = workDoneSection.match(/\*\*([^*]+)\*\*/g);
|
|
237
252
|
if (boldMatches && boldMatches.length > 0) {
|
|
238
253
|
const firstBold = boldMatches[0].replace(/\*\*/g, '').trim();
|
|
239
|
-
if (firstBold.length > 3 && firstBold.length < 50) {
|
|
254
|
+
if (!isMeaninglessCandidate(firstBold) && firstBold.length > 3 && firstBold.length < 50) {
|
|
240
255
|
return sanitizeForFilename(firstBold);
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
258
|
|
|
244
259
|
const numberedItems = workDoneSection.match(/^\d+\.\s+\*\*([^*]+)\*\*/m);
|
|
245
|
-
if (numberedItems
|
|
260
|
+
if (numberedItems && !isMeaninglessCandidate(numberedItems[1])) {
|
|
261
|
+
return sanitizeForFilename(numberedItems[1]);
|
|
262
|
+
}
|
|
246
263
|
}
|
|
247
264
|
|
|
248
|
-
if (summary && summary.length > 5 && summary !== 'Session completed.') {
|
|
265
|
+
if (summary && summary.length > 5 && summary !== 'Session completed.' && !isMeaninglessCandidate(summary)) {
|
|
249
266
|
const cleanSummary = summary
|
|
250
267
|
.replace(/[^\w\s-]/g, ' ')
|
|
251
268
|
.trim()
|
|
252
269
|
.split(/\s+/)
|
|
253
270
|
.slice(0, 5)
|
|
254
271
|
.join(' ');
|
|
255
|
-
if (cleanSummary.length > 3
|
|
272
|
+
if (cleanSummary.length > 3 && !isMeaninglessCandidate(cleanSummary)) {
|
|
273
|
+
return sanitizeForFilename(cleanSummary);
|
|
274
|
+
}
|
|
256
275
|
}
|
|
257
276
|
|
|
258
277
|
return '';
|
|
@@ -239,36 +239,20 @@ async function main() {
|
|
|
239
239
|
if (notesDir) { // notesDir is always set now (local or central)
|
|
240
240
|
const currentNotePath = getCurrentNotePath(notesDir);
|
|
241
241
|
|
|
242
|
-
//
|
|
243
|
-
|
|
242
|
+
// Only create a new note if there is truly no note at all.
|
|
243
|
+
// A completed note is still used — it will be updated or continued.
|
|
244
|
+
// This prevents duplicate notes at month boundaries and on every compaction.
|
|
244
245
|
if (!currentNotePath) {
|
|
245
|
-
|
|
246
|
+
// Defensive: ensure projectName is a usable string
|
|
247
|
+
const safeProjectName = (typeof projectName === 'string' && projectName.trim().length > 0)
|
|
248
|
+
? projectName.trim()
|
|
249
|
+
: 'Untitled Session';
|
|
246
250
|
console.error('\nNo previous session notes found - creating new one');
|
|
247
|
-
|
|
248
|
-
// Check if the existing note is completed
|
|
249
|
-
try {
|
|
250
|
-
const content = readFileSync(currentNotePath, 'utf-8');
|
|
251
|
-
if (content.includes('**Status:** Completed') || content.includes('**Completed:**')) {
|
|
252
|
-
needsNewNote = true;
|
|
253
|
-
console.error(`\nPrevious note completed - creating new one`);
|
|
254
|
-
const summaryMatch = content.match(/## Next Steps\n\n([^\n]+)/);
|
|
255
|
-
if (summaryMatch) {
|
|
256
|
-
console.error(` Previous: ${summaryMatch[1].substring(0, 60)}...`);
|
|
257
|
-
}
|
|
258
|
-
} else {
|
|
259
|
-
console.error(`\nContinuing session note: ${basename(currentNotePath)}`);
|
|
260
|
-
}
|
|
261
|
-
} catch {
|
|
262
|
-
needsNewNote = true;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Create new note if needed
|
|
267
|
-
if (needsNewNote) {
|
|
268
|
-
activeNotePath = createSessionNote(notesDir, projectName);
|
|
251
|
+
activeNotePath = createSessionNote(notesDir, String(safeProjectName));
|
|
269
252
|
console.error(`Created: ${basename(activeNotePath)}`);
|
|
270
253
|
} else {
|
|
271
254
|
activeNotePath = currentNotePath!;
|
|
255
|
+
console.error(`\nUsing existing session note: ${basename(activeNotePath)}`);
|
|
272
256
|
// Show preview of current note
|
|
273
257
|
try {
|
|
274
258
|
const content = readFileSync(activeNotePath, 'utf-8');
|