get-tbd 0.1.18 → 0.1.20
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 -100
- package/dist/bin.mjs.map +1 -1
- package/dist/cli.mjs +137 -103
- package/dist/cli.mjs.map +1 -1
- package/dist/docs/SKILL.md +3 -0
- package/dist/docs/guidelines/cli-agent-skill-patterns.md +591 -67
- package/dist/docs/guidelines/tbd-sync-troubleshooting.md +17 -0
- package/dist/docs/guidelines/writing-style-guidelines.md +42 -0
- package/dist/docs/shortcuts/standard/new-qa-playbook.md +59 -0
- package/dist/docs/shortcuts/standard/plan-implementation-with-beads.md +2 -1
- package/dist/docs/shortcuts/standard/sync-failure-recovery.md +3 -0
- package/dist/docs/shortcuts/system/skill-baseline.md +3 -0
- package/dist/docs/tbd-design.md +95 -34
- package/dist/docs/tbd-docs.md +14 -4
- package/dist/docs/tbd-prime.md +1 -0
- package/dist/docs/templates/qa-playbook.md +189 -0
- package/dist/{id-mapping-BuOwpq9Q.mjs → id-mapping-D6mJ1bjS.mjs} +2 -2
- package/dist/{id-mapping-BuOwpq9Q.mjs.map → id-mapping-D6mJ1bjS.mjs.map} +1 -1
- package/dist/{id-mapping-DVaCzV-d.mjs → id-mapping-tbhnzNON.mjs} +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{src-D7HkI38H.mjs → src-BiKxOaNe.mjs} +3 -3
- package/dist/{src-D7HkI38H.mjs.map → src-BiKxOaNe.mjs.map} +1 -1
- package/dist/tbd +140 -100
- package/dist/{yaml-utils-DBInVbLU.mjs → yaml-utils-pmgpOtBk.mjs} +8 -2
- package/dist/{yaml-utils-DBInVbLU.mjs.map → yaml-utils-pmgpOtBk.mjs.map} +1 -1
- package/package.json +1 -1
package/dist/bin.mjs
CHANGED
|
@@ -13576,6 +13576,12 @@ const YAML_STRINGIFY_OPTIONS_COMPACT = {
|
|
|
13576
13576
|
* ~50 lines is slightly more than one terminal screen.
|
|
13577
13577
|
*/
|
|
13578
13578
|
const PAGINATION_LINE_THRESHOLD = 50;
|
|
13579
|
+
/**
|
|
13580
|
+
* Maximum lines to display when showing parent bead context in `tbd show`.
|
|
13581
|
+
* The parent's full serialized output is truncated to this many lines,
|
|
13582
|
+
* with an ellipsis and omitted-line count appended if exceeded.
|
|
13583
|
+
*/
|
|
13584
|
+
const PARENT_CONTEXT_MAX_LINES = 50;
|
|
13579
13585
|
|
|
13580
13586
|
//#endregion
|
|
13581
13587
|
//#region src/utils/yaml-utils.ts
|
|
@@ -13878,7 +13884,7 @@ function serializeIssue(issue) {
|
|
|
13878
13884
|
* Package version, derived from git at build time.
|
|
13879
13885
|
* Format: X.Y.Z for releases, X.Y.Z-dev.N.hash for dev builds.
|
|
13880
13886
|
*/
|
|
13881
|
-
const VERSION$1 = "0.1.
|
|
13887
|
+
const VERSION$1 = "0.1.20";
|
|
13882
13888
|
|
|
13883
13889
|
//#endregion
|
|
13884
13890
|
//#region src/cli/lib/version.ts
|
|
@@ -97286,17 +97292,15 @@ async function writeFileAsync(filePath, data, options = DEFAULT_WRITE_OPTIONS) {
|
|
|
97286
97292
|
*
|
|
97287
97293
|
* On main/dev branches:
|
|
97288
97294
|
* .tbd/
|
|
97289
|
-
*
|
|
97290
|
-
*
|
|
97291
|
-
*
|
|
97292
|
-
*
|
|
97293
|
-
*
|
|
97294
|
-
* .
|
|
97295
|
-
*
|
|
97296
|
-
*
|
|
97297
|
-
*
|
|
97298
|
-
* attic/
|
|
97299
|
-
* meta.yml
|
|
97295
|
+
* Committed to the repo:
|
|
97296
|
+
* config.yml - Project configuration
|
|
97297
|
+
* .gitignore - Controls what's gitignored below
|
|
97298
|
+
* workspaces/ - Persistent state (outbox, named workspaces)
|
|
97299
|
+
* Gitignored (local only):
|
|
97300
|
+
* state.yml - Local state
|
|
97301
|
+
* docs/ - Installed documentation (regenerated on setup)
|
|
97302
|
+
* data-sync-worktree/ - Hidden worktree checkout of tbd-sync branch
|
|
97303
|
+
* .tbd/data-sync/ - issues/, mappings/, attic/, meta.yml
|
|
97300
97304
|
*
|
|
97301
97305
|
* On tbd-sync branch:
|
|
97302
97306
|
* .tbd/
|
|
@@ -97444,14 +97448,14 @@ let _resolvedAllowFallback = null;
|
|
|
97444
97448
|
* 1. Worktree path if worktree exists: .tbd/data-sync-worktree/.tbd/data-sync/
|
|
97445
97449
|
* 2. Direct path as fallback (only if allowFallback: true)
|
|
97446
97450
|
*
|
|
97447
|
-
* @param baseDir - The
|
|
97451
|
+
* @param baseDir - The tbd root directory (from requireInit or findTbdRoot)
|
|
97448
97452
|
* @param options - Options for path resolution
|
|
97449
97453
|
* @returns Resolved data sync directory path
|
|
97450
97454
|
* @throws WorktreeMissingError if worktree missing and allowFallback is false
|
|
97451
97455
|
*
|
|
97452
97456
|
* See: plan-2026-01-28-sync-worktree-recovery-and-hardening.md
|
|
97453
97457
|
*/
|
|
97454
|
-
async function resolveDataSyncDir(baseDir
|
|
97458
|
+
async function resolveDataSyncDir(baseDir, options) {
|
|
97455
97459
|
const allowFallback = options?.allowFallback ?? true;
|
|
97456
97460
|
if (_resolvedDataSyncDir && _resolvedBaseDir === baseDir && _resolvedAllowFallback === allowFallback) return _resolvedDataSyncDir;
|
|
97457
97461
|
const worktreePath = join(baseDir, DATA_SYNC_DIR_VIA_WORKTREE);
|
|
@@ -97474,7 +97478,7 @@ async function resolveDataSyncDir(baseDir = process.cwd(), options) {
|
|
|
97474
97478
|
/**
|
|
97475
97479
|
* Resolve attic directory path.
|
|
97476
97480
|
*/
|
|
97477
|
-
async function resolveAtticDir(baseDir
|
|
97481
|
+
async function resolveAtticDir(baseDir, options) {
|
|
97478
97482
|
return join(await resolveDataSyncDir(baseDir, options), "attic");
|
|
97479
97483
|
}
|
|
97480
97484
|
/**
|
|
@@ -97807,13 +97811,17 @@ async function writeConfig(baseDir, config) {
|
|
|
97807
97811
|
await writeFile(configPath, content);
|
|
97808
97812
|
}
|
|
97809
97813
|
/**
|
|
97810
|
-
* Check if tbd is initialized in the given directory
|
|
97811
|
-
* Returns true if .tbd/
|
|
97814
|
+
* Check if tbd is properly initialized in the given directory.
|
|
97815
|
+
* Returns true only if .tbd/config.yml exists (not just a .tbd/ directory).
|
|
97816
|
+
*
|
|
97817
|
+
* This prevents spurious .tbd/ directories (e.g., containing only state.yml
|
|
97818
|
+
* created by a bug) from being mistaken for tbd roots. A valid tbd root
|
|
97819
|
+
* always has config.yml created during `tbd init`.
|
|
97812
97820
|
*/
|
|
97813
97821
|
async function hasTbdDir(dir) {
|
|
97814
|
-
const
|
|
97822
|
+
const configPath = join(dir, CONFIG_FILE);
|
|
97815
97823
|
try {
|
|
97816
|
-
await access(
|
|
97824
|
+
await access(configPath);
|
|
97817
97825
|
return true;
|
|
97818
97826
|
} catch {
|
|
97819
97827
|
return false;
|
|
@@ -97858,11 +97866,20 @@ async function readLocalState(baseDir) {
|
|
|
97858
97866
|
}
|
|
97859
97867
|
/**
|
|
97860
97868
|
* Write local state to .tbd/state.yml
|
|
97869
|
+
*
|
|
97870
|
+
* Uses `atomically` for safe writes (atomic rename, auto parent-dir creation).
|
|
97871
|
+
* However, we intentionally guard against .tbd/ not existing: `atomically`
|
|
97872
|
+
* would auto-create it, which is wrong if baseDir is a subdirectory rather
|
|
97873
|
+
* than the true tbd root. Only `tbd init` (via initConfig) should create .tbd/.
|
|
97861
97874
|
*/
|
|
97862
97875
|
async function writeLocalState(baseDir, state) {
|
|
97863
|
-
const
|
|
97864
|
-
|
|
97865
|
-
|
|
97876
|
+
const tbdDir = join(baseDir, ".tbd");
|
|
97877
|
+
try {
|
|
97878
|
+
await access(tbdDir);
|
|
97879
|
+
} catch {
|
|
97880
|
+
throw new Error(`Cannot write state: .tbd/ directory does not exist at ${baseDir}. Run 'tbd init' first or ensure the correct tbd root is being used.`);
|
|
97881
|
+
}
|
|
97882
|
+
await writeFile(join(baseDir, STATE_FILE), stringifyYaml(state, { lineWidth: 0 }));
|
|
97866
97883
|
}
|
|
97867
97884
|
/**
|
|
97868
97885
|
* Update specific fields in local state (merge with existing).
|
|
@@ -99137,7 +99154,10 @@ Example:
|
|
|
99137
99154
|
"",
|
|
99138
99155
|
"# Temporary files",
|
|
99139
99156
|
"*.tmp",
|
|
99140
|
-
"*.temp"
|
|
99157
|
+
"*.temp",
|
|
99158
|
+
"",
|
|
99159
|
+
"# workspaces/ stores state (including outbox) committed to the working branch",
|
|
99160
|
+
"!workspaces/"
|
|
99141
99161
|
]);
|
|
99142
99162
|
this.output.debug(`Created ${TBD_DIR}/.gitignore`);
|
|
99143
99163
|
await mkdir(join(cwd, TBD_SHORTCUTS_SYSTEM), { recursive: true });
|
|
@@ -100789,6 +100809,45 @@ const listCommand = new Command("list").description("List issues").option("--sta
|
|
|
100789
100809
|
*
|
|
100790
100810
|
* See: tbd-design.md §4.4 Show
|
|
100791
100811
|
*/
|
|
100812
|
+
/**
|
|
100813
|
+
* Render a serialized issue with colorized output, optionally truncated.
|
|
100814
|
+
*
|
|
100815
|
+
* @param issue - The issue to render
|
|
100816
|
+
* @param colors - Color functions
|
|
100817
|
+
* @param maxLines - If set, truncate output to this many lines with an omission notice
|
|
100818
|
+
* @returns Array of formatted lines
|
|
100819
|
+
*/
|
|
100820
|
+
function renderIssueLines(issue, colors) {
|
|
100821
|
+
const serialized = serializeIssue(issue);
|
|
100822
|
+
const output = [];
|
|
100823
|
+
for (const line of serialized.split("\n")) if (line === "---") output.push(colors.dim(line));
|
|
100824
|
+
else if (line.startsWith("id:")) output.push(`${colors.dim("id:")} ${colors.id(line.slice(4))}`);
|
|
100825
|
+
else if (line.startsWith("status:")) {
|
|
100826
|
+
const status = line.slice(8).trim();
|
|
100827
|
+
const statusColor = getStatusColor(status, colors);
|
|
100828
|
+
output.push(`${colors.dim("status:")} ${statusColor(status)}`);
|
|
100829
|
+
} else if (line.startsWith("priority:")) {
|
|
100830
|
+
const priority = parseInt(line.slice(10).trim(), 10);
|
|
100831
|
+
const priorityColor = getPriorityColor(priority, colors);
|
|
100832
|
+
output.push(`${colors.dim("priority:")} ${priorityColor(formatPriority(priority))}`);
|
|
100833
|
+
} else if (line.startsWith("title:")) output.push(`${colors.dim("title:")} ${colors.bold(line.slice(7))}`);
|
|
100834
|
+
else if (line.startsWith("spec_path:")) output.push(`${colors.dim("spec_path:")} ${colors.id(line.slice(11))}`);
|
|
100835
|
+
else if (line.startsWith("## Notes")) output.push(colors.bold(line));
|
|
100836
|
+
else if (line.startsWith(" - ")) output.push(` - ${colors.label(line.slice(4))}`);
|
|
100837
|
+
else output.push(line);
|
|
100838
|
+
return output;
|
|
100839
|
+
}
|
|
100840
|
+
/**
|
|
100841
|
+
* Print lines with optional max-lines truncation.
|
|
100842
|
+
* If maxLines is set and the output exceeds it, truncates and appends an omission notice.
|
|
100843
|
+
*/
|
|
100844
|
+
function printWithTruncation(lines, colors, maxLines) {
|
|
100845
|
+
if (maxLines && lines.length > maxLines) {
|
|
100846
|
+
const omitted = lines.length - maxLines;
|
|
100847
|
+
for (const line of lines.slice(0, maxLines)) console.log(line);
|
|
100848
|
+
console.log(colors.dim(`… [${omitted} line${omitted === 1 ? "" : "s"} omitted]`));
|
|
100849
|
+
} else for (const line of lines) console.log(line);
|
|
100850
|
+
}
|
|
100792
100851
|
var ShowHandler = class extends BaseCommand {
|
|
100793
100852
|
async run(id, command, options) {
|
|
100794
100853
|
const ctx = await loadFullContext(command);
|
|
@@ -100799,29 +100858,28 @@ var ShowHandler = class extends BaseCommand {
|
|
|
100799
100858
|
} catch {
|
|
100800
100859
|
throw new NotFoundError("Issue", id);
|
|
100801
100860
|
}
|
|
100861
|
+
let parentIssue;
|
|
100862
|
+
if (issue.parent_id && options.parent !== false) try {
|
|
100863
|
+
parentIssue = await readIssue(ctx.dataSyncDir, issue.parent_id);
|
|
100864
|
+
} catch {}
|
|
100865
|
+
const maxLines = options.maxLines ? parseInt(options.maxLines, 10) : void 0;
|
|
100802
100866
|
const displayId = ctx.displayId(issue.id);
|
|
100803
100867
|
const displayIssue = {
|
|
100804
100868
|
...issue,
|
|
100805
|
-
displayId
|
|
100869
|
+
displayId,
|
|
100870
|
+
...parentIssue ? { parent: {
|
|
100871
|
+
...parentIssue,
|
|
100872
|
+
displayId: ctx.displayId(parentIssue.id)
|
|
100873
|
+
} } : {}
|
|
100806
100874
|
};
|
|
100807
100875
|
this.output.data(displayIssue, () => {
|
|
100808
100876
|
const colors = this.output.getColors();
|
|
100809
|
-
|
|
100810
|
-
|
|
100811
|
-
|
|
100812
|
-
|
|
100813
|
-
|
|
100814
|
-
|
|
100815
|
-
console.log(`${colors.dim("status:")} ${statusColor(status)}`);
|
|
100816
|
-
} else if (line.startsWith("priority:")) {
|
|
100817
|
-
const priority = parseInt(line.slice(10).trim(), 10);
|
|
100818
|
-
const priorityColor = getPriorityColor(priority, colors);
|
|
100819
|
-
console.log(`${colors.dim("priority:")} ${priorityColor(formatPriority(priority))}`);
|
|
100820
|
-
} else if (line.startsWith("title:")) console.log(`${colors.dim("title:")} ${colors.bold(line.slice(7))}`);
|
|
100821
|
-
else if (line.startsWith("spec_path:")) console.log(`${colors.dim("spec_path:")} ${colors.id(line.slice(11))}`);
|
|
100822
|
-
else if (line.startsWith("## Notes")) console.log(colors.bold(line));
|
|
100823
|
-
else if (line.startsWith(" - ")) console.log(` - ${colors.label(line.slice(4))}`);
|
|
100824
|
-
else console.log(line);
|
|
100877
|
+
printWithTruncation(renderIssueLines(issue, colors), colors, maxLines);
|
|
100878
|
+
if (parentIssue) {
|
|
100879
|
+
console.log("");
|
|
100880
|
+
console.log(colors.dim("The parent of this bead is:"));
|
|
100881
|
+
printWithTruncation(renderIssueLines(parentIssue, colors), colors, PARENT_CONTEXT_MAX_LINES);
|
|
100882
|
+
}
|
|
100825
100883
|
if (options.showOrder) {
|
|
100826
100884
|
console.log("");
|
|
100827
100885
|
console.log(colors.dim("child_order_hints:"));
|
|
@@ -100834,7 +100892,7 @@ var ShowHandler = class extends BaseCommand {
|
|
|
100834
100892
|
});
|
|
100835
100893
|
}
|
|
100836
100894
|
};
|
|
100837
|
-
const showCommand = new Command("show").description("Show issue details").argument("<id>", "Issue ID").option("--show-order", "Display children ordering hints").action(async (id, options, command) => {
|
|
100895
|
+
const showCommand = new Command("show").description("Show issue details").argument("<id>", "Issue ID").option("--show-order", "Display children ordering hints").option("--no-parent", "Suppress automatic parent context display").option("--max-lines <n>", "Truncate output to N lines").action(async (id, options, command) => {
|
|
100838
100896
|
await new ShowHandler(command).run(id, command, options);
|
|
100839
100897
|
});
|
|
100840
100898
|
|
|
@@ -103165,6 +103223,8 @@ var SyncHandler = class extends BaseCommand {
|
|
|
103165
103223
|
console.log(" 1. Commit: git add .tbd/workspaces && git commit -m 'tbd: save outbox'");
|
|
103166
103224
|
console.log(" 2. Push your working branch: git push");
|
|
103167
103225
|
console.log(" 3. Run 'tbd sync' when push access is available");
|
|
103226
|
+
console.log("");
|
|
103227
|
+
console.log(" WARNING: Do NOT add .tbd/workspaces/ to .gitignore -- that would cause data loss.");
|
|
103168
103228
|
} else {
|
|
103169
103229
|
const totalInOutbox = existingOutboxCount + result.saved;
|
|
103170
103230
|
if (existingOutboxCount > 0) {
|
|
@@ -103180,6 +103240,8 @@ var SyncHandler = class extends BaseCommand {
|
|
|
103180
103240
|
console.log(" 2. Push your working branch: git push");
|
|
103181
103241
|
console.log(" 3. Run 'tbd sync' when push access is available");
|
|
103182
103242
|
console.log(" (outbox will be imported automatically on successful sync)");
|
|
103243
|
+
console.log("");
|
|
103244
|
+
console.log(" WARNING: Do NOT add .tbd/workspaces/ to .gitignore -- that would cause data loss.");
|
|
103183
103245
|
}
|
|
103184
103246
|
} catch (saveError) {
|
|
103185
103247
|
const saveErrorMsg = saveError instanceof Error ? saveError.message : String(saveError);
|
|
@@ -103295,44 +103357,17 @@ function formatTimestampAgo(timestamp) {
|
|
|
103295
103357
|
* See: tbd-design.md §4.8 Search Commands
|
|
103296
103358
|
*/
|
|
103297
103359
|
const STALE_THRESHOLD_MS = 300 * 1e3;
|
|
103298
|
-
/**
|
|
103299
|
-
* Read local state file.
|
|
103300
|
-
*/
|
|
103301
|
-
async function readState() {
|
|
103302
|
-
try {
|
|
103303
|
-
return (0, import_dist$2.parse)(await readFile(STATE_FILE, "utf-8"));
|
|
103304
|
-
} catch {
|
|
103305
|
-
return {};
|
|
103306
|
-
}
|
|
103307
|
-
}
|
|
103308
|
-
/**
|
|
103309
|
-
* Update local state file.
|
|
103310
|
-
*/
|
|
103311
|
-
async function updateState(updates) {
|
|
103312
|
-
await writeFile(STATE_FILE, stringifyYaml({
|
|
103313
|
-
...await readState(),
|
|
103314
|
-
...updates
|
|
103315
|
-
}));
|
|
103316
|
-
}
|
|
103317
|
-
/**
|
|
103318
|
-
* Check if worktree is stale and needs refresh.
|
|
103319
|
-
*/
|
|
103320
|
-
async function isWorktreeStale() {
|
|
103321
|
-
const state = await readState();
|
|
103322
|
-
if (!state.last_sync_at) return true;
|
|
103323
|
-
const lastSync = new Date(state.last_sync_at).getTime();
|
|
103324
|
-
return Date.now() - lastSync > STALE_THRESHOLD_MS;
|
|
103325
|
-
}
|
|
103326
103360
|
var SearchHandler = class extends BaseCommand {
|
|
103327
103361
|
async run(query, options) {
|
|
103328
103362
|
const tbdRoot = await requireInit();
|
|
103329
103363
|
if (!options.noRefresh) {
|
|
103330
|
-
const state = await
|
|
103331
|
-
|
|
103364
|
+
const state = await readLocalState(tbdRoot);
|
|
103365
|
+
const lastSync = state.last_sync_at ? new Date(state.last_sync_at).getTime() : 0;
|
|
103366
|
+
if (Date.now() - lastSync > STALE_THRESHOLD_MS) {
|
|
103332
103367
|
const lastSyncAgo = formatTimestampAgo(state.last_sync_at);
|
|
103333
103368
|
const staleInfo = lastSyncAgo ? ` (last synced ${lastSyncAgo})` : "";
|
|
103334
103369
|
this.output.info(`Refreshing worktree${staleInfo}...`);
|
|
103335
|
-
await
|
|
103370
|
+
await updateLocalState(tbdRoot, { last_sync_at: now() });
|
|
103336
103371
|
}
|
|
103337
103372
|
}
|
|
103338
103373
|
let issues;
|
|
@@ -103961,10 +103996,10 @@ const PRIORITY_LABELS = [
|
|
|
103961
103996
|
];
|
|
103962
103997
|
var StatsHandler = class extends BaseCommand {
|
|
103963
103998
|
async run() {
|
|
103964
|
-
await requireInit();
|
|
103999
|
+
const tbdRoot = await requireInit();
|
|
103965
104000
|
let issues;
|
|
103966
104001
|
try {
|
|
103967
|
-
issues = await listIssues(await resolveDataSyncDir());
|
|
104002
|
+
issues = await listIssues(await resolveDataSyncDir(tbdRoot));
|
|
103968
104003
|
} catch {
|
|
103969
104004
|
throw new NotInitializedError("No issue store found. Run `tbd init` first.");
|
|
103970
104005
|
}
|
|
@@ -104909,10 +104944,10 @@ const doctorCommand = new Command("doctor").description("Diagnose and repair rep
|
|
|
104909
104944
|
*/
|
|
104910
104945
|
var ConfigShowHandler = class extends BaseCommand {
|
|
104911
104946
|
async run() {
|
|
104912
|
-
await requireInit();
|
|
104947
|
+
const tbdRoot = await requireInit();
|
|
104913
104948
|
let config;
|
|
104914
104949
|
try {
|
|
104915
|
-
config = await readConfig(
|
|
104950
|
+
config = await readConfig(tbdRoot);
|
|
104916
104951
|
} catch {
|
|
104917
104952
|
throw new NotInitializedError("No configuration found. Run `tbd init` first.");
|
|
104918
104953
|
}
|
|
@@ -104931,10 +104966,10 @@ var ConfigShowHandler = class extends BaseCommand {
|
|
|
104931
104966
|
};
|
|
104932
104967
|
var ConfigSetHandler = class extends BaseCommand {
|
|
104933
104968
|
async run(key, value) {
|
|
104934
|
-
await requireInit();
|
|
104969
|
+
const tbdRoot = await requireInit();
|
|
104935
104970
|
let config;
|
|
104936
104971
|
try {
|
|
104937
|
-
config = await readConfig(
|
|
104972
|
+
config = await readConfig(tbdRoot);
|
|
104938
104973
|
} catch {
|
|
104939
104974
|
throw new NotInitializedError("No configuration found. Run `tbd init` first.");
|
|
104940
104975
|
}
|
|
@@ -104950,7 +104985,7 @@ var ConfigSetHandler = class extends BaseCommand {
|
|
|
104950
104985
|
throw new ValidationError(`Invalid key: ${key}`);
|
|
104951
104986
|
}
|
|
104952
104987
|
await this.execute(async () => {
|
|
104953
|
-
await writeConfig(
|
|
104988
|
+
await writeConfig(tbdRoot, config);
|
|
104954
104989
|
}, "Failed to write config");
|
|
104955
104990
|
this.output.success(`Set ${key} = ${value}`);
|
|
104956
104991
|
}
|
|
@@ -104975,10 +105010,10 @@ var ConfigSetHandler = class extends BaseCommand {
|
|
|
104975
105010
|
};
|
|
104976
105011
|
var ConfigGetHandler = class extends BaseCommand {
|
|
104977
105012
|
async run(key) {
|
|
104978
|
-
await requireInit();
|
|
105013
|
+
const tbdRoot = await requireInit();
|
|
104979
105014
|
let config;
|
|
104980
105015
|
try {
|
|
104981
|
-
config = await readConfig(
|
|
105016
|
+
config = await readConfig(tbdRoot);
|
|
104982
105017
|
} catch {
|
|
104983
105018
|
throw new NotInitializedError("No configuration found. Run `tbd init` first.");
|
|
104984
105019
|
}
|
|
@@ -105030,8 +105065,8 @@ function parseAtticFilename(filename) {
|
|
|
105030
105065
|
/**
|
|
105031
105066
|
* List all attic entries.
|
|
105032
105067
|
*/
|
|
105033
|
-
async function listAtticEntries(filterById) {
|
|
105034
|
-
const atticPath = await resolveAtticDir();
|
|
105068
|
+
async function listAtticEntries(tbdRoot, filterById) {
|
|
105069
|
+
const atticPath = await resolveAtticDir(tbdRoot);
|
|
105035
105070
|
let files;
|
|
105036
105071
|
try {
|
|
105037
105072
|
files = await readdir(atticPath);
|
|
@@ -105057,7 +105092,7 @@ async function listAtticEntries(filterById) {
|
|
|
105057
105092
|
var AtticListHandler = class extends BaseCommand {
|
|
105058
105093
|
async run(id) {
|
|
105059
105094
|
const tbdRoot = await requireInit();
|
|
105060
|
-
const entries = await listAtticEntries(id ? normalizeIssueId(id) : void 0);
|
|
105095
|
+
const entries = await listAtticEntries(tbdRoot, id ? normalizeIssueId(id) : void 0);
|
|
105061
105096
|
const mapping = await loadIdMapping(await resolveDataSyncDir(tbdRoot));
|
|
105062
105097
|
const prefix = (await readConfig(tbdRoot)).display.id_prefix;
|
|
105063
105098
|
const showDebug = this.ctx.debug;
|
|
@@ -105084,7 +105119,7 @@ var AtticListHandler = class extends BaseCommand {
|
|
|
105084
105119
|
var AtticShowHandler = class extends BaseCommand {
|
|
105085
105120
|
async run(id, timestamp) {
|
|
105086
105121
|
const tbdRoot = await requireInit();
|
|
105087
|
-
const entry = (await listAtticEntries(normalizeIssueId(id))).find((e) => e.timestamp === timestamp || e.timestamp.replace(/:/g, "-") === timestamp);
|
|
105122
|
+
const entry = (await listAtticEntries(tbdRoot, normalizeIssueId(id))).find((e) => e.timestamp === timestamp || e.timestamp.replace(/:/g, "-") === timestamp);
|
|
105088
105123
|
if (!entry) throw new NotFoundError("Attic entry", `${id} at ${timestamp}`);
|
|
105089
105124
|
const mapping = await loadIdMapping(await resolveDataSyncDir(tbdRoot));
|
|
105090
105125
|
const prefix = (await readConfig(tbdRoot)).display.id_prefix;
|
|
@@ -105114,7 +105149,7 @@ var AtticRestoreHandler = class extends BaseCommand {
|
|
|
105114
105149
|
async run(id, timestamp) {
|
|
105115
105150
|
const tbdRoot = await requireInit();
|
|
105116
105151
|
const normalizedId = normalizeIssueId(id);
|
|
105117
|
-
const entry = (await listAtticEntries(normalizedId)).find((e) => e.timestamp === timestamp || e.timestamp.replace(/:/g, "-") === timestamp);
|
|
105152
|
+
const entry = (await listAtticEntries(tbdRoot, normalizedId)).find((e) => e.timestamp === timestamp || e.timestamp.replace(/:/g, "-") === timestamp);
|
|
105118
105153
|
if (!entry) throw new NotFoundError("Attic entry", `${id} at ${timestamp}`);
|
|
105119
105154
|
if (this.checkDryRun("Would restore from attic", {
|
|
105120
105155
|
id: normalizedId,
|
|
@@ -105991,27 +106026,26 @@ const readmeCommand = new Command("readme").description("Display the README (sam
|
|
|
105991
106026
|
var UninstallHandler = class extends BaseCommand {
|
|
105992
106027
|
async run(options) {
|
|
105993
106028
|
const colors = this.output.getColors();
|
|
105994
|
-
|
|
105995
|
-
|
|
105996
|
-
} catch {
|
|
105997
|
-
throw new NotInitializedError("No .tbd directory found. Nothing to uninstall.");
|
|
105998
|
-
}
|
|
106029
|
+
const tbdRoot = await findTbdRoot(process.cwd());
|
|
106030
|
+
if (!tbdRoot) throw new NotInitializedError("No .tbd directory found. Nothing to uninstall.");
|
|
105999
106031
|
let config;
|
|
106000
106032
|
try {
|
|
106001
|
-
config = await readConfig(
|
|
106033
|
+
config = await readConfig(tbdRoot);
|
|
106002
106034
|
} catch {
|
|
106003
106035
|
config = null;
|
|
106004
106036
|
}
|
|
106005
106037
|
const syncBranch = config?.sync.branch ?? SYNC_BRANCH;
|
|
106006
106038
|
const remote = config?.sync.remote ?? "origin";
|
|
106007
|
-
const
|
|
106039
|
+
const tbdDir = join(tbdRoot, ".tbd");
|
|
106040
|
+
const worktreePath = join(tbdDir, "data-sync-worktree");
|
|
106041
|
+
const displayPath = (p) => relative(process.cwd(), p) || p;
|
|
106008
106042
|
const items = [];
|
|
106009
106043
|
let worktreeExists = false;
|
|
106010
106044
|
try {
|
|
106011
106045
|
await access(worktreePath);
|
|
106012
106046
|
worktreeExists = true;
|
|
106013
106047
|
const worktreeStats = await this.getDirectoryStats(worktreePath);
|
|
106014
|
-
items.push(` - Worktree: ${worktreePath} (${worktreeStats.files} files)`);
|
|
106048
|
+
items.push(` - Worktree: ${displayPath(worktreePath)} (${worktreeStats.files} files)`);
|
|
106015
106049
|
} catch {}
|
|
106016
106050
|
let localBranchExists = false;
|
|
106017
106051
|
try {
|
|
@@ -106039,8 +106073,8 @@ var UninstallHandler = class extends BaseCommand {
|
|
|
106039
106073
|
remoteBranchExists = true;
|
|
106040
106074
|
items.push(` - Remote branch: ${remote}/${syncBranch}`);
|
|
106041
106075
|
} catch {}
|
|
106042
|
-
const tbdStats = await this.getDirectoryStats(
|
|
106043
|
-
items.push(` - Directory:
|
|
106076
|
+
const tbdStats = await this.getDirectoryStats(tbdDir);
|
|
106077
|
+
items.push(` - Directory: ${displayPath(tbdDir)}/ (${tbdStats.files} files)`);
|
|
106044
106078
|
console.log(colors.bold("The following will be removed:"));
|
|
106045
106079
|
console.log("");
|
|
106046
106080
|
for (const item of items) console.log(colors.warn(item));
|
|
@@ -106113,7 +106147,7 @@ var UninstallHandler = class extends BaseCommand {
|
|
|
106113
106147
|
});
|
|
106114
106148
|
} catch {}
|
|
106115
106149
|
try {
|
|
106116
|
-
await rm(
|
|
106150
|
+
await rm(tbdDir, {
|
|
106117
106151
|
recursive: true,
|
|
106118
106152
|
force: true
|
|
106119
106153
|
});
|
|
@@ -107381,7 +107415,7 @@ function inferGuidelineCategory(name) {
|
|
|
107381
107415
|
if (name.startsWith("typescript-")) return "typescript";
|
|
107382
107416
|
if (name.startsWith("python-")) return "python";
|
|
107383
107417
|
if (name.includes("tdd") || name.includes("testing") || name.includes("golden")) return "testing";
|
|
107384
|
-
if (name.startsWith("general-") || name.includes("rules") || name.includes("patterns") || name.startsWith("backward-") || name.startsWith("convex-") || name.startsWith("release-")) return "general";
|
|
107418
|
+
if (name.startsWith("general-") || name.includes("rules") || name.includes("patterns") || name.startsWith("backward-") || name.startsWith("convex-") || name.startsWith("release-") || name.startsWith("writing-")) return "general";
|
|
107385
107419
|
}
|
|
107386
107420
|
var GuidelinesHandler = class extends DocCommandHandler {
|
|
107387
107421
|
constructor(command) {
|
|
@@ -108285,7 +108319,10 @@ var SetupDefaultHandler = class extends BaseCommand {
|
|
|
108285
108319
|
"",
|
|
108286
108320
|
"# Temporary files",
|
|
108287
108321
|
"*.tmp",
|
|
108288
|
-
"*.temp"
|
|
108322
|
+
"*.temp",
|
|
108323
|
+
"",
|
|
108324
|
+
"# workspaces/ stores state (including outbox) committed to the working branch",
|
|
108325
|
+
"!workspaces/"
|
|
108289
108326
|
]);
|
|
108290
108327
|
if (tbdGitignoreResult.created) console.log(` ${colors.success("✓")} Created .tbd/.gitignore`);
|
|
108291
108328
|
else if (tbdGitignoreResult.added.length > 0) console.log(` ${colors.success("✓")} Updated .tbd/.gitignore with new patterns`);
|
|
@@ -108412,7 +108449,10 @@ Example:
|
|
|
108412
108449
|
"",
|
|
108413
108450
|
"# Temporary files",
|
|
108414
108451
|
"*.tmp",
|
|
108415
|
-
"*.temp"
|
|
108452
|
+
"*.temp",
|
|
108453
|
+
"",
|
|
108454
|
+
"# workspaces/ stores state (including outbox) committed to the working branch",
|
|
108455
|
+
"!workspaces/"
|
|
108416
108456
|
]);
|
|
108417
108457
|
if (tbdGitignoreResult.created) console.log(` ${colors.success("✓")} Created .tbd/.gitignore`);
|
|
108418
108458
|
else if (tbdGitignoreResult.added.length > 0) console.log(` ${colors.success("✓")} Updated .tbd/.gitignore`);
|