bitacora-cli 1.1.0 → 1.1.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/README.md +36 -4
- package/dist/src/cli.js +31 -0
- package/dist/src/commands/init.js +2 -60
- package/dist/src/commands/skill.js +16 -0
- package/dist/src/core/skill-installer.js +72 -0
- package/dist/src/core/templates.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ bitacora --help
|
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Use `--root <path>` on any command to target a different project directory.
|
|
18
|
+
Command examples are available in `examples/cli-workflows.md`.
|
|
18
19
|
|
|
19
20
|
## What Each Bitacora File Stores
|
|
20
21
|
|
|
@@ -50,23 +51,30 @@ Bitacora now supports compacting finished tracks to reduce active context size a
|
|
|
50
51
|
|
|
51
52
|
If gates fail, command exits with code `1` and no compaction is applied.
|
|
52
53
|
|
|
54
|
+
## New in v1.1.1: Skill-only update
|
|
55
|
+
|
|
56
|
+
Use `bitacora skill` to install/update only `.agents/skills/bitacora/SKILL.md` and `skills-lock.json` without recreating `bitacora/` context files.
|
|
57
|
+
|
|
53
58
|
## Typical flow
|
|
54
59
|
|
|
55
60
|
```bash
|
|
56
61
|
# 1) bootstrap
|
|
57
62
|
bitacora init
|
|
58
63
|
|
|
59
|
-
# 2)
|
|
64
|
+
# 2) update skill only (after CLI upgrades)
|
|
65
|
+
bitacora skill
|
|
66
|
+
|
|
67
|
+
# 3) create work
|
|
60
68
|
bitacora new-track
|
|
61
69
|
|
|
62
|
-
#
|
|
70
|
+
# 4) append progress
|
|
63
71
|
bitacora log --track-id TRACK-001 --message "implemented parser"
|
|
64
72
|
bitacora log --track-id TRACK-001 --message "TEST: npm test -- --run tests/core/parser.test.ts -> pass"
|
|
65
73
|
|
|
66
|
-
#
|
|
74
|
+
# 5) compact when fully completed
|
|
67
75
|
bitacora compact --track-id TRACK-001 --complete
|
|
68
76
|
|
|
69
|
-
#
|
|
77
|
+
# 6) inspect archive only when needed
|
|
70
78
|
bitacora history --track-id TRACK-001
|
|
71
79
|
bitacora history --track-id TRACK-001 --show
|
|
72
80
|
```
|
|
@@ -80,6 +88,14 @@ Creates the `bitacora/` memory structure in the project root.
|
|
|
80
88
|
- `--force`: recreates memory files if they already exist.
|
|
81
89
|
- `--root <path>`: sets the project root (default: current directory).
|
|
82
90
|
|
|
91
|
+
### `bitacora skill [--root <path>]`
|
|
92
|
+
|
|
93
|
+
Installs or updates only the Bitacora local agent skill and its lock entry.
|
|
94
|
+
|
|
95
|
+
- Updates `.agents/skills/bitacora/SKILL.md`.
|
|
96
|
+
- Updates `skills-lock.json` entry for `bitacora` while preserving other skills.
|
|
97
|
+
- Does not recreate or modify `bitacora/` project memory files.
|
|
98
|
+
|
|
83
99
|
### `bitacora new-track [trackId] [--status <status>] [--priority <priority>] [--root <path>]`
|
|
84
100
|
|
|
85
101
|
Creates a new track file. If `trackId` is omitted, Bitacora picks the next sequential ID.
|
|
@@ -106,6 +122,13 @@ Compacts tracks by summarizing content and archiving full detail.
|
|
|
106
122
|
- `--complete`: mark target tracks as completed (requires completion gates).
|
|
107
123
|
- `--dry-run`: report estimated byte/token savings without writing files.
|
|
108
124
|
- `--root <path>`: sets the project root.
|
|
125
|
+
- `--complete` gates:
|
|
126
|
+
- `# Tasks` must not contain unchecked items (`- [ ]`).
|
|
127
|
+
- `# Log` must include at least one `TEST:` line.
|
|
128
|
+
- rewrite/archive model:
|
|
129
|
+
- full source track is archived under `bitacora/history/TRACK-###.md`.
|
|
130
|
+
- active `tracks/TRACK-###/track.md` is rewritten into compact summary form.
|
|
131
|
+
- `tracks/tracks.md` is regenerated and the previous snapshot is archived in `bitacora/history/tracks-*.md`.
|
|
109
132
|
|
|
110
133
|
Examples:
|
|
111
134
|
|
|
@@ -131,6 +154,15 @@ Reads archived track history.
|
|
|
131
154
|
- `--show`: print full archived content (default prints only metadata/path).
|
|
132
155
|
- `--root <path>`: sets the project root.
|
|
133
156
|
|
|
157
|
+
### `bitacora --help`
|
|
158
|
+
|
|
159
|
+
`bitacora --help` includes full command details for:
|
|
160
|
+
- `init`, `skill`, `new-track`, `validate`, `rebuild-state`, `log`
|
|
161
|
+
- `compact` (flags, completion gates, output/archive model)
|
|
162
|
+
- `history` (metadata mode vs `--show`)
|
|
163
|
+
|
|
164
|
+
For a maintained example output, see `examples/help-output.txt`.
|
|
165
|
+
|
|
134
166
|
### `bitacora validate [--json] [--root <path>]`
|
|
135
167
|
|
|
136
168
|
Validates the Bitacora file/folder structure and reports errors.
|
package/dist/src/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const history_1 = require("./commands/history");
|
|
|
10
10
|
const log_1 = require("./commands/log");
|
|
11
11
|
const new_track_1 = require("./commands/new-track");
|
|
12
12
|
const rebuild_state_1 = require("./commands/rebuild-state");
|
|
13
|
+
const skill_1 = require("./commands/skill");
|
|
13
14
|
const validate_1 = require("./commands/validate");
|
|
14
15
|
const COMMAND_HELP_OVERVIEW = `
|
|
15
16
|
Command details:
|
|
@@ -19,6 +20,11 @@ Command details:
|
|
|
19
20
|
--force Recreate bitacora memory if it already exists.
|
|
20
21
|
--root <path> Project root path (default: current directory).
|
|
21
22
|
|
|
23
|
+
skill
|
|
24
|
+
Installs or updates only the bitacora agent skill and skills lock entry.
|
|
25
|
+
Options:
|
|
26
|
+
--root <path> Project root path (default: current directory).
|
|
27
|
+
|
|
22
28
|
new-track [trackId]
|
|
23
29
|
Creates a new track file, automatically picking the next track id when omitted.
|
|
24
30
|
Options:
|
|
@@ -52,6 +58,13 @@ Command details:
|
|
|
52
58
|
--complete Mark target tracks as completed (requires completion gates).
|
|
53
59
|
--dry-run Show savings without modifying files.
|
|
54
60
|
--root <path> Project root path (default: current directory).
|
|
61
|
+
Completion gates (--complete):
|
|
62
|
+
- # Tasks has no unchecked item (- [ ]).
|
|
63
|
+
- # Log includes at least one line containing TEST:.
|
|
64
|
+
Output model:
|
|
65
|
+
- Full source moves to bitacora/history/TRACK-###.md.
|
|
66
|
+
- Active track.md is rewritten into compact summary form.
|
|
67
|
+
- tracks/tracks.md is regenerated; previous snapshot is archived in history/.
|
|
55
68
|
|
|
56
69
|
history
|
|
57
70
|
Reads archived history for a compacted track.
|
|
@@ -59,6 +72,9 @@ Command details:
|
|
|
59
72
|
--track-id <trackId> Track identifier.
|
|
60
73
|
--show Print full archived content.
|
|
61
74
|
--root <path> Project root path (default: current directory).
|
|
75
|
+
Notes:
|
|
76
|
+
- Without --show, prints metadata/path only.
|
|
77
|
+
- Use --show only when compact summary is insufficient.
|
|
62
78
|
`;
|
|
63
79
|
function writeLine(writer, message) {
|
|
64
80
|
writer(message.endsWith("\n") ? message : `${message}\n`);
|
|
@@ -91,6 +107,18 @@ function createCliProgram(runtime = {}, onCommandExitCode) {
|
|
|
91
107
|
});
|
|
92
108
|
onCommandExitCode?.(exitCode);
|
|
93
109
|
});
|
|
110
|
+
program
|
|
111
|
+
.command("skill")
|
|
112
|
+
.description("Install or update only the bitacora agent skill.")
|
|
113
|
+
.option("--root <path>", "project root path")
|
|
114
|
+
.action((options) => {
|
|
115
|
+
const exitCode = (0, skill_1.runSkillCommand)({
|
|
116
|
+
rootDir: options.root ?? cwd()
|
|
117
|
+
}, {
|
|
118
|
+
onError: (message) => writeLine(stderr, message)
|
|
119
|
+
});
|
|
120
|
+
onCommandExitCode?.(exitCode);
|
|
121
|
+
});
|
|
94
122
|
program
|
|
95
123
|
.command("new-track [trackId]")
|
|
96
124
|
.description("Create a new track with optional id, status, and priority.")
|
|
@@ -217,6 +245,9 @@ async function runCli(argv, runtime = {}) {
|
|
|
217
245
|
}
|
|
218
246
|
catch (error) {
|
|
219
247
|
if (error instanceof commander_1.CommanderError) {
|
|
248
|
+
if (error.code === "commander.helpDisplayed") {
|
|
249
|
+
return 0;
|
|
250
|
+
}
|
|
220
251
|
return commandExitCode !== 0 ? commandExitCode : 1;
|
|
221
252
|
}
|
|
222
253
|
throw error;
|
|
@@ -6,63 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runInitCommand = runInitCommand;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const node_crypto_1 = require("node:crypto");
|
|
10
9
|
const templates_1 = require("../core/templates");
|
|
11
|
-
|
|
12
|
-
return (0, node_crypto_1.createHash)("sha256").update(content).digest("hex");
|
|
13
|
-
}
|
|
14
|
-
function readSkillsLockFile(filePath) {
|
|
15
|
-
if (!node_fs_1.default.existsSync(filePath)) {
|
|
16
|
-
return {
|
|
17
|
-
version: 1,
|
|
18
|
-
skills: {}
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
try {
|
|
22
|
-
const parsed = JSON.parse(node_fs_1.default.readFileSync(filePath, "utf8"));
|
|
23
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
24
|
-
return { version: 1, skills: {} };
|
|
25
|
-
}
|
|
26
|
-
const versionRaw = parsed.version;
|
|
27
|
-
const skillsRaw = parsed.skills;
|
|
28
|
-
const normalized = {};
|
|
29
|
-
if (typeof skillsRaw === "object" && skillsRaw !== null) {
|
|
30
|
-
for (const [name, value] of Object.entries(skillsRaw)) {
|
|
31
|
-
if (typeof value !== "object" || value === null) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
const source = value.source;
|
|
35
|
-
const sourceType = value.sourceType;
|
|
36
|
-
const computedHash = value.computedHash;
|
|
37
|
-
if (typeof source === "string" &&
|
|
38
|
-
typeof sourceType === "string" &&
|
|
39
|
-
typeof computedHash === "string") {
|
|
40
|
-
normalized[name] = { source, sourceType, computedHash };
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
version: typeof versionRaw === "number" ? versionRaw : 1,
|
|
46
|
-
skills: normalized
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
return {
|
|
51
|
-
version: 1,
|
|
52
|
-
skills: {}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function writeSkillsLockFile(rootDir, skillContent) {
|
|
57
|
-
const lockPath = node_path_1.default.join(rootDir, "skills-lock.json");
|
|
58
|
-
const lock = readSkillsLockFile(lockPath);
|
|
59
|
-
lock.skills.bitacora = {
|
|
60
|
-
source: ".agents/skills/bitacora/SKILL.md",
|
|
61
|
-
sourceType: "local",
|
|
62
|
-
computedHash: computeHash(skillContent)
|
|
63
|
-
};
|
|
64
|
-
node_fs_1.default.writeFileSync(lockPath, `${JSON.stringify(lock, null, 2)}\n`, "utf8");
|
|
65
|
-
}
|
|
10
|
+
const skill_installer_1 = require("../core/skill-installer");
|
|
66
11
|
function runInitCommand(options, dependencies = {}) {
|
|
67
12
|
const now = dependencies.now ?? (() => new Date().toISOString());
|
|
68
13
|
const onError = dependencies.onError ?? (() => { });
|
|
@@ -79,15 +24,12 @@ function runInitCommand(options, dependencies = {}) {
|
|
|
79
24
|
const trackId = "TRACK-001";
|
|
80
25
|
node_fs_1.default.mkdirSync(node_path_1.default.join(memoryRoot, "tracks", trackId), { recursive: true });
|
|
81
26
|
node_fs_1.default.mkdirSync(node_path_1.default.join(memoryRoot, "history"), { recursive: true });
|
|
82
|
-
node_fs_1.default.mkdirSync(node_path_1.default.join(options.rootDir, ".agents", "skills", "bitacora"), { recursive: true });
|
|
83
27
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "product.md"), (0, templates_1.createProductTemplate)(), "utf8");
|
|
84
28
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "tech-stack.md"), (0, templates_1.createTechStackTemplate)(), "utf8");
|
|
85
29
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "workflow.md"), (0, templates_1.createWorkflowTemplate)(), "utf8");
|
|
86
30
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "ux-style-guide.md"), (0, templates_1.createUxStyleGuideTemplate)(), "utf8");
|
|
87
31
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "index.md"), (0, templates_1.createIndexTemplate)(), "utf8");
|
|
88
|
-
|
|
89
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(options.rootDir, ".agents", "skills", "bitacora", "SKILL.md"), skillContent, "utf8");
|
|
90
|
-
writeSkillsLockFile(options.rootDir, skillContent);
|
|
32
|
+
(0, skill_installer_1.installBitacoraSkill)(options.rootDir);
|
|
91
33
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "tracks", "tracks.md"), (0, templates_1.createTracksRegistryTemplate)(createdOnDate), "utf8");
|
|
92
34
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "tracks", "tracks-template.md"), (0, templates_1.createTracksTemplate)(), "utf8");
|
|
93
35
|
node_fs_1.default.writeFileSync(node_path_1.default.join(memoryRoot, "tracks", trackId, "track.md"), (0, templates_1.createTrackTemplate)(trackId, "active", "medium", createdAt), "utf8");
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runSkillCommand = runSkillCommand;
|
|
4
|
+
const skill_installer_1 = require("../core/skill-installer");
|
|
5
|
+
function runSkillCommand(options, dependencies = {}) {
|
|
6
|
+
const onError = dependencies.onError ?? (() => { });
|
|
7
|
+
try {
|
|
8
|
+
(0, skill_installer_1.installBitacoraSkill)(options.rootDir);
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13
|
+
onError(message);
|
|
14
|
+
return 1;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.installBitacoraSkill = installBitacoraSkill;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
|
+
const templates_1 = require("./templates");
|
|
11
|
+
function computeHash(content) {
|
|
12
|
+
return (0, node_crypto_1.createHash)("sha256").update(content).digest("hex");
|
|
13
|
+
}
|
|
14
|
+
function readSkillsLockFile(filePath) {
|
|
15
|
+
if (!node_fs_1.default.existsSync(filePath)) {
|
|
16
|
+
return {
|
|
17
|
+
version: 1,
|
|
18
|
+
skills: {}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(node_fs_1.default.readFileSync(filePath, "utf8"));
|
|
23
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
24
|
+
return { version: 1, skills: {} };
|
|
25
|
+
}
|
|
26
|
+
const versionRaw = parsed.version;
|
|
27
|
+
const skillsRaw = parsed.skills;
|
|
28
|
+
const normalized = {};
|
|
29
|
+
if (typeof skillsRaw === "object" && skillsRaw !== null) {
|
|
30
|
+
for (const [name, value] of Object.entries(skillsRaw)) {
|
|
31
|
+
if (typeof value !== "object" || value === null) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const source = value.source;
|
|
35
|
+
const sourceType = value.sourceType;
|
|
36
|
+
const computedHash = value.computedHash;
|
|
37
|
+
if (typeof source === "string" &&
|
|
38
|
+
typeof sourceType === "string" &&
|
|
39
|
+
typeof computedHash === "string") {
|
|
40
|
+
normalized[name] = { source, sourceType, computedHash };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
version: typeof versionRaw === "number" ? versionRaw : 1,
|
|
46
|
+
skills: normalized
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return {
|
|
51
|
+
version: 1,
|
|
52
|
+
skills: {}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function writeSkillsLockFile(rootDir, skillContent) {
|
|
57
|
+
const lockPath = node_path_1.default.join(rootDir, "skills-lock.json");
|
|
58
|
+
const lock = readSkillsLockFile(lockPath);
|
|
59
|
+
lock.skills.bitacora = {
|
|
60
|
+
source: ".agents/skills/bitacora/SKILL.md",
|
|
61
|
+
sourceType: "local",
|
|
62
|
+
computedHash: computeHash(skillContent)
|
|
63
|
+
};
|
|
64
|
+
node_fs_1.default.writeFileSync(lockPath, `${JSON.stringify(lock, null, 2)}\n`, "utf8");
|
|
65
|
+
}
|
|
66
|
+
function installBitacoraSkill(rootDir) {
|
|
67
|
+
const skillDir = node_path_1.default.join(rootDir, ".agents", "skills", "bitacora");
|
|
68
|
+
node_fs_1.default.mkdirSync(skillDir, { recursive: true });
|
|
69
|
+
const skillContent = (0, templates_1.createAgentSkillTemplate)();
|
|
70
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(skillDir, "SKILL.md"), skillContent, "utf8");
|
|
71
|
+
writeSkillsLockFile(rootDir, skillContent);
|
|
72
|
+
}
|
|
@@ -169,7 +169,7 @@ function createAgentSkillTemplate() {
|
|
|
169
169
|
return `---
|
|
170
170
|
name: bitacora
|
|
171
171
|
description: Keep deterministic project memory in bitacora/ and update it continuously during implementation sessions.
|
|
172
|
-
version: 1.
|
|
172
|
+
version: 1.1.1
|
|
173
173
|
type: local
|
|
174
174
|
source: .agents/skills/bitacora/SKILL.md
|
|
175
175
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bitacora-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Deterministic agent-oriented project memory system. Provides structured Markdown-based long-term memory, strict validation, state reconstruction, and an enforcement CLI with agent skill integration to guide and limit agent behavior.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|