@justestif/pk 0.1.14 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/index.js +276 -59
- package/package.json +1 -1
- package/skill/SKILL.md +0 -2
- package/skill/references/knowledge-model.md +9 -9
- package/skill/references/git-workflow.md +0 -77
package/README.md
CHANGED
|
@@ -30,25 +30,25 @@ Non-interactive:
|
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
pk init my-project --harness claude
|
|
33
|
-
pk init my-project --harness claude,omp
|
|
33
|
+
pk init my-project --harness claude,omp # multiple harnesses
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
Available harnesses: `claude
|
|
36
|
+
Available harnesses: `claude` (Claude Code), `omp` (Oh My Pi), `cursor` (Cursor), `gemini` (Gemini CLI), `codex` (Codex), `opencode` (OpenCode).
|
|
37
37
|
|
|
38
38
|
`pk init` does three things:
|
|
39
39
|
|
|
40
40
|
1. Creates `~/.pk/<name>/` as the knowledge home for this project
|
|
41
41
|
2. Writes an MCP server config so your harness discovers `pk mcp`
|
|
42
|
-
3.
|
|
42
|
+
3. Installs a harness adapter that calls `pk prime` at session start to inject the skill into context
|
|
43
43
|
|
|
44
|
-
| Harness |
|
|
44
|
+
| Harness | Files written |
|
|
45
45
|
|---|---|
|
|
46
|
-
| `claude` | `.mcp.json`
|
|
47
|
-
| `
|
|
48
|
-
| `cursor` | `.cursor/mcp.json` |
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
46
|
+
| `claude` | `.mcp.json`, `CLAUDE.md`, `.claude/hooks/pk-eval.ts`, `.claude/settings.json` |
|
|
47
|
+
| `omp` | `.omp/mcp.json`, `AGENTS.md`, `.omp/extensions/pk-eval.ts` |
|
|
48
|
+
| `cursor` | `.cursor/mcp.json`, `.cursor/rules/pk.mdc`, `.cursor/hooks/pk-eval.sh`, `.cursor/hooks.json` |
|
|
49
|
+
| `gemini` | `.gemini/settings.json`, `GEMINI.md`, `.gemini/hooks/pk-eval.sh` |
|
|
50
|
+
| `codex` | `.codex/config.toml`, `AGENTS.md`, `.codex/hooks/pk-eval.sh`, `.codex/hooks.json` |
|
|
51
|
+
| `opencode` | `opencode.json`, `AGENTS.md`, `CLAUDE.md`, `.opencode/plugins/pk-eval.ts` |
|
|
52
52
|
|
|
53
53
|
## How it works
|
|
54
54
|
|
package/dist/index.js
CHANGED
|
@@ -17713,7 +17713,7 @@ var {
|
|
|
17713
17713
|
var package_default = {
|
|
17714
17714
|
name: "@justestif/pk",
|
|
17715
17715
|
type: "module",
|
|
17716
|
-
version: "0.
|
|
17716
|
+
version: "0.2.0",
|
|
17717
17717
|
description: "Project knowledge \u2014 structured intake, search, and recall",
|
|
17718
17718
|
bin: {
|
|
17719
17719
|
pk: "dist/index.js"
|
|
@@ -34112,28 +34112,28 @@ ${c2}
|
|
|
34112
34112
|
|
|
34113
34113
|
// src/commands/init.ts
|
|
34114
34114
|
var HARNESSES = [
|
|
34115
|
-
{ hint: ".mcp.json
|
|
34116
|
-
{ hint: "
|
|
34117
|
-
{ hint: ".cursor/mcp.json
|
|
34118
|
-
{ hint: ".
|
|
34119
|
-
{ hint: "
|
|
34120
|
-
{ hint: ".
|
|
34115
|
+
{ hint: ".mcp.json + CLAUDE.md + forced-eval hook", label: "Claude Code", value: "claude" },
|
|
34116
|
+
{ hint: ".omp/mcp.json + AGENTS.md + forced-eval hook", label: "Oh My Pi", value: "omp" },
|
|
34117
|
+
{ hint: ".cursor/mcp.json + .cursor/rules/pk.mdc + hook", label: "Cursor", value: "cursor" },
|
|
34118
|
+
{ hint: ".gemini/settings.json + GEMINI.md + hook", label: "Gemini CLI", value: "gemini" },
|
|
34119
|
+
{ hint: ".codex/config.toml + AGENTS.md + hook", label: "Codex", value: "codex" },
|
|
34120
|
+
{ hint: "opencode.json + plugin (reads AGENTS.md/CLAUDE.md)", label: "OpenCode", value: "opencode" }
|
|
34121
34121
|
];
|
|
34122
34122
|
var HARNESS_VALUES = new Set(HARNESSES.map((h2) => h2.value));
|
|
34123
34123
|
var HARNESS_ACTIVATION = {
|
|
34124
34124
|
claude: "start a new Claude Code session in this project",
|
|
34125
|
-
"claude-desktop": "quit and restart Claude Desktop",
|
|
34126
|
-
codex: "restart the Codex CLI",
|
|
34127
|
-
cursor: "reload the Cursor window (Cmd+Shift+P \u2192 Reload Window)",
|
|
34128
34125
|
omp: "restart your Oh My Pi session",
|
|
34129
|
-
|
|
34126
|
+
cursor: "restart Cursor for changes to take effect",
|
|
34127
|
+
gemini: "restart your Gemini CLI session",
|
|
34128
|
+
codex: "restart Codex for MCP to connect",
|
|
34129
|
+
opencode: "reload OpenCode or restart the app"
|
|
34130
34130
|
};
|
|
34131
34131
|
function buildOutro(created, knowledgeDir, harnesses, skillPaths) {
|
|
34132
34132
|
const lines = [
|
|
34133
34133
|
created ? `Created project: ${knowledgeDir}` : `Connected to existing project: ${knowledgeDir}`
|
|
34134
34134
|
];
|
|
34135
34135
|
for (const h2 of harnesses) {
|
|
34136
|
-
lines.push(` ${h2}:
|
|
34136
|
+
lines.push(` ${h2}: configured \u2192 ${HARNESS_ACTIVATION[h2]}`);
|
|
34137
34137
|
}
|
|
34138
34138
|
for (const sp of skillPaths) {
|
|
34139
34139
|
lines.push(` skill installed to ${sp}`);
|
|
@@ -34179,14 +34179,96 @@ async function writeClaudeConfig(projectRoot, _name, knowledgeDir) {
|
|
|
34179
34179
|
cfg.mcpServers = servers;
|
|
34180
34180
|
await writeJson(cfgPath, cfg);
|
|
34181
34181
|
}
|
|
34182
|
-
async function
|
|
34183
|
-
const cfgPath = path7.join(
|
|
34182
|
+
async function writeOmpConfig(projectRoot, _name, knowledgeDir) {
|
|
34183
|
+
const cfgPath = path7.join(projectRoot, ".omp", "mcp.json");
|
|
34184
34184
|
const cfg = await readJson(cfgPath);
|
|
34185
34185
|
const servers = cfg.mcpServers ?? {};
|
|
34186
|
-
servers
|
|
34186
|
+
servers.pk = pkMcpEntry(knowledgeDir);
|
|
34187
34187
|
cfg.mcpServers = servers;
|
|
34188
34188
|
await writeJson(cfgPath, cfg);
|
|
34189
34189
|
}
|
|
34190
|
+
var PK_SECTION_START = "<!-- pk:start -->";
|
|
34191
|
+
var PK_SECTION_END = "<!-- pk:end -->";
|
|
34192
|
+
var PK_INSTRUCTION = `## pk \u2014 project knowledge
|
|
34193
|
+
|
|
34194
|
+
Use the pk skill and its MCP tools (pk_synthesize, pk_search, pk_read, pk_new, pk_lint) to manage project knowledge for this project. Run pk_synthesize({ sessionStart: true }) at the start of every session.`;
|
|
34195
|
+
async function writeInstructionSection(filePath, content) {
|
|
34196
|
+
const section = `${PK_SECTION_START}
|
|
34197
|
+
${content}
|
|
34198
|
+
${PK_SECTION_END}
|
|
34199
|
+
`;
|
|
34200
|
+
let existing = "";
|
|
34201
|
+
try {
|
|
34202
|
+
existing = await Bun.file(filePath).text();
|
|
34203
|
+
} catch {}
|
|
34204
|
+
const startIdx = existing.indexOf(PK_SECTION_START);
|
|
34205
|
+
const endIdx = existing.indexOf(PK_SECTION_END);
|
|
34206
|
+
let updated;
|
|
34207
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
34208
|
+
updated = existing.slice(0, startIdx) + section + existing.slice(endIdx + PK_SECTION_END.length + 1);
|
|
34209
|
+
} else {
|
|
34210
|
+
updated = existing ? existing.trimEnd() + `
|
|
34211
|
+
|
|
34212
|
+
` + section : section;
|
|
34213
|
+
}
|
|
34214
|
+
mkdirSync4(path7.dirname(filePath), { recursive: true });
|
|
34215
|
+
await Bun.write(filePath, updated);
|
|
34216
|
+
}
|
|
34217
|
+
async function writeClaudeMd(projectRoot) {
|
|
34218
|
+
await writeInstructionSection(path7.join(projectRoot, "CLAUDE.md"), PK_INSTRUCTION);
|
|
34219
|
+
}
|
|
34220
|
+
async function writeAgentsMd(projectRoot) {
|
|
34221
|
+
await writeInstructionSection(path7.join(projectRoot, "AGENTS.md"), PK_INSTRUCTION);
|
|
34222
|
+
}
|
|
34223
|
+
var FORCED_EVAL_PROMPT = "SKILL EVALUATION REQUIRED: Before responding, explicitly decide YES or NO" + " \u2014 does this request involve project work, investigation, decisions, or knowledge capture" + " where the pk skill applies? If YES, activate the pk skill, then proceed.";
|
|
34224
|
+
function claudeHookScript() {
|
|
34225
|
+
return `// pk forced-eval hook \u2014 auto-generated by pk init
|
|
34226
|
+
async function handleUserPromptSubmit() {
|
|
34227
|
+
console.log(JSON.stringify({
|
|
34228
|
+
hookSpecificOutput: {
|
|
34229
|
+
hookEventName: 'UserPromptSubmit',
|
|
34230
|
+
additionalContext: ${JSON.stringify(FORCED_EVAL_PROMPT)},
|
|
34231
|
+
},
|
|
34232
|
+
suppressOutput: true,
|
|
34233
|
+
}));
|
|
34234
|
+
}
|
|
34235
|
+
|
|
34236
|
+
handleUserPromptSubmit().catch(() => process.exit(0));
|
|
34237
|
+
`;
|
|
34238
|
+
}
|
|
34239
|
+
async function writeClaudeHook(projectRoot) {
|
|
34240
|
+
const hookDir = path7.join(projectRoot, ".claude", "hooks");
|
|
34241
|
+
const hookPath = path7.join(hookDir, "pk-eval.ts");
|
|
34242
|
+
mkdirSync4(hookDir, { recursive: true });
|
|
34243
|
+
await Bun.write(hookPath, claudeHookScript());
|
|
34244
|
+
const settingsPath = path7.join(projectRoot, ".claude", "settings.json");
|
|
34245
|
+
const settings = await readJson(settingsPath);
|
|
34246
|
+
const hooks = settings.hooks ?? {};
|
|
34247
|
+
const ups = hooks.UserPromptSubmit ?? [];
|
|
34248
|
+
const hookCmd = `bun run ${hookPath}`;
|
|
34249
|
+
if (!ups.some((h2) => h2.command === hookCmd)) {
|
|
34250
|
+
ups.push({ command: hookCmd });
|
|
34251
|
+
}
|
|
34252
|
+
hooks.UserPromptSubmit = ups;
|
|
34253
|
+
settings.hooks = hooks;
|
|
34254
|
+
await writeJson(settingsPath, settings);
|
|
34255
|
+
}
|
|
34256
|
+
function ompHookScript() {
|
|
34257
|
+
return `// pk forced-eval hook \u2014 auto-generated by pk init
|
|
34258
|
+
import type {HookAPI} from '@oh-my-pi/pi-coding-agent/extensibility/hooks';
|
|
34259
|
+
|
|
34260
|
+
export default function (pi: HookAPI) {
|
|
34261
|
+
pi.on('before_agent_start', (event: {systemPrompt?: string}) => ({
|
|
34262
|
+
systemPrompt: ${JSON.stringify(FORCED_EVAL_PROMPT)} + '\\n\\n' + (event.systemPrompt ?? ''),
|
|
34263
|
+
}));
|
|
34264
|
+
}
|
|
34265
|
+
`;
|
|
34266
|
+
}
|
|
34267
|
+
async function writeOmpHook(projectRoot) {
|
|
34268
|
+
const hookPath = path7.join(projectRoot, ".omp", "extensions", "pk-eval.ts");
|
|
34269
|
+
mkdirSync4(path7.dirname(hookPath), { recursive: true });
|
|
34270
|
+
await Bun.write(hookPath, ompHookScript());
|
|
34271
|
+
}
|
|
34190
34272
|
async function writeCursorConfig(projectRoot, _name, knowledgeDir) {
|
|
34191
34273
|
const cfgPath = path7.join(projectRoot, ".cursor", "mcp.json");
|
|
34192
34274
|
const cfg = await readJson(cfgPath);
|
|
@@ -34195,62 +34277,171 @@ async function writeCursorConfig(projectRoot, _name, knowledgeDir) {
|
|
|
34195
34277
|
cfg.mcpServers = servers;
|
|
34196
34278
|
await writeJson(cfgPath, cfg);
|
|
34197
34279
|
}
|
|
34198
|
-
async function
|
|
34199
|
-
const
|
|
34280
|
+
async function writeCursorRules(projectRoot) {
|
|
34281
|
+
const rulesPath = path7.join(projectRoot, ".cursor", "rules", "pk.mdc");
|
|
34282
|
+
const content = `---
|
|
34283
|
+
description: "pk knowledge base integration"
|
|
34284
|
+
alwaysApply: true
|
|
34285
|
+
---
|
|
34286
|
+
|
|
34287
|
+
${PK_INSTRUCTION}
|
|
34288
|
+
`;
|
|
34289
|
+
mkdirSync4(path7.dirname(rulesPath), { recursive: true });
|
|
34290
|
+
await Bun.write(rulesPath, content);
|
|
34291
|
+
}
|
|
34292
|
+
function cursorHookScript() {
|
|
34293
|
+
return `#!/bin/bash
|
|
34294
|
+
# pk forced-eval hook \u2014 auto-generated by pk init
|
|
34295
|
+
# Exit 0 to allow, exit 2 to block
|
|
34296
|
+
|
|
34297
|
+
# Return the forced-eval prompt as additional context
|
|
34298
|
+
cat <<EOF
|
|
34299
|
+
{
|
|
34300
|
+
"continue": true,
|
|
34301
|
+
"additionalContext": ${JSON.stringify(FORCED_EVAL_PROMPT)}
|
|
34302
|
+
}
|
|
34303
|
+
EOF
|
|
34304
|
+
`;
|
|
34305
|
+
}
|
|
34306
|
+
async function writeCursorHook(projectRoot) {
|
|
34307
|
+
const hookPath = path7.join(projectRoot, ".cursor", "hooks", "pk-eval.sh");
|
|
34308
|
+
mkdirSync4(path7.dirname(hookPath), { recursive: true });
|
|
34309
|
+
await Bun.write(hookPath, cursorHookScript());
|
|
34310
|
+
const hooksPath = path7.join(projectRoot, ".cursor", "hooks.json");
|
|
34311
|
+
const hooks = await readJson(hooksPath);
|
|
34312
|
+
const hooksObj = hooks.hooks ?? {};
|
|
34313
|
+
const bsp = hooksObj.beforeSubmitPrompt ?? [];
|
|
34314
|
+
if (!bsp.some((h2) => h2.command === hookPath)) {
|
|
34315
|
+
bsp.push({ command: hookPath });
|
|
34316
|
+
}
|
|
34317
|
+
hooksObj.beforeSubmitPrompt = bsp;
|
|
34318
|
+
hooks.hooks = hooksObj;
|
|
34319
|
+
await writeJson(hooksPath, hooks);
|
|
34320
|
+
}
|
|
34321
|
+
async function writeGeminiConfig(projectRoot, _name, knowledgeDir) {
|
|
34322
|
+
const cfgPath = path7.join(projectRoot, ".gemini", "settings.json");
|
|
34200
34323
|
const cfg = await readJson(cfgPath);
|
|
34201
34324
|
const servers = cfg.mcpServers ?? {};
|
|
34202
34325
|
servers.pk = pkMcpEntry(knowledgeDir);
|
|
34203
34326
|
cfg.mcpServers = servers;
|
|
34204
34327
|
await writeJson(cfgPath, cfg);
|
|
34205
34328
|
}
|
|
34329
|
+
async function writeGeminiMd(projectRoot) {
|
|
34330
|
+
await writeInstructionSection(path7.join(projectRoot, "GEMINI.md"), PK_INSTRUCTION);
|
|
34331
|
+
}
|
|
34332
|
+
function geminiHookScript() {
|
|
34333
|
+
return `#!/bin/bash
|
|
34334
|
+
# pk forced-eval hook \u2014 auto-generated by pk init
|
|
34335
|
+
# Output JSON to stdout with the forced-eval prompt
|
|
34336
|
+
|
|
34337
|
+
cat <<EOF
|
|
34338
|
+
{
|
|
34339
|
+
"hookSpecificOutput": {
|
|
34340
|
+
"hookEventName": "BeforeAgent",
|
|
34341
|
+
"additionalContext": ${JSON.stringify(FORCED_EVAL_PROMPT)}
|
|
34342
|
+
}
|
|
34343
|
+
}
|
|
34344
|
+
EOF
|
|
34345
|
+
`;
|
|
34346
|
+
}
|
|
34347
|
+
async function writeGeminiHook(projectRoot) {
|
|
34348
|
+
const hookPath = path7.join(projectRoot, ".gemini", "hooks", "pk-eval.sh");
|
|
34349
|
+
mkdirSync4(path7.dirname(hookPath), { recursive: true });
|
|
34350
|
+
await Bun.write(hookPath, geminiHookScript());
|
|
34351
|
+
const cfgPath = path7.join(projectRoot, ".gemini", "settings.json");
|
|
34352
|
+
const cfg = await readJson(cfgPath);
|
|
34353
|
+
const hooks = cfg.hooks ?? {};
|
|
34354
|
+
const beforeAgent = hooks.BeforeAgent ?? [];
|
|
34355
|
+
if (!beforeAgent.some((h2) => h2.command === hookPath)) {
|
|
34356
|
+
beforeAgent.push({ command: hookPath });
|
|
34357
|
+
}
|
|
34358
|
+
hooks.BeforeAgent = beforeAgent;
|
|
34359
|
+
cfg.hooks = hooks;
|
|
34360
|
+
await writeJson(cfgPath, cfg);
|
|
34361
|
+
}
|
|
34362
|
+
async function writeToml(filePath, content) {
|
|
34363
|
+
mkdirSync4(path7.dirname(filePath), { recursive: true });
|
|
34364
|
+
await Bun.write(filePath, content);
|
|
34365
|
+
}
|
|
34366
|
+
async function writeCodexConfig(projectRoot, _name, knowledgeDir) {
|
|
34367
|
+
const cfgPath = path7.join(projectRoot, ".codex", "config.toml");
|
|
34368
|
+
const pkCmd = resolvePkCommand();
|
|
34369
|
+
const toml = `[mcp_servers.pk]
|
|
34370
|
+
command = "${pkCmd}"
|
|
34371
|
+
args = ["mcp"]
|
|
34372
|
+
env = { PK_KNOWLEDGE_DIR = "${knowledgeDir}" }
|
|
34373
|
+
`;
|
|
34374
|
+
await writeToml(cfgPath, toml);
|
|
34375
|
+
}
|
|
34376
|
+
function codexHookScript() {
|
|
34377
|
+
return `#!/bin/bash
|
|
34378
|
+
# pk forced-eval hook \u2014 auto-generated by pk init
|
|
34379
|
+
# Output JSON to stdout
|
|
34380
|
+
|
|
34381
|
+
cat <<EOF
|
|
34382
|
+
{
|
|
34383
|
+
"continue": true,
|
|
34384
|
+
"suppressOutput": false
|
|
34385
|
+
}
|
|
34386
|
+
EOF
|
|
34387
|
+
`;
|
|
34388
|
+
}
|
|
34389
|
+
async function writeCodexHook(projectRoot) {
|
|
34390
|
+
const hookPath = path7.join(projectRoot, ".codex", "hooks", "pk-eval.sh");
|
|
34391
|
+
mkdirSync4(path7.dirname(hookPath), { recursive: true });
|
|
34392
|
+
await Bun.write(hookPath, codexHookScript());
|
|
34393
|
+
const hooksPath = path7.join(projectRoot, ".codex", "hooks.json");
|
|
34394
|
+
const hooks = await readJson(hooksPath);
|
|
34395
|
+
const hooksObj = hooks.hooks ?? {};
|
|
34396
|
+
const ups = hooksObj.UserPromptSubmit ?? [];
|
|
34397
|
+
if (!ups.some((h2) => typeof h2 === "object" && h2 !== null && ("command" in h2) && typeof h2.command === "string" && h2.command.includes("pk-eval"))) {
|
|
34398
|
+
ups.push({ command: hookPath });
|
|
34399
|
+
}
|
|
34400
|
+
hooksObj.UserPromptSubmit = ups;
|
|
34401
|
+
hooks.hooks = hooksObj;
|
|
34402
|
+
await writeJson(hooksPath, hooks);
|
|
34403
|
+
}
|
|
34206
34404
|
async function writeOpenCodeConfig(projectRoot, _name, knowledgeDir) {
|
|
34207
34405
|
const cfgPath = path7.join(projectRoot, "opencode.json");
|
|
34208
34406
|
const cfg = await readJson(cfgPath);
|
|
34209
34407
|
const mcp = cfg.mcp ?? {};
|
|
34210
|
-
|
|
34408
|
+
const pkCmd = resolvePkCommand();
|
|
34409
|
+
mcp.pk = {
|
|
34410
|
+
type: "local",
|
|
34411
|
+
enabled: true,
|
|
34412
|
+
command: [pkCmd, "mcp"],
|
|
34413
|
+
environment: { PK_KNOWLEDGE_DIR: knowledgeDir }
|
|
34414
|
+
};
|
|
34211
34415
|
cfg.mcp = mcp;
|
|
34212
34416
|
await writeJson(cfgPath, cfg);
|
|
34213
34417
|
}
|
|
34214
|
-
|
|
34215
|
-
|
|
34216
|
-
|
|
34217
|
-
|
|
34218
|
-
|
|
34219
|
-
|
|
34220
|
-
|
|
34221
|
-
|
|
34222
|
-
|
|
34223
|
-
|
|
34224
|
-
|
|
34225
|
-
|
|
34226
|
-
|
|
34227
|
-
if (existsSync3(cfgPath)) {
|
|
34228
|
-
const existing = await Bun.file(cfgPath).text();
|
|
34229
|
-
if (existing.includes("[mcp_servers.pk]")) {
|
|
34230
|
-
return;
|
|
34231
|
-
}
|
|
34232
|
-
await Bun.write(cfgPath, existing.trimEnd() + `
|
|
34233
|
-
|
|
34234
|
-
` + toml);
|
|
34235
|
-
} else {
|
|
34236
|
-
await Bun.write(cfgPath, toml);
|
|
34237
|
-
}
|
|
34418
|
+
function openCodePluginScript() {
|
|
34419
|
+
return `// pk forced-eval plugin \u2014 auto-generated by pk init
|
|
34420
|
+
export const experimental = {
|
|
34421
|
+
async 'chat.system.transform'({ system }: { system: string[] }): Promise<void> {
|
|
34422
|
+
system.unshift(${JSON.stringify(FORCED_EVAL_PROMPT)});
|
|
34423
|
+
},
|
|
34424
|
+
};
|
|
34425
|
+
`;
|
|
34426
|
+
}
|
|
34427
|
+
async function writeOpenCodePlugin(projectRoot) {
|
|
34428
|
+
const pluginPath = path7.join(projectRoot, ".opencode", "plugins", "pk-eval.ts");
|
|
34429
|
+
mkdirSync4(path7.dirname(pluginPath), { recursive: true });
|
|
34430
|
+
await Bun.write(pluginPath, openCodePluginScript());
|
|
34238
34431
|
}
|
|
34239
34432
|
function skillTargetDir(harness, projectRoot) {
|
|
34240
34433
|
switch (harness) {
|
|
34241
|
-
case "claude":
|
|
34242
|
-
case "claude-desktop": {
|
|
34434
|
+
case "claude": {
|
|
34243
34435
|
return path7.join(os3.homedir(), ".claude", "skills", "pk");
|
|
34244
34436
|
}
|
|
34245
|
-
case "omp":
|
|
34437
|
+
case "omp":
|
|
34438
|
+
case "cursor":
|
|
34439
|
+
case "gemini":
|
|
34440
|
+
case "opencode": {
|
|
34246
34441
|
return path7.join(projectRoot, ".agents", "skills", "pk");
|
|
34247
34442
|
}
|
|
34248
|
-
case "cursor": {
|
|
34249
|
-
return path7.join(projectRoot, ".cursor", "skills", "pk");
|
|
34250
|
-
}
|
|
34251
|
-
case "opencode":
|
|
34252
34443
|
case "codex": {
|
|
34253
|
-
return "";
|
|
34444
|
+
return path7.join(os3.homedir(), ".codex", "skills", "pk");
|
|
34254
34445
|
}
|
|
34255
34446
|
}
|
|
34256
34447
|
}
|
|
@@ -34286,30 +34477,43 @@ async function ensureProject(name) {
|
|
|
34286
34477
|
return { created: !alreadyExists, knowledgeDir: kDir };
|
|
34287
34478
|
}
|
|
34288
34479
|
async function applyHarness(harness, ctx) {
|
|
34289
|
-
const { name, knowledgeDir, projectRoot
|
|
34480
|
+
const { name, knowledgeDir, projectRoot } = ctx;
|
|
34290
34481
|
switch (harness) {
|
|
34291
34482
|
case "claude": {
|
|
34292
34483
|
await writeClaudeConfig(projectRoot, name, knowledgeDir);
|
|
34484
|
+
await writeClaudeMd(projectRoot);
|
|
34485
|
+
await writeClaudeHook(projectRoot);
|
|
34293
34486
|
break;
|
|
34294
34487
|
}
|
|
34295
|
-
case "
|
|
34296
|
-
await
|
|
34297
|
-
|
|
34298
|
-
|
|
34299
|
-
case "codex": {
|
|
34300
|
-
await writeCodexConfig(projectRoot, name, knowledgeDir);
|
|
34488
|
+
case "omp": {
|
|
34489
|
+
await writeOmpConfig(projectRoot, name, knowledgeDir);
|
|
34490
|
+
await writeAgentsMd(projectRoot);
|
|
34491
|
+
await writeOmpHook(projectRoot);
|
|
34301
34492
|
break;
|
|
34302
34493
|
}
|
|
34303
34494
|
case "cursor": {
|
|
34304
34495
|
await writeCursorConfig(projectRoot, name, knowledgeDir);
|
|
34496
|
+
await writeCursorRules(projectRoot);
|
|
34497
|
+
await writeCursorHook(projectRoot);
|
|
34305
34498
|
break;
|
|
34306
34499
|
}
|
|
34307
|
-
case "
|
|
34308
|
-
await
|
|
34500
|
+
case "gemini": {
|
|
34501
|
+
await writeGeminiConfig(projectRoot, name, knowledgeDir);
|
|
34502
|
+
await writeGeminiMd(projectRoot);
|
|
34503
|
+
await writeGeminiHook(projectRoot);
|
|
34504
|
+
break;
|
|
34505
|
+
}
|
|
34506
|
+
case "codex": {
|
|
34507
|
+
await writeCodexConfig(projectRoot, name, knowledgeDir);
|
|
34508
|
+
await writeAgentsMd(projectRoot);
|
|
34509
|
+
await writeCodexHook(projectRoot);
|
|
34309
34510
|
break;
|
|
34310
34511
|
}
|
|
34311
34512
|
case "opencode": {
|
|
34312
34513
|
await writeOpenCodeConfig(projectRoot, name, knowledgeDir);
|
|
34514
|
+
await writeAgentsMd(projectRoot);
|
|
34515
|
+
await writeClaudeMd(projectRoot);
|
|
34516
|
+
await writeOpenCodePlugin(projectRoot);
|
|
34313
34517
|
break;
|
|
34314
34518
|
}
|
|
34315
34519
|
}
|
|
@@ -42963,6 +43167,18 @@ function registerMcp(program2) {
|
|
|
42963
43167
|
});
|
|
42964
43168
|
}
|
|
42965
43169
|
|
|
43170
|
+
// src/commands/prime.ts
|
|
43171
|
+
import path8 from "path";
|
|
43172
|
+
function skillPath() {
|
|
43173
|
+
return path8.resolve(import.meta.dir, "..", "skill", "SKILL.md");
|
|
43174
|
+
}
|
|
43175
|
+
function registerPrime(program2) {
|
|
43176
|
+
program2.command("prime").description("Print the pk skill to stdout \u2014 used by harness adapters to inject into system prompt at session start").action(async () => {
|
|
43177
|
+
const text = await Bun.file(skillPath()).text();
|
|
43178
|
+
process.stdout.write(text.replace(/^---[\s\S]*?---\n/v, ""));
|
|
43179
|
+
});
|
|
43180
|
+
}
|
|
43181
|
+
|
|
42966
43182
|
// src/index.ts
|
|
42967
43183
|
var program2 = new Command().name("pk").description("Project knowledge \u2014 structured intake, search, and recall").version(package_default.version);
|
|
42968
43184
|
registerNew(program2);
|
|
@@ -42975,4 +43191,5 @@ registerInit(program2);
|
|
|
42975
43191
|
registerInstructions(program2);
|
|
42976
43192
|
registerVocab(program2);
|
|
42977
43193
|
registerMcp(program2);
|
|
43194
|
+
registerPrime(program2);
|
|
42978
43195
|
program2.parse();
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -72,8 +72,6 @@ No MCP tool for status changes. Use your file Edit tool directly on the frontmat
|
|
|
72
72
|
|
|
73
73
|
**MANDATORY READ `references/knowledge-model.md`** when: creating a note type you haven't used before, unsure which folder a type belongs in, validating frontmatter fields, or unsure which status values are valid for a given type. (Read with your standard file Read tool — these are local skill files, not MCP-accessible.)
|
|
74
74
|
|
|
75
|
-
**MANDATORY READ `references/git-workflow.md`** when: committing knowledge changes or unsure whether to auto-commit. (Same — standard file Read tool.)
|
|
76
|
-
|
|
77
75
|
## NEVER
|
|
78
76
|
|
|
79
77
|
- **NEVER skip `pk_search` before `pk_new`**
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
This system is project-specific. It is not a personal second brain, a full wiki platform, or a semantic memory database.
|
|
6
6
|
|
|
7
|
-
The canonical store is plain markdown
|
|
7
|
+
The canonical store is plain markdown files managed via `pk` MCP tools. The root directory is set by `PK_KNOWLEDGE_DIR`. The knowledge base is for durable context and future answers — not for task tracking.
|
|
8
8
|
|
|
9
9
|
## Folder and Type Rules
|
|
10
10
|
|
|
11
|
-
| Type |
|
|
11
|
+
| Type | Subfolder | Purpose | Status values |
|
|
12
12
|
| --- | --- | --- | --- |
|
|
13
|
-
| `source` | `
|
|
14
|
-
| `note` | `
|
|
15
|
-
| `decision` | `
|
|
16
|
-
| `question` | `
|
|
17
|
-
| `index` | `
|
|
13
|
+
| `source` | `sources/` | Provenance and raw/lightly cleaned input | `unprocessed`, `processed`, `archived` |
|
|
14
|
+
| `note` | `notes/` | Durable project knowledge | `active`, `superseded`, `archived` |
|
|
15
|
+
| `decision` | `decisions/` | Chosen direction and rationale | `proposed`, `accepted`, `superseded` |
|
|
16
|
+
| `question` | `questions/` | Unresolved or resolved uncertainty | `open`, `answered`, `obsolete` |
|
|
17
|
+
| `index` | `indexes/` | Navigation/MOC pages | `active`, `archived` |
|
|
18
18
|
|
|
19
19
|
## Frontmatter
|
|
20
20
|
|
|
@@ -34,7 +34,7 @@ tags: [tag-one, tag-two]
|
|
|
34
34
|
|
|
35
35
|
Rules:
|
|
36
36
|
|
|
37
|
-
- `id` must be unique across
|
|
37
|
+
- `id` must be unique across all notes in the knowledge directory.
|
|
38
38
|
- `type` must match both status set and folder.
|
|
39
39
|
- `tags` must be a flat list of lowercase slugs.
|
|
40
40
|
- Do not use nested YAML, multiline YAML, or relationship arrays.
|
|
@@ -85,7 +85,7 @@ Classify extracted material this way:
|
|
|
85
85
|
- Chosen path with rationale/consequences → `decision`
|
|
86
86
|
- Unknown that blocks or informs work → `question`
|
|
87
87
|
- Navigation over a topic/type/tag → `index`
|
|
88
|
-
- Action item/task →
|
|
88
|
+
- Action item/task → not a knowledge note; track elsewhere
|
|
89
89
|
- Low-signal commentary → ignore or keep only in `source`
|
|
90
90
|
|
|
91
91
|
## Update Policy
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# Git Workflow for Project Knowledge
|
|
2
|
-
|
|
3
|
-
Git is the audit, safety, and review layer for `knowledge/`.
|
|
4
|
-
|
|
5
|
-
## Before Modifying Knowledge
|
|
6
|
-
|
|
7
|
-
Check repository state:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
git status --short
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Stop before editing if unrelated user changes would be mixed into the same commit. If changes are clearly knowledge-system work in scope, continue.
|
|
14
|
-
|
|
15
|
-
## After Modifying Knowledge
|
|
16
|
-
|
|
17
|
-
Run mechanical maintenance:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
scripts/knowledge-index
|
|
21
|
-
scripts/knowledge-lint
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Review what changed:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
git diff -- knowledge scripts/knowledge-* assets/templates hk.pkl
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Summarize:
|
|
31
|
-
|
|
32
|
-
- files created
|
|
33
|
-
- files updated
|
|
34
|
-
- generated indexes
|
|
35
|
-
- lint result
|
|
36
|
-
- any ignored/deferred material
|
|
37
|
-
|
|
38
|
-
## Auto-Commit Policy
|
|
39
|
-
|
|
40
|
-
Auto-commit coherent completed knowledge operations unless a safety stop applies.
|
|
41
|
-
|
|
42
|
-
Normal intake commits stage only:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
git add knowledge/
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Knowledge-system implementation commits may stage:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
git add knowledge/ scripts/knowledge-* assets/templates/ hk.pkl
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Use concise commit messages:
|
|
55
|
-
|
|
56
|
-
```txt
|
|
57
|
-
knowledge: intake <topic>
|
|
58
|
-
knowledge: update <topic>
|
|
59
|
-
knowledge: answer <topic>
|
|
60
|
-
knowledge-system: update <topic>
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Safety Stops
|
|
64
|
-
|
|
65
|
-
Do not auto-commit when:
|
|
66
|
-
|
|
67
|
-
- unrelated project files are modified
|
|
68
|
-
- lint fails
|
|
69
|
-
- the edit deletes or rewrites existing knowledge ambiguously
|
|
70
|
-
- the working tree contains user changes outside the allowed commit boundary
|
|
71
|
-
- the user says not to commit
|
|
72
|
-
|
|
73
|
-
When stopped, report the exact reason and show the staged/unstaged state.
|
|
74
|
-
|
|
75
|
-
## Hooks
|
|
76
|
-
|
|
77
|
-
If hk is used, run `knowledge-lint` on pre-commit only when `knowledge/**/*.md` changes. Avoid every-N-commit scheduling; it is arbitrary and less transparent than change-triggered checks.
|