project-logbook 0.3.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.
Files changed (102) hide show
  1. package/README.md +34 -0
  2. package/dist/commands/build.d.ts +1 -0
  3. package/dist/commands/build.js +174 -0
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.js +83 -0
  6. package/dist/commands/lint.d.ts +1 -0
  7. package/dist/commands/lint.js +78 -0
  8. package/dist/commands/list.d.ts +3 -0
  9. package/dist/commands/list.js +127 -0
  10. package/dist/commands/log.d.ts +3 -0
  11. package/dist/commands/log.js +31 -0
  12. package/dist/commands/new.d.ts +1 -0
  13. package/dist/commands/new.js +135 -0
  14. package/dist/commands/preview.d.ts +1 -0
  15. package/dist/commands/preview.js +19 -0
  16. package/dist/commands/release.d.ts +3 -0
  17. package/dist/commands/release.js +66 -0
  18. package/dist/commands/start.d.ts +1 -0
  19. package/dist/commands/start.js +87 -0
  20. package/dist/commands/steer.d.ts +1 -0
  21. package/dist/commands/steer.js +22 -0
  22. package/dist/commands/upgrade.d.ts +1 -0
  23. package/dist/commands/upgrade.js +23 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +92 -0
  26. package/dist/lib/about-content.d.ts +1 -0
  27. package/dist/lib/about-content.js +7 -0
  28. package/dist/lib/build-helpers.d.ts +15 -0
  29. package/dist/lib/build-helpers.js +171 -0
  30. package/dist/lib/config.d.ts +14 -0
  31. package/dist/lib/config.js +41 -0
  32. package/dist/lib/git-helpers.d.ts +16 -0
  33. package/dist/lib/git-helpers.js +93 -0
  34. package/dist/lib/image-helpers.d.ts +19 -0
  35. package/dist/lib/image-helpers.js +121 -0
  36. package/dist/lib/jira-helpers.d.ts +5 -0
  37. package/dist/lib/jira-helpers.js +5 -0
  38. package/dist/lib/lint-runner.d.ts +2 -0
  39. package/dist/lib/lint-runner.js +31 -0
  40. package/dist/lib/lint-types.d.ts +24 -0
  41. package/dist/lib/lint-types.js +1 -0
  42. package/dist/lib/lockfile.d.ts +6 -0
  43. package/dist/lib/lockfile.js +1 -0
  44. package/dist/lib/logbook-client.d.ts +5 -0
  45. package/dist/lib/logbook-client.js +11 -0
  46. package/dist/lib/migrations.d.ts +11 -0
  47. package/dist/lib/migrations.js +34 -0
  48. package/dist/lib/session.d.ts +16 -0
  49. package/dist/lib/session.js +74 -0
  50. package/dist/lib/styles.d.ts +1 -0
  51. package/dist/lib/styles.js +21 -0
  52. package/dist/lib/template-types.d.ts +118 -0
  53. package/dist/lib/template-types.js +1 -0
  54. package/dist/lib/templates.d.ts +14 -0
  55. package/dist/lib/templates.js +158 -0
  56. package/dist/linters/frontmatter.d.ts +3 -0
  57. package/dist/linters/frontmatter.js +68 -0
  58. package/dist/linters/index.d.ts +1 -0
  59. package/dist/linters/index.js +18 -0
  60. package/dist/linters/jira-prefix.d.ts +3 -0
  61. package/dist/linters/jira-prefix.js +34 -0
  62. package/dist/linters/links.d.ts +3 -0
  63. package/dist/linters/links.js +28 -0
  64. package/dist/linters/lockfile.d.ts +3 -0
  65. package/dist/linters/lockfile.js +20 -0
  66. package/dist/linters/placeholders.d.ts +3 -0
  67. package/dist/linters/placeholders.js +62 -0
  68. package/dist/linters/project-integrity.d.ts +3 -0
  69. package/dist/linters/project-integrity.js +29 -0
  70. package/dist/linters/readability.d.ts +3 -0
  71. package/dist/linters/readability.js +41 -0
  72. package/dist/linters/workspaces.d.ts +3 -0
  73. package/dist/linters/workspaces.js +26 -0
  74. package/dist/templates/ABOUT.md +23 -0
  75. package/dist/templates/CONTRIBUTING.md +78 -0
  76. package/dist/templates/favicon.svg +21 -0
  77. package/dist/templates/index.md +30 -0
  78. package/dist/templates/log.md +4 -0
  79. package/dist/templates/logbook-client.js +162 -0
  80. package/dist/templates/steer.txt +25 -0
  81. package/dist/templates/styles.css +641 -0
  82. package/dist/templates/ticket.md +4 -0
  83. package/dist/utils/date.d.ts +8 -0
  84. package/dist/utils/date.js +47 -0
  85. package/dist/utils/fs.d.ts +13 -0
  86. package/dist/utils/fs.js +38 -0
  87. package/dist/utils/id.d.ts +7 -0
  88. package/dist/utils/id.js +36 -0
  89. package/dist/utils/slug.d.ts +2 -0
  90. package/dist/utils/slug.js +9 -0
  91. package/dist/utils/string.d.ts +2 -0
  92. package/dist/utils/string.js +4 -0
  93. package/package.json +69 -0
  94. package/src/templates/ABOUT.md +23 -0
  95. package/src/templates/CONTRIBUTING.md +78 -0
  96. package/src/templates/favicon.svg +21 -0
  97. package/src/templates/index.md +30 -0
  98. package/src/templates/log.md +4 -0
  99. package/src/templates/logbook-client.js +162 -0
  100. package/src/templates/steer.txt +25 -0
  101. package/src/templates/styles.css +641 -0
  102. package/src/templates/ticket.md +4 -0
@@ -0,0 +1,26 @@
1
+ import { getWorkspaces } from '../lib/config.js';
2
+ const linter = {
3
+ name: 'workspaces',
4
+ description: 'Validates workspaces field against package.json',
5
+ async check(context) {
6
+ if (!context.entryName || !context.frontmatter)
7
+ return [];
8
+ const { frontmatter } = context;
9
+ if (frontmatter.workspaces === undefined)
10
+ return [];
11
+ const issues = [];
12
+ const availableWorkspaces = getWorkspaces();
13
+ const entryWorkspaces = Array.isArray(frontmatter.workspaces) ? frontmatter.workspaces : [];
14
+ for (const ws of entryWorkspaces) {
15
+ if (!availableWorkspaces.includes(ws)) {
16
+ issues.push({
17
+ level: 'error',
18
+ category: 'workspace',
19
+ message: `Invalid workspace '${ws}'. Available workspaces: ${availableWorkspaces.join(', ')}`,
20
+ });
21
+ }
22
+ }
23
+ return issues;
24
+ },
25
+ };
26
+ export default linter;
@@ -0,0 +1,23 @@
1
+ # About this Logbook
2
+
3
+ This is a **Project Logbook** — a living documentation approach that tracks project evolution through ticket-based entries.
4
+
5
+ ## The Problem
6
+
7
+ Traditional project documentation often becomes stale quickly. Decisions get lost, the rationale behind changes remains undocumented, and onboarding new team members becomes challenging.
8
+
9
+ ## The Solution
10
+
11
+ The Project Logbook captures every significant change as a structured entry containing:
12
+
13
+ - **Ticket**: Requirements and acceptance criteria
14
+ - **Technical Log**: Real-time implementation notes and decisions
15
+ - **Narrative**: A polished story explaining the why and how
16
+
17
+ ## How It Works
18
+
19
+ Each entry in this logbook represents a discrete piece of work, documented using the same tool that generated this website. The timeline presents these entries as "news items", creating a narrative history of the project.
20
+
21
+ ## Dogfooding
22
+
23
+ This website itself is built using the logbook tool it documents. Every feature added to this CLI is first documented as a logbook entry, demonstrating the tool's capabilities in real-time.
@@ -0,0 +1,78 @@
1
+ # Contributing to Project Logbook
2
+
3
+ This project follows a strict **Agentic Documentation Workflow**. Whether you are a human or an AI agent, please adhere to the following protocol to ensure the history of this project remains professional, readable, and technically traceable.
4
+
5
+ ## The Three-File Standard
6
+ Every change must be documented in a dedicated folder within `logbook/` using three files:
7
+
8
+ 1. **`ticket.md`**: The source of truth. Contains the requirements, background, and acceptance criteria.
9
+ 2. **`log.md`**: The chronological scratchpad. A real-time trace of technical decisions, pivots, and obstacles.
10
+ 3. **`index.md`**: The narrative. A polished, high-level "story" of the change for stakeholders and future developers.
11
+
12
+ ## Working Protocol
13
+
14
+ ### 1. Inception
15
+ Always start by creating and activating a new entry:
16
+ ```bash
17
+ logbook new [ID] [Slug]
18
+ logbook start [ID]
19
+ ```
20
+
21
+ The `new` command accepts optional parameters. When invoked without arguments, it enters interactive mode:
22
+ - If `jiraPrefix` is configured, suggests the next ID with that prefix (e.g., LB-14)
23
+ - Prompts for title, auto-converts to slug
24
+
25
+ `logbook start` looks up the entry folder by ID prefix, so `logbook start LB-5` resolves to `LB-5-jira-support` automatically.
26
+
27
+ `logbook start` writes a `.logbook-active` JSON lockfile to ensure only one entry is worked on at a time. It also automatically records the current git user as the `prompter` in the `index.md` frontmatter — useful for tracking which human directed or reviewed an AI-assisted session.
28
+
29
+ Fill the `ticket.md` immediately so the context is anchored before you start coding. Optionally run:
30
+ ```bash
31
+ logbook steer
32
+ ```
33
+ to receive strategic guidance for the active entry based on the ticket content.
34
+
35
+ ### 2. Execution
36
+ As you code, keep the `log.md` updated in real-time using the `logbook log` command. Do not wait until the end.
37
+
38
+ ```bash
39
+ logbook log "Investigated root cause — found issue in src/lib/config.ts"
40
+ logbook log "Fixed the bug" "Added tests" "All passing"
41
+ ```
42
+
43
+ Each message is automatically prefixed with an ISO timestamp and appended as a bullet to the active `log.md`. You may pass multiple quoted strings in one call. If you encounter a bug or change your design, log it immediately. This is the most valuable file for future debugging.
44
+
45
+ Only update the currently active logbook entry. Do not edit other existing entries while working.
46
+
47
+ When you finish writing `index.md`, **remove the boilerplate link line** that the template inserts:
48
+
49
+ ### 3. Quality Assurance
50
+ Before submitting your work, you MUST release the active entry and run the linter:
51
+ ```bash
52
+ logbook release
53
+ logbook lint
54
+ ```
55
+ `logbook release` removes the `.logbook-active` lockfile. The linter will fail if the lockfile is still present, enforcing that no entry is left dangling in a committed state.
56
+
57
+ The linter enforces rules to be followed.
58
+
59
+ ### 4. Final Review
60
+ Use the preview command to see how your entry looks in the context of the whole project:
61
+ ```bash
62
+ logbook preview
63
+ ```
64
+
65
+ ## The `prompter` Field
66
+
67
+ The optional `prompter` frontmatter field in `index.md` records the human who directed, reviewed, or collaborated on a session — distinct from the AI `author`. It is set automatically by `logbook start` from the git `user.name` and injected into `index.md`. In fully automated pipelines without a human prompter, it may be omitted.
68
+
69
+ ## Jira Integration
70
+
71
+ If the project has a `jiraBaseUrl` set in `.project-logbook`, the `ticket` field in `index.md` frontmatter is used to generate a direct link to the Jira issue in the built website. Ensure `ticket` is set correctly (e.g. `LB-5`) for every entry.
72
+
73
+ If `jiraPrefix` is configured, entry folder names and ticket references must match the prefix pattern.
74
+
75
+ ## Tone & Style
76
+ - **Narrative over Lists**: In `index.md`, tell a story. Why did we make this change? What were the challenges?
77
+ - **Technical Precision**: In `log.md`, be specific. Mention file paths, error messages, and specific design patterns. Log in real time — do not reconstruct after the fact.
78
+ - **No Boilerplate in Commits**: All template placeholders must be replaced or removed before `logbook release`.
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
2
+ <style>
3
+ .logo-path {
4
+ fill: white;
5
+ stroke: black;
6
+ stroke-width: 3;
7
+ stroke-linejoin: round;
8
+ stroke-linecap: round;
9
+ }
10
+ </style>
11
+
12
+ <!-- Letter 'L' -->
13
+ <path class="logo-path" d="M 5 20 v 60 h 22 v -10 h -12 v -50 z" />
14
+
15
+ <!-- Letter 'O' -->
16
+ <path class="logo-path" fill-rule="evenodd" d="M 33 20 v 60 h 28 v -60 z M 43 30 v 40 h 8 v -40 z" />
17
+
18
+ <!-- Letter 'G' -->
19
+ <path class="logo-path"
20
+ d="M 67 20 v 60 h 28 v -30 h -12 v 10 h 2 v 10 h -8 v -40 h 8 v 5 h 10 v -15 z" />
21
+ </svg>
@@ -0,0 +1,30 @@
1
+ ---
2
+ # The ticket field should match the ID portion (e.g., LB-34)
3
+ ticket: {{id}}
4
+ # The title should be a human-readable description of the work
5
+ title: {{title}}
6
+ prompter: [PROMPTER]
7
+ harness: [HARNESS]
8
+ llm: [LLM]
9
+ summary: [WRITE_SUMMARY_HERE]
10
+ # Tags for categorizing the change (must be from allowed list in .project-logbook)
11
+ tags: []
12
+ # Workspace(s) this change affects (must match package.json workspaces; leave empty for single-project)
13
+ # Example: workspaces: ["frontend", "shared"]
14
+ workspaces: []
15
+ # Set automatically by `logbook start`
16
+ dateStart: [DATE_START]
17
+ # Set automatically by `logbook release`
18
+ dateEnd: [DATE_END]
19
+ ---
20
+
21
+ ## Summary
22
+ TODO: Write a polished, highly readable ticket summary that reads like an engaging technical narrative (similar to a well-written dev blog post).
23
+
24
+ ### Formatting & Style Rules:
25
+ - **Maintain the narrative tone:** TODO: Keep the storytelling flair (e.g., describing how problems accumulated or how gaps surfaced), but stay strictly factual based on the provided changes.
26
+ - **Add thematic headings:** TODO: Break the narrative down into logical chapters using Markdown headings (e.g., ### The Friction Points, ### The Fix, ### Closing the Gap).
27
+ - **Use bullet points:** TODO: Whenever listing multiple items (like friction points, test scenarios, or rewritten paths), use a bulleted list instead of a dense paragraph to make it scannable.
28
+ - **Use bold emphasis:** TODO: Bold key concepts, problems, and solutions to guide the reader's eye.
29
+ - **Format code:** TODO: Use inline backticks for files, plugins, HTML elements, and code snippets (e.g., `src/lib/build-helpers.ts`).
30
+ - **Keep paragraphs short:** TODO: Ensure no paragraph is longer than 3-4 sentences. Keep the pacing quick and engaging.
@@ -0,0 +1,4 @@
1
+ # Technical Log: {{id}}-{{slug}}
2
+
3
+ ## Protocol
4
+ - {{fullIso}}: Started investigation.
@@ -0,0 +1,162 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ /* ── 1. Real-time relative dates ──────────────────────────────────────── */
5
+ function relativeDate(isoString) {
6
+ var d = new Date(isoString);
7
+ var now = new Date();
8
+ // Normalise both to midnight local time for day-diff calculation
9
+ var dDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());
10
+ var nDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
11
+ var diffDays = Math.round((nDay - dDay) / 86400000);
12
+
13
+ var relative;
14
+ if (diffDays === 0) relative = 'today';
15
+ else if (diffDays === 1) relative = 'yesterday';
16
+ else if (diffDays < 7) relative = diffDays + ' days ago';
17
+ else if (diffDays < 14) relative = '1 week ago';
18
+ else if (diffDays < 30) relative = Math.floor(diffDays / 7) + ' weeks ago';
19
+ else if (diffDays < 60) relative = '1 month ago';
20
+ else if (diffDays < 365) relative = Math.floor(diffDays / 30) + ' months ago';
21
+ else if (diffDays < 730) relative = '1 year ago';
22
+ else relative = Math.floor(diffDays / 365) + ' years ago';
23
+
24
+ var absolute = d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
25
+ return relative + ', ' + absolute;
26
+ }
27
+
28
+ function updateRelativeDates() {
29
+ var els = document.querySelectorAll('[data-date]');
30
+ for (var i = 0; i < els.length; i++) {
31
+ var el = els[i];
32
+ var iso = el.getAttribute('data-date');
33
+ if (iso) el.textContent = relativeDate(iso);
34
+ }
35
+ }
36
+
37
+ /* ── 2. localStorage-based "NEW" indicator ─────────────────────────────── */
38
+ var STORAGE_KEY = 'logbook_visited';
39
+
40
+ function getVisited() {
41
+ try {
42
+ return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
43
+ } catch (e) {
44
+ return [];
45
+ }
46
+ }
47
+
48
+ function markVisited(slug) {
49
+ try {
50
+ var visited = getVisited();
51
+ if (visited.indexOf(slug) === -1) {
52
+ visited.push(slug);
53
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(visited));
54
+ }
55
+ } catch (e) {
56
+ /* localStorage unavailable */
57
+ }
58
+ }
59
+
60
+ function applyNewBadges() {
61
+ var visited = getVisited();
62
+ var items = document.querySelectorAll('[data-entry-slug]');
63
+ for (var i = 0; i < items.length; i++) {
64
+ var item = items[i];
65
+ var slug = item.getAttribute('data-entry-slug');
66
+ if (slug && visited.indexOf(slug) === -1) {
67
+ var badge = item.querySelector('.new-badge');
68
+ if (badge) badge.style.display = 'inline-block';
69
+ }
70
+ }
71
+ }
72
+
73
+ /* ── 3. Tab switching functionality ────────────────────────────────────── */
74
+ function showTab(event, id) {
75
+ var eventTarget = event.currentTarget;
76
+ if (!eventTarget) return;
77
+
78
+ // Find the tabs-wrapper container that scopes this tab group
79
+ var wrapper = eventTarget.closest('.tabs-wrapper');
80
+ if (!wrapper) return;
81
+
82
+ // Hide all content sections within this wrapper only
83
+ var contentSections = wrapper.querySelectorAll('.content-section');
84
+ for (var i = 0; i < contentSections.length; i++) {
85
+ contentSections[i].style.display = 'none';
86
+ }
87
+
88
+ // Deactivate all tabs within this wrapper only
89
+ var tabs = wrapper.querySelectorAll('.tab');
90
+ for (var i = 0; i < tabs.length; i++) {
91
+ tabs[i].classList.remove('active');
92
+ tabs[i].setAttribute('aria-selected', 'false');
93
+ tabs[i].setAttribute('tabindex', '-1');
94
+ }
95
+
96
+ // Activate selected tab and content
97
+ var targetContent = document.getElementById(id);
98
+ if (targetContent) {
99
+ targetContent.style.display = 'block';
100
+ }
101
+
102
+ // Find and activate the clicked tab
103
+ var clickedTab = null;
104
+ for (var i = 0; i < tabs.length; i++) {
105
+ if (tabs[i].getAttribute('aria-controls') === id) {
106
+ clickedTab = tabs[i];
107
+ break;
108
+ }
109
+ }
110
+ if (clickedTab) {
111
+ clickedTab.classList.add('active');
112
+ clickedTab.setAttribute('aria-selected', 'true');
113
+ clickedTab.setAttribute('tabindex', '0');
114
+ clickedTab.focus();
115
+ }
116
+ }
117
+
118
+ function initTabs() {
119
+ var tabLists = document.querySelectorAll('[role="tablist"]');
120
+ for (var i = 0; i < tabLists.length; i++) {
121
+ var tabList = tabLists[i];
122
+
123
+ // Add keyboard navigation
124
+ tabList.addEventListener('keydown', function (event) {
125
+ var tabs = Array.from(this.querySelectorAll('.tab'));
126
+ var current = tabs.findIndex(function (t) {
127
+ return t.getAttribute('aria-selected') === 'true';
128
+ });
129
+ var next = -1;
130
+
131
+ if (event.key === 'ArrowRight') {
132
+ next = (current + 1) % tabs.length;
133
+ } else if (event.key === 'ArrowLeft') {
134
+ next = (current - 1 + tabs.length) % tabs.length;
135
+ }
136
+
137
+ if (next !== -1) {
138
+ event.preventDefault();
139
+ tabs[next].click();
140
+ }
141
+ });
142
+ }
143
+ }
144
+
145
+ /* ── Bootstrap ─────────────────────────────────────────────────────────── */
146
+ document.addEventListener('DOMContentLoaded', function () {
147
+ updateRelativeDates();
148
+
149
+ // On post pages: mark this entry as visited
150
+ var pageSlug = document.body.getAttribute('data-page-slug');
151
+ if (pageSlug) markVisited(pageSlug);
152
+
153
+ // On the timeline: apply NEW badges
154
+ applyNewBadges();
155
+
156
+ // Initialize tab functionality
157
+ initTabs();
158
+ });
159
+
160
+ // Expose showTab globally for onclick handlers
161
+ window.showTab = showTab;
162
+ })();
@@ -0,0 +1,25 @@
1
+ PROJECT LOGBOOK: AI AGENT STEERING PROTOCOL
2
+
3
+ The human prompter has already initialized and activated the current logbook entry.
4
+ Do NOT run `logbook new` or `logbook release` — these are prompter responsibilities.
5
+
6
+ Phase 1: Understand
7
+ 1. Read `ticket.md` in the active entry. This is your source of truth for requirements.
8
+ 2. Review `AGENTS.md` and `CONTRIBUTING.md` if you need architectural or workflow context.
9
+
10
+ Phase 2: Execute & Trace
11
+ 1. Use `log.md` as a live technical scratchpad.
12
+ 2. Log your work in real-time using the `logbook log "<message>"` command. Record every major decision, error, and pivot. Do not reconstruct this at the end.
13
+ Example: logbook log "Investigated root cause — found issue in src/lib/config.ts"
14
+ 3. You may pass multiple messages in one call: logbook log "Msg A" "Msg B"
15
+ 4. Stick to the active entry; never modify past entries in the logbook folder.
16
+
17
+ Phase 3: Synthesize
18
+ 1. When implementation is finished, write the narrative in `index.md`.
19
+ 2. Storytelling Mode: Explain the "Why" and the "Journey." Avoid simple technical bullet points.
20
+ 3. Clean up all template placeholders and complete the frontmatter (author, summary, dates).
21
+
22
+ Phase 4: Verify
23
+ 1. Run `npm run pre` (which includes `logbook lint` and other quality gates).
24
+ 2. Ensure there are no linter errors, unreplaced placeholders, or architectural violations before concluding your work.
25
+ 3. Hand back to the prompter, who will review and run `logbook release`.