get-tbd 0.1.29 → 0.1.30
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 +442 -124
- package/dist/bin.mjs.map +1 -1
- package/dist/cli.mjs +440 -126
- package/dist/cli.mjs.map +1 -1
- package/dist/{config-C0ITTrtc.mjs → config-BPHcePSm.mjs} +1 -1
- package/dist/{config-B38rbI9u.mjs → config-DVap9omo.mjs} +6 -2
- package/dist/config-DVap9omo.mjs.map +1 -0
- package/dist/docs/SKILL.md +0 -1
- package/dist/docs/guidelines/cli-agent-skill-patterns.md +336 -23
- package/dist/docs/install/ensure-gh-cli.sh +59 -24
- package/dist/index.mjs +1 -1
- package/dist/{src-CJyVkC3V.mjs → src-BK_EF6mk.mjs} +2 -2
- package/dist/{src-CJyVkC3V.mjs.map → src-BK_EF6mk.mjs.map} +1 -1
- package/dist/tbd +442 -124
- package/package.json +1 -1
- package/dist/config-B38rbI9u.mjs.map +0 -1
package/dist/tbd
CHANGED
|
@@ -14067,7 +14067,7 @@ function serializeIssue(issue) {
|
|
|
14067
14067
|
* Package version, derived from git at build time.
|
|
14068
14068
|
* Format: X.Y.Z for releases, X.Y.Z-dev.N.hash for dev builds.
|
|
14069
14069
|
*/
|
|
14070
|
-
const VERSION$1 = "0.1.
|
|
14070
|
+
const VERSION$1 = "0.1.30";
|
|
14071
14071
|
|
|
14072
14072
|
//#endregion
|
|
14073
14073
|
//#region src/cli/lib/version.ts
|
|
@@ -97685,6 +97685,10 @@ const CHARS_PER_TOKEN = 3.5;
|
|
|
97685
97685
|
* WHEN TO BUMP THE FORMAT VERSION:
|
|
97686
97686
|
* - Bump when changes REQUIRE migration (deleting files, changing formats, moving files)
|
|
97687
97687
|
* - **Bump when changing config schema** (adding, removing, or modifying fields)
|
|
97688
|
+
* - **Bump when the shape of a generated agent-integration surface changes** (e.g. the
|
|
97689
|
+
* managed AGENTS.md block). This same format is stamped there via
|
|
97690
|
+
* AGENT_INTEGRATION_FORMAT (integration-paths.ts), so there is ONE format code across
|
|
97691
|
+
* all tbd-managed surfaces.
|
|
97688
97692
|
* - Do NOT bump for additive changes that don't affect config.yml (new directories, etc.)
|
|
97689
97693
|
*
|
|
97690
97694
|
* HOW TO ADD A NEW FORMAT VERSION:
|
|
@@ -104232,9 +104236,10 @@ function renderFooter(suggestions, colors) {
|
|
|
104232
104236
|
/**
|
|
104233
104237
|
* Centralized path constants and utilities for coding agent integrations.
|
|
104234
104238
|
*
|
|
104235
|
-
* IMPORTANT: All tbd integration files (hooks, settings,
|
|
104236
|
-
* to PROJECT-LOCAL directories (.
|
|
104237
|
-
* global/user directories
|
|
104239
|
+
* IMPORTANT: All tbd integration files (skills, hooks, settings, scripts) are
|
|
104240
|
+
* installed to PROJECT-LOCAL directories (.agents/, .claude/, .codex/,
|
|
104241
|
+
* scripts/agent/, AGENTS.md) ONLY. We do NOT install to global/user directories
|
|
104242
|
+
* (~/.claude/, ~/.codex/, ~/.agents/).
|
|
104238
104243
|
*
|
|
104239
104244
|
* This file defines all path constants in one place to:
|
|
104240
104245
|
* 1. Ensure consistency across the codebase
|
|
@@ -104242,6 +104247,19 @@ function renderFooter(suggestions, colors) {
|
|
|
104242
104247
|
* 3. Simplify future changes to path conventions
|
|
104243
104248
|
*/
|
|
104244
104249
|
/**
|
|
104250
|
+
* Format version stamped into generated agent integration artifacts (e.g. the
|
|
104251
|
+
* AGENTS.md managed block's begin marker: `... format=f03 surface=...`).
|
|
104252
|
+
*
|
|
104253
|
+
* UNIFIED with the `.tbd/` directory format (`tbd_format`): there is one format
|
|
104254
|
+
* code for all tbd-managed surfaces, sourced from `tbd-format.ts` (the single
|
|
104255
|
+
* source of truth). Bump `CURRENT_FORMAT` there when any managed surface — config
|
|
104256
|
+
* schema OR a generated agent surface — changes shape. A marked AGENTS.md block
|
|
104257
|
+
* with no `format=` field predates this and is treated as `f01`; a running tbd
|
|
104258
|
+
* that finds a HIGHER format than it knows refuses to overwrite it and tells the
|
|
104259
|
+
* user to upgrade tbd.
|
|
104260
|
+
*/
|
|
104261
|
+
const AGENT_INTEGRATION_FORMAT = CURRENT_FORMAT;
|
|
104262
|
+
/**
|
|
104245
104263
|
* Relative path to Claude Code settings file from project root.
|
|
104246
104264
|
* This is where hooks are configured.
|
|
104247
104265
|
*/
|
|
@@ -104275,11 +104293,33 @@ const TBD_CLOSING_REMINDER_REL = ".claude/hooks/tbd-closing-reminder.sh";
|
|
|
104275
104293
|
*/
|
|
104276
104294
|
const GH_CLI_SCRIPT_REL = ".claude/scripts/ensure-gh-cli.sh";
|
|
104277
104295
|
/**
|
|
104296
|
+
* Canonical portable project Agent Skill, scanned by Codex, Gemini CLI, Cursor,
|
|
104297
|
+
* GitHub Copilot, Amp, OpenCode, pi, and other Agent Skills clients.
|
|
104298
|
+
*/
|
|
104299
|
+
const AGENTS_SKILL_REL = ".agents/skills/tbd/SKILL.md";
|
|
104300
|
+
/**
|
|
104301
|
+
* Repository distribution copy of the skill, for skills.sh-style installers
|
|
104302
|
+
* (`npx skills add`) and direct GitHub browsing.
|
|
104303
|
+
*/
|
|
104304
|
+
const SKILLS_DIST_REL = "skills/tbd/SKILL.md";
|
|
104305
|
+
/**
|
|
104278
104306
|
* Relative path to AGENTS.md file from project root.
|
|
104279
104307
|
* Used by Codex, Factory.ai, Cursor (v1.6+), and other compatible tools.
|
|
104280
104308
|
*/
|
|
104281
104309
|
const AGENTS_MD_REL = "AGENTS.md";
|
|
104282
104310
|
/**
|
|
104311
|
+
* Codex project-local config/hook directory.
|
|
104312
|
+
*/
|
|
104313
|
+
const CODEX_DIR_REL = ".codex";
|
|
104314
|
+
/**
|
|
104315
|
+
* Codex project-local hooks file (Claude-compatible event schema).
|
|
104316
|
+
*/
|
|
104317
|
+
const CODEX_HOOKS_REL = ".codex/hooks.json";
|
|
104318
|
+
/**
|
|
104319
|
+
* Codex project-local config; may also carry an inline `[hooks]` table.
|
|
104320
|
+
*/
|
|
104321
|
+
const CODEX_CONFIG_REL = ".codex/config.toml";
|
|
104322
|
+
/**
|
|
104283
104323
|
* Global Claude Code directory in user's home.
|
|
104284
104324
|
* Used ONLY for detecting if Claude Code is installed (for agent detection).
|
|
104285
104325
|
* All installations are project-local.
|
|
@@ -104313,6 +104353,31 @@ function getAgentsMdPath(projectRoot) {
|
|
|
104313
104353
|
return join(projectRoot, AGENTS_MD_REL);
|
|
104314
104354
|
}
|
|
104315
104355
|
/**
|
|
104356
|
+
* Get the three SKILL.md targets: the portable Agent Skills install, the Claude
|
|
104357
|
+
* Code mirror, and the committed distribution copy.
|
|
104358
|
+
*
|
|
104359
|
+
* @param projectRoot - The project root directory (containing .tbd/)
|
|
104360
|
+
*/
|
|
104361
|
+
function getAgentSkillPaths(projectRoot) {
|
|
104362
|
+
return {
|
|
104363
|
+
portable: join(projectRoot, AGENTS_SKILL_REL),
|
|
104364
|
+
claudeMirror: join(projectRoot, CLAUDE_SKILL_REL),
|
|
104365
|
+
distribution: join(projectRoot, SKILLS_DIST_REL)
|
|
104366
|
+
};
|
|
104367
|
+
}
|
|
104368
|
+
/**
|
|
104369
|
+
* Get project-local Codex config/hook paths.
|
|
104370
|
+
*
|
|
104371
|
+
* @param projectRoot - The project root directory
|
|
104372
|
+
*/
|
|
104373
|
+
function getCodexPaths(projectRoot) {
|
|
104374
|
+
return {
|
|
104375
|
+
dir: join(projectRoot, CODEX_DIR_REL),
|
|
104376
|
+
hooks: join(projectRoot, CODEX_HOOKS_REL),
|
|
104377
|
+
config: join(projectRoot, CODEX_CONFIG_REL)
|
|
104378
|
+
};
|
|
104379
|
+
}
|
|
104380
|
+
/**
|
|
104316
104381
|
* Display path for Claude Code settings in status/doctor output.
|
|
104317
104382
|
*/
|
|
104318
104383
|
const CLAUDE_SETTINGS_DISPLAY = "./.claude/settings.json";
|
|
@@ -104320,6 +104385,14 @@ const CLAUDE_SETTINGS_DISPLAY = "./.claude/settings.json";
|
|
|
104320
104385
|
* Display path for AGENTS.md in status/doctor output.
|
|
104321
104386
|
*/
|
|
104322
104387
|
const AGENTS_MD_DISPLAY = "./AGENTS.md";
|
|
104388
|
+
/**
|
|
104389
|
+
* Display path for the portable Agent Skill in status/doctor output.
|
|
104390
|
+
*/
|
|
104391
|
+
const AGENTS_SKILL_DISPLAY = "./.agents/skills/tbd/SKILL.md";
|
|
104392
|
+
/**
|
|
104393
|
+
* Display path for the Codex hooks file in status/doctor output.
|
|
104394
|
+
*/
|
|
104395
|
+
const CODEX_HOOKS_DISPLAY = "./.codex/hooks.json";
|
|
104323
104396
|
|
|
104324
104397
|
//#endregion
|
|
104325
104398
|
//#region src/cli/commands/status.ts
|
|
@@ -104357,10 +104430,14 @@ var StatusHandler = class extends BaseCommand {
|
|
|
104357
104430
|
worktree_healthy: null,
|
|
104358
104431
|
workspaces: [],
|
|
104359
104432
|
integrations: {
|
|
104433
|
+
portable_skill: false,
|
|
104434
|
+
portable_skill_path: AGENTS_SKILL_DISPLAY,
|
|
104360
104435
|
claude_code: false,
|
|
104361
104436
|
claude_code_path: CLAUDE_SETTINGS_DISPLAY,
|
|
104362
104437
|
codex: false,
|
|
104363
|
-
codex_path: AGENTS_MD_DISPLAY
|
|
104438
|
+
codex_path: AGENTS_MD_DISPLAY,
|
|
104439
|
+
codex_hooks: false,
|
|
104440
|
+
codex_hooks_path: CODEX_HOOKS_DISPLAY
|
|
104364
104441
|
}
|
|
104365
104442
|
};
|
|
104366
104443
|
const gitInfo = await this.checkGitRepo();
|
|
@@ -104428,11 +104505,23 @@ var StatusHandler = class extends BaseCommand {
|
|
|
104428
104505
|
const claudePaths = getClaudePaths(projectRoot);
|
|
104429
104506
|
const agentsPath = getAgentsMdPath(projectRoot);
|
|
104430
104507
|
const result = {
|
|
104508
|
+
portable_skill: false,
|
|
104509
|
+
portable_skill_path: AGENTS_SKILL_DISPLAY,
|
|
104431
104510
|
claude_code: false,
|
|
104432
104511
|
claude_code_path: CLAUDE_SETTINGS_DISPLAY,
|
|
104433
104512
|
codex: false,
|
|
104434
|
-
codex_path: AGENTS_MD_DISPLAY
|
|
104513
|
+
codex_path: AGENTS_MD_DISPLAY,
|
|
104514
|
+
codex_hooks: false,
|
|
104515
|
+
codex_hooks_path: CODEX_HOOKS_DISPLAY
|
|
104435
104516
|
};
|
|
104517
|
+
try {
|
|
104518
|
+
await access(getAgentSkillPaths(projectRoot).portable);
|
|
104519
|
+
result.portable_skill = true;
|
|
104520
|
+
} catch {}
|
|
104521
|
+
try {
|
|
104522
|
+
await access(getCodexPaths(projectRoot).hooks);
|
|
104523
|
+
result.codex_hooks = true;
|
|
104524
|
+
} catch {}
|
|
104436
104525
|
try {
|
|
104437
104526
|
await access(claudePaths.settings);
|
|
104438
104527
|
const content = await readFile(claudePaths.settings, "utf-8");
|
|
@@ -104481,15 +104570,28 @@ var StatusHandler = class extends BaseCommand {
|
|
|
104481
104570
|
remote: data.remote,
|
|
104482
104571
|
displayPrefix: data.display_prefix
|
|
104483
104572
|
}, colors);
|
|
104484
|
-
if (renderIntegrationsSection([
|
|
104485
|
-
|
|
104486
|
-
|
|
104487
|
-
|
|
104488
|
-
|
|
104489
|
-
|
|
104490
|
-
|
|
104491
|
-
|
|
104492
|
-
|
|
104573
|
+
if (renderIntegrationsSection([
|
|
104574
|
+
{
|
|
104575
|
+
name: "Portable Agent Skill",
|
|
104576
|
+
installed: data.integrations.portable_skill,
|
|
104577
|
+
path: data.integrations.portable_skill_path
|
|
104578
|
+
},
|
|
104579
|
+
{
|
|
104580
|
+
name: "Claude Code hooks",
|
|
104581
|
+
installed: data.integrations.claude_code,
|
|
104582
|
+
path: data.integrations.claude_code_path
|
|
104583
|
+
},
|
|
104584
|
+
{
|
|
104585
|
+
name: "Codex AGENTS.md",
|
|
104586
|
+
installed: data.integrations.codex,
|
|
104587
|
+
path: data.integrations.codex_path
|
|
104588
|
+
},
|
|
104589
|
+
{
|
|
104590
|
+
name: "Codex hooks",
|
|
104591
|
+
installed: data.integrations.codex_hooks,
|
|
104592
|
+
path: data.integrations.codex_hooks_path
|
|
104593
|
+
}
|
|
104594
|
+
], colors)) {
|
|
104493
104595
|
console.log("");
|
|
104494
104596
|
console.log(`Run ${colors.bold("tbd setup auto")} to configure detected agents`);
|
|
104495
104597
|
}
|
|
@@ -104829,8 +104931,10 @@ var DoctorHandler = class extends BaseCommand {
|
|
|
104829
104931
|
healthChecks.push(await this.checkCloneScenarios());
|
|
104830
104932
|
healthChecks.push(await this.checkSyncConsistency());
|
|
104831
104933
|
const integrationChecks = [];
|
|
104934
|
+
integrationChecks.push(await this.checkPortableSkill());
|
|
104832
104935
|
integrationChecks.push(await this.checkClaudeSkill());
|
|
104833
104936
|
integrationChecks.push(await this.checkCodexAgents());
|
|
104937
|
+
integrationChecks.push(await this.checkCodexHooks());
|
|
104834
104938
|
const allChecks = [...healthChecks, ...integrationChecks];
|
|
104835
104939
|
const allOk = allChecks.every((c) => c.status === "ok");
|
|
104836
104940
|
const hasFixable = allChecks.some((c) => c.fixable && c.status !== "ok");
|
|
@@ -105294,6 +105398,25 @@ var DoctorHandler = class extends BaseCommand {
|
|
|
105294
105398
|
suggestion: "Run: tbd doctor --fix to create missing mappings"
|
|
105295
105399
|
};
|
|
105296
105400
|
}
|
|
105401
|
+
async checkPortableSkill() {
|
|
105402
|
+
const { portable } = getAgentSkillPaths(this.cwd);
|
|
105403
|
+
try {
|
|
105404
|
+
await access(portable);
|
|
105405
|
+
return {
|
|
105406
|
+
name: "Portable Agent Skill",
|
|
105407
|
+
status: "ok",
|
|
105408
|
+
path: AGENTS_SKILL_REL
|
|
105409
|
+
};
|
|
105410
|
+
} catch {
|
|
105411
|
+
return {
|
|
105412
|
+
name: "Portable Agent Skill",
|
|
105413
|
+
status: "warn",
|
|
105414
|
+
message: "not installed",
|
|
105415
|
+
path: AGENTS_SKILL_REL,
|
|
105416
|
+
suggestion: "Run: tbd setup --auto"
|
|
105417
|
+
};
|
|
105418
|
+
}
|
|
105419
|
+
}
|
|
105297
105420
|
async checkClaudeSkill() {
|
|
105298
105421
|
const claudePaths = getClaudePaths(this.cwd);
|
|
105299
105422
|
try {
|
|
@@ -105313,6 +105436,25 @@ var DoctorHandler = class extends BaseCommand {
|
|
|
105313
105436
|
};
|
|
105314
105437
|
}
|
|
105315
105438
|
}
|
|
105439
|
+
async checkCodexHooks() {
|
|
105440
|
+
const codexPaths = getCodexPaths(this.cwd);
|
|
105441
|
+
try {
|
|
105442
|
+
await access(codexPaths.hooks);
|
|
105443
|
+
return {
|
|
105444
|
+
name: "Codex hooks",
|
|
105445
|
+
status: "ok",
|
|
105446
|
+
path: CODEX_HOOKS_REL
|
|
105447
|
+
};
|
|
105448
|
+
} catch {
|
|
105449
|
+
return {
|
|
105450
|
+
name: "Codex hooks",
|
|
105451
|
+
status: "warn",
|
|
105452
|
+
message: "not installed",
|
|
105453
|
+
path: CODEX_HOOKS_REL,
|
|
105454
|
+
suggestion: "Run: tbd setup --auto"
|
|
105455
|
+
};
|
|
105456
|
+
}
|
|
105457
|
+
}
|
|
105316
105458
|
async checkCodexAgents() {
|
|
105317
105459
|
const agentsPath = getAgentsMdPath(this.cwd);
|
|
105318
105460
|
try {
|
|
@@ -108323,16 +108465,89 @@ async function getShortcutDirectory(quiet = false) {
|
|
|
108323
108465
|
return generateShortcutDirectory(shortcuts, guidelines);
|
|
108324
108466
|
}
|
|
108325
108467
|
/**
|
|
108326
|
-
*
|
|
108327
|
-
*
|
|
108468
|
+
* DO NOT EDIT marker inserted after the frontmatter of every generated SKILL.md.
|
|
108469
|
+
* Formatted to match flowmark output.
|
|
108470
|
+
*/
|
|
108471
|
+
const SKILL_DO_NOT_EDIT_MARKER = "<!-- DO NOT EDIT: Generated by tbd setup.\nRun 'tbd setup' to update.\n-->";
|
|
108472
|
+
/**
|
|
108473
|
+
* Build the full generated SKILL.md payload: the bundled skill content with the
|
|
108474
|
+
* shortcut/guideline directory appended and a DO NOT EDIT marker after the
|
|
108475
|
+
* frontmatter. This is the single source for every skill surface (the portable
|
|
108476
|
+
* .agents/skills install and the .claude/skills mirror) so they stay identical.
|
|
108328
108477
|
*
|
|
108329
|
-
* @param quiet - If true, suppress auto-sync output
|
|
108478
|
+
* @param quiet - If true, suppress auto-sync output.
|
|
108330
108479
|
*/
|
|
108331
|
-
async function
|
|
108332
|
-
let
|
|
108480
|
+
async function buildSkillPayload(quiet = false) {
|
|
108481
|
+
let skillContent = await loadSkillContent();
|
|
108333
108482
|
const directory = await getShortcutDirectory(quiet);
|
|
108334
|
-
if (directory)
|
|
108335
|
-
|
|
108483
|
+
if (directory) skillContent = skillContent.trimEnd() + "\n\n" + directory;
|
|
108484
|
+
skillContent = insertAfterFrontmatter(skillContent, SKILL_DO_NOT_EDIT_MARKER);
|
|
108485
|
+
return skillContent.trimEnd() + "\n";
|
|
108486
|
+
}
|
|
108487
|
+
/**
|
|
108488
|
+
* Write a generated SKILL.md payload to a target path, creating parent dirs.
|
|
108489
|
+
*/
|
|
108490
|
+
async function writeSkillFile(targetPath, payload) {
|
|
108491
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
108492
|
+
await writeFile(targetPath, payload);
|
|
108493
|
+
}
|
|
108494
|
+
/**
|
|
108495
|
+
* AGENTS.md managed-block markers. `CODEX_BEGIN_MARKER` is the stable PREFIX of
|
|
108496
|
+
* the begin line — the metadata (`format=fNN surface=agents-md`) follows it on the
|
|
108497
|
+
* same line, e.g. `<!-- BEGIN TBD INTEGRATION format=f02 surface=agents-md -->`.
|
|
108498
|
+
* Cleanup/upgrade code matches on this prefix so it finds both legacy
|
|
108499
|
+
* (`<!-- BEGIN TBD INTEGRATION -->`) and current marked blocks.
|
|
108500
|
+
*/
|
|
108501
|
+
const CODEX_BEGIN_MARKER = "<!-- BEGIN TBD INTEGRATION";
|
|
108502
|
+
const CODEX_END_MARKER = "<!-- END TBD INTEGRATION -->";
|
|
108503
|
+
/** The full begin marker line for newly generated blocks. */
|
|
108504
|
+
const CODEX_BEGIN_LINE = `${CODEX_BEGIN_MARKER} format=${AGENT_INTEGRATION_FORMAT} surface=agents-md -->`;
|
|
108505
|
+
/** Numeric value of an `fNN` format string, for ordering comparisons. */
|
|
108506
|
+
function formatToNumber(format) {
|
|
108507
|
+
return Number.parseInt(format.replace(/^f/, ""), 10);
|
|
108508
|
+
}
|
|
108509
|
+
/**
|
|
108510
|
+
* Read the integration format (`fNN`) stamped in a generated artifact's begin
|
|
108511
|
+
* marker. Returns `f01` for a legacy marked block with no `format=` field, or
|
|
108512
|
+
* null when there is no tbd-managed block at all.
|
|
108513
|
+
*/
|
|
108514
|
+
function parseIntegrationFormat(content) {
|
|
108515
|
+
const match = /format=f(\d+)/.exec(content);
|
|
108516
|
+
if (match?.[1]) return `f${match[1]}`;
|
|
108517
|
+
return content.includes(CODEX_BEGIN_MARKER) ? "f01" : null;
|
|
108518
|
+
}
|
|
108519
|
+
/**
|
|
108520
|
+
* Forward-compatibility guard. If a generated artifact was written by a NEWER
|
|
108521
|
+
* tbd than this one understands, refuse to rewrite it and tell the user to
|
|
108522
|
+
* upgrade tbd — overwriting would downgrade a newer managed format. This is what
|
|
108523
|
+
* makes pinning safe on a team: an older tbd fails loudly instead of clobbering.
|
|
108524
|
+
*/
|
|
108525
|
+
function assertNotNewerFormat(content, artifact) {
|
|
108526
|
+
const format = parseIntegrationFormat(content);
|
|
108527
|
+
if (format !== null && formatToNumber(format) > formatToNumber(AGENT_INTEGRATION_FORMAT)) throw new CLIError(`${artifact} was generated by a newer tbd (integration format ${format}; this tbd supports up to ${AGENT_INTEGRATION_FORMAT}).\nUpgrade tbd to manage it: npm install -g get-tbd@latest`);
|
|
108528
|
+
}
|
|
108529
|
+
/**
|
|
108530
|
+
* Get the tbd managed block for AGENTS.md.
|
|
108531
|
+
*
|
|
108532
|
+
* This is a COMPACT always-on bootstrap, not a copy of the full skill: it names
|
|
108533
|
+
* tbd, states the operating rule, and points to the CLI commands that provide
|
|
108534
|
+
* progressive disclosure (`tbd prime`, `tbd skill`, `tbd shortcut/guidelines
|
|
108535
|
+
* --list`). The full skill body lives in the SKILL.md surfaces, not here, so the
|
|
108536
|
+
* block stays well under the AGENTS.md prompt-budget guidance.
|
|
108537
|
+
*/
|
|
108538
|
+
function getCodexTbdSection() {
|
|
108539
|
+
return `${CODEX_BEGIN_LINE}\n## tbd
|
|
108540
|
+
|
|
108541
|
+
This repository uses **tbd** for git-native issue tracking (beads), spec-driven
|
|
108542
|
+
planning, and on-demand engineering guidelines.
|
|
108543
|
+
As the agent, you operate tbd on the user’s behalf — translate their requests into tbd
|
|
108544
|
+
actions rather than telling them to run commands.
|
|
108545
|
+
|
|
108546
|
+
- Run \`tbd prime\` to load current project state and the full tbd workflow.
|
|
108547
|
+
- Run \`tbd skill\` for the complete reusable tbd skill instructions.
|
|
108548
|
+
- Run \`tbd shortcut --list\` and \`tbd guidelines --list\` for on-demand resources.
|
|
108549
|
+
- Track all work as beads: \`tbd create\`, \`tbd ready\`, \`tbd close\`, and \`tbd sync\`.
|
|
108550
|
+
\n${CODEX_END_MARKER}\n`;
|
|
108336
108551
|
}
|
|
108337
108552
|
/**
|
|
108338
108553
|
* Script to ensure tbd CLI is installed and run tbd prime.
|
|
@@ -108344,82 +108559,32 @@ async function getCodexTbdSection(quiet = false) {
|
|
|
108344
108559
|
* tbd-session.sh --brief # Ensure tbd + run tbd prime --brief (for PreCompact)
|
|
108345
108560
|
*/
|
|
108346
108561
|
const TBD_SESSION_SCRIPT = `#!/bin/bash
|
|
108347
|
-
# Ensure tbd CLI is
|
|
108348
|
-
# Installed by: tbd setup --auto
|
|
108349
|
-
#
|
|
108350
|
-
|
|
108351
|
-
#
|
|
108352
|
-
|
|
108353
|
-
|
|
108354
|
-
NPM_PREFIX=$(npm config get prefix 2>/dev/null)
|
|
108355
|
-
if [ -n "$NPM_PREFIX" ] && [ -d "$NPM_PREFIX/bin" ]; then
|
|
108356
|
-
NPM_GLOBAL_BIN="$NPM_PREFIX/bin"
|
|
108357
|
-
fi
|
|
108358
|
-
fi
|
|
108562
|
+
# Ensure the tbd CLI is available and run \`tbd prime\`.
|
|
108563
|
+
# Installed by: tbd setup --auto. Runs on SessionStart and PreCompact.
|
|
108564
|
+
#
|
|
108565
|
+
# Local-first, then a VERSION-PINNED zero-install fallback. Pinning is both a
|
|
108566
|
+
# supply-chain control (an unpinned runner re-resolves to latest on every run
|
|
108567
|
+
# and bypasses any cool-off) and a consistency control (every teammate and agent
|
|
108568
|
+
# runs the same tbd version).
|
|
108359
108569
|
|
|
108360
|
-
#
|
|
108361
|
-
|
|
108362
|
-
export PATH="$NPM_GLOBAL_BIN:$HOME/.local/bin:$HOME/bin:/usr/local/bin:$PATH"
|
|
108570
|
+
# Prefer common local bin locations.
|
|
108571
|
+
export PATH="$HOME/.local/bin:$HOME/bin:/usr/local/bin:$PATH"
|
|
108363
108572
|
|
|
108364
|
-
#
|
|
108365
|
-
|
|
108366
|
-
|
|
108367
|
-
|
|
108368
|
-
|
|
108369
|
-
fi
|
|
108370
|
-
|
|
108371
|
-
echo "[tbd] CLI not found, installing..."
|
|
108372
|
-
|
|
108373
|
-
# Try npm first (most common for Node.js tools)
|
|
108374
|
-
if command -v npm &> /dev/null; then
|
|
108375
|
-
echo "[tbd] Installing via npm..."
|
|
108376
|
-
npm install -g get-tbd 2>/dev/null || {
|
|
108377
|
-
# If global install fails (permissions), try local install
|
|
108378
|
-
echo "[tbd] Global npm install failed, trying user install..."
|
|
108379
|
-
mkdir -p ~/.local/bin
|
|
108380
|
-
npm install --prefix ~/.local get-tbd
|
|
108381
|
-
# Create symlink if needed
|
|
108382
|
-
if [ -f ~/.local/node_modules/.bin/tbd ]; then
|
|
108383
|
-
ln -sf ~/.local/node_modules/.bin/tbd ~/.local/bin/tbd
|
|
108384
|
-
fi
|
|
108385
|
-
}
|
|
108386
|
-
elif command -v pnpm &> /dev/null; then
|
|
108387
|
-
echo "[tbd] Installing via pnpm..."
|
|
108388
|
-
pnpm add -g get-tbd
|
|
108389
|
-
elif command -v yarn &> /dev/null; then
|
|
108390
|
-
echo "[tbd] Installing via yarn..."
|
|
108391
|
-
yarn global add get-tbd
|
|
108392
|
-
else
|
|
108393
|
-
echo "[tbd] ERROR: No package manager found (npm, pnpm, or yarn required)"
|
|
108394
|
-
echo "[tbd] Please install Node.js and npm, then run: npm install -g get-tbd"
|
|
108395
|
-
return 1
|
|
108396
|
-
fi
|
|
108397
|
-
|
|
108398
|
-
# Verify installation
|
|
108399
|
-
if command -v tbd &> /dev/null; then
|
|
108400
|
-
echo "[tbd] Successfully installed to $(which tbd)"
|
|
108401
|
-
return 0
|
|
108402
|
-
else
|
|
108403
|
-
echo "[tbd] WARNING: tbd installed but not found in PATH"
|
|
108404
|
-
echo "[tbd] Checking common locations..."
|
|
108405
|
-
# Try to find and add to path (include npm global bin)
|
|
108406
|
-
for dir in "$NPM_GLOBAL_BIN" ~/.local/bin ~/.local/node_modules/.bin /usr/local/bin; do
|
|
108407
|
-
if [ -n "$dir" ] && [ -x "$dir/tbd" ]; then
|
|
108408
|
-
export PATH="$dir:$PATH"
|
|
108409
|
-
echo "[tbd] Found at $dir/tbd"
|
|
108410
|
-
return 0
|
|
108411
|
-
fi
|
|
108412
|
-
done
|
|
108413
|
-
echo "[tbd] Could not locate tbd after installation"
|
|
108414
|
-
return 1
|
|
108415
|
-
fi
|
|
108416
|
-
}
|
|
108573
|
+
# Local-first: use tbd if it is already on PATH.
|
|
108574
|
+
if command -v tbd &> /dev/null; then
|
|
108575
|
+
tbd prime "$@"
|
|
108576
|
+
exit $?
|
|
108577
|
+
fi
|
|
108417
108578
|
|
|
108418
|
-
#
|
|
108419
|
-
|
|
108579
|
+
# Pinned zero-install fallback. Never use an unpinned runner here.
|
|
108580
|
+
if command -v npx &> /dev/null; then
|
|
108581
|
+
npx --yes get-tbd@${VERSION} prime "$@"
|
|
108582
|
+
exit $?
|
|
108583
|
+
fi
|
|
108420
108584
|
|
|
108421
|
-
|
|
108422
|
-
tbd
|
|
108585
|
+
echo "[tbd] tbd CLI not found and npx is unavailable."
|
|
108586
|
+
echo "[tbd] Install it with: npm install -g get-tbd@${VERSION}"
|
|
108587
|
+
exit 1
|
|
108423
108588
|
`;
|
|
108424
108589
|
/**
|
|
108425
108590
|
* Claude Code session hooks configuration.
|
|
@@ -108509,22 +108674,14 @@ async function loadBundledScript(name) {
|
|
|
108509
108674
|
throw new Error(`Bundled script not found: ${name}`);
|
|
108510
108675
|
}
|
|
108511
108676
|
/**
|
|
108512
|
-
* AGENTS.md integration markers for Codex/Factory.ai
|
|
108513
|
-
* Content is now generated dynamically from SKILL.md via getCodexTbdSection()
|
|
108514
|
-
*/
|
|
108515
|
-
const CODEX_BEGIN_MARKER = "<!-- BEGIN TBD INTEGRATION -->";
|
|
108516
|
-
const CODEX_END_MARKER = "<!-- END TBD INTEGRATION -->";
|
|
108517
|
-
/**
|
|
108518
108677
|
* Generate a new AGENTS.md file with tbd integration.
|
|
108519
|
-
*
|
|
108520
|
-
* @param quiet - If true, suppress auto-sync output (default: false)
|
|
108521
108678
|
*/
|
|
108522
|
-
|
|
108679
|
+
function getCodexNewAgentsFile() {
|
|
108523
108680
|
return `# Project Instructions for AI Agents
|
|
108524
108681
|
|
|
108525
108682
|
This file provides instructions and context for AI coding agents working on this project.
|
|
108526
108683
|
|
|
108527
|
-
${
|
|
108684
|
+
${getCodexTbdSection()}
|
|
108528
108685
|
## Build & Test
|
|
108529
108686
|
|
|
108530
108687
|
_Add your build and test commands here_
|
|
@@ -108545,6 +108702,54 @@ _Add your project-specific conventions here_
|
|
|
108545
108702
|
`;
|
|
108546
108703
|
}
|
|
108547
108704
|
/**
|
|
108705
|
+
* Codex project-local script paths (relative to repo root). Codex hooks
|
|
108706
|
+
* reference ONLY these `.codex/` paths, never `.claude/`, so Codex setup stays
|
|
108707
|
+
* independent of Claude Code setup.
|
|
108708
|
+
*/
|
|
108709
|
+
const CODEX_SESSION_SCRIPT_REL = ".codex/tbd-session.sh";
|
|
108710
|
+
const CODEX_CLOSING_REMINDER_REL = ".codex/tbd-closing-reminder.sh";
|
|
108711
|
+
const CODEX_GH_CLI_SCRIPT_REL = ".codex/ensure-gh-cli.sh";
|
|
108712
|
+
/**
|
|
108713
|
+
* Build the Codex hooks.json content. Codex uses the same lifecycle event
|
|
108714
|
+
* schema as Claude Code (command handlers), so tbd's hooks map almost 1:1:
|
|
108715
|
+
* SessionStart and PreCompact run `tbd prime`, PostToolUse reminds about sync
|
|
108716
|
+
* after `git push`, and (when enabled) a second SessionStart entry ensures gh.
|
|
108717
|
+
*/
|
|
108718
|
+
function getCodexHooksConfig(useGhCli) {
|
|
108719
|
+
const sessionStart = [{
|
|
108720
|
+
matcher: "",
|
|
108721
|
+
hooks: [{
|
|
108722
|
+
type: "command",
|
|
108723
|
+
command: `bash ${CODEX_SESSION_SCRIPT_REL}`
|
|
108724
|
+
}]
|
|
108725
|
+
}];
|
|
108726
|
+
if (useGhCli) sessionStart.push({
|
|
108727
|
+
matcher: "",
|
|
108728
|
+
hooks: [{
|
|
108729
|
+
type: "command",
|
|
108730
|
+
command: `bash ${CODEX_GH_CLI_SCRIPT_REL}`,
|
|
108731
|
+
timeout: 120
|
|
108732
|
+
}]
|
|
108733
|
+
});
|
|
108734
|
+
return { hooks: {
|
|
108735
|
+
SessionStart: sessionStart,
|
|
108736
|
+
PreCompact: [{
|
|
108737
|
+
matcher: "",
|
|
108738
|
+
hooks: [{
|
|
108739
|
+
type: "command",
|
|
108740
|
+
command: `bash ${CODEX_SESSION_SCRIPT_REL} --brief`
|
|
108741
|
+
}]
|
|
108742
|
+
}],
|
|
108743
|
+
PostToolUse: [{
|
|
108744
|
+
matcher: "Bash",
|
|
108745
|
+
hooks: [{
|
|
108746
|
+
type: "command",
|
|
108747
|
+
command: `bash ${CODEX_CLOSING_REMINDER_REL}`
|
|
108748
|
+
}]
|
|
108749
|
+
}]
|
|
108750
|
+
} };
|
|
108751
|
+
}
|
|
108752
|
+
/**
|
|
108548
108753
|
* Legacy script patterns to clean up from .claude/scripts/
|
|
108549
108754
|
* These were used in older versions of tbd before hooks moved to `tbd prime`
|
|
108550
108755
|
*/
|
|
@@ -108805,13 +109010,7 @@ var SetupClaudeHandler = class extends BaseCommand {
|
|
|
108805
109010
|
await writeFile(claudePaths.closingReminder, TBD_CLOSE_PROTOCOL_SCRIPT);
|
|
108806
109011
|
await chmod(claudePaths.closingReminder, 493);
|
|
108807
109012
|
this.output.success("Installed sync reminder hook script");
|
|
108808
|
-
await
|
|
108809
|
-
let skillContent = await loadSkillContent();
|
|
108810
|
-
const directory = await getShortcutDirectory(this.ctx.quiet);
|
|
108811
|
-
if (directory) skillContent = skillContent.trimEnd() + "\n\n" + directory;
|
|
108812
|
-
skillContent = insertAfterFrontmatter(skillContent, "<!-- DO NOT EDIT: Generated by tbd setup.\nRun 'tbd setup' to update.\n-->");
|
|
108813
|
-
skillContent = skillContent.trimEnd() + "\n";
|
|
108814
|
-
await writeFile(skillPath, skillContent);
|
|
109013
|
+
await writeSkillFile(skillPath, await buildSkillPayload(this.ctx.quiet));
|
|
108815
109014
|
this.output.success("Installed skill file");
|
|
108816
109015
|
this.output.info(` ${skillPath}`);
|
|
108817
109016
|
this.output.info("");
|
|
@@ -108844,16 +109043,93 @@ var SetupCodexHandler = class extends BaseCommand {
|
|
|
108844
109043
|
this.projectDir = dir;
|
|
108845
109044
|
}
|
|
108846
109045
|
async run(options) {
|
|
108847
|
-
const
|
|
109046
|
+
const cwd = this.projectDir ?? process.cwd();
|
|
109047
|
+
const agentsPath = join(cwd, "AGENTS.md");
|
|
108848
109048
|
if (options.check) {
|
|
108849
109049
|
await this.checkCodexSetup(agentsPath);
|
|
108850
109050
|
return;
|
|
108851
109051
|
}
|
|
108852
109052
|
if (options.remove) {
|
|
108853
109053
|
await this.removeCodexSection(agentsPath);
|
|
109054
|
+
await this.removeCodexHooks(cwd);
|
|
108854
109055
|
return;
|
|
108855
109056
|
}
|
|
108856
109057
|
await this.installCodexSection(agentsPath);
|
|
109058
|
+
await this.installCodexHooks(cwd);
|
|
109059
|
+
}
|
|
109060
|
+
/**
|
|
109061
|
+
* Read the use_gh_cli setting; defaults to true (so fresh setup installs it).
|
|
109062
|
+
*/
|
|
109063
|
+
async getUseGhCliSetting(cwd) {
|
|
109064
|
+
try {
|
|
109065
|
+
const tbdRoot = await findTbdRoot(cwd);
|
|
109066
|
+
if (!tbdRoot) return true;
|
|
109067
|
+
return (await readConfig(tbdRoot)).settings.use_gh_cli ?? true;
|
|
109068
|
+
} catch {
|
|
109069
|
+
return true;
|
|
109070
|
+
}
|
|
109071
|
+
}
|
|
109072
|
+
/**
|
|
109073
|
+
* Install Codex lifecycle hooks: writes .codex/ scripts and a .codex/hooks.json
|
|
109074
|
+
* (merged idempotently with any user hooks). Scripts reuse the same bodies as
|
|
109075
|
+
* the Claude install but live under .codex/ so Codex never references .claude/.
|
|
109076
|
+
*/
|
|
109077
|
+
async installCodexHooks(cwd) {
|
|
109078
|
+
if (this.checkDryRun("Would install Codex hooks", { path: "./.codex/hooks.json" })) return;
|
|
109079
|
+
const codexPaths = getCodexPaths(cwd);
|
|
109080
|
+
await mkdir(codexPaths.dir, { recursive: true });
|
|
109081
|
+
const useGhCli = await this.getUseGhCliSetting(cwd);
|
|
109082
|
+
await writeFile(join(cwd, CODEX_SESSION_SCRIPT_REL), TBD_SESSION_SCRIPT);
|
|
109083
|
+
await chmod(join(cwd, CODEX_SESSION_SCRIPT_REL), 493);
|
|
109084
|
+
await writeFile(join(cwd, CODEX_CLOSING_REMINDER_REL), TBD_CLOSE_PROTOCOL_SCRIPT);
|
|
109085
|
+
await chmod(join(cwd, CODEX_CLOSING_REMINDER_REL), 493);
|
|
109086
|
+
if (useGhCli) {
|
|
109087
|
+
const ghScriptContent = await loadBundledScript("ensure-gh-cli.sh");
|
|
109088
|
+
await writeFile(join(cwd, CODEX_GH_CLI_SCRIPT_REL), ghScriptContent);
|
|
109089
|
+
await chmod(join(cwd, CODEX_GH_CLI_SCRIPT_REL), 493);
|
|
109090
|
+
} else await rm(join(cwd, CODEX_GH_CLI_SCRIPT_REL), { force: true });
|
|
109091
|
+
let existing = {};
|
|
109092
|
+
try {
|
|
109093
|
+
existing = JSON.parse(await readFile(codexPaths.hooks, "utf-8"));
|
|
109094
|
+
} catch {}
|
|
109095
|
+
const isTbdOwned = (entry) => {
|
|
109096
|
+
return (entry.hooks ?? []).some((h) => h.command?.includes(".codex/"));
|
|
109097
|
+
};
|
|
109098
|
+
const merged = { ...existing.hooks ?? {} };
|
|
109099
|
+
const tbdHooks = getCodexHooksConfig(useGhCli).hooks;
|
|
109100
|
+
for (const [event, entries] of Object.entries(tbdHooks)) merged[event] = [...(merged[event] ?? []).filter((e) => !isTbdOwned(e)), ...entries];
|
|
109101
|
+
await writeFile(codexPaths.hooks, JSON.stringify({
|
|
109102
|
+
...existing,
|
|
109103
|
+
hooks: merged
|
|
109104
|
+
}, null, 2) + "\n");
|
|
109105
|
+
this.output.success("Installed Codex hooks (.codex/hooks.json)");
|
|
109106
|
+
}
|
|
109107
|
+
/**
|
|
109108
|
+
* Remove tbd-owned Codex hook entries and scripts, preserving user hooks.
|
|
109109
|
+
*/
|
|
109110
|
+
async removeCodexHooks(cwd) {
|
|
109111
|
+
const codexPaths = getCodexPaths(cwd);
|
|
109112
|
+
try {
|
|
109113
|
+
const existing = JSON.parse(await readFile(codexPaths.hooks, "utf-8"));
|
|
109114
|
+
const hooks = existing.hooks ?? {};
|
|
109115
|
+
for (const event of Object.keys(hooks)) {
|
|
109116
|
+
const kept = (hooks[event] ?? []).filter((entry) => {
|
|
109117
|
+
return !(entry.hooks ?? []).some((h) => h.command?.includes(".codex/"));
|
|
109118
|
+
});
|
|
109119
|
+
if (kept.length === 0) delete hooks[event];
|
|
109120
|
+
else hooks[event] = kept;
|
|
109121
|
+
}
|
|
109122
|
+
if (Object.keys(hooks).length === 0) await rm(codexPaths.hooks, { force: true });
|
|
109123
|
+
else await writeFile(codexPaths.hooks, JSON.stringify({
|
|
109124
|
+
...existing,
|
|
109125
|
+
hooks
|
|
109126
|
+
}, null, 2) + "\n");
|
|
109127
|
+
} catch {}
|
|
109128
|
+
for (const rel of [
|
|
109129
|
+
CODEX_SESSION_SCRIPT_REL,
|
|
109130
|
+
CODEX_CLOSING_REMINDER_REL,
|
|
109131
|
+
CODEX_GH_CLI_SCRIPT_REL
|
|
109132
|
+
]) await rm(join(cwd, rel), { force: true });
|
|
108857
109133
|
}
|
|
108858
109134
|
async checkCodexSetup(agentsPath) {
|
|
108859
109135
|
const agentsRelPath = "./AGENTS.md";
|
|
@@ -108938,8 +109214,9 @@ var SetupCodexHandler = class extends BaseCommand {
|
|
|
108938
109214
|
existingContent = await readFile(agentsPath, "utf-8");
|
|
108939
109215
|
} catch {}
|
|
108940
109216
|
let newContent;
|
|
108941
|
-
const tbdSection =
|
|
109217
|
+
const tbdSection = getCodexTbdSection();
|
|
108942
109218
|
if (existingContent) if (existingContent.includes(CODEX_BEGIN_MARKER)) {
|
|
109219
|
+
assertNotNewerFormat(existingContent, "AGENTS.md");
|
|
108943
109220
|
newContent = this.updatetbdSection(existingContent, tbdSection);
|
|
108944
109221
|
await writeFile(agentsPath, newContent);
|
|
108945
109222
|
this.output.success("Updated existing tbd section in AGENTS.md");
|
|
@@ -108949,7 +109226,7 @@ var SetupCodexHandler = class extends BaseCommand {
|
|
|
108949
109226
|
this.output.success("Added tbd section to existing AGENTS.md");
|
|
108950
109227
|
}
|
|
108951
109228
|
else {
|
|
108952
|
-
await writeFile(agentsPath,
|
|
109229
|
+
await writeFile(agentsPath, getCodexNewAgentsFile());
|
|
108953
109230
|
this.output.success("Created new AGENTS.md with tbd integration");
|
|
108954
109231
|
}
|
|
108955
109232
|
this.output.info(` File: ${agentsPath}`);
|
|
@@ -109319,9 +109596,11 @@ var SetupAutoHandler = class extends BaseCommand {
|
|
|
109319
109596
|
console.log(colors.dim(`Cleaned up legacy ${parts.join(" and ")}`));
|
|
109320
109597
|
}
|
|
109321
109598
|
await this.syncDocs(cwd);
|
|
109322
|
-
const
|
|
109599
|
+
const targeting = this.resolveTargeting();
|
|
109600
|
+
await this.installPortableSkill(cwd);
|
|
109601
|
+
const claudeResult = await this.setupClaudeIfDetected(cwd, targeting.claude);
|
|
109323
109602
|
results.push(claudeResult);
|
|
109324
|
-
const codexResult = await this.setupCodexIfDetected(cwd);
|
|
109603
|
+
const codexResult = await this.setupCodexIfDetected(cwd, targeting.codex);
|
|
109325
109604
|
results.push(codexResult);
|
|
109326
109605
|
const installed = results.filter((r) => r.installed && !r.alreadyInstalled);
|
|
109327
109606
|
const alreadyInstalled = results.filter((r) => r.alreadyInstalled);
|
|
@@ -109364,16 +109643,51 @@ var SetupAutoHandler = class extends BaseCommand {
|
|
|
109364
109643
|
if (result.pruned.length > 0) console.log(colors.dim(`Pruned ${result.pruned.length} stale config entry/entries`));
|
|
109365
109644
|
if (result.errors.length > 0) for (const { path, error } of result.errors) console.log(colors.warn(`Warning: ${path}: ${error}`));
|
|
109366
109645
|
}
|
|
109367
|
-
|
|
109646
|
+
/**
|
|
109647
|
+
* Write the canonical portable Agent Skill to .agents/skills/tbd/SKILL.md.
|
|
109648
|
+
* Runs for every initialized repo, independent of agent detection, so the
|
|
109649
|
+
* skill is portable across Codex, Gemini CLI, Cursor, and other clients.
|
|
109650
|
+
*/
|
|
109651
|
+
async installPortableSkill(cwd) {
|
|
109652
|
+
const colors = this.output.getColors();
|
|
109653
|
+
if (this.checkDryRun("Would install portable Agent Skill", { path: AGENTS_SKILL_DISPLAY })) return;
|
|
109654
|
+
const { portable } = getAgentSkillPaths(cwd);
|
|
109655
|
+
await writeSkillFile(portable, await buildSkillPayload(this.ctx.quiet));
|
|
109656
|
+
console.log(` ${colors.success("✓")} Portable Agent Skill (${AGENTS_SKILL_DISPLAY})`);
|
|
109657
|
+
}
|
|
109658
|
+
/**
|
|
109659
|
+
* Resolve which agent surfaces to install from the explicit targeting flags.
|
|
109660
|
+
* `--all`/`--claude`/`--codex` force surfaces on (and suppress auto-detection
|
|
109661
|
+
* of untargeted surfaces); `--skip-claude`/`--skip-codex` force them off; with
|
|
109662
|
+
* no targeting flag each surface falls back to detection-based auto behavior.
|
|
109663
|
+
*/
|
|
109664
|
+
resolveTargeting() {
|
|
109665
|
+
const opts = this.cmd.optsWithGlobals();
|
|
109666
|
+
const all = opts.all === true;
|
|
109667
|
+
const anyPositive = all || opts.claude === true || opts.codex === true;
|
|
109668
|
+
const resolve = (on, skip) => {
|
|
109669
|
+
if (skip === true) return "off";
|
|
109670
|
+
if (on === true || all) return "on";
|
|
109671
|
+
return anyPositive ? "off" : "auto";
|
|
109672
|
+
};
|
|
109673
|
+
return {
|
|
109674
|
+
claude: resolve(opts.claude, opts.skipClaude),
|
|
109675
|
+
codex: resolve(opts.codex, opts.skipCodex)
|
|
109676
|
+
};
|
|
109677
|
+
}
|
|
109678
|
+
async setupClaudeIfDetected(cwd, mode) {
|
|
109368
109679
|
const result = {
|
|
109369
109680
|
name: "Claude Code",
|
|
109370
109681
|
detected: false,
|
|
109371
109682
|
installed: false,
|
|
109372
109683
|
alreadyInstalled: false
|
|
109373
109684
|
};
|
|
109374
|
-
|
|
109375
|
-
|
|
109376
|
-
|
|
109685
|
+
if (mode === "off") return result;
|
|
109686
|
+
if (mode === "auto") {
|
|
109687
|
+
const hasClaudeDir = await pathExists(GLOBAL_CLAUDE_DIR);
|
|
109688
|
+
const hasClaudeEnv = Object.keys(process.env).some((k) => k.startsWith("CLAUDE_"));
|
|
109689
|
+
if (!hasClaudeDir && !hasClaudeEnv) return result;
|
|
109690
|
+
}
|
|
109377
109691
|
result.detected = true;
|
|
109378
109692
|
const claudePaths = getClaudePaths(cwd);
|
|
109379
109693
|
try {
|
|
@@ -109393,17 +109707,20 @@ var SetupAutoHandler = class extends BaseCommand {
|
|
|
109393
109707
|
}
|
|
109394
109708
|
return result;
|
|
109395
109709
|
}
|
|
109396
|
-
async setupCodexIfDetected(cwd) {
|
|
109710
|
+
async setupCodexIfDetected(cwd, mode) {
|
|
109397
109711
|
const result = {
|
|
109398
109712
|
name: "Codex/AGENTS.md",
|
|
109399
109713
|
detected: false,
|
|
109400
109714
|
installed: false,
|
|
109401
109715
|
alreadyInstalled: false
|
|
109402
109716
|
};
|
|
109717
|
+
if (mode === "off") return result;
|
|
109403
109718
|
const agentsPath = getAgentsMdPath(cwd);
|
|
109404
109719
|
const hasAgentsMd = await pathExists(agentsPath);
|
|
109405
|
-
|
|
109406
|
-
|
|
109720
|
+
if (mode === "auto") {
|
|
109721
|
+
const hasCodexEnv = Object.keys(process.env).some((k) => k.startsWith("CODEX_"));
|
|
109722
|
+
if (!hasAgentsMd && !hasCodexEnv) return result;
|
|
109723
|
+
}
|
|
109407
109724
|
result.detected = true;
|
|
109408
109725
|
if (hasAgentsMd) {
|
|
109409
109726
|
if ((await readFile(agentsPath, "utf-8")).includes("BEGIN TBD INTEGRATION")) result.alreadyInstalled = true;
|
|
@@ -109414,12 +109731,13 @@ var SetupAutoHandler = class extends BaseCommand {
|
|
|
109414
109731
|
await handler.run({});
|
|
109415
109732
|
result.installed = true;
|
|
109416
109733
|
} catch (error) {
|
|
109734
|
+
if (error instanceof CLIError) throw error;
|
|
109417
109735
|
result.error = error.message;
|
|
109418
109736
|
}
|
|
109419
109737
|
return result;
|
|
109420
109738
|
}
|
|
109421
109739
|
};
|
|
109422
|
-
const setupCommand = new Command("setup").description("Configure tbd integration with editors and tools").option("--auto", "Non-interactive mode with smart defaults (for agents/scripts)").option("--interactive", "Interactive mode with prompts (for humans)").option("--from-beads", "Migrate from Beads to tbd").option("--prefix <name>", "Project prefix for issue IDs (required for fresh setup)").option("--force", "Allow non-recommended prefix format (not 2-8 alphabetic)").option("--no-gh-cli", "Disable automatic GitHub CLI installation hook").action(async (options, command) => {
|
|
109740
|
+
const setupCommand = new Command("setup").description("Configure tbd integration with editors and tools").option("--auto", "Non-interactive mode with smart defaults (for agents/scripts)").option("--interactive", "Interactive mode with prompts (for humans)").option("--from-beads", "Migrate from Beads to tbd").option("--prefix <name>", "Project prefix for issue IDs (required for fresh setup)").option("--force", "Allow non-recommended prefix format (not 2-8 alphabetic)").option("--no-gh-cli", "Disable automatic GitHub CLI installation hook").option("--all", "Install every supported agent surface (Claude + Codex)").option("--claude", "Install the Claude Code surface (skill mirror + hooks)").option("--codex", "Install the Codex surface (AGENTS.md block + .codex hooks)").option("--skip-claude", "Skip the Claude Code surface even if detected").option("--skip-codex", "Skip the Codex surface even if detected").action(async (options, command) => {
|
|
109423
109741
|
if (options.auto || options.interactive) {
|
|
109424
109742
|
await new SetupDefaultHandler(command).run(options);
|
|
109425
109743
|
return;
|