project-logbook 0.4.1 → 1.1.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 (169) hide show
  1. package/README.md +38 -2
  2. package/dist/commands/build.js +75 -85
  3. package/dist/commands/build.js.map +1 -0
  4. package/dist/commands/init.js +1 -0
  5. package/dist/commands/init.js.map +1 -0
  6. package/dist/commands/lint.js +9 -3
  7. package/dist/commands/lint.js.map +1 -0
  8. package/dist/commands/list.js +14 -26
  9. package/dist/commands/list.js.map +1 -0
  10. package/dist/commands/log.d.ts +1 -3
  11. package/dist/commands/log.js +28 -4
  12. package/dist/commands/log.js.map +1 -0
  13. package/dist/commands/new.d.ts +4 -1
  14. package/dist/commands/new.js +73 -52
  15. package/dist/commands/new.js.map +1 -0
  16. package/dist/commands/preview.js +1 -0
  17. package/dist/commands/preview.js.map +1 -0
  18. package/dist/commands/release.js +2 -1
  19. package/dist/commands/release.js.map +1 -0
  20. package/dist/commands/start.d.ts +1 -1
  21. package/dist/commands/start.js +76 -16
  22. package/dist/commands/start.js.map +1 -0
  23. package/dist/commands/status.js +10 -18
  24. package/dist/commands/status.js.map +1 -0
  25. package/dist/commands/steer.js +1 -0
  26. package/dist/commands/steer.js.map +1 -0
  27. package/dist/commands/upgrade.js +1 -0
  28. package/dist/commands/upgrade.js.map +1 -0
  29. package/dist/index.js +7 -5
  30. package/dist/index.js.map +1 -0
  31. package/dist/lib/about-content.js +1 -0
  32. package/dist/lib/about-content.js.map +1 -0
  33. package/dist/lib/adr-renderer.d.ts +12 -0
  34. package/dist/lib/adr-renderer.js +53 -0
  35. package/dist/lib/adr-renderer.js.map +1 -0
  36. package/dist/lib/autolink.d.ts +15 -0
  37. package/dist/lib/autolink.js +39 -0
  38. package/dist/lib/autolink.js.map +1 -0
  39. package/dist/lib/build-helpers.d.ts +1 -1
  40. package/dist/lib/build-helpers.js +24 -7
  41. package/dist/lib/build-helpers.js.map +1 -0
  42. package/dist/lib/build-steps.d.ts +16 -2
  43. package/dist/lib/build-steps.js +124 -20
  44. package/dist/lib/build-steps.js.map +1 -0
  45. package/dist/lib/config.d.ts +22 -0
  46. package/dist/lib/config.js +29 -1
  47. package/dist/lib/config.js.map +1 -0
  48. package/dist/lib/custom-card-renderer.d.ts +2 -0
  49. package/dist/lib/custom-card-renderer.js +58 -0
  50. package/dist/lib/custom-card-renderer.js.map +1 -0
  51. package/dist/lib/custom-types-builder.d.ts +4 -0
  52. package/dist/lib/custom-types-builder.js +37 -0
  53. package/dist/lib/custom-types-builder.js.map +1 -0
  54. package/dist/lib/entry-id.js +1 -0
  55. package/dist/lib/entry-id.js.map +1 -0
  56. package/dist/lib/entry-paths.js +1 -0
  57. package/dist/lib/entry-paths.js.map +1 -0
  58. package/dist/lib/git-helpers.d.ts +5 -16
  59. package/dist/lib/git-helpers.js +61 -78
  60. package/dist/lib/git-helpers.js.map +1 -0
  61. package/dist/lib/git-url-helpers.d.ts +16 -0
  62. package/dist/lib/git-url-helpers.js +76 -0
  63. package/dist/lib/git-url-helpers.js.map +1 -0
  64. package/dist/lib/hast-helpers.js +1 -0
  65. package/dist/lib/hast-helpers.js.map +1 -0
  66. package/dist/lib/html-attributes.js +1 -0
  67. package/dist/lib/html-attributes.js.map +1 -0
  68. package/dist/lib/html-escape.js +1 -0
  69. package/dist/lib/html-escape.js.map +1 -0
  70. package/dist/lib/image-dimension-parser.d.ts +11 -0
  71. package/dist/lib/image-dimension-parser.js +127 -0
  72. package/dist/lib/image-dimension-parser.js.map +1 -0
  73. package/dist/lib/image-helpers.d.ts +2 -0
  74. package/dist/lib/image-helpers.js +22 -30
  75. package/dist/lib/image-helpers.js.map +1 -0
  76. package/dist/lib/jira-helpers.js +1 -0
  77. package/dist/lib/jira-helpers.js.map +1 -0
  78. package/dist/lib/lint-runner.js +1 -0
  79. package/dist/lib/lint-runner.js.map +1 -0
  80. package/dist/lib/lint-types.js +1 -0
  81. package/dist/lib/lint-types.js.map +1 -0
  82. package/dist/lib/lockfile.js +1 -0
  83. package/dist/lib/lockfile.js.map +1 -0
  84. package/dist/lib/logbook-client.js +1 -0
  85. package/dist/lib/logbook-client.js.map +1 -0
  86. package/dist/lib/markdown-processors.js +1 -0
  87. package/dist/lib/markdown-processors.js.map +1 -0
  88. package/dist/lib/migrations.js +1 -0
  89. package/dist/lib/migrations.js.map +1 -0
  90. package/dist/lib/package-version.js +1 -0
  91. package/dist/lib/package-version.js.map +1 -0
  92. package/dist/lib/post-template.d.ts +5 -0
  93. package/dist/lib/post-template.js +48 -0
  94. package/dist/lib/post-template.js.map +1 -0
  95. package/dist/lib/rss.js +1 -0
  96. package/dist/lib/rss.js.map +1 -0
  97. package/dist/lib/session.d.ts +2 -2
  98. package/dist/lib/session.js +75 -35
  99. package/dist/lib/session.js.map +1 -0
  100. package/dist/lib/styles.js +1 -0
  101. package/dist/lib/styles.js.map +1 -0
  102. package/dist/lib/template-helpers.d.ts +6 -1
  103. package/dist/lib/template-helpers.js +81 -1
  104. package/dist/lib/template-helpers.js.map +1 -0
  105. package/dist/lib/template-types.d.ts +37 -5
  106. package/dist/lib/template-types.js +1 -0
  107. package/dist/lib/template-types.js.map +1 -0
  108. package/dist/lib/templates.d.ts +11 -8
  109. package/dist/lib/templates.js +59 -60
  110. package/dist/lib/templates.js.map +1 -0
  111. package/dist/lib/theme.js +1 -0
  112. package/dist/lib/theme.js.map +1 -0
  113. package/dist/lib/url-helpers.js +1 -0
  114. package/dist/lib/url-helpers.js.map +1 -0
  115. package/dist/linters/diff-to-narrative.d.ts +2 -1
  116. package/dist/linters/diff-to-narrative.js +3 -10
  117. package/dist/linters/diff-to-narrative.js.map +1 -0
  118. package/dist/linters/frontmatter.js +1 -0
  119. package/dist/linters/frontmatter.js.map +1 -0
  120. package/dist/linters/index.js +1 -0
  121. package/dist/linters/index.js.map +1 -0
  122. package/dist/linters/jira-prefix.js +1 -0
  123. package/dist/linters/jira-prefix.js.map +1 -0
  124. package/dist/linters/links.js +26 -4
  125. package/dist/linters/links.js.map +1 -0
  126. package/dist/linters/lockfile.js +1 -0
  127. package/dist/linters/lockfile.js.map +1 -0
  128. package/dist/linters/placeholders.js +6 -4
  129. package/dist/linters/placeholders.js.map +1 -0
  130. package/dist/linters/project-integrity.js +1 -0
  131. package/dist/linters/project-integrity.js.map +1 -0
  132. package/dist/linters/readability.js +2 -3
  133. package/dist/linters/readability.js.map +1 -0
  134. package/dist/linters/technical-log.js +1 -0
  135. package/dist/linters/technical-log.js.map +1 -0
  136. package/dist/linters/workspaces.js +1 -0
  137. package/dist/linters/workspaces.js.map +1 -0
  138. package/dist/templates/CONTRIBUTING.md +10 -1
  139. package/dist/templates/index.md +2 -1
  140. package/dist/templates/log.md +1 -1
  141. package/dist/templates/styles.css +171 -32
  142. package/dist/utils/date.js +1 -0
  143. package/dist/utils/date.js.map +1 -0
  144. package/dist/utils/frontmatter.d.ts +9 -0
  145. package/dist/utils/frontmatter.js +16 -0
  146. package/dist/utils/frontmatter.js.map +1 -0
  147. package/dist/utils/fs.d.ts +10 -0
  148. package/dist/utils/fs.js +112 -0
  149. package/dist/utils/fs.js.map +1 -0
  150. package/dist/utils/id.js +1 -0
  151. package/dist/utils/id.js.map +1 -0
  152. package/dist/utils/log-timeline.d.ts +2 -1
  153. package/dist/utils/log-timeline.js +1 -0
  154. package/dist/utils/log-timeline.js.map +1 -0
  155. package/dist/utils/slug.js +1 -0
  156. package/dist/utils/slug.js.map +1 -0
  157. package/dist/utils/string.js +1 -0
  158. package/dist/utils/string.js.map +1 -0
  159. package/dist/utils/timeline-helpers.d.ts +2 -2
  160. package/dist/utils/timeline-helpers.js +5 -2
  161. package/dist/utils/timeline-helpers.js.map +1 -0
  162. package/dist/utils/validation.d.ts +5 -0
  163. package/dist/utils/validation.js +21 -0
  164. package/dist/utils/validation.js.map +1 -0
  165. package/package.json +12 -6
  166. package/src/templates/CONTRIBUTING.md +10 -1
  167. package/src/templates/index.md +2 -1
  168. package/src/templates/log.md +1 -1
  169. package/src/templates/styles.css +171 -32
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ![Screenshot of generated website](/static/screenshot.jpg "Generated website")
8
8
 
9
- See [CONTRIBUTING.md](CONTRIBUTING.md) for the mandatory working protocol.
9
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the mandatory working protocol. (Or read this [unauthorized, cynical review](review-article-project-logbook.md) — also available in [German](review-article-project-logbook-de.md) — about how this project got dragged and saved.)
10
10
 
11
11
 
12
12
  ## The Three-File Standard
@@ -20,18 +20,54 @@ Each entry in `logbook/` consists of:
20
20
  npm i project-logbook -g
21
21
  ```
22
22
 
23
+ You can run the CLI using either `logbook` or the shortcut alias `lb`. For example, `lb status` works as a drop-in replacement for `logbook status`.
24
+
23
25
  ## Commands
24
26
 
25
27
  | Command | Description |
26
28
  |---|---|
27
29
  | `logbook init` | Initialize configuration and directory. |
28
- | `logbook new <id> <slug>` | Create a new entry folder with templates. |
30
+ | `logbook new <id> <slug>` | Create a new entry folder with templates. Use `-r` or `--research` option to scaffold a Research Log with an auto-incrementing `RES-` ID. |
29
31
  | `logbook start <id>` | Mark a logbook entry as active (writes `.logbook-active` lockfile). The active entry is also auto-detected from the current Git branch — a branch named `feat/LB-123-my-feature` will automatically resolve to entry `LB-123`. |
30
32
  | `logbook release` | Release the active logbook entry (removes `.logbook-active` lockfile). |
31
33
  | `logbook log <message>` | Append a timestamped log entry to the active `log.md`. |
32
34
  | `logbook list` | List all logbook entries with their status. |
35
+ | `logbook status` | Show current active logbook task, configuration settings, and statistics. |
33
36
  | `logbook lint` | Validate structure, frontmatter, and internal links. |
34
37
  | `logbook build` | Compile logbook entries into a static HTML site (default: `public/`). |
35
38
  | `logbook preview` | Build and open the logbook in your default browser. |
36
39
  | `logbook upgrade` | Synchronize core project files (like `CONTRIBUTING.md`) with latest templates. |
37
40
  | `logbook steer` | Output agentic protocol for AI assistants. |
41
+
42
+
43
+ ## Configuration
44
+
45
+ Running `logbook init` creates a `.project-logbook` configuration file in your project root. You can customize the following properties:
46
+
47
+ | Key | Type | Default | Description |
48
+ |---|---|---|---|
49
+ | `projectName` | `string` | `"My Project"` | Title shown on the generated static website. |
50
+ | `logbookDir` | `string` | `"logbook"` | The directory where logbook entries are located. |
51
+ | `researchDir` | `string` | `"docs/research"` | The directory where Research Logs are located. |
52
+ | `outputDir` | `string` | `"dist/logbook"` | The output directory where the compiled website is built. |
53
+ | `adrDir` | `string` | `"docs/adr"` | The directory where Architecture Decision Records (ADRs) are located. Set to `null` or omit to disable ADR integration. |
54
+ | `primaryColor` | `string` | `"#2563eb"` | The theme's accent color (CSS variable `--primary`). Must be a hex code. |
55
+ | `jiraBaseUrl` | `string` | `undefined` | Optional base URL of your Jira workspace (e.g. `https://myorg.atlassian.net/browse/`). Enables clickable Jira link buttons. |
56
+ | `jiraPrefix` | `string` | `undefined` | Optional Jira project prefix (e.g. `PROJ`) used to validate IDs and auto-link issues. |
57
+ | `repositoryUrl` | `string` | *Auto-detected* | Optional base web URL of your Git repository (e.g. `https://github.com/org/repo`). Automatically falls back to parsing your git remote URL if not specified. |
58
+ | `tags` | `object` | See below | Optional configuration for categorization tags. |
59
+
60
+ ### Tags Configuration Example
61
+
62
+ ```json
63
+ {
64
+ "projectName": "My API Gateway",
65
+ "primaryColor": "#0f766e",
66
+ "jiraBaseUrl": "https://mycompany.atlassian.net/browse/",
67
+ "jiraPrefix": "GW",
68
+ "tags": {
69
+ "allowed": ["#bugfix", "#feature", "#refactor", "#security", "#performance"]
70
+ }
71
+ }
72
+ ```
73
+
@@ -1,19 +1,20 @@
1
1
  import fs from 'fs-extra';
2
2
  import { join } from 'node:path';
3
3
  import { error, neutral, success } from '../lib/theme.js';
4
- import { getConfig, getWorkspaces, getLogbookDirPath, getOutputDirPath } from '../lib/config.js';
4
+ import { getConfig, getWorkspaces, getLogbookDirPath, getOutputDirPath, getAdrDirPath, getResearchDirPath, } from '../lib/config.js';
5
+ import { getActiveEntry } from '../lib/session.js';
5
6
  import { layout, timelineTemplate } from '../lib/templates.js';
6
- import { buildProjectMdFiles, renderPost, generateBuildMeta } from '../lib/build-helpers.js';
7
+ import { registerResearchEntries } from '../lib/autolink.js';
8
+ import { loadCustomTypesData } from '../lib/custom-types-builder.js';
9
+ import { buildProjectMdFiles, renderPost, generateBuildMeta, mdToHtml } from '../lib/build-helpers.js';
7
10
  import { getGitCommits, getGitTags } from '../lib/git-helpers.js';
8
- import { setupOutputDirectory, processReadme, copyReadmeImages, processAboutContent, processWelcomeContent, } from '../lib/build-steps.js';
11
+ import { setupOutputDirectory, processReadme, copyReadmeImages, processAboutContent, processWelcomeContent, buildRssFeed, processTimelineEntries, } from '../lib/build-steps.js';
12
+ import { renderAdr } from '../lib/adr-renderer.js';
9
13
  import { formatAbsoluteDate, getMonthYear, getSortTime, formatDateTimeForDisplay } from '../utils/date.js';
10
- import { getLogbookEntries } from '../utils/fs.js';
11
- import { toDisplayString, asString, asStringArray } from '../utils/frontmatter.js';
14
+ import { getLogbookEntries, getAdrEntries } from '../utils/fs.js';
12
15
  import { getAboutContent } from '../lib/about-content.js';
13
16
  import { getPackageVersion } from '../lib/package-version.js';
14
17
  import { groupTimelineItems } from '../utils/timeline-helpers.js';
15
- import { getEntryDisplayId, getEntryDisplayTitle } from '../lib/entry-id.js';
16
- import { generateRssFeed, validateRssXml } from '../lib/rss.js';
17
18
  const version = getPackageVersion();
18
19
  export async function build() {
19
20
  const config = getConfig();
@@ -22,7 +23,7 @@ export async function build() {
22
23
  const buildTime = formatDateTimeForDisplay(new Date());
23
24
  if (!(await fs.pathExists(logbookDir))) {
24
25
  console.error(error(`Error: Logbook directory '${config.logbookDir}' not found.`));
25
- return;
26
+ process.exit(1);
26
27
  }
27
28
  await setupOutputDirectory(outputDir, config);
28
29
  const projectRoot = process.cwd();
@@ -31,55 +32,38 @@ export async function build() {
31
32
  const aboutHtml = await processAboutContent(getAboutContent());
32
33
  const welcomeHtml = await processWelcomeContent();
33
34
  const logbookEntries = await getLogbookEntries(logbookDir);
34
- const timelineEntries = [];
35
+ const activeEntry = await getActiveEntry();
35
36
  const availableWorkspaces = getWorkspaces();
36
- for (const entry of logbookEntries) {
37
- if (!entry.hasIndex)
38
- continue;
39
- const { data, content, slug } = entry;
40
- let summary = data.summary;
41
- if (!summary) {
42
- const firstParagraph = content.split('\n\n').find((p) => p.trim() && !p.trim().startsWith('#'));
43
- summary = firstParagraph
44
- ? firstParagraph.trim().substring(0, 200).replace(/[*#`]/g, '') + '...'
45
- : 'No summary available.';
37
+ const timelineEntries = await processTimelineEntries(logbookEntries, activeEntry, availableWorkspaces);
38
+ // Fetch global git commits, tags, and ADRs concurrently.
39
+ const adrDir = getAdrDirPath(config);
40
+ const relativeAdrDir = config.adrDir || 'docs/adr';
41
+ const researchDir = getResearchDirPath(config);
42
+ const [globalCommits, rawTags, adrItems, researchEntriesRaw] = await Promise.all([
43
+ getGitCommits(process.cwd()),
44
+ getGitTags(),
45
+ adrDir ? getAdrEntries(adrDir, relativeAdrDir) : Promise.resolve([]),
46
+ researchDir && (await fs.pathExists(researchDir)) ? getLogbookEntries(researchDir) : Promise.resolve([]),
47
+ ]);
48
+ const researchEntries = (await processTimelineEntries(researchEntriesRaw, activeEntry, availableWorkspaces)).map((entry) => {
49
+ const raw = researchEntriesRaw.find((r) => r.slug === entry.slug);
50
+ const status = String(raw?.data?.status || 'active');
51
+ const updated = String(raw?.data?.updated || entry.dateStart);
52
+ return {
53
+ ...entry,
54
+ status,
55
+ updated,
56
+ };
57
+ });
58
+ researchEntries.sort((a, b) => new Date(b.updated || b.dateStart).getTime() - new Date(a.updated || a.dateStart).getTime());
59
+ const customTypesData = await loadCustomTypesData(config, projectRoot, activeEntry, availableWorkspaces);
60
+ const allReferenceEntries = [...researchEntries.map((e) => ({ ticket: e.ticket, slug: e.slug }))];
61
+ if (config.customTypes) {
62
+ for (const [typeName, entries] of Object.entries(customTypesData)) {
63
+ allReferenceEntries.push(...entries.map((e) => ({ ticket: e.ticket, slug: e.slug, customTypeName: typeName })));
46
64
  }
47
- const entryWorkspaces = asStringArray(data.workspaces).filter((ws) => availableWorkspaces.includes(ws));
48
- const dateStartValue = data.dateStart;
49
- const dateStart = typeof dateStartValue === 'string'
50
- ? dateStartValue
51
- : dateStartValue instanceof Date
52
- ? dateStartValue.toISOString()
53
- : '';
54
- // Skip DRAFT entries (no valid dateStart) — they break the timeline
55
- if (!dateStart || dateStart.includes('{{') || dateStart === '[DATE_START]')
56
- continue;
57
- const dateEndValue = data.dateEnd;
58
- const dateEnd = typeof dateEndValue === 'string' && dateEndValue !== '[DATE_END]'
59
- ? dateEndValue
60
- : dateEndValue instanceof Date
61
- ? dateEndValue.toISOString()
62
- : undefined;
63
- timelineEntries.push({
64
- kind: 'entry',
65
- slug,
66
- dateStart,
67
- dateEnd,
68
- displayDate: formatAbsoluteDate(dateStart),
69
- sortTime: getSortTime(dateStart, dateEnd),
70
- summary: asString(summary, 'No summary available.') || '',
71
- ticket: getEntryDisplayId(asString(data.ticket), slug),
72
- monthGroup: getMonthYear(dateStart),
73
- tags: asStringArray(data.tags),
74
- workspaces: entryWorkspaces,
75
- title: getEntryDisplayTitle(asString(data.title), slug),
76
- harness: toDisplayString(data.harness),
77
- llm: toDisplayString(data.llm),
78
- prompter: toDisplayString(data.prompter),
79
- });
80
65
  }
81
- // Fetch global git commits and tags concurrently.
82
- const [globalCommits, rawTags] = await Promise.all([getGitCommits(process.cwd()), getGitTags()]);
66
+ registerResearchEntries(allReferenceEntries);
83
67
  const commitItems = globalCommits.map((c) => ({
84
68
  kind: 'commit',
85
69
  sha: c.sha,
@@ -97,15 +81,24 @@ export async function build() {
97
81
  monthGroup: getMonthYear(t.timestamp),
98
82
  sortTime: getSortTime(t.timestamp),
99
83
  }));
100
- console.log(neutral(`Found ${timelineEntries.length} entr${timelineEntries.length === 1 ? 'y' : 'ies'}, ${commitItems.length} commit${commitItems.length === 1 ? '' : 's'} (max 100), and ${tagItems.length} tag${tagItems.length === 1 ? '' : 's'}.`));
101
- timelineEntries.sort((a, b) => {
102
- const aEnd = a.dateEnd ? new Date(a.dateEnd).getTime() : new Date(a.dateStart).getTime();
103
- const bEnd = b.dateEnd ? new Date(b.dateEnd).getTime() : new Date(b.dateStart).getTime();
104
- return bEnd - aEnd;
105
- });
106
- await Promise.all(timelineEntries.map((entry, i) => renderPost(entry, i, timelineEntries, { logbookDir, outputDir, config, version, buildTime })));
107
- // Build the full merged, chronologically sorted groups once, then paginate the flat item list.
108
- const allGroups = groupTimelineItems(timelineEntries, commitItems, tagItems);
84
+ console.log(neutral(`Found ${timelineEntries.length} entr${timelineEntries.length === 1 ? 'y' : 'ies'}, ${commitItems.length} commit${commitItems.length === 1 ? '' : 's'} (max 100), ${tagItems.length} tag${tagItems.length === 1 ? '' : 's'}, ${adrItems.length} ADR${adrItems.length === 1 ? '' : 's'}, and ${researchEntries.length} Research task${researchEntries.length === 1 ? '' : 's'}.`));
85
+ timelineEntries.sort((a, b) => new Date(b.dateEnd || b.dateStart).getTime() - new Date(a.dateEnd || a.dateStart).getTime());
86
+ const customRenderPromises = [];
87
+ if (config.customTypes) {
88
+ for (const [typeName, entries] of Object.entries(customTypesData)) {
89
+ customRenderPromises.push(...entries.map((entry, i) => renderPost(entry, i, entries, { logbookDir, outputDir, config, version, buildTime }, false, typeName)));
90
+ }
91
+ }
92
+ await Promise.all([
93
+ ...timelineEntries.map((entry, i) => renderPost(entry, i, timelineEntries, { logbookDir, outputDir, config, version, buildTime })),
94
+ ...researchEntries.map((entry, i) => renderPost(entry, i, researchEntries, { logbookDir, outputDir, config, version, buildTime }, true)),
95
+ ...customRenderPromises,
96
+ ...adrItems.map(async (adr) => {
97
+ adr.decisionHtml = await mdToHtml(adr.decision);
98
+ await renderAdr(adr, { adrDir: adrDir, outputDir, config, version, buildTime });
99
+ }),
100
+ ]);
101
+ const allGroups = groupTimelineItems(timelineEntries, commitItems, tagItems, adrItems);
109
102
  const flatItems = allGroups.flatMap((g) => g.items);
110
103
  const pageSize = 50;
111
104
  const totalPages = Math.max(1, Math.ceil(flatItems.length / pageSize));
@@ -115,14 +108,18 @@ export async function build() {
115
108
  // Re-group this page's items by month for rendering.
116
109
  const pageGroups = [];
117
110
  for (const item of pageItems) {
118
- const month = item.monthGroup;
119
- let group = pageGroups.find((g) => g.month === month);
120
- if (!group) {
121
- group = { month, items: [] };
111
+ const group = pageGroups.find((g) => g.month === item.monthGroup) || { month: item.monthGroup, items: [] };
112
+ if (group.items.length === 0)
122
113
  pageGroups.push(group);
123
- }
124
114
  group.items.push(item);
125
115
  }
116
+ const customTabs = config.customTypes
117
+ ? Object.entries(customTypesData).map(([typeName, entries]) => ({
118
+ id: typeName,
119
+ title: config.customTypes[typeName].tabTitle,
120
+ items: entries,
121
+ }))
122
+ : [];
126
123
  const { header: timelineHeader, content: timelineMainContent } = timelineTemplate({
127
124
  projectName: config.projectName,
128
125
  version,
@@ -137,8 +134,13 @@ export async function build() {
137
134
  currentPage,
138
135
  totalPages,
139
136
  includeRssLink: currentPage === 1, // Only show RSS link on first page
140
- }); // prettier-ignore
137
+ researchEntries,
138
+ adrItems,
139
+ customTabs,
140
+ });
141
141
  const buildMeta = generateBuildMeta(version, buildTime);
142
+ const prevPageUrl = currentPage > 1 ? (currentPage === 2 ? './index.html' : `./index-${currentPage - 1}.html`) : undefined;
143
+ const nextPageUrl = currentPage < totalPages ? `./index-${currentPage + 1}.html` : undefined;
142
144
  const timelineHtml = layout({
143
145
  title: 'Timeline',
144
146
  projectName: config.projectName,
@@ -147,6 +149,8 @@ export async function build() {
147
149
  header: timelineHeader,
148
150
  content: timelineMainContent,
149
151
  includeRssLink: currentPage === 1, // Only show RSS link on first page
152
+ prevUrl: prevPageUrl,
153
+ nextUrl: nextPageUrl,
150
154
  });
151
155
  const fileName = currentPage === 1 ? 'index.html' : `index-${currentPage}.html`;
152
156
  await fs.writeFile(join(outputDir, fileName), timelineHtml);
@@ -157,21 +161,7 @@ export async function build() {
157
161
  buildTime,
158
162
  });
159
163
  // Generate RSS feed
160
- const rssConfig = {
161
- title: `${config.projectName} - Recent Updates`,
162
- description: `Latest logbook entries from ${config.projectName}`,
163
- language: 'en',
164
- feed_url: `${config.projectName.toLowerCase().replace(/\s+/g, '-')}/rss.xml`,
165
- site_url: config.projectName,
166
- generator: `Project Logbook CLI v${version}`,
167
- };
168
- const rssXml = generateRssFeed(timelineEntries, rssConfig);
169
- // Basic validation
170
- if (!validateRssXml(rssXml)) {
171
- console.error(error('Error: Generated RSS feed failed basic validation.'));
172
- return;
173
- }
174
- await fs.writeFile(join(outputDir, 'rss.xml'), rssXml);
175
- console.log(neutral(` Generated RSS feed with ${Math.min(50, timelineEntries.length)} entries`));
164
+ await buildRssFeed(outputDir, timelineEntries, config, version);
176
165
  console.log(success(`\nSuccessfully built logbook to ${config.outputDir}/`));
177
166
  }
167
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"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"}
@@ -81,3 +81,4 @@ export async function init() {
81
81
  console.log(info('\n💡 Tip: Edit .project-logbook to customize primaryColor, add more tags, or configure Jira settings.'));
82
82
  console.log(info(' Run `logbook new` to create your first entry.\n'));
83
83
  }
84
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs-extra';
2
2
  import { join } from 'node:path';
3
- import { error as errorStyle, header, success as successStyle, neutral as neutralStyle } from '../lib/theme.js';
3
+ import { error as errorStyle, header, success as successStyle, neutral as neutralStyle, warning as warningStyle, } from '../lib/theme.js';
4
4
  import { getConfig, getLogbookDirPath } from '../lib/config.js';
5
5
  import { runLinters } from '../lib/lint-runner.js';
6
6
  import { getLogbookEntries } from '../utils/fs.js';
@@ -11,13 +11,14 @@ export async function lint() {
11
11
  const logbookDir = getLogbookDirPath(config);
12
12
  if (!(await fs.pathExists(logbookDir))) {
13
13
  console.error(errorStyle(`Error: Logbook directory '${config.logbookDir}' not found.`));
14
- return;
14
+ process.exit(1);
15
15
  }
16
16
  let overallSuccess = true;
17
17
  // Show last log entry nudge if an entry is active
18
18
  const active = await getActiveEntry();
19
19
  if (active) {
20
- const logPath = join(logbookDir, active.slug, 'log.md');
20
+ const entryDir = active.path || join(logbookDir, active.slug);
21
+ const logPath = join(entryDir, 'log.md');
21
22
  if (await fs.pathExists(logPath)) {
22
23
  const logContent = await fs.readFile(logPath, 'utf8');
23
24
  const lastEntry = getLastLogEntry(logContent);
@@ -46,6 +47,10 @@ export async function lint() {
46
47
  }
47
48
  if (isDraft(entry)) {
48
49
  skippedCount++;
50
+ if (active && active.slug === entry.slug) {
51
+ console.log(warningStyle(`\n [SKIPPED] Active entry '${entry.slug}' is a draft (missing valid dateStart).`));
52
+ console.log(warningStyle(` → Run 'logbook start ${entry.slug.split('-')[0]}' to activate it, which sets dateStart and enables linting.\n`));
53
+ }
49
54
  continue;
50
55
  }
51
56
  const entrySuccess = await runLinters({
@@ -85,3 +90,4 @@ function isDraft(entry) {
85
90
  // 2. OR the string representation of 'dateStart' is '[DATE_START]'.
86
91
  return !frontmatter?.dateStart || String(frontmatter.dateStart) === '[DATE_START]';
87
92
  }
93
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"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"}
@@ -1,24 +1,25 @@
1
1
  import fs from 'fs-extra';
2
2
  import { getConfig, getLogbookDirPath } from '../lib/config.js';
3
3
  import { getLogbookEntries } from '../utils/fs.js';
4
+ import { hasUnfilledPlaceholders } from '../utils/validation.js';
4
5
  import { stripAnsi } from '../utils/string.js';
5
6
  import { parseTicketId } from '../utils/id.js';
6
7
  import { getActiveEntry } from '../lib/session.js';
7
8
  import { asString } from '../utils/frontmatter.js';
8
9
  import { error, neutral, warning, highlight, success, bold } from '../lib/theme.js';
9
10
  export async function list(options = {}) {
10
- const config = getConfig();
11
- const logbookDir = getLogbookDirPath(config);
12
- if (!(await fs.pathExists(logbookDir))) {
13
- console.error(error(`Error: Logbook directory '${config.logbookDir}' not found. Run 'logbook init' first.`));
11
+ const currentConfig = getConfig();
12
+ const dirPath = getLogbookDirPath(currentConfig);
13
+ if (!(await fs.pathExists(dirPath))) {
14
+ console.error(error(`Error: Logbook directory '${currentConfig.logbookDir}' not found. Run 'logbook init' first.`));
14
15
  process.exit(1);
15
16
  }
16
- // Detect currently active entry (if any)
17
- const active = await getActiveEntry();
18
- const activeSlug = active?.slug;
19
- const logbookEntries = await getLogbookEntries(logbookDir);
17
+ // Find the active entry if one exists
18
+ const currentActive = await getActiveEntry();
19
+ const activeSlug = currentActive?.slug;
20
+ const allEntries = await getLogbookEntries(dirPath);
20
21
  const rows = [];
21
- for (const entry of logbookEntries) {
22
+ for (const entry of allEntries) {
22
23
  if (!entry.hasIndex) {
23
24
  // Parse ticket ID and title from directory name slug
24
25
  const parsed = parseTicketId(entry.slug);
@@ -41,23 +42,9 @@ export async function list(options = {}) {
41
42
  });
42
43
  continue;
43
44
  }
44
- const { data, content } = entry;
45
+ const { data } = entry;
45
46
  const isActive = activeSlug === entry.slug;
46
- // Check frontmatter field values for bracket-style unfilled placeholders
47
- const dataValues = Object.values(data)
48
- .filter((v) => typeof v === 'string')
49
- .join('\n');
50
- const frontmatterHasPlaceholders = dataValues.includes('[DATE_END]') ||
51
- dataValues.includes('[DATE_START]') ||
52
- dataValues.includes('[WRITE_SUMMARY_HERE]') ||
53
- dataValues.includes('[PROMPTER]') ||
54
- dataValues.includes('[HARNESS]') ||
55
- dataValues.includes('[LLM]');
56
- // Check body content for unfilled template hints (strip inline code spans to avoid false positives)
57
- const contentWithoutCode = content.replace(/`[^`]*`/g, '');
58
- const bodyHasPlaceholders = contentWithoutCode.includes('TODO:') ||
59
- content.includes('Write a polished, highly readable "short story" of the change here.');
60
- const hasPlaceholders = frontmatterHasPlaceholders || bodyHasPlaceholders;
47
+ const hasPlaceholders = hasUnfilledPlaceholders(entry);
61
48
  const status = isActive ? highlight('● ACTIVE') : hasPlaceholders ? warning('DRAFT') : success('DONE');
62
49
  rows.push({
63
50
  ticketId: asString(data.ticket) || neutral('-'),
@@ -123,5 +110,6 @@ export async function list(options = {}) {
123
110
  const countText = displayedRows.length === totalEntries
124
111
  ? `${totalEntries} ${totalEntries === 1 ? 'entry' : 'entries'}`
125
112
  : `Showing latest ${displayedRows.length} of ${totalEntries} entries (use --all to show all)`;
126
- console.log(neutral(`${countText} in ${config.logbookDir}/`));
113
+ console.log(neutral(`${countText} in ${currentConfig.logbookDir}/`));
127
114
  }
115
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1 @@
1
- export declare function log(messages: string[], options?: {
2
- id?: string;
3
- }): Promise<void>;
1
+ export declare function log(messages: string[]): Promise<void>;
@@ -3,17 +3,19 @@ import { join } from 'node:path';
3
3
  import { error as errorStyle, successMessage } from '../lib/theme.js';
4
4
  import { getConfig } from '../lib/config.js';
5
5
  import { getActiveEntry } from '../lib/session.js';
6
- export async function log(messages, options = {}) {
6
+ import matter from 'gray-matter';
7
+ export async function log(messages) {
7
8
  const cwd = process.cwd();
8
9
  // 1. Require an active entry
9
- const active = await getActiveEntry(options, cwd);
10
+ const active = await getActiveEntry({}, cwd);
10
11
  if (!active) {
11
12
  console.error(errorStyle(`Error: No active logbook entry resolved.`));
12
- console.error(errorStyle(`Activate an entry via 'logbook start <id>', checkout a feature branch, or pass --id.`));
13
+ console.error(errorStyle(`Activate an entry via 'logbook start <id>' or checkout a feature branch.`));
13
14
  process.exit(1);
14
15
  }
15
16
  const config = getConfig();
16
- const logPath = join(cwd, config.logbookDir, active.slug, 'log.md');
17
+ const entryPath = active.path || join(cwd, config.logbookDir, active.slug);
18
+ const logPath = join(entryPath, 'log.md');
17
19
  if (!(await fs.pathExists(logPath))) {
18
20
  console.error(errorStyle(`Error: log.md not found`));
19
21
  process.exit(1);
@@ -25,7 +27,29 @@ export async function log(messages, options = {}) {
25
27
  const existing = await fs.readFile(logPath, 'utf8');
26
28
  const separator = existing.endsWith('\n') ? '' : '\n';
27
29
  await fs.writeFile(logPath, existing + separator + newLines + '\n');
30
+ // 4. If it's a research entry or custom type entry, update 'updated' in index.md
31
+ const isResearchOrCustom = active.slug.toLowerCase().startsWith('res-') ||
32
+ (config.customTypes &&
33
+ Object.values(config.customTypes).some((tc) => active.slug.toLowerCase().startsWith(tc.prefix.toLowerCase() + '-')));
34
+ if (isResearchOrCustom) {
35
+ const indexPath = join(entryPath, 'index.md');
36
+ if (await fs.pathExists(indexPath)) {
37
+ try {
38
+ const rawIndex = await fs.readFile(indexPath, 'utf8');
39
+ const parsed = matter(rawIndex);
40
+ if (parsed.data) {
41
+ parsed.data.updated = timestamp;
42
+ const newContent = matter.stringify(parsed.content, parsed.data);
43
+ await fs.writeFile(indexPath, newContent);
44
+ }
45
+ }
46
+ catch {
47
+ // ignore errors
48
+ }
49
+ }
50
+ }
28
51
  for (const msg of messages) {
29
52
  console.log(successMessage('Logged', `${active.slug} (via ${active.source}): ${timestamp}: ${msg}`));
30
53
  }
31
54
  }
55
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"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"}
@@ -1 +1,4 @@
1
- export declare function createNewEntry(id?: string, slug?: string): Promise<void>;
1
+ export declare function createNewEntry(id?: string, slug?: string, options?: {
2
+ research?: boolean;
3
+ type?: string;
4
+ }): Promise<void>;