@codeharbor/agent-playbook 0.1.1 → 0.1.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/README.md +4 -2
- package/package.json +1 -1
- package/src/cli.js +82 -10
package/README.md
CHANGED
|
@@ -23,16 +23,18 @@ pnpm dlx @codeharbor/agent-playbook init --project
|
|
|
23
23
|
- Records a metadata block in `~/.codex/config.toml`.
|
|
24
24
|
|
|
25
25
|
## Commands
|
|
26
|
-
- `agent-playbook init [--project] [--copy] [--hooks] [--no-hooks] [--session-dir <path>] [--dry-run] [--repo <path>]`
|
|
26
|
+
- `agent-playbook init [--project] [--copy] [--overwrite] [--hooks] [--no-hooks] [--session-dir <path>] [--dry-run] [--repo <path>]`
|
|
27
27
|
- `agent-playbook status`
|
|
28
28
|
- `agent-playbook doctor`
|
|
29
|
-
- `agent-playbook repair`
|
|
29
|
+
- `agent-playbook repair [--overwrite]`
|
|
30
30
|
- `agent-playbook uninstall`
|
|
31
31
|
- `agent-playbook session-log [--session-dir <path>]`
|
|
32
32
|
- `agent-playbook self-improve`
|
|
33
33
|
|
|
34
34
|
## Notes
|
|
35
35
|
- Default session logs go to repo `sessions/` if a Git root is found; otherwise `~/.claude/sessions/`.
|
|
36
|
+
- If skill folders already exist, you will be prompted before overwriting. Use `--overwrite` to skip the prompt.
|
|
37
|
+
- Session logs and self-improve entries record the agent-playbook version.
|
|
36
38
|
- Hooks are merged without overwriting existing user hooks.
|
|
37
39
|
- Requires Node.js 18+.
|
|
38
40
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -48,10 +48,10 @@ function printHelp() {
|
|
|
48
48
|
`${APP_NAME} ${VERSION}`,
|
|
49
49
|
"",
|
|
50
50
|
"Usage:",
|
|
51
|
-
` ${APP_NAME} init [--project] [--copy] [--hooks] [--no-hooks] [--session-dir <path>] [--dry-run] [--repo <path>]`,
|
|
51
|
+
` ${APP_NAME} init [--project] [--copy] [--overwrite] [--hooks] [--no-hooks] [--session-dir <path>] [--dry-run] [--repo <path>]`,
|
|
52
52
|
` ${APP_NAME} status [--project] [--repo <path>]`,
|
|
53
53
|
` ${APP_NAME} doctor [--project] [--repo <path>]`,
|
|
54
|
-
` ${APP_NAME} repair [--project] [--repo <path>]`,
|
|
54
|
+
` ${APP_NAME} repair [--project] [--overwrite] [--repo <path>]`,
|
|
55
55
|
` ${APP_NAME} uninstall [--project] [--repo <path>]`,
|
|
56
56
|
"",
|
|
57
57
|
"Hook commands:",
|
|
@@ -116,6 +116,7 @@ function handleInit(options, context) {
|
|
|
116
116
|
const hooksEnabled = options.hooks !== false;
|
|
117
117
|
const repoRoot = settings.repoRoot;
|
|
118
118
|
const warnings = [];
|
|
119
|
+
const overwriteState = createOverwriteState(options);
|
|
119
120
|
|
|
120
121
|
if (!settings.skillsSource) {
|
|
121
122
|
if (options.repair) {
|
|
@@ -143,8 +144,8 @@ function handleInit(options, context) {
|
|
|
143
144
|
let claudeLinks = { created: [], skipped: [] };
|
|
144
145
|
let codexLinks = { created: [], skipped: [] };
|
|
145
146
|
if (settings.skillsSource) {
|
|
146
|
-
claudeLinks = linkSkills(settings.skillsSource, settings.claudeSkillsDir, options);
|
|
147
|
-
codexLinks = linkSkills(settings.skillsSource, settings.codexSkillsDir, options);
|
|
147
|
+
claudeLinks = linkSkills(settings.skillsSource, settings.claudeSkillsDir, options, overwriteState);
|
|
148
|
+
codexLinks = linkSkills(settings.skillsSource, settings.codexSkillsDir, options, overwriteState);
|
|
148
149
|
manifest.links.claude = claudeLinks.created;
|
|
149
150
|
manifest.links.codex = codexLinks.created;
|
|
150
151
|
|
|
@@ -251,6 +252,7 @@ async function handleSelfImprove(options) {
|
|
|
251
252
|
session_id: sessionId,
|
|
252
253
|
cwd,
|
|
253
254
|
transcript_path: transcriptPath,
|
|
255
|
+
agent_playbook_version: VERSION,
|
|
254
256
|
hook_event: input.hook_event_name || "PostToolUse",
|
|
255
257
|
tool_name: input.tool_name || "",
|
|
256
258
|
tool_input: input.tool_input || "",
|
|
@@ -339,9 +341,65 @@ function resolveSkillsSource(candidates) {
|
|
|
339
341
|
return null;
|
|
340
342
|
}
|
|
341
343
|
|
|
342
|
-
function
|
|
344
|
+
function createOverwriteState(options) {
|
|
345
|
+
return {
|
|
346
|
+
decision: options.overwrite === true ? true : null,
|
|
347
|
+
prompted: false,
|
|
348
|
+
nonInteractive: false,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function promptYesNo(question, defaultYes) {
|
|
353
|
+
const suffix = defaultYes ? "[Y/n]" : "[y/N]";
|
|
354
|
+
process.stdout.write(`${question} ${suffix} `);
|
|
355
|
+
const answer = readLineSync().toLowerCase();
|
|
356
|
+
if (!answer) {
|
|
357
|
+
return defaultYes;
|
|
358
|
+
}
|
|
359
|
+
return answer === "y" || answer === "yes";
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function readLineSync() {
|
|
363
|
+
const buffer = Buffer.alloc(1024);
|
|
364
|
+
let input = "";
|
|
365
|
+
while (true) {
|
|
366
|
+
const bytes = fs.readSync(0, buffer, 0, buffer.length, null);
|
|
367
|
+
if (bytes <= 0) {
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
input += buffer.toString("utf8", 0, bytes);
|
|
371
|
+
if (input.includes("\n")) {
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return input.trim();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function shouldOverwriteExisting(options, state, targetPath) {
|
|
379
|
+
if (options.overwrite) {
|
|
380
|
+
state.decision = true;
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
384
|
+
state.nonInteractive = true;
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
if (state.decision !== null) {
|
|
388
|
+
return state.decision;
|
|
389
|
+
}
|
|
390
|
+
state.prompted = true;
|
|
391
|
+
state.decision = promptYesNo(
|
|
392
|
+
`Existing skill found at ${targetPath}. Overwrite all existing skills?`,
|
|
393
|
+
false
|
|
394
|
+
);
|
|
395
|
+
return state.decision;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function linkSkills(sourceDir, targetDir, options, overwriteState) {
|
|
343
399
|
const created = [];
|
|
344
400
|
const skipped = [];
|
|
401
|
+
const overwritten = [];
|
|
402
|
+
const state = overwriteState || createOverwriteState(options);
|
|
345
403
|
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
346
404
|
|
|
347
405
|
entries.forEach((entry) => {
|
|
@@ -364,8 +422,14 @@ function linkSkills(sourceDir, targetDir, options) {
|
|
|
364
422
|
skipped.push({ source: skillDir, target: targetPath, reason: "already linked" });
|
|
365
423
|
return;
|
|
366
424
|
}
|
|
367
|
-
|
|
368
|
-
|
|
425
|
+
if (!shouldOverwriteExisting(options, state, targetPath)) {
|
|
426
|
+
skipped.push({ source: skillDir, target: targetPath, reason: "exists" });
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
overwritten.push({ source: skillDir, target: targetPath });
|
|
430
|
+
if (!options["dry-run"]) {
|
|
431
|
+
safeUnlink(targetPath);
|
|
432
|
+
}
|
|
369
433
|
}
|
|
370
434
|
|
|
371
435
|
if (options["dry-run"]) {
|
|
@@ -389,7 +453,7 @@ function linkSkills(sourceDir, targetDir, options) {
|
|
|
389
453
|
}
|
|
390
454
|
});
|
|
391
455
|
|
|
392
|
-
return { created, skipped };
|
|
456
|
+
return { created, skipped, overwritten };
|
|
393
457
|
}
|
|
394
458
|
|
|
395
459
|
function ensureLocalCli(settings, context, options) {
|
|
@@ -800,6 +864,7 @@ function buildSessionSummary(insights, sessionId, cwd) {
|
|
|
800
864
|
`**Date**: ${date}`,
|
|
801
865
|
`**Duration**: unknown`,
|
|
802
866
|
`**Context**: ${repoRoot}`,
|
|
867
|
+
`**Agent Playbook Version**: ${VERSION}`,
|
|
803
868
|
"",
|
|
804
869
|
"## Summary",
|
|
805
870
|
"Auto-generated session log.",
|
|
@@ -907,6 +972,12 @@ function printInitSummary(settings, hooksEnabled, options, claudeLinks, codexLin
|
|
|
907
972
|
console.log(`- Codex skills: ${settings.codexSkillsDir}`);
|
|
908
973
|
console.log(`- Hooks: ${hooksEnabled ? "enabled" : "disabled"}`);
|
|
909
974
|
console.log(`- Linked skills: ${claudeLinks.created.length + codexLinks.created.length}`);
|
|
975
|
+
const overwrittenCount =
|
|
976
|
+
(claudeLinks.overwritten ? claudeLinks.overwritten.length : 0) +
|
|
977
|
+
(codexLinks.overwritten ? codexLinks.overwritten.length : 0);
|
|
978
|
+
if (overwrittenCount) {
|
|
979
|
+
console.log(`- Overwritten skills: ${overwrittenCount}`);
|
|
980
|
+
}
|
|
910
981
|
if (claudeLinks.skipped.length || codexLinks.skipped.length) {
|
|
911
982
|
console.log("- Some skills were skipped due to existing paths.");
|
|
912
983
|
}
|
|
@@ -1064,6 +1135,7 @@ function handleRepair(options, context) {
|
|
|
1064
1135
|
const settings = resolveSettings(options, context);
|
|
1065
1136
|
const status = collectStatus(settings);
|
|
1066
1137
|
const warnings = [];
|
|
1138
|
+
const overwriteState = createOverwriteState(options);
|
|
1067
1139
|
|
|
1068
1140
|
if (!settings.skillsSource) {
|
|
1069
1141
|
warnings.push("Skills directory not found; skipping skill linking.");
|
|
@@ -1094,8 +1166,8 @@ function handleRepair(options, context) {
|
|
|
1094
1166
|
}
|
|
1095
1167
|
|
|
1096
1168
|
if (settings.skillsSource) {
|
|
1097
|
-
linkSkills(settings.skillsSource, settings.claudeSkillsDir, options);
|
|
1098
|
-
linkSkills(settings.skillsSource, settings.codexSkillsDir, options);
|
|
1169
|
+
linkSkills(settings.skillsSource, settings.claudeSkillsDir, options, overwriteState);
|
|
1170
|
+
linkSkills(settings.skillsSource, settings.codexSkillsDir, options, overwriteState);
|
|
1099
1171
|
if (!options["dry-run"]) {
|
|
1100
1172
|
const manifestPath = path.join(settings.claudeSkillsDir, ".agent-playbook.json");
|
|
1101
1173
|
if (!fs.existsSync(manifestPath)) {
|