get-tbd 0.1.27 → 0.1.28
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/dist/bin.mjs +140 -104
- package/dist/bin.mjs.map +1 -1
- package/dist/cli.mjs +41 -15
- package/dist/cli.mjs.map +1 -1
- package/dist/docs/guidelines/bun-monorepo-patterns.md +328 -58
- package/dist/docs/guidelines/pnpm-monorepo-patterns.md +399 -64
- package/dist/docs/guidelines/typescript-cli-tool-rules.md +39 -8
- package/dist/docs/guidelines/typescript-code-coverage.md +27 -3
- package/dist/docs/guidelines/typescript-rules.md +18 -0
- package/dist/docs/guidelines/typescript-yaml-handling-rules.md +12 -0
- package/dist/docs/tbd-design.md +16 -1
- package/dist/docs/tbd-docs.md +11 -2
- package/dist/index.mjs +1 -1
- package/dist/{src-BIE27KDA.mjs → src-D2xEmH4L.mjs} +2 -2
- package/dist/{src-BIE27KDA.mjs.map → src-D2xEmH4L.mjs.map} +1 -1
- package/dist/tbd +140 -104
- package/package.json +2 -2
|
@@ -5,6 +5,20 @@ author: Joshua Levy (github.com/jlevy) with LLM assistance
|
|
|
5
5
|
---
|
|
6
6
|
# CLI Tool Development Rules
|
|
7
7
|
|
|
8
|
+
**Last Updated**: 2026-05-21
|
|
9
|
+
|
|
10
|
+
**Tracks**: Commander.js `^15.0.0` (ESM-only, requires Node v22.12.0+),
|
|
11
|
+
picocolors `^1.1.1` (stable; no recent changes), Node.js 24 LTS / Node 26 Current.
|
|
12
|
+
Commander 14 moves to security-only maintenance until May 2027.
|
|
13
|
+
|
|
14
|
+
**Related**:
|
|
15
|
+
|
|
16
|
+
- [TypeScript Rules](./typescript-rules.md)
|
|
17
|
+
- [Supply-Chain Mitigation](./pnpm-monorepo-patterns.md#supply-chain-mitigation) —
|
|
18
|
+
follow the 14-day package-age rule for every CLI dependency. Bundlers and
|
|
19
|
+
CLI dependencies that execute at install time (`postinstall` scripts) are a
|
|
20
|
+
primary attack surface.
|
|
21
|
+
|
|
8
22
|
These rules apply to all CLI tools, command-line scripts, and terminal utilities.
|
|
9
23
|
Examples may be inspired by modern TypeScript repos, but guidance here is intentionally
|
|
10
24
|
generic and reusable across projects.
|
|
@@ -93,7 +107,9 @@ generic and reusable across projects.
|
|
|
93
107
|
## Commander.js Patterns
|
|
94
108
|
|
|
95
109
|
- **Use Commander.js for all CLI tools:** Import from `commander` and follow established
|
|
96
|
-
patterns for command registration and option handling.
|
|
110
|
+
patterns for command registration and option handling. **Target Commander 15+
|
|
111
|
+
(ESM-only, requires Node v22.12.0+).** Commander 14 is security-maintenance
|
|
112
|
+
only until May 2027; do not start new projects on it.
|
|
97
113
|
|
|
98
114
|
- **Apply colored help globally, not per-command:** Use Commander v14+ `configureHelp()`
|
|
99
115
|
with style functions, applied recursively to all commands at program initialization.
|
|
@@ -549,15 +565,30 @@ When supporting environment variables, especially those used by SDK libraries (l
|
|
|
549
565
|
`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.), also support `.env` loading so CLIs work
|
|
550
566
|
seamlessly in local dev and in remote environments.
|
|
551
567
|
|
|
552
|
-
- **
|
|
553
|
-
|
|
568
|
+
- **Prefer Node.js native `--env-file` for Node ≥20.6**: Production-ready on
|
|
569
|
+
Node 24 LTS. Pass `--env-file=.env.local --env-file=.env` on the CLI
|
|
570
|
+
invocation; later files do not override earlier ones, so list higher-priority
|
|
571
|
+
first. No dependency required:
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
node --env-file=.env.local --env-file=.env ./dist/bin.js
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Make this the default for new projects. Reserve `dotenv` for advanced needs
|
|
578
|
+
(variable expansion, multiline values, custom precedence logic, or runtime
|
|
579
|
+
conditional loading from inside the CLI).
|
|
580
|
+
|
|
581
|
+
- **Use `dotenv` only when needed:** Add `dotenv` only if your CLI must load
|
|
582
|
+
env files programmatically — e.g., it reads them after parsing command-line
|
|
583
|
+
flags, performs variable expansion, or supports custom file paths the user
|
|
584
|
+
cannot pre-bake into the `node` invocation.
|
|
554
585
|
|
|
555
|
-
- **Load `.env.local` and `.env` automatically (recommended):**
|
|
556
|
-
|
|
557
|
-
`.env
|
|
586
|
+
- **Load `.env.local` and `.env` automatically (recommended):** Whichever
|
|
587
|
+
mechanism you use, support both `.env.local` (higher priority, gitignored)
|
|
588
|
+
and `.env` (lower priority, committed defaults only).
|
|
558
589
|
|
|
559
|
-
- **Manual dotenv loading:**
|
|
560
|
-
|
|
590
|
+
- **Manual `dotenv` loading:** When you do need `dotenv`, load with explicit
|
|
591
|
+
precedence:
|
|
561
592
|
|
|
562
593
|
```ts
|
|
563
594
|
import dotenv from 'dotenv';
|
|
@@ -5,6 +5,18 @@ author: Joshua Levy (github.com/jlevy) with LLM assistance
|
|
|
5
5
|
---
|
|
6
6
|
# Code Coverage Best Practices for TypeScript with Vitest
|
|
7
7
|
|
|
8
|
+
**Last Updated**: 2026-05-21
|
|
9
|
+
|
|
10
|
+
**Tracks**: Vitest `^4.1.7`, `@vitest/coverage-v8` `^4.1.7`. Vitest 5.0 is in
|
|
11
|
+
beta — do not adopt yet.
|
|
12
|
+
|
|
13
|
+
**Related**:
|
|
14
|
+
|
|
15
|
+
- [Companion: pnpm Monorepo Patterns — Testing](./pnpm-monorepo-patterns.md#8-testing)
|
|
16
|
+
- [Supply-Chain Mitigation](./pnpm-monorepo-patterns.md#supply-chain-mitigation) —
|
|
17
|
+
follow the 14-day package-age rule when installing or upgrading `vitest` and
|
|
18
|
+
`@vitest/coverage-v8`.
|
|
19
|
+
|
|
8
20
|
## Coverage Metrics
|
|
9
21
|
|
|
10
22
|
### Essential Metrics
|
|
@@ -70,9 +82,21 @@ Low branch coverage often indicates untested error paths and edge cases.
|
|
|
70
82
|
### Installation
|
|
71
83
|
|
|
72
84
|
```bash
|
|
73
|
-
|
|
85
|
+
# Pin to a specific minor to stay on a stable line; align both packages.
|
|
86
|
+
pnpm add -D vitest@^4.1 @vitest/coverage-v8@^4.1
|
|
74
87
|
```
|
|
75
88
|
|
|
89
|
+
Follow the [14-day package-age rule](./pnpm-monorepo-patterns.md#supply-chain-mitigation)
|
|
90
|
+
on every upgrade: use `ncu --cooldown 14` or
|
|
91
|
+
`pnpm install --frozen-lockfile`.
|
|
92
|
+
|
|
93
|
+
### Vitest 4.x changes that affect coverage
|
|
94
|
+
|
|
95
|
+
- **`coverage.all` was removed** in Vitest 4. Use `coverage.include` and
|
|
96
|
+
`coverage.exclude` to define exactly which files are reported.
|
|
97
|
+
- Coverage reporters and v8 provider now ship as part of `@vitest/coverage-v8`
|
|
98
|
+
aligned with the Vitest major version — pin them together.
|
|
99
|
+
|
|
76
100
|
### Example Configuration
|
|
77
101
|
|
|
78
102
|
```typescript
|
|
@@ -131,10 +155,10 @@ export default defineConfig({
|
|
|
131
155
|
|
|
132
156
|
```yaml
|
|
133
157
|
- name: Run tests with coverage
|
|
134
|
-
run:
|
|
158
|
+
run: pnpm run test:coverage
|
|
135
159
|
|
|
136
160
|
- name: Upload coverage to Codecov
|
|
137
|
-
uses: codecov/codecov-action@
|
|
161
|
+
uses: codecov/codecov-action@v5
|
|
138
162
|
with:
|
|
139
163
|
files: ./coverage/lcov.info
|
|
140
164
|
fail_ci_if_error: true
|
|
@@ -7,6 +7,24 @@ alwaysApply: true
|
|
|
7
7
|
---
|
|
8
8
|
# TypeScript Rules
|
|
9
9
|
|
|
10
|
+
**Last Updated**: 2026-05-21
|
|
11
|
+
|
|
12
|
+
**Tracks**: TypeScript `^6.0.3` (stable). TypeScript 7.0 Beta
|
|
13
|
+
(`@typescript/native-preview`, binary `tsgo`) is available but **not yet
|
|
14
|
+
production-ready** — do not adopt for shipped builds.
|
|
15
|
+
|
|
16
|
+
**Related**:
|
|
17
|
+
|
|
18
|
+
- [TypeScript CLI Tool Rules](./typescript-cli-tool-rules.md)
|
|
19
|
+
- [TypeScript Sorting Patterns](./typescript-sorting-patterns.md)
|
|
20
|
+
- [TypeScript YAML Handling Rules](./typescript-yaml-handling-rules.md)
|
|
21
|
+
- [TypeScript Code Coverage](./typescript-code-coverage.md)
|
|
22
|
+
- [pnpm Monorepo Patterns](./pnpm-monorepo-patterns.md) and
|
|
23
|
+
[Bun Monorepo Patterns](./bun-monorepo-patterns.md)
|
|
24
|
+
- [Supply-Chain Mitigation](./pnpm-monorepo-patterns.md#supply-chain-mitigation) —
|
|
25
|
+
the 14-day package-age rule applies to every TypeScript dependency
|
|
26
|
+
(`zod`, `commander`, `vitest`, `eslint`, type packages, etc.).
|
|
27
|
+
|
|
10
28
|
## Coding Style
|
|
11
29
|
|
|
12
30
|
- Use clear lowerCamelCase or UpperCamelCase names for functions and variables, per
|
|
@@ -6,6 +6,18 @@ globs: "*.ts"
|
|
|
6
6
|
---
|
|
7
7
|
# TypeScript YAML Handling Rules
|
|
8
8
|
|
|
9
|
+
**Last Updated**: 2026-05-21
|
|
10
|
+
|
|
11
|
+
**Tracks**: `yaml@^2.8.4` (latest stable; 2026-05-02). The `yaml@3.0.0-1`
|
|
12
|
+
release is tagged `next` (pre-release) — do not adopt yet. Zod 4.x is the
|
|
13
|
+
recommended validation companion.
|
|
14
|
+
|
|
15
|
+
**Related**:
|
|
16
|
+
|
|
17
|
+
- [TypeScript Rules](./typescript-rules.md)
|
|
18
|
+
- [Supply-Chain Mitigation](./pnpm-monorepo-patterns.md#supply-chain-mitigation) —
|
|
19
|
+
follow the 14-day package-age rule for `yaml`, `zod`, and `gray-matter`.
|
|
20
|
+
|
|
9
21
|
These guidelines ensure consistent, safe, and readable YAML handling across TypeScript
|
|
10
22
|
codebases. YAML is deceptively tricky—inconsistent quoting, serialization differences,
|
|
11
23
|
and lack of validation cause subtle bugs.
|
package/dist/docs/tbd-design.md
CHANGED
|
@@ -2631,9 +2631,24 @@ Options:
|
|
|
2631
2631
|
|
|
2632
2632
|
**Output:**
|
|
2633
2633
|
|
|
2634
|
-
The `show` command outputs the issue in
|
|
2634
|
+
The `show` command outputs the issue in a storage-compatible format (YAML frontmatter +
|
|
2635
2635
|
Markdown body). This format is both human-readable and machine-parseable, enabling
|
|
2636
2636
|
round-trip editing workflows.
|
|
2637
|
+
For dependency direction, text output may include YAML comments immediately above the
|
|
2638
|
+
`dependencies` field:
|
|
2639
|
+
|
|
2640
|
+
```yaml
|
|
2641
|
+
# Blocks: proj-c3d4
|
|
2642
|
+
# Blocked by: proj-f14c
|
|
2643
|
+
dependencies:
|
|
2644
|
+
- type: blocks
|
|
2645
|
+
target: is-c3d4...
|
|
2646
|
+
```
|
|
2647
|
+
|
|
2648
|
+
These comments are ignored by `tbd update --from-file` and exist only to clarify the raw
|
|
2649
|
+
edge list. In storage, `type: blocks` means the shown issue blocks the target.
|
|
2650
|
+
For dependency-direction checks, prefer `tbd dep list <id>`, which renders the
|
|
2651
|
+
human-facing `Blocks:` and `Blocked by:` sections directly.
|
|
2637
2652
|
|
|
2638
2653
|
**Parent context (auto-displayed for child issues):**
|
|
2639
2654
|
|
package/dist/docs/tbd-docs.md
CHANGED
|
@@ -292,8 +292,13 @@ tbd show proj-a7k2 --no-parent # Suppress parent context
|
|
|
292
292
|
|
|
293
293
|
Output includes all fields: title, description, status, priority, labels, dependencies,
|
|
294
294
|
timestamps, and working notes.
|
|
295
|
-
|
|
296
|
-
|
|
295
|
+
The raw `dependencies` field is a storage-format edge list: an entry with `type: blocks`
|
|
296
|
+
means the shown issue blocks the target.
|
|
297
|
+
When dependency directions exist, text output adds YAML comments above `dependencies`
|
|
298
|
+
with human-facing `Blocks:` and `Blocked by:` sections using display IDs.
|
|
299
|
+
For dependency-direction checks, prefer `tbd dep list <id>`. For child issues, the
|
|
300
|
+
parent’s details (ID, title, status, priority, description) are automatically displayed
|
|
301
|
+
below the child for context.
|
|
297
302
|
|
|
298
303
|
### update
|
|
299
304
|
|
|
@@ -450,6 +455,10 @@ Subcommands:
|
|
|
450
455
|
- `remove <issue> <depends-on>` - Remove dependency
|
|
451
456
|
- `list <id>` - List dependencies for an issue (what it blocks and what blocks it)
|
|
452
457
|
|
|
458
|
+
Use `tbd dep list <id>` when checking dependency direction.
|
|
459
|
+
The raw `dependencies` frontmatter in `tbd show` stores graph edges where `type: blocks`
|
|
460
|
+
means the shown issue blocks the target.
|
|
461
|
+
|
|
453
462
|
### sync
|
|
454
463
|
|
|
455
464
|
Synchronize issues with remote repository.
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { A as Ulid, C as LOCAL_STATE_FIELD_ORDER, D as Priority, E as MetaSchema, O as ShortId, S as IssueTitle, T as META_FIELD_ORDER, _ as IdMappingYamlSchema, a as ConfigSchema, b as IssueSchema, c as DocCacheConfigSchema, d as ExternalIssueIdInput, f as GitBranchName, g as ISSUE_TITLE_MAX_LENGTH, h as ISSUE_FIELD_ORDER, i as CONFIG_FIELD_ORDER, j as Version, k as Timestamp, l as DocsCacheSchema, m as ISSUE_BODY_MAX_LENGTH, n as AtticEntrySchema, o as Dependency, p as GitRemoteName, r as BaseEntity, s as DependencyRelationType, t as ATTIC_ENTRY_FIELD_ORDER, u as EntityType, v as IssueId, w as LocalStateSchema, x as IssueStatus, y as IssueKind } from "./schemas-C8mOQykE.mjs";
|
|
2
|
-
import { c as noopLogger, i as serializeIssue, n as parseIssue, t as VERSION } from "./src-
|
|
2
|
+
import { c as noopLogger, i as serializeIssue, n as parseIssue, t as VERSION } from "./src-D2xEmH4L.mjs";
|
|
3
3
|
|
|
4
4
|
export { ATTIC_ENTRY_FIELD_ORDER, AtticEntrySchema, BaseEntity, CONFIG_FIELD_ORDER, ConfigSchema, Dependency, DependencyRelationType, DocCacheConfigSchema, DocsCacheSchema, EntityType, ExternalIssueIdInput, GitBranchName, GitRemoteName, ISSUE_BODY_MAX_LENGTH, ISSUE_FIELD_ORDER, ISSUE_TITLE_MAX_LENGTH, IdMappingYamlSchema, IssueId, IssueKind, IssueSchema, IssueStatus, IssueTitle, LOCAL_STATE_FIELD_ORDER, LocalStateSchema, META_FIELD_ORDER, MetaSchema, Priority, ShortId, Timestamp, Ulid, VERSION, Version, noopLogger, parseIssue, serializeIssue };
|
|
@@ -183,8 +183,8 @@ function serializeIssue(issue) {
|
|
|
183
183
|
* Package version, derived from git at build time.
|
|
184
184
|
* Format: X.Y.Z for releases, X.Y.Z-dev.N.hash for dev builds.
|
|
185
185
|
*/
|
|
186
|
-
const VERSION = "0.1.
|
|
186
|
+
const VERSION = "0.1.28";
|
|
187
187
|
|
|
188
188
|
//#endregion
|
|
189
189
|
export { insertAfterFrontmatter as a, noopLogger as c, serializeIssue as i, parseIssue as n, parseMarkdown as o, parseMarkdownWithFrontmatter as r, stripFrontmatter as s, VERSION as t };
|
|
190
|
-
//# sourceMappingURL=src-
|
|
190
|
+
//# sourceMappingURL=src-D2xEmH4L.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src-BIE27KDA.mjs","names":["parseYaml"],"sources":["../src/lib/types.ts","../src/utils/markdown-utils.ts","../src/file/parser.ts","../src/index.ts"],"sourcesContent":["/**\n * TypeScript types derived from Zod schemas.\n *\n * These types are the canonical TypeScript interface for tbd entities.\n */\n\nimport type { z } from 'zod';\n\nimport type {\n IssueSchema,\n IssueStatus,\n IssueKind,\n Priority,\n Dependency,\n ConfigSchema,\n MetaSchema,\n LocalStateSchema,\n AtticEntrySchema,\n} from './schemas.js';\n\n// =============================================================================\n// Entity Types\n// =============================================================================\n\n/**\n * A tbd issue entity.\n */\nexport type Issue = z.infer<typeof IssueSchema>;\n\n/**\n * Issue status enum values.\n */\nexport type IssueStatusType = z.infer<typeof IssueStatus>;\n\n/**\n * Issue kind enum values.\n */\nexport type IssueKindType = z.infer<typeof IssueKind>;\n\n/**\n * Priority level (0-4).\n */\nexport type PriorityType = z.infer<typeof Priority>;\n\n/**\n * A dependency relationship.\n */\nexport type DependencyType = z.infer<typeof Dependency>;\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\n/**\n * Project configuration.\n */\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/**\n * Shared metadata.\n */\nexport type Meta = z.infer<typeof MetaSchema>;\n\n/**\n * Per-node local state.\n */\nexport type LocalState = z.infer<typeof LocalStateSchema>;\n\n/**\n * Attic entry for conflict losers.\n */\nexport type AtticEntry = z.infer<typeof AtticEntrySchema>;\n\n// =============================================================================\n// Input Types for Commands\n// =============================================================================\n\n/**\n * Options for creating an issue.\n */\nexport interface CreateIssueOptions {\n title: string;\n description?: string;\n kind?: IssueKindType;\n priority?: PriorityType;\n assignee?: string;\n labels?: string[];\n parent_id?: string;\n due_date?: string;\n deferred_until?: string;\n}\n\n/**\n * Options for updating an issue.\n */\nexport interface UpdateIssueOptions {\n title?: string;\n description?: string;\n notes?: string;\n kind?: IssueKindType;\n status?: IssueStatusType;\n priority?: PriorityType;\n assignee?: string | null;\n addLabels?: string[];\n removeLabels?: string[];\n parent_id?: string | null;\n due_date?: string | null;\n deferred_until?: string | null;\n}\n\n/**\n * Options for listing issues.\n */\nexport interface ListIssuesOptions {\n status?: IssueStatusType | IssueStatusType[];\n kind?: IssueKindType | IssueKindType[];\n priority?: PriorityType;\n assignee?: string;\n labels?: string[];\n parent?: string;\n all?: boolean;\n sort?: 'priority' | 'created' | 'updated';\n limit?: number;\n}\n\n/**\n * Options for searching issues.\n */\nexport interface SearchIssuesOptions {\n query: string;\n status?: IssueStatusType | IssueStatusType[];\n limit?: number;\n}\n\n// =============================================================================\n// CLI Utility Types\n// =============================================================================\n\n/**\n * A documentation section with title and slug.\n * Used by docs and design commands.\n */\nexport interface DocSection {\n title: string;\n slug: string;\n}\n\n/**\n * Logger interface for long-running operations in non-CLI layers.\n *\n * Allows core logic (file/, lib/) to report progress without depending on\n * the CLI output layer. CLI commands create an OperationLogger via\n * `OutputManager.logger(spinner)` and pass it to core functions.\n *\n * All methods are required. Use `noopLogger` when no logging is needed.\n */\nexport interface OperationLogger {\n /** Key milestones — drives the spinner in CLI context */\n progress: (message: string) => void;\n /** Operational detail (shown with --verbose or --debug) */\n info: (message: string) => void;\n /** Non-fatal warnings */\n warn: (message: string) => void;\n /** Internal state for troubleshooting (shown with --debug only) */\n debug: (message: string) => void;\n}\n\n/**\n * No-op logger for when no logging is needed.\n * Analogous to noopSpinner in the CLI layer.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst noop = () => {};\nexport const noopLogger: OperationLogger = {\n progress: noop,\n info: noop,\n warn: noop,\n debug: noop,\n};\n","/**\n * Markdown utilities for processing markdown content.\n *\n * Uses gray-matter for parsing and centralized yaml-utils for stringify to ensure\n * proper handling of special YAML characters (colons, quotes, etc.).\n */\n\nimport matter from 'gray-matter';\n\nimport { stringifyYamlCompact } from './yaml-utils.js';\n\nexport interface ParsedMarkdown {\n /** Raw frontmatter string (without --- delimiters), or null if no frontmatter */\n frontmatter: string | null;\n /** Body content after frontmatter, with leading newlines trimmed */\n body: string;\n}\n\n/**\n * Normalize line endings to LF.\n */\nexport function normalizeLineEndings(content: string): string {\n return content.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n}\n\n/**\n * Parse markdown content into frontmatter and body.\n * Handles both LF and CRLF line endings.\n *\n * @returns Object with frontmatter (null if none) and body\n */\nexport function parseMarkdown(content: string): ParsedMarkdown {\n const normalized = normalizeLineEndings(content);\n\n if (!matter.test(normalized)) {\n return { frontmatter: null, body: content };\n }\n\n try {\n const parsed = matter(normalized);\n\n // Extract frontmatter from parsed.data by stringifying back to YAML\n // The matter property is unreliable, so we reconstruct from data\n const data = parsed.data;\n let frontmatter: string | null = null;\n\n if (data && Object.keys(data).length > 0) {\n // Use centralized yaml-utils for proper handling of special characters\n // (colons, quotes, multiline strings, etc.)\n frontmatter = stringifyYamlCompact(data).trimEnd();\n } else {\n // Empty frontmatter (just --- followed by ---)\n frontmatter = '';\n }\n\n // Body with leading newlines trimmed\n const body = parsed.content.replace(/^\\n+/, '');\n\n return { frontmatter, body };\n } catch {\n // Invalid/unclosed frontmatter - treat as no frontmatter\n return { frontmatter: null, body: content };\n }\n}\n\n/**\n * Parse YAML frontmatter from markdown content.\n * Returns the frontmatter content (without delimiters) or null if no valid frontmatter.\n * Handles both LF and CRLF line endings.\n */\nexport function parseFrontmatter(content: string): string | null {\n return parseMarkdown(content).frontmatter;\n}\n\n/**\n * Strip YAML frontmatter from markdown content.\n * Returns the body content without frontmatter, with leading newlines trimmed.\n * Handles both LF and CRLF line endings.\n */\nexport function stripFrontmatter(content: string): string {\n return parseMarkdown(content).body;\n}\n\n/**\n * Insert content after YAML frontmatter.\n * If no frontmatter exists, prepends the content.\n * Content is inserted directly after ---. Include leading newlines in toInsert if needed.\n */\nexport function insertAfterFrontmatter(content: string, toInsert: string): string {\n const { frontmatter, body } = parseMarkdown(content);\n\n if (frontmatter === null) {\n return toInsert + content;\n }\n\n const frontmatterBlock = frontmatter ? `---\\n${frontmatter}\\n---` : '---\\n---';\n return `${frontmatterBlock}\\n${toInsert}\\n\\n${body}`;\n}\n","/**\n * YAML front matter parser and serializer for issue files.\n *\n * Issues are stored as Markdown files with YAML front matter:\n * ---\n * type: is\n * id: is-a1b2c3\n * ...\n * ---\n *\n * Description body here.\n *\n * ## Notes\n *\n * Working notes here.\n *\n * See: tbd-design.md §2.1 Markdown + YAML Front Matter Format\n */\n\nimport matter from 'gray-matter';\nimport { parse as parseYaml } from 'yaml';\n\nimport { normalizeLineEndings } from '../utils/markdown-utils.js';\nimport { sortKeys, stringifyYaml } from '../utils/yaml-utils.js';\nimport type { Issue } from '../lib/types.js';\nimport { IssueSchema, ISSUE_FIELD_ORDER } from '../lib/schemas.js';\n\n/**\n * gray-matter options using the 'yaml' package as engine.\n * This preserves date strings instead of converting them to Date objects.\n */\nexport const matterOptions = {\n engines: {\n yaml: {\n parse: (str: string): object => parseYaml(str) as object,\n stringify: (obj: object): string => stringifyYaml(obj),\n },\n },\n};\n\n/**\n * Parsed issue file content.\n */\nexport interface ParsedIssueFile {\n frontmatter: Record<string, unknown>;\n description: string;\n notes: string;\n}\n\n/**\n * Parse a Markdown file with YAML front matter.\n * Uses gray-matter for consistent frontmatter parsing.\n * Handles both LF and CRLF line endings.\n */\nexport function parseMarkdownWithFrontmatter(content: string): ParsedIssueFile {\n // Normalize CRLF to LF before parsing\n const normalizedContent = normalizeLineEndings(content);\n\n // Check for valid frontmatter\n if (!matter.test(normalizedContent)) {\n throw new Error('Invalid format: missing front matter opening delimiter');\n }\n\n const parsed = matter(normalizedContent, matterOptions);\n\n // gray-matter returns empty object if no closing delimiter found\n // but the raw matter string will be empty if parsing failed\n if (parsed.matter === '' && !normalizedContent.includes('---\\n---')) {\n // Check if there's actually a closing delimiter\n const lines = normalizedContent.split('\\n');\n let hasClosing = false;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i]?.trim() === '---') {\n hasClosing = true;\n break;\n }\n }\n if (!hasClosing) {\n throw new Error('Invalid format: missing front matter closing delimiter');\n }\n }\n\n const frontmatter = parsed.data as Record<string, unknown>;\n\n // Parse body - split into description and notes\n const body = parsed.content.trim();\n\n // Find notes section\n const notesMatch = /\\n## Notes\\n/i.exec(body);\n let description = body;\n let notes = '';\n\n if (notesMatch?.index !== undefined) {\n description = body.slice(0, notesMatch.index).trim();\n notes = body.slice(notesMatch.index + notesMatch[0].length).trim();\n }\n\n return { frontmatter, description, notes };\n}\n\n/**\n * Parse an issue from Markdown file content.\n */\nexport function parseIssue(content: string): Issue {\n const { frontmatter, description, notes } = parseMarkdownWithFrontmatter(content);\n\n // Merge body content into frontmatter\n const data = {\n ...frontmatter,\n description: description || undefined,\n notes: notes || undefined,\n };\n\n // Validate and parse with Zod\n return IssueSchema.parse(data);\n}\n\n/**\n * Serialize an issue to Markdown file content.\n * Uses canonical serialization for deterministic output.\n */\nexport function serializeIssue(issue: Issue): string {\n // Extract body fields\n const { description, notes, ...metadata } = issue;\n\n // Sort keys using canonical field order (not alphabetical)\n const sortedMetadata = sortKeys(metadata, ISSUE_FIELD_ORDER);\n\n // Serialize YAML with compact output for frontmatter.\n // sortMapEntries: false preserves our manual ordering.\n const yaml = stringifyYaml(sortedMetadata, {\n lineWidth: 0,\n nullStr: 'null',\n sortMapEntries: false,\n });\n\n // Build the file content\n // Note: No blank line between closing --- and body content\n const parts = ['---', yaml.trim(), '---'];\n\n if (description) {\n parts.push(description.trim());\n }\n\n if (notes) {\n parts.push('');\n parts.push('## Notes');\n parts.push('');\n parts.push(notes.trim());\n }\n\n // Single newline at end\n return parts.join('\\n') + '\\n';\n}\n","/**\n * tbd: Git-native issue tracking for AI agents and humans\n *\n * This is the library entry point. All exports here should be node-free\n * to support browser/edge runtime usage. CLI-specific code is in ./cli/.\n */\n\n// Version injected at build time\ndeclare const __TBD_VERSION__: string;\n\n/**\n * Package version, derived from git at build time.\n * Format: X.Y.Z for releases, X.Y.Z-dev.N.hash for dev builds.\n */\nexport const VERSION: string =\n typeof __TBD_VERSION__ !== 'undefined' ? __TBD_VERSION__ : 'development';\n\n// Re-export schemas for library consumers\nexport * from './lib/schemas.js';\nexport * from './lib/types.js';\n\n// Re-export core operations (these should be node-free)\nexport { parseIssue, serializeIssue } from './file/parser.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"src-D2xEmH4L.mjs","names":["parseYaml"],"sources":["../src/lib/types.ts","../src/utils/markdown-utils.ts","../src/file/parser.ts","../src/index.ts"],"sourcesContent":["/**\n * TypeScript types derived from Zod schemas.\n *\n * These types are the canonical TypeScript interface for tbd entities.\n */\n\nimport type { z } from 'zod';\n\nimport type {\n IssueSchema,\n IssueStatus,\n IssueKind,\n Priority,\n Dependency,\n ConfigSchema,\n MetaSchema,\n LocalStateSchema,\n AtticEntrySchema,\n} from './schemas.js';\n\n// =============================================================================\n// Entity Types\n// =============================================================================\n\n/**\n * A tbd issue entity.\n */\nexport type Issue = z.infer<typeof IssueSchema>;\n\n/**\n * Issue status enum values.\n */\nexport type IssueStatusType = z.infer<typeof IssueStatus>;\n\n/**\n * Issue kind enum values.\n */\nexport type IssueKindType = z.infer<typeof IssueKind>;\n\n/**\n * Priority level (0-4).\n */\nexport type PriorityType = z.infer<typeof Priority>;\n\n/**\n * A dependency relationship.\n */\nexport type DependencyType = z.infer<typeof Dependency>;\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\n/**\n * Project configuration.\n */\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/**\n * Shared metadata.\n */\nexport type Meta = z.infer<typeof MetaSchema>;\n\n/**\n * Per-node local state.\n */\nexport type LocalState = z.infer<typeof LocalStateSchema>;\n\n/**\n * Attic entry for conflict losers.\n */\nexport type AtticEntry = z.infer<typeof AtticEntrySchema>;\n\n// =============================================================================\n// Input Types for Commands\n// =============================================================================\n\n/**\n * Options for creating an issue.\n */\nexport interface CreateIssueOptions {\n title: string;\n description?: string;\n kind?: IssueKindType;\n priority?: PriorityType;\n assignee?: string;\n labels?: string[];\n parent_id?: string;\n due_date?: string;\n deferred_until?: string;\n}\n\n/**\n * Options for updating an issue.\n */\nexport interface UpdateIssueOptions {\n title?: string;\n description?: string;\n notes?: string;\n kind?: IssueKindType;\n status?: IssueStatusType;\n priority?: PriorityType;\n assignee?: string | null;\n addLabels?: string[];\n removeLabels?: string[];\n parent_id?: string | null;\n due_date?: string | null;\n deferred_until?: string | null;\n}\n\n/**\n * Options for listing issues.\n */\nexport interface ListIssuesOptions {\n status?: IssueStatusType | IssueStatusType[];\n kind?: IssueKindType | IssueKindType[];\n priority?: PriorityType;\n assignee?: string;\n labels?: string[];\n parent?: string;\n all?: boolean;\n sort?: 'priority' | 'created' | 'updated';\n limit?: number;\n}\n\n/**\n * Options for searching issues.\n */\nexport interface SearchIssuesOptions {\n query: string;\n status?: IssueStatusType | IssueStatusType[];\n limit?: number;\n}\n\n// =============================================================================\n// CLI Utility Types\n// =============================================================================\n\n/**\n * A documentation section with title and slug.\n * Used by docs and design commands.\n */\nexport interface DocSection {\n title: string;\n slug: string;\n}\n\n/**\n * Logger interface for long-running operations in non-CLI layers.\n *\n * Allows core logic (file/, lib/) to report progress without depending on\n * the CLI output layer. CLI commands create an OperationLogger via\n * `OutputManager.logger(spinner)` and pass it to core functions.\n *\n * All methods are required. Use `noopLogger` when no logging is needed.\n */\nexport interface OperationLogger {\n /** Key milestones — drives the spinner in CLI context */\n progress: (message: string) => void;\n /** Operational detail (shown with --verbose or --debug) */\n info: (message: string) => void;\n /** Non-fatal warnings */\n warn: (message: string) => void;\n /** Internal state for troubleshooting (shown with --debug only) */\n debug: (message: string) => void;\n}\n\n/**\n * No-op logger for when no logging is needed.\n * Analogous to noopSpinner in the CLI layer.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst noop = () => {};\nexport const noopLogger: OperationLogger = {\n progress: noop,\n info: noop,\n warn: noop,\n debug: noop,\n};\n","/**\n * Markdown utilities for processing markdown content.\n *\n * Uses gray-matter for parsing and centralized yaml-utils for stringify to ensure\n * proper handling of special YAML characters (colons, quotes, etc.).\n */\n\nimport matter from 'gray-matter';\n\nimport { stringifyYamlCompact } from './yaml-utils.js';\n\nexport interface ParsedMarkdown {\n /** Raw frontmatter string (without --- delimiters), or null if no frontmatter */\n frontmatter: string | null;\n /** Body content after frontmatter, with leading newlines trimmed */\n body: string;\n}\n\n/**\n * Normalize line endings to LF.\n */\nexport function normalizeLineEndings(content: string): string {\n return content.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n}\n\n/**\n * Parse markdown content into frontmatter and body.\n * Handles both LF and CRLF line endings.\n *\n * @returns Object with frontmatter (null if none) and body\n */\nexport function parseMarkdown(content: string): ParsedMarkdown {\n const normalized = normalizeLineEndings(content);\n\n if (!matter.test(normalized)) {\n return { frontmatter: null, body: content };\n }\n\n try {\n const parsed = matter(normalized);\n\n // Extract frontmatter from parsed.data by stringifying back to YAML\n // The matter property is unreliable, so we reconstruct from data\n const data = parsed.data;\n let frontmatter: string | null = null;\n\n if (data && Object.keys(data).length > 0) {\n // Use centralized yaml-utils for proper handling of special characters\n // (colons, quotes, multiline strings, etc.)\n frontmatter = stringifyYamlCompact(data).trimEnd();\n } else {\n // Empty frontmatter (just --- followed by ---)\n frontmatter = '';\n }\n\n // Body with leading newlines trimmed\n const body = parsed.content.replace(/^\\n+/, '');\n\n return { frontmatter, body };\n } catch {\n // Invalid/unclosed frontmatter - treat as no frontmatter\n return { frontmatter: null, body: content };\n }\n}\n\n/**\n * Parse YAML frontmatter from markdown content.\n * Returns the frontmatter content (without delimiters) or null if no valid frontmatter.\n * Handles both LF and CRLF line endings.\n */\nexport function parseFrontmatter(content: string): string | null {\n return parseMarkdown(content).frontmatter;\n}\n\n/**\n * Strip YAML frontmatter from markdown content.\n * Returns the body content without frontmatter, with leading newlines trimmed.\n * Handles both LF and CRLF line endings.\n */\nexport function stripFrontmatter(content: string): string {\n return parseMarkdown(content).body;\n}\n\n/**\n * Insert content after YAML frontmatter.\n * If no frontmatter exists, prepends the content.\n * Content is inserted directly after ---. Include leading newlines in toInsert if needed.\n */\nexport function insertAfterFrontmatter(content: string, toInsert: string): string {\n const { frontmatter, body } = parseMarkdown(content);\n\n if (frontmatter === null) {\n return toInsert + content;\n }\n\n const frontmatterBlock = frontmatter ? `---\\n${frontmatter}\\n---` : '---\\n---';\n return `${frontmatterBlock}\\n${toInsert}\\n\\n${body}`;\n}\n","/**\n * YAML front matter parser and serializer for issue files.\n *\n * Issues are stored as Markdown files with YAML front matter:\n * ---\n * type: is\n * id: is-a1b2c3\n * ...\n * ---\n *\n * Description body here.\n *\n * ## Notes\n *\n * Working notes here.\n *\n * See: tbd-design.md §2.1 Markdown + YAML Front Matter Format\n */\n\nimport matter from 'gray-matter';\nimport { parse as parseYaml } from 'yaml';\n\nimport { normalizeLineEndings } from '../utils/markdown-utils.js';\nimport { sortKeys, stringifyYaml } from '../utils/yaml-utils.js';\nimport type { Issue } from '../lib/types.js';\nimport { IssueSchema, ISSUE_FIELD_ORDER } from '../lib/schemas.js';\n\n/**\n * gray-matter options using the 'yaml' package as engine.\n * This preserves date strings instead of converting them to Date objects.\n */\nexport const matterOptions = {\n engines: {\n yaml: {\n parse: (str: string): object => parseYaml(str) as object,\n stringify: (obj: object): string => stringifyYaml(obj),\n },\n },\n};\n\n/**\n * Parsed issue file content.\n */\nexport interface ParsedIssueFile {\n frontmatter: Record<string, unknown>;\n description: string;\n notes: string;\n}\n\n/**\n * Parse a Markdown file with YAML front matter.\n * Uses gray-matter for consistent frontmatter parsing.\n * Handles both LF and CRLF line endings.\n */\nexport function parseMarkdownWithFrontmatter(content: string): ParsedIssueFile {\n // Normalize CRLF to LF before parsing\n const normalizedContent = normalizeLineEndings(content);\n\n // Check for valid frontmatter\n if (!matter.test(normalizedContent)) {\n throw new Error('Invalid format: missing front matter opening delimiter');\n }\n\n const parsed = matter(normalizedContent, matterOptions);\n\n // gray-matter returns empty object if no closing delimiter found\n // but the raw matter string will be empty if parsing failed\n if (parsed.matter === '' && !normalizedContent.includes('---\\n---')) {\n // Check if there's actually a closing delimiter\n const lines = normalizedContent.split('\\n');\n let hasClosing = false;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i]?.trim() === '---') {\n hasClosing = true;\n break;\n }\n }\n if (!hasClosing) {\n throw new Error('Invalid format: missing front matter closing delimiter');\n }\n }\n\n const frontmatter = parsed.data as Record<string, unknown>;\n\n // Parse body - split into description and notes\n const body = parsed.content.trim();\n\n // Find notes section\n const notesMatch = /\\n## Notes\\n/i.exec(body);\n let description = body;\n let notes = '';\n\n if (notesMatch?.index !== undefined) {\n description = body.slice(0, notesMatch.index).trim();\n notes = body.slice(notesMatch.index + notesMatch[0].length).trim();\n }\n\n return { frontmatter, description, notes };\n}\n\n/**\n * Parse an issue from Markdown file content.\n */\nexport function parseIssue(content: string): Issue {\n const { frontmatter, description, notes } = parseMarkdownWithFrontmatter(content);\n\n // Merge body content into frontmatter\n const data = {\n ...frontmatter,\n description: description || undefined,\n notes: notes || undefined,\n };\n\n // Validate and parse with Zod\n return IssueSchema.parse(data);\n}\n\n/**\n * Serialize an issue to Markdown file content.\n * Uses canonical serialization for deterministic output.\n */\nexport function serializeIssue(issue: Issue): string {\n // Extract body fields\n const { description, notes, ...metadata } = issue;\n\n // Sort keys using canonical field order (not alphabetical)\n const sortedMetadata = sortKeys(metadata, ISSUE_FIELD_ORDER);\n\n // Serialize YAML with compact output for frontmatter.\n // sortMapEntries: false preserves our manual ordering.\n const yaml = stringifyYaml(sortedMetadata, {\n lineWidth: 0,\n nullStr: 'null',\n sortMapEntries: false,\n });\n\n // Build the file content\n // Note: No blank line between closing --- and body content\n const parts = ['---', yaml.trim(), '---'];\n\n if (description) {\n parts.push(description.trim());\n }\n\n if (notes) {\n parts.push('');\n parts.push('## Notes');\n parts.push('');\n parts.push(notes.trim());\n }\n\n // Single newline at end\n return parts.join('\\n') + '\\n';\n}\n","/**\n * tbd: Git-native issue tracking for AI agents and humans\n *\n * This is the library entry point. All exports here should be node-free\n * to support browser/edge runtime usage. CLI-specific code is in ./cli/.\n */\n\n// Version injected at build time\ndeclare const __TBD_VERSION__: string;\n\n/**\n * Package version, derived from git at build time.\n * Format: X.Y.Z for releases, X.Y.Z-dev.N.hash for dev builds.\n */\nexport const VERSION: string =\n typeof __TBD_VERSION__ !== 'undefined' ? __TBD_VERSION__ : 'development';\n\n// Re-export schemas for library consumers\nexport * from './lib/schemas.js';\nexport * from './lib/types.js';\n\n// Re-export core operations (these should be node-free)\nexport { parseIssue, serializeIssue } from './file/parser.js';\n"],"mappings":"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"}
|