@draht/coding-agent 2026.3.11-1 → 2026.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/bin/draht-tools.cjs +187 -32
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +2 -2
  5. package/dist/config.js.map +1 -1
  6. package/dist/core/package-manager.d.ts.map +1 -1
  7. package/dist/core/package-manager.js +1 -1
  8. package/dist/core/package-manager.js.map +1 -1
  9. package/dist/gsd/domain.d.ts +5 -1
  10. package/dist/gsd/domain.d.ts.map +1 -1
  11. package/dist/gsd/domain.js +71 -1
  12. package/dist/gsd/domain.js.map +1 -1
  13. package/dist/gsd/git.d.ts.map +1 -1
  14. package/dist/gsd/git.js +18 -0
  15. package/dist/gsd/git.js.map +1 -1
  16. package/dist/gsd/index.d.ts +1 -0
  17. package/dist/gsd/index.d.ts.map +1 -1
  18. package/dist/gsd/index.js.map +1 -1
  19. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  20. package/dist/modes/interactive/interactive-mode.js +2 -0
  21. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  22. package/dist/prompts/commands/execute-phase.md +2 -2
  23. package/dist/prompts/commands/fix.md +2 -2
  24. package/dist/prompts/commands/plan-phase.md +5 -1
  25. package/dist/prompts/commands/quick.md +5 -1
  26. package/dist/utils/changelog.d.ts +12 -0
  27. package/dist/utils/changelog.d.ts.map +1 -1
  28. package/dist/utils/changelog.js +25 -14
  29. package/dist/utils/changelog.js.map +1 -1
  30. package/dist/utils/notify.d.ts +12 -0
  31. package/dist/utils/notify.d.ts.map +1 -0
  32. package/dist/utils/notify.js +41 -0
  33. package/dist/utils/notify.js.map +1 -0
  34. package/examples/extensions/antigravity-image-gen.ts +5 -4
  35. package/examples/extensions/custom-provider-gitlab-duo/test.ts +2 -2
  36. package/examples/extensions/notify.ts +9 -2
  37. package/examples/extensions/preset.ts +2 -3
  38. package/examples/extensions/sandbox/index.ts +2 -3
  39. package/examples/extensions/tool-override.ts +2 -3
  40. package/package.json +4 -4
  41. package/prompts/commands/execute-phase.md +2 -2
  42. package/prompts/commands/fix.md +2 -2
  43. package/prompts/commands/plan-phase.md +5 -1
  44. package/prompts/commands/quick.md +5 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## [2026.3.14] - 2026-03-14
4
+
5
+ ### Added
6
+
7
+ - built-in terminal notification on agent turn end
8
+
9
+ ### Changed
10
+
11
+ - fix(coding-agent): use getAgentDir() in example extensions (#2009)
12
+ - Export the structured mapping contract through the public GSD entrypoint
13
+ - Add typed extraction results to GSD domain mapping
14
+ - consolidate quality gate fixture helpers
15
+ - Cover strict-mode TypeScript error detection
16
+ - add TypeScript-error quality gate scenario
17
+ - Cover passing and failing test-suite outcomes
18
+ - add failing test-suite quality gate scenario
19
+ - Create a real-hook quality gate test harness
20
+ - add real quality gate hook harness test
21
+ - verify phase 21 lifecycle execution logs
22
+ - add failing phase 21 execution log verification test
23
+ - exercise phase 21 lifecycle task commit flow
24
+ - add failing phase 21 lifecycle commit flow test
25
+ - define mapCodebase structured extraction contract
26
+ - build phase 21 lifecycle workspace fixture
27
+ - add failing phase 21 lifecycle fixture test
28
+ - reduce duplicated domain fixture assertions
29
+ - Create a stable domain fixture codebase
30
+ - replace gsd structure checks with runtime loading coverage
31
+ - specify stable GSD domain fixture exports
32
+ - add gsd extension runtime loading spec
33
+ - extract reusable temp git repo setup steps
34
+ - Implement the shared git repo helper
35
+ - specify isolated temp git repo helper behavior
36
+
37
+ ### Fixed
38
+
39
+ - add stdin support to all draht-tools write commands
40
+ - add cmux support to notify example extension
41
+ - add stdin support to create-quick-plan and fix plan prompts to pipe actual content
42
+ - use conventional commit prefixes instead of TDD annotations in prompt templates
43
+ - restore phase 21 verification baseline
44
+ - The draht-tools create-plan command now reads stdin content when piped
45
+ - handle date-based version suffixes in changelog parsing
46
+ - change default update instruction to bun add -g
47
+
3
48
  ## [2026.3.11] - 2026-03-11
4
49
 
5
50
  ### Added
@@ -305,7 +305,8 @@ commands["phase-info"] = function (n) {
305
305
  };
306
306
 
307
307
  // --- save-context ---
308
- commands["save-context"] = function (n, ...rest) {
308
+ // Supports stdin: echo "content" | draht-tools save-context N
309
+ commands["save-context"] = async function (n, ...rest) {
309
310
  const num = parseInt(n, 10);
310
311
  if (!num) { console.error("Usage: draht-tools save-context N"); process.exit(1); }
311
312
 
@@ -314,7 +315,22 @@ commands["save-context"] = function (n, ...rest) {
314
315
  ensureDir(dir);
315
316
 
316
317
  const contextPath = path.join(dir, `${padNum(num)}-CONTEXT.md`);
317
- if (fs.existsSync(contextPath)) {
318
+
319
+ // Check for stdin content (piped input)
320
+ let stdinContent = "";
321
+ if (!process.stdin.isTTY) {
322
+ stdinContent = await new Promise((resolve) => {
323
+ let data = "";
324
+ process.stdin.setEncoding("utf-8");
325
+ process.stdin.on("data", (chunk) => { data += chunk; });
326
+ process.stdin.on("end", () => { resolve(data.trim()); });
327
+ });
328
+ }
329
+
330
+ if (stdinContent) {
331
+ writeMd(contextPath, stdinContent);
332
+ console.log(`Created: ${contextPath}`);
333
+ } else if (fs.existsSync(contextPath)) {
318
334
  console.log(`Context already exists at ${contextPath}`);
319
335
  console.log("Edit it directly or pass content via stdin.");
320
336
  } else {
@@ -372,7 +388,8 @@ commands["load-phase-context"] = function (n) {
372
388
  };
373
389
 
374
390
  // --- create-plan ---
375
- commands["create-plan"] = function (n, p, ...titleWords) {
391
+ // Supports stdin: echo "content" | draht-tools create-plan N P [title]
392
+ commands["create-plan"] = async function (n, p, ...titleWords) {
376
393
  const phaseNum = parseInt(n, 10);
377
394
  const planNum = parseInt(p, 10);
378
395
  if (!phaseNum || !planNum) { console.error("Usage: draht-tools create-plan N P [title]"); process.exit(1); }
@@ -384,7 +401,24 @@ commands["create-plan"] = function (n, p, ...titleWords) {
384
401
  const title = titleWords.join(" ") || `Plan ${planNum}`;
385
402
  const planPath = path.join(dir, `${padNum(phaseNum)}-${padNum(planNum)}-PLAN.md`);
386
403
 
387
- const tmpl = `---
404
+ // Check for stdin content (piped input)
405
+ let stdinContent = "";
406
+ if (!process.stdin.isTTY) {
407
+ stdinContent = await new Promise((resolve) => {
408
+ let data = "";
409
+ process.stdin.setEncoding("utf-8");
410
+ process.stdin.on("data", (chunk) => { data += chunk; });
411
+ process.stdin.on("end", () => { resolve(data.trim()); });
412
+ });
413
+ }
414
+
415
+ let content;
416
+ if (stdinContent) {
417
+ // Use stdin content directly
418
+ content = stdinContent;
419
+ } else {
420
+ // Generate template
421
+ content = `---
388
422
  phase: ${phaseNum}
389
423
  plan: ${planNum}
390
424
  depends_on: []
@@ -417,7 +451,9 @@ must_haves:
417
451
  ---
418
452
  Created: ${timestamp()}
419
453
  `;
420
- writeMd(planPath, tmpl);
454
+ }
455
+
456
+ writeMd(planPath, content);
421
457
  console.log(`Created: ${planPath}`);
422
458
  };
423
459
 
@@ -547,7 +583,8 @@ commands["commit-task"] = function (n, p, t, ...desc) {
547
583
  };
548
584
 
549
585
  // --- write-summary ---
550
- commands["write-summary"] = function (n, p) {
586
+ // Supports stdin: echo "content" | draht-tools write-summary N P
587
+ commands["write-summary"] = async function (n, p) {
551
588
  const phaseNum = parseInt(n, 10);
552
589
  const planNum = parseInt(p, 10);
553
590
  if (!phaseNum || !planNum) { console.error("Usage: draht-tools write-summary N P"); process.exit(1); }
@@ -556,8 +593,26 @@ commands["write-summary"] = function (n, p) {
556
593
  if (!phaseDir) { console.error(`Phase ${phaseNum} not found`); process.exit(1); }
557
594
 
558
595
  const summaryPath = path.join(phaseDir, `${padNum(phaseNum)}-${padNum(planNum)}-SUMMARY.md`);
559
- const tmpl = `# Phase ${phaseNum}, Plan ${planNum} Summary\n\n## Completed Tasks\n| # | Task | Status | Commit |\n|---|------|--------|--------|\n| 1 | [task] | ✅ Done | [hash] |\n\n## Files Changed\n- [files]\n\n## Verification Results\n- [results]\n\n## Notes\n[deviations, decisions]\n\n---\nCompleted: ${timestamp()}\n`;
560
- writeMd(summaryPath, tmpl);
596
+
597
+ // Check for stdin content (piped input)
598
+ let stdinContent = "";
599
+ if (!process.stdin.isTTY) {
600
+ stdinContent = await new Promise((resolve) => {
601
+ let data = "";
602
+ process.stdin.setEncoding("utf-8");
603
+ process.stdin.on("data", (chunk) => { data += chunk; });
604
+ process.stdin.on("end", () => { resolve(data.trim()); });
605
+ });
606
+ }
607
+
608
+ let content;
609
+ if (stdinContent) {
610
+ content = stdinContent;
611
+ } else {
612
+ content = `# Phase ${phaseNum}, Plan ${planNum} Summary\n\n## Completed Tasks\n| # | Task | Status | Commit |\n|---|------|--------|--------|\n| 1 | [task] | ✅ Done | [hash] |\n\n## Files Changed\n- [files]\n\n## Verification Results\n- [results]\n\n## Notes\n[deviations, decisions]\n\n---\nCompleted: ${timestamp()}\n`;
613
+ }
614
+
615
+ writeMd(summaryPath, content);
561
616
  console.log(`Created: ${summaryPath}`);
562
617
  };
563
618
 
@@ -628,17 +683,35 @@ commands["extract-deliverables"] = function (n) {
628
683
  };
629
684
 
630
685
  // --- create-fix-plan ---
631
- commands["create-fix-plan"] = function (n, p, ...issueWords) {
686
+ // Supports stdin: echo "content" | draht-tools create-fix-plan N P [issue]
687
+ commands["create-fix-plan"] = async function (n, p, ...issueWords) {
632
688
  const phaseNum = parseInt(n, 10);
633
689
  const planNum = parseInt(p, 10);
634
690
  if (!phaseNum || !planNum) { console.error("Usage: draht-tools create-fix-plan N P [issue]"); process.exit(1); }
635
691
 
636
692
  const slug = getPhaseSlug(phaseNum) || `phase-${phaseNum}`;
637
693
  const dir = planningPath("phases", `${padNum(phaseNum)}-${slug}`);
694
+ ensureDir(dir);
638
695
  const issue = issueWords.join(" ") || "Fix identified issues";
639
696
 
640
697
  const fixPath = path.join(dir, `${padNum(phaseNum)}-${padNum(planNum)}-FIX-PLAN.md`);
641
- const tmpl = `---
698
+
699
+ // Check for stdin content (piped input)
700
+ let stdinContent = "";
701
+ if (!process.stdin.isTTY) {
702
+ stdinContent = await new Promise((resolve) => {
703
+ let data = "";
704
+ process.stdin.setEncoding("utf-8");
705
+ process.stdin.on("data", (chunk) => { data += chunk; });
706
+ process.stdin.on("end", () => { resolve(data.trim()); });
707
+ });
708
+ }
709
+
710
+ let content;
711
+ if (stdinContent) {
712
+ content = stdinContent;
713
+ } else {
714
+ content = `---
642
715
  gap_closure: true
643
716
  fixes_plan: ${planNum}
644
717
  issue: "${issue}"
@@ -662,12 +735,15 @@ ${issue}
662
735
  ---
663
736
  Created: ${timestamp()}
664
737
  `;
665
- writeMd(fixPath, tmpl);
738
+ }
739
+
740
+ writeMd(fixPath, content);
666
741
  console.log(`Created: ${fixPath}`);
667
742
  };
668
743
 
669
744
  // --- write-uat ---
670
- commands["write-uat"] = function (n) {
745
+ // Supports stdin: echo "content" | draht-tools write-uat N
746
+ commands["write-uat"] = async function (n) {
671
747
  const num = parseInt(n, 10);
672
748
  if (!num) { console.error("Usage: draht-tools write-uat N"); process.exit(1); }
673
749
 
@@ -675,8 +751,26 @@ commands["write-uat"] = function (n) {
675
751
  if (!phaseDir) { console.error(`Phase ${num} not found`); process.exit(1); }
676
752
 
677
753
  const uatPath = path.join(phaseDir, `${padNum(num)}-UAT.md`);
678
- const tmpl = `# Phase ${num} User Acceptance Testing\n\n## Test Date: ${dateStamp()}\n\n## Results\n| # | Deliverable | Status | Notes |\n|---|-------------|--------|-------|\n| 1 | [description] | ✅ Pass | |\n\n## Summary\n- Passed: X/Y\n- Failed: 0/Y\n- Skipped: 0/Y\n\n## Fix Plans Created\n(none)\n`;
679
- writeMd(uatPath, tmpl);
754
+
755
+ // Check for stdin content (piped input)
756
+ let stdinContent = "";
757
+ if (!process.stdin.isTTY) {
758
+ stdinContent = await new Promise((resolve) => {
759
+ let data = "";
760
+ process.stdin.setEncoding("utf-8");
761
+ process.stdin.on("data", (chunk) => { data += chunk; });
762
+ process.stdin.on("end", () => { resolve(data.trim()); });
763
+ });
764
+ }
765
+
766
+ let content;
767
+ if (stdinContent) {
768
+ content = stdinContent;
769
+ } else {
770
+ content = `# Phase ${num} User Acceptance Testing\n\n## Test Date: ${dateStamp()}\n\n## Results\n| # | Deliverable | Status | Notes |\n|---|-------------|--------|-------|\n| 1 | [description] | ✅ Pass | |\n\n## Summary\n- Passed: X/Y\n- Failed: 0/Y\n- Skipped: 0/Y\n\n## Fix Plans Created\n(none)\n`;
771
+ }
772
+
773
+ writeMd(uatPath, content);
680
774
  console.log(`Created: ${uatPath}`);
681
775
  };
682
776
 
@@ -691,7 +785,8 @@ commands["next-quick-number"] = function () {
691
785
  };
692
786
 
693
787
  // --- create-quick-plan ---
694
- commands["create-quick-plan"] = function (n, ...descWords) {
788
+ // Supports stdin: echo "content" | draht-tools create-quick-plan NNN [desc]
789
+ commands["create-quick-plan"] = async function (n, ...descWords) {
695
790
  const num = padNum(parseInt(n, 10), 3);
696
791
  const desc = descWords.join(" ") || "Quick task";
697
792
  const slug = slugify(desc);
@@ -699,13 +794,34 @@ commands["create-quick-plan"] = function (n, ...descWords) {
699
794
  ensureDir(dir);
700
795
 
701
796
  const planPath = path.join(dir, `${num}-PLAN.md`);
702
- const tmpl = `# Quick Task ${num}: ${desc}\n\n## Tasks\n\n<task type="auto">\n <n>[Task]</n>\n <files>[files]</files>\n <action>[instructions]</action>\n <verify>[verify]</verify>\n <done>[done]</done>\n</task>\n\n---\nCreated: ${timestamp()}\n`;
703
- writeMd(planPath, tmpl);
797
+
798
+ // Check for stdin content (piped input)
799
+ let stdinContent = "";
800
+ if (!process.stdin.isTTY) {
801
+ stdinContent = await new Promise((resolve) => {
802
+ let data = "";
803
+ process.stdin.setEncoding("utf-8");
804
+ process.stdin.on("data", (chunk) => { data += chunk; });
805
+ process.stdin.on("end", () => { resolve(data.trim()); });
806
+ });
807
+ }
808
+
809
+ let content;
810
+ if (stdinContent) {
811
+ // Use stdin content directly
812
+ content = stdinContent;
813
+ } else {
814
+ // Generate template
815
+ content = `# Quick Task ${num}: ${desc}\n\n## Tasks\n\n<task type="auto">\n <n>[Task]</n>\n <files>[files]</files>\n <action>[instructions]</action>\n <verify>[verify]</verify>\n <done>[done]</done>\n</task>\n\n---\nCreated: ${timestamp()}\n`;
816
+ }
817
+
818
+ writeMd(planPath, content);
704
819
  console.log(`Created: ${planPath}`);
705
820
  };
706
821
 
707
822
  // --- write-quick-summary ---
708
- commands["write-quick-summary"] = function (n) {
823
+ // Supports stdin: echo "content" | draht-tools write-quick-summary NNN
824
+ commands["write-quick-summary"] = async function (n) {
709
825
  const num = padNum(parseInt(n, 10), 3);
710
826
  const dir = planningPath("quick");
711
827
  if (!fs.existsSync(dir)) { console.error("No quick tasks directory"); process.exit(1); }
@@ -713,8 +829,26 @@ commands["write-quick-summary"] = function (n) {
713
829
  if (!match) { console.error(`Quick task ${num} not found`); process.exit(1); }
714
830
 
715
831
  const summaryPath = path.join(dir, match, `${num}-SUMMARY.md`);
716
- const tmpl = `# Quick Task ${num} Summary\n\n## Tasks Completed\n| # | Task | Status | Commit |\n|---|------|--------|--------|\n| 1 | [task] | ✅ Done | [hash] |\n\n## Files Changed\n- [files]\n\n---\nCompleted: ${timestamp()}\n`;
717
- writeMd(summaryPath, tmpl);
832
+
833
+ // Check for stdin content (piped input)
834
+ let stdinContent = "";
835
+ if (!process.stdin.isTTY) {
836
+ stdinContent = await new Promise((resolve) => {
837
+ let data = "";
838
+ process.stdin.setEncoding("utf-8");
839
+ process.stdin.on("data", (chunk) => { data += chunk; });
840
+ process.stdin.on("end", () => { resolve(data.trim()); });
841
+ });
842
+ }
843
+
844
+ let content;
845
+ if (stdinContent) {
846
+ content = stdinContent;
847
+ } else {
848
+ content = `# Quick Task ${num} Summary\n\n## Tasks Completed\n| # | Task | Status | Commit |\n|---|------|--------|--------|\n| 1 | [task] | ✅ Done | [hash] |\n\n## Files Changed\n- [files]\n\n---\nCompleted: ${timestamp()}\n`;
849
+ }
850
+
851
+ writeMd(summaryPath, content);
718
852
  console.log(`Created: ${summaryPath}`);
719
853
  };
720
854
 
@@ -826,7 +960,8 @@ commands["commit-docs"] = function (...msg) {
826
960
  };
827
961
 
828
962
  // --- research-phase ---
829
- commands["research-phase"] = function (n) {
963
+ // Supports stdin: echo "content" | draht-tools research-phase N
964
+ commands["research-phase"] = async function (n) {
830
965
  const num = parseInt(n, 10);
831
966
  if (!num) { console.error("Usage: draht-tools research-phase N"); process.exit(1); }
832
967
 
@@ -835,10 +970,28 @@ commands["research-phase"] = function (n) {
835
970
  ensureDir(dir);
836
971
 
837
972
  const resPath = path.join(dir, `${padNum(num)}-RESEARCH.md`);
838
- const tmpl = `# Phase ${num} Research\n\nGenerated: ${timestamp()}\n\n## Best Practices\n[Fill in]\n\n## Patterns & Anti-Patterns\n[Fill in]\n\n## Library Recommendations\n[Fill in]\n\n## Edge Cases & Gotchas\n[Fill in]\n`;
839
- writeMd(resPath, tmpl);
973
+
974
+ // Check for stdin content (piped input)
975
+ let stdinContent = "";
976
+ if (!process.stdin.isTTY) {
977
+ stdinContent = await new Promise((resolve) => {
978
+ let data = "";
979
+ process.stdin.setEncoding("utf-8");
980
+ process.stdin.on("data", (chunk) => { data += chunk; });
981
+ process.stdin.on("end", () => { resolve(data.trim()); });
982
+ });
983
+ }
984
+
985
+ let content;
986
+ if (stdinContent) {
987
+ content = stdinContent;
988
+ } else {
989
+ content = `# Phase ${num} Research\n\nGenerated: ${timestamp()}\n\n## Best Practices\n[Fill in]\n\n## Patterns & Anti-Patterns\n[Fill in]\n\n## Library Recommendations\n[Fill in]\n\n## Edge Cases & Gotchas\n[Fill in]\n`;
990
+ }
991
+
992
+ writeMd(resPath, content);
840
993
  console.log(`Created: ${resPath}`);
841
- console.log("→ Fill in research findings, then plan the phase.");
994
+ if (!stdinContent) console.log("→ Fill in research findings, then plan the phase.");
842
995
  };
843
996
 
844
997
  // ============================================================================
@@ -902,11 +1055,13 @@ Version: 1.0.0
902
1055
  // Dispatch
903
1056
  const [cmd, ...args] = process.argv.slice(2);
904
1057
 
905
- if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
906
- commands.help();
907
- } else if (commands[cmd]) {
908
- commands[cmd](...args);
909
- } else {
910
- console.error(`Unknown command: ${cmd}\nRun: draht-tools help`);
911
- process.exit(1);
912
- }
1058
+ (async () => {
1059
+ if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
1060
+ commands.help();
1061
+ } else if (commands[cmd]) {
1062
+ await commands[cmd](...args);
1063
+ } else {
1064
+ console.error(`Unknown command: ${cmd}\nRun: draht-tools help`);
1065
+ process.exit(1);
1066
+ }
1067
+ })();
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,eAAO,MAAM,WAAW,SACqF,CAAC;AAE9G,gEAAgE;AAChE,eAAO,MAAM,YAAY,SAAyB,CAAC;AAMnD,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAEvF,wBAAgB,mBAAmB,IAAI,aAAa,CAqBnD;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAuBtC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAO7C;AAED,+BAA+B;AAC/B,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,iCAAiC;AACjC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,qCAAqC;AACrC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAQD,eAAO,MAAM,QAAQ,EAAE,MAAyC,CAAC;AACjE,eAAO,MAAM,eAAe,EAAE,MAA+C,CAAC;AAC9E,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAC5C,eAAO,MAAM,OAAO,EAAE,MAAwE,CAAC;AAE/F;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMvD;AAGD,eAAO,MAAM,aAAa,QAA+C,CAAC;AAI1E,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAMD,6DAA6D;AAC7D,wBAAgB,WAAW,IAAI,MAAM,CASpC;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,gCAAgC;AAChC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,kCAAkC;AAClC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAK3C;AAED,qCAAqC;AACrC,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,iCAAiC;AACjC,wBAAgB,eAAe,IAAI,MAAM,CAExC","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// =============================================================================\n// Package Detection\n// =============================================================================\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Detect if we're running as a Bun compiled binary.\n * Bun binaries have import.meta.url containing \"$bunfs\", \"~BUN\", or \"%7EBUN\" (Bun's virtual filesystem path)\n */\nexport const isBunBinary =\n\timport.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\n\n/** Detect if Bun is the runtime (compiled binary or bun run) */\nexport const isBunRuntime = !!process.versions.bun;\n\n// =============================================================================\n// Install Method Detection\n// =============================================================================\n\nexport type InstallMethod = \"bun-binary\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport function detectInstallMethod(): InstallMethod {\n\tif (isBunBinary) {\n\t\treturn \"bun-binary\";\n\t}\n\n\tconst resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase();\n\n\tif (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\") || resolvedPath.includes(\"\\\\pnpm\\\\\")) {\n\t\treturn \"pnpm\";\n\t}\n\tif (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\") || resolvedPath.includes(\"\\\\yarn\\\\\")) {\n\t\treturn \"yarn\";\n\t}\n\tif (isBunRuntime) {\n\t\treturn \"bun\";\n\t}\n\tif (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\") || resolvedPath.includes(\"\\\\npm\\\\\")) {\n\t\treturn \"npm\";\n\t}\n\n\treturn \"unknown\";\n}\n\nexport function getUpdateInstruction(packageName: string): string {\n\tconst method = detectInstallMethod();\n\tswitch (method) {\n\t\tcase \"bun-binary\":\n\t\t\treturn `Download from: https://github.com/draht-dev/draht/releases/latest`;\n\t\tcase \"pnpm\":\n\t\t\treturn `Run: pnpm install -g ${packageName}`;\n\t\tcase \"yarn\":\n\t\t\treturn `Run: yarn global add ${packageName}`;\n\t\tcase \"bun\":\n\t\t\treturn `Run: bun install -g ${packageName}`;\n\t\tcase \"npm\":\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t\tdefault:\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t}\n}\n\n// =============================================================================\n// Package Asset Paths (shipped with executable)\n// =============================================================================\n\n/**\n * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).\n * - For Bun binary: returns the directory containing the executable\n * - For Node.js (dist/): returns __dirname (the dist/ directory)\n * - For tsx (src/): returns parent directory (the package root)\n */\nexport function getPackageDir(): string {\n\t// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)\n\tconst envDir = process.env.DRAHT_PACKAGE_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\n\tif (isBunBinary) {\n\t\t// Bun binary: process.execPath points to the compiled executable\n\t\treturn dirname(process.execPath);\n\t}\n\t// Node.js: walk up from __dirname until we find package.json\n\tlet dir = __dirname;\n\twhile (dir !== dirname(dir)) {\n\t\tif (existsSync(join(dir, \"package.json\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\t// Fallback (shouldn't happen)\n\treturn __dirname;\n}\n\n/**\n * Get path to built-in themes directory (shipped with package)\n * - For Bun binary: theme/ next to executable\n * - For Node.js (dist/): dist/modes/interactive/theme/\n * - For tsx (src/): src/modes/interactive/theme/\n */\nexport function getThemesDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"theme\");\n\t}\n\t// Theme is in modes/interactive/theme/ relative to src/ or dist/\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\n\n/**\n * Get path to HTML export template directory (shipped with package)\n * - For Bun binary: export-html/ next to executable\n * - For Node.js (dist/): dist/core/export-html/\n * - For tsx (src/): src/core/export-html/\n */\nexport function getExportTemplateDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"export-html\");\n\t}\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"core\", \"export-html\");\n}\n\n/** Get path to package.json */\nexport function getPackageJsonPath(): string {\n\treturn join(getPackageDir(), \"package.json\");\n}\n\n/** Get path to README.md */\nexport function getReadmePath(): string {\n\treturn resolve(join(getPackageDir(), \"README.md\"));\n}\n\n/** Get path to docs directory */\nexport function getDocsPath(): string {\n\treturn resolve(join(getPackageDir(), \"docs\"));\n}\n\n/** Get path to examples directory */\nexport function getExamplesPath(): string {\n\treturn resolve(join(getPackageDir(), \"examples\"));\n}\n\n/** Get path to CHANGELOG.md */\nexport function getChangelogPath(): string {\n\treturn resolve(join(getPackageDir(), \"CHANGELOG.md\"));\n}\n\n// =============================================================================\n// App Config (from package.json drahtConfig)\n// =============================================================================\n\nconst pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n\nexport const APP_NAME: string = pkg.drahtConfig?.name || \"draht\";\nexport const CONFIG_DIR_NAME: string = pkg.drahtConfig?.configDir || \".draht\";\nexport const LEGACY_CONFIG_DIR_NAME = \".pi\";\nexport const VERSION: string = existsSync(join(getPackageDir(), \".dev\")) ? \"dev\" : pkg.version;\n\n/**\n * Resolve the project config directory. Prefers `CONFIG_DIR_NAME` (`.draht`),\n * falls back to `LEGACY_CONFIG_DIR_NAME` (`.pi`) if the primary doesn't exist\n * but the legacy one does.\n */\nexport function getProjectConfigDir(cwd: string): string {\n\tconst primary = join(cwd, CONFIG_DIR_NAME);\n\tif (existsSync(primary)) return primary;\n\tconst legacy = join(cwd, LEGACY_CONFIG_DIR_NAME);\n\tif (existsSync(legacy)) return legacy;\n\treturn primary; // default to primary even if it doesn't exist yet\n}\n\n// e.g., DRAHT_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR\nexport const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\n\nconst DEFAULT_SHARE_VIEWER_URL = \"https://draht.dev/session/\";\n\n/** Get the share viewer URL for a gist ID */\nexport function getShareViewerUrl(gistId: string): string {\n\tconst baseUrl = process.env.DRAHT_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n\treturn `${baseUrl}#${gistId}`;\n}\n\n// =============================================================================\n// User Config Paths (~/.draht/agent/*)\n// =============================================================================\n\n/** Get the agent config directory (e.g., ~/.draht/agent/) */\nexport function getAgentDir(): string {\n\tconst envDir = process.env[ENV_AGENT_DIR];\n\tif (envDir) {\n\t\t// Expand tilde to home directory\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\n/** Get path to user's custom themes directory */\nexport function getCustomThemesDir(): string {\n\treturn join(getAgentDir(), \"themes\");\n}\n\n/** Get path to models.json */\nexport function getModelsPath(): string {\n\treturn join(getAgentDir(), \"models.json\");\n}\n\n/** Get path to auth.json */\nexport function getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/** Get path to settings.json */\nexport function getSettingsPath(): string {\n\treturn join(getAgentDir(), \"settings.json\");\n}\n\n/** Get path to tools directory */\nexport function getToolsDir(): string {\n\treturn join(getAgentDir(), \"tools\");\n}\n\n/** Get path to managed binaries directory (fd, rg) */\nexport function getBinDir(): string {\n\treturn join(getAgentDir(), \"bin\");\n}\n\n/** Get path to prompt templates directory */\nexport function getPromptsDir(): string {\n\treturn join(getAgentDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped prompt templates (bundled with the package).\n * - For Bun binary: prompts/ next to executable\n * - For Node.js: prompts/ at package root\n */\nexport function getShippedPromptsDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"prompts\");\n\t}\n\treturn join(getPackageDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped hooks (bundled with the package).\n */\nexport function getShippedHooksDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"hooks\");\n\t}\n\treturn join(getPackageDir(), \"hooks\");\n}\n\n/** Get path to sessions directory */\nexport function getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\n/** Get path to debug log file */\nexport function getDebugLogPath(): string {\n\treturn join(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n"]}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,eAAO,MAAM,WAAW,SACqF,CAAC;AAE9G,gEAAgE;AAChE,eAAO,MAAM,YAAY,SAAyB,CAAC;AAMnD,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAEvF,wBAAgB,mBAAmB,IAAI,aAAa,CAqBnD;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAuBtC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAO7C;AAED,+BAA+B;AAC/B,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,iCAAiC;AACjC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,qCAAqC;AACrC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAQD,eAAO,MAAM,QAAQ,EAAE,MAAyC,CAAC;AACjE,eAAO,MAAM,eAAe,EAAE,MAA+C,CAAC;AAC9E,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAC5C,eAAO,MAAM,OAAO,EAAE,MAAwE,CAAC;AAE/F;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMvD;AAGD,eAAO,MAAM,aAAa,QAA+C,CAAC;AAI1E,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAMD,6DAA6D;AAC7D,wBAAgB,WAAW,IAAI,MAAM,CASpC;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,gCAAgC;AAChC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,kCAAkC;AAClC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAK3C;AAED,qCAAqC;AACrC,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,iCAAiC;AACjC,wBAAgB,eAAe,IAAI,MAAM,CAExC","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// =============================================================================\n// Package Detection\n// =============================================================================\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Detect if we're running as a Bun compiled binary.\n * Bun binaries have import.meta.url containing \"$bunfs\", \"~BUN\", or \"%7EBUN\" (Bun's virtual filesystem path)\n */\nexport const isBunBinary =\n\timport.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\n\n/** Detect if Bun is the runtime (compiled binary or bun run) */\nexport const isBunRuntime = !!process.versions.bun;\n\n// =============================================================================\n// Install Method Detection\n// =============================================================================\n\nexport type InstallMethod = \"bun-binary\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport function detectInstallMethod(): InstallMethod {\n\tif (isBunBinary) {\n\t\treturn \"bun-binary\";\n\t}\n\n\tconst resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase();\n\n\tif (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\") || resolvedPath.includes(\"\\\\pnpm\\\\\")) {\n\t\treturn \"pnpm\";\n\t}\n\tif (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\") || resolvedPath.includes(\"\\\\yarn\\\\\")) {\n\t\treturn \"yarn\";\n\t}\n\tif (isBunRuntime) {\n\t\treturn \"bun\";\n\t}\n\tif (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\") || resolvedPath.includes(\"\\\\npm\\\\\")) {\n\t\treturn \"npm\";\n\t}\n\n\treturn \"unknown\";\n}\n\nexport function getUpdateInstruction(packageName: string): string {\n\tconst method = detectInstallMethod();\n\tswitch (method) {\n\t\tcase \"bun-binary\":\n\t\t\treturn `Download from: https://github.com/draht-dev/draht/releases/latest`;\n\t\tcase \"pnpm\":\n\t\t\treturn `Run: pnpm install -g ${packageName}`;\n\t\tcase \"yarn\":\n\t\t\treturn `Run: yarn global add ${packageName}`;\n\t\tcase \"bun\":\n\t\t\treturn `Run: bun add -g ${packageName}`;\n\t\tcase \"npm\":\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t\tdefault:\n\t\t\treturn `Run: bun add -g ${packageName}`;\n\t}\n}\n\n// =============================================================================\n// Package Asset Paths (shipped with executable)\n// =============================================================================\n\n/**\n * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).\n * - For Bun binary: returns the directory containing the executable\n * - For Node.js (dist/): returns __dirname (the dist/ directory)\n * - For tsx (src/): returns parent directory (the package root)\n */\nexport function getPackageDir(): string {\n\t// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)\n\tconst envDir = process.env.DRAHT_PACKAGE_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\n\tif (isBunBinary) {\n\t\t// Bun binary: process.execPath points to the compiled executable\n\t\treturn dirname(process.execPath);\n\t}\n\t// Node.js: walk up from __dirname until we find package.json\n\tlet dir = __dirname;\n\twhile (dir !== dirname(dir)) {\n\t\tif (existsSync(join(dir, \"package.json\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\t// Fallback (shouldn't happen)\n\treturn __dirname;\n}\n\n/**\n * Get path to built-in themes directory (shipped with package)\n * - For Bun binary: theme/ next to executable\n * - For Node.js (dist/): dist/modes/interactive/theme/\n * - For tsx (src/): src/modes/interactive/theme/\n */\nexport function getThemesDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"theme\");\n\t}\n\t// Theme is in modes/interactive/theme/ relative to src/ or dist/\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\n\n/**\n * Get path to HTML export template directory (shipped with package)\n * - For Bun binary: export-html/ next to executable\n * - For Node.js (dist/): dist/core/export-html/\n * - For tsx (src/): src/core/export-html/\n */\nexport function getExportTemplateDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"export-html\");\n\t}\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"core\", \"export-html\");\n}\n\n/** Get path to package.json */\nexport function getPackageJsonPath(): string {\n\treturn join(getPackageDir(), \"package.json\");\n}\n\n/** Get path to README.md */\nexport function getReadmePath(): string {\n\treturn resolve(join(getPackageDir(), \"README.md\"));\n}\n\n/** Get path to docs directory */\nexport function getDocsPath(): string {\n\treturn resolve(join(getPackageDir(), \"docs\"));\n}\n\n/** Get path to examples directory */\nexport function getExamplesPath(): string {\n\treturn resolve(join(getPackageDir(), \"examples\"));\n}\n\n/** Get path to CHANGELOG.md */\nexport function getChangelogPath(): string {\n\treturn resolve(join(getPackageDir(), \"CHANGELOG.md\"));\n}\n\n// =============================================================================\n// App Config (from package.json drahtConfig)\n// =============================================================================\n\nconst pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n\nexport const APP_NAME: string = pkg.drahtConfig?.name || \"draht\";\nexport const CONFIG_DIR_NAME: string = pkg.drahtConfig?.configDir || \".draht\";\nexport const LEGACY_CONFIG_DIR_NAME = \".pi\";\nexport const VERSION: string = existsSync(join(getPackageDir(), \".dev\")) ? \"dev\" : pkg.version;\n\n/**\n * Resolve the project config directory. Prefers `CONFIG_DIR_NAME` (`.draht`),\n * falls back to `LEGACY_CONFIG_DIR_NAME` (`.pi`) if the primary doesn't exist\n * but the legacy one does.\n */\nexport function getProjectConfigDir(cwd: string): string {\n\tconst primary = join(cwd, CONFIG_DIR_NAME);\n\tif (existsSync(primary)) return primary;\n\tconst legacy = join(cwd, LEGACY_CONFIG_DIR_NAME);\n\tif (existsSync(legacy)) return legacy;\n\treturn primary; // default to primary even if it doesn't exist yet\n}\n\n// e.g., DRAHT_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR\nexport const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\n\nconst DEFAULT_SHARE_VIEWER_URL = \"https://draht.dev/session/\";\n\n/** Get the share viewer URL for a gist ID */\nexport function getShareViewerUrl(gistId: string): string {\n\tconst baseUrl = process.env.DRAHT_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n\treturn `${baseUrl}#${gistId}`;\n}\n\n// =============================================================================\n// User Config Paths (~/.draht/agent/*)\n// =============================================================================\n\n/** Get the agent config directory (e.g., ~/.draht/agent/) */\nexport function getAgentDir(): string {\n\tconst envDir = process.env[ENV_AGENT_DIR];\n\tif (envDir) {\n\t\t// Expand tilde to home directory\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\n/** Get path to user's custom themes directory */\nexport function getCustomThemesDir(): string {\n\treturn join(getAgentDir(), \"themes\");\n}\n\n/** Get path to models.json */\nexport function getModelsPath(): string {\n\treturn join(getAgentDir(), \"models.json\");\n}\n\n/** Get path to auth.json */\nexport function getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/** Get path to settings.json */\nexport function getSettingsPath(): string {\n\treturn join(getAgentDir(), \"settings.json\");\n}\n\n/** Get path to tools directory */\nexport function getToolsDir(): string {\n\treturn join(getAgentDir(), \"tools\");\n}\n\n/** Get path to managed binaries directory (fd, rg) */\nexport function getBinDir(): string {\n\treturn join(getAgentDir(), \"bin\");\n}\n\n/** Get path to prompt templates directory */\nexport function getPromptsDir(): string {\n\treturn join(getAgentDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped prompt templates (bundled with the package).\n * - For Bun binary: prompts/ next to executable\n * - For Node.js: prompts/ at package root\n */\nexport function getShippedPromptsDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"prompts\");\n\t}\n\treturn join(getPackageDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped hooks (bundled with the package).\n */\nexport function getShippedHooksDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"hooks\");\n\t}\n\treturn join(getPackageDir(), \"hooks\");\n}\n\n/** Get path to sessions directory */\nexport function getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\n/** Get path to debug log file */\nexport function getDebugLogPath(): string {\n\treturn join(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n"]}
package/dist/config.js CHANGED
@@ -43,11 +43,11 @@ export function getUpdateInstruction(packageName) {
43
43
  case "yarn":
44
44
  return `Run: yarn global add ${packageName}`;
45
45
  case "bun":
46
- return `Run: bun install -g ${packageName}`;
46
+ return `Run: bun add -g ${packageName}`;
47
47
  case "npm":
48
48
  return `Run: npm install -g ${packageName}`;
49
49
  default:
50
- return `Run: npm install -g ${packageName}`;
50
+ return `Run: bun add -g ${packageName}`;
51
51
  }
52
52
  }
53
53
  // =============================================================================
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// =============================================================================\n// Package Detection\n// =============================================================================\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Detect if we're running as a Bun compiled binary.\n * Bun binaries have import.meta.url containing \"$bunfs\", \"~BUN\", or \"%7EBUN\" (Bun's virtual filesystem path)\n */\nexport const isBunBinary =\n\timport.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\n\n/** Detect if Bun is the runtime (compiled binary or bun run) */\nexport const isBunRuntime = !!process.versions.bun;\n\n// =============================================================================\n// Install Method Detection\n// =============================================================================\n\nexport type InstallMethod = \"bun-binary\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport function detectInstallMethod(): InstallMethod {\n\tif (isBunBinary) {\n\t\treturn \"bun-binary\";\n\t}\n\n\tconst resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase();\n\n\tif (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\") || resolvedPath.includes(\"\\\\pnpm\\\\\")) {\n\t\treturn \"pnpm\";\n\t}\n\tif (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\") || resolvedPath.includes(\"\\\\yarn\\\\\")) {\n\t\treturn \"yarn\";\n\t}\n\tif (isBunRuntime) {\n\t\treturn \"bun\";\n\t}\n\tif (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\") || resolvedPath.includes(\"\\\\npm\\\\\")) {\n\t\treturn \"npm\";\n\t}\n\n\treturn \"unknown\";\n}\n\nexport function getUpdateInstruction(packageName: string): string {\n\tconst method = detectInstallMethod();\n\tswitch (method) {\n\t\tcase \"bun-binary\":\n\t\t\treturn `Download from: https://github.com/draht-dev/draht/releases/latest`;\n\t\tcase \"pnpm\":\n\t\t\treturn `Run: pnpm install -g ${packageName}`;\n\t\tcase \"yarn\":\n\t\t\treturn `Run: yarn global add ${packageName}`;\n\t\tcase \"bun\":\n\t\t\treturn `Run: bun install -g ${packageName}`;\n\t\tcase \"npm\":\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t\tdefault:\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t}\n}\n\n// =============================================================================\n// Package Asset Paths (shipped with executable)\n// =============================================================================\n\n/**\n * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).\n * - For Bun binary: returns the directory containing the executable\n * - For Node.js (dist/): returns __dirname (the dist/ directory)\n * - For tsx (src/): returns parent directory (the package root)\n */\nexport function getPackageDir(): string {\n\t// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)\n\tconst envDir = process.env.DRAHT_PACKAGE_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\n\tif (isBunBinary) {\n\t\t// Bun binary: process.execPath points to the compiled executable\n\t\treturn dirname(process.execPath);\n\t}\n\t// Node.js: walk up from __dirname until we find package.json\n\tlet dir = __dirname;\n\twhile (dir !== dirname(dir)) {\n\t\tif (existsSync(join(dir, \"package.json\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\t// Fallback (shouldn't happen)\n\treturn __dirname;\n}\n\n/**\n * Get path to built-in themes directory (shipped with package)\n * - For Bun binary: theme/ next to executable\n * - For Node.js (dist/): dist/modes/interactive/theme/\n * - For tsx (src/): src/modes/interactive/theme/\n */\nexport function getThemesDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"theme\");\n\t}\n\t// Theme is in modes/interactive/theme/ relative to src/ or dist/\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\n\n/**\n * Get path to HTML export template directory (shipped with package)\n * - For Bun binary: export-html/ next to executable\n * - For Node.js (dist/): dist/core/export-html/\n * - For tsx (src/): src/core/export-html/\n */\nexport function getExportTemplateDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"export-html\");\n\t}\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"core\", \"export-html\");\n}\n\n/** Get path to package.json */\nexport function getPackageJsonPath(): string {\n\treturn join(getPackageDir(), \"package.json\");\n}\n\n/** Get path to README.md */\nexport function getReadmePath(): string {\n\treturn resolve(join(getPackageDir(), \"README.md\"));\n}\n\n/** Get path to docs directory */\nexport function getDocsPath(): string {\n\treturn resolve(join(getPackageDir(), \"docs\"));\n}\n\n/** Get path to examples directory */\nexport function getExamplesPath(): string {\n\treturn resolve(join(getPackageDir(), \"examples\"));\n}\n\n/** Get path to CHANGELOG.md */\nexport function getChangelogPath(): string {\n\treturn resolve(join(getPackageDir(), \"CHANGELOG.md\"));\n}\n\n// =============================================================================\n// App Config (from package.json drahtConfig)\n// =============================================================================\n\nconst pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n\nexport const APP_NAME: string = pkg.drahtConfig?.name || \"draht\";\nexport const CONFIG_DIR_NAME: string = pkg.drahtConfig?.configDir || \".draht\";\nexport const LEGACY_CONFIG_DIR_NAME = \".pi\";\nexport const VERSION: string = existsSync(join(getPackageDir(), \".dev\")) ? \"dev\" : pkg.version;\n\n/**\n * Resolve the project config directory. Prefers `CONFIG_DIR_NAME` (`.draht`),\n * falls back to `LEGACY_CONFIG_DIR_NAME` (`.pi`) if the primary doesn't exist\n * but the legacy one does.\n */\nexport function getProjectConfigDir(cwd: string): string {\n\tconst primary = join(cwd, CONFIG_DIR_NAME);\n\tif (existsSync(primary)) return primary;\n\tconst legacy = join(cwd, LEGACY_CONFIG_DIR_NAME);\n\tif (existsSync(legacy)) return legacy;\n\treturn primary; // default to primary even if it doesn't exist yet\n}\n\n// e.g., DRAHT_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR\nexport const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\n\nconst DEFAULT_SHARE_VIEWER_URL = \"https://draht.dev/session/\";\n\n/** Get the share viewer URL for a gist ID */\nexport function getShareViewerUrl(gistId: string): string {\n\tconst baseUrl = process.env.DRAHT_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n\treturn `${baseUrl}#${gistId}`;\n}\n\n// =============================================================================\n// User Config Paths (~/.draht/agent/*)\n// =============================================================================\n\n/** Get the agent config directory (e.g., ~/.draht/agent/) */\nexport function getAgentDir(): string {\n\tconst envDir = process.env[ENV_AGENT_DIR];\n\tif (envDir) {\n\t\t// Expand tilde to home directory\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\n/** Get path to user's custom themes directory */\nexport function getCustomThemesDir(): string {\n\treturn join(getAgentDir(), \"themes\");\n}\n\n/** Get path to models.json */\nexport function getModelsPath(): string {\n\treturn join(getAgentDir(), \"models.json\");\n}\n\n/** Get path to auth.json */\nexport function getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/** Get path to settings.json */\nexport function getSettingsPath(): string {\n\treturn join(getAgentDir(), \"settings.json\");\n}\n\n/** Get path to tools directory */\nexport function getToolsDir(): string {\n\treturn join(getAgentDir(), \"tools\");\n}\n\n/** Get path to managed binaries directory (fd, rg) */\nexport function getBinDir(): string {\n\treturn join(getAgentDir(), \"bin\");\n}\n\n/** Get path to prompt templates directory */\nexport function getPromptsDir(): string {\n\treturn join(getAgentDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped prompt templates (bundled with the package).\n * - For Bun binary: prompts/ next to executable\n * - For Node.js: prompts/ at package root\n */\nexport function getShippedPromptsDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"prompts\");\n\t}\n\treturn join(getPackageDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped hooks (bundled with the package).\n */\nexport function getShippedHooksDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"hooks\");\n\t}\n\treturn join(getPackageDir(), \"hooks\");\n}\n\n/** Get path to sessions directory */\nexport function getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\n/** Get path to debug log file */\nexport function getDebugLogPath(): string {\n\treturn join(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GACvB,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAE9G,gEAAgE;AAChE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;AAQnD,MAAM,UAAU,mBAAmB,GAAkB;IACpD,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,MAAM,YAAY,GAAG,GAAG,SAAS,KAAK,OAAO,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC;IAE7E,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9G,OAAO,MAAM,CAAC;IACf,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9G,OAAO,MAAM,CAAC;IACf,CAAC;IACD,IAAI,YAAY,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACnH,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,oBAAoB,CAAC,WAAmB,EAAU;IACjE,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;IACrC,QAAQ,MAAM,EAAE,CAAC;QAChB,KAAK,YAAY;YAChB,OAAO,mEAAmE,CAAC;QAC5E,KAAK,MAAM;YACV,OAAO,wBAAwB,WAAW,EAAE,CAAC;QAC9C,KAAK,MAAM;YACV,OAAO,wBAAwB,WAAW,EAAE,CAAC;QAC9C,KAAK,KAAK;YACT,OAAO,mBAAmB,WAAW,EAAE,CAAC;QACzC,KAAK,KAAK;YACT,OAAO,uBAAuB,WAAW,EAAE,CAAC;QAC7C;YACC,OAAO,mBAAmB,WAAW,EAAE,CAAC;IAC1C,CAAC;AAAA,CACD;AAED,gFAAgF;AAChF,gDAAgD;AAChD,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,UAAU,aAAa,GAAW;IACvC,kGAAkG;IAClG,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC7C,IAAI,MAAM,EAAE,CAAC;QACZ,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,OAAO,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,MAAM,CAAC;IACf,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QACjB,iEAAiE;QACjE,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,6DAA6D;IAC7D,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,OAAO,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC3C,OAAO,GAAG,CAAC;QACZ,CAAC;QACD,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC;IACD,8BAA8B;IAC9B,OAAO,SAAS,CAAC;AAAA,CACjB;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,GAAW;IACtC,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IACD,iEAAiE;IACjE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACvE,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;AAAA,CACpE;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,GAAW;IAC9C,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACvE,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAAA,CAC1D;AAED,+BAA+B;AAC/B,MAAM,UAAU,kBAAkB,GAAW;IAC5C,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,cAAc,CAAC,CAAC;AAAA,CAC7C;AAED,4BAA4B;AAC5B,MAAM,UAAU,aAAa,GAAW;IACvC,OAAO,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;AAAA,CACnD;AAED,iCAAiC;AACjC,MAAM,UAAU,WAAW,GAAW;IACrC,OAAO,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;AAAA,CAC9C;AAED,qCAAqC;AACrC,MAAM,UAAU,eAAe,GAAW;IACzC,OAAO,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;AAAA,CAClD;AAED,+BAA+B;AAC/B,MAAM,UAAU,gBAAgB,GAAW;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;AAAA,CACtD;AAED,gFAAgF;AAChF,6CAA6C;AAC7C,gFAAgF;AAEhF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE,MAAM,CAAC,MAAM,QAAQ,GAAW,GAAG,CAAC,WAAW,EAAE,IAAI,IAAI,OAAO,CAAC;AACjE,MAAM,CAAC,MAAM,eAAe,GAAW,GAAG,CAAC,WAAW,EAAE,SAAS,IAAI,QAAQ,CAAC;AAC9E,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAC5C,MAAM,CAAC,MAAM,OAAO,GAAW,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAE/F;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAU;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAC3C,IAAI,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IACjD,IAAI,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,OAAO,CAAC,CAAC,kDAAkD;AAAnD,CACf;AAED,uDAAuD;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC;AAE1E,MAAM,wBAAwB,GAAG,4BAA4B,CAAC;AAE9D,6CAA6C;AAC7C,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAU;IACzD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,wBAAwB,CAAC;IAC/E,OAAO,GAAG,OAAO,IAAI,MAAM,EAAE,CAAC;AAAA,CAC9B;AAED,gFAAgF;AAChF,uCAAuC;AACvC,gFAAgF;AAEhF,6DAA6D;AAC7D,MAAM,UAAU,WAAW,GAAW;IACrC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC1C,IAAI,MAAM,EAAE,CAAC;QACZ,iCAAiC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,OAAO,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,MAAM,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;AAAA,CACjD;AAED,iDAAiD;AACjD,MAAM,UAAU,kBAAkB,GAAW;IAC5C,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAC;AAAA,CACrC;AAED,8BAA8B;AAC9B,MAAM,UAAU,aAAa,GAAW;IACvC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AAAA,CAC1C;AAED,4BAA4B;AAC5B,MAAM,UAAU,WAAW,GAAW;IACrC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,CAAC,CAAC;AAAA,CACxC;AAED,gCAAgC;AAChC,MAAM,UAAU,eAAe,GAAW;IACzC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC;AAAA,CAC5C;AAED,kCAAkC;AAClC,MAAM,UAAU,WAAW,GAAW;IACrC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;AAAA,CACpC;AAED,sDAAsD;AACtD,MAAM,UAAU,SAAS,GAAW;IACnC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;AAAA,CAClC;AAED,6CAA6C;AAC7C,MAAM,UAAU,aAAa,GAAW;IACvC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,CAAC,CAAC;AAAA,CACtC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,GAAW;IAC9C,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,SAAS,CAAC,CAAC;AAAA,CACxC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,GAAW;IAC5C,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;AAAA,CACtC;AAED,qCAAqC;AACrC,MAAM,UAAU,cAAc,GAAW;IACxC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,CACvC;AAED,iCAAiC;AACjC,MAAM,UAAU,eAAe,GAAW;IACzC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,QAAQ,YAAY,CAAC,CAAC;AAAA,CACpD","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// =============================================================================\n// Package Detection\n// =============================================================================\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Detect if we're running as a Bun compiled binary.\n * Bun binaries have import.meta.url containing \"$bunfs\", \"~BUN\", or \"%7EBUN\" (Bun's virtual filesystem path)\n */\nexport const isBunBinary =\n\timport.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\n\n/** Detect if Bun is the runtime (compiled binary or bun run) */\nexport const isBunRuntime = !!process.versions.bun;\n\n// =============================================================================\n// Install Method Detection\n// =============================================================================\n\nexport type InstallMethod = \"bun-binary\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport function detectInstallMethod(): InstallMethod {\n\tif (isBunBinary) {\n\t\treturn \"bun-binary\";\n\t}\n\n\tconst resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase();\n\n\tif (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\") || resolvedPath.includes(\"\\\\pnpm\\\\\")) {\n\t\treturn \"pnpm\";\n\t}\n\tif (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\") || resolvedPath.includes(\"\\\\yarn\\\\\")) {\n\t\treturn \"yarn\";\n\t}\n\tif (isBunRuntime) {\n\t\treturn \"bun\";\n\t}\n\tif (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\") || resolvedPath.includes(\"\\\\npm\\\\\")) {\n\t\treturn \"npm\";\n\t}\n\n\treturn \"unknown\";\n}\n\nexport function getUpdateInstruction(packageName: string): string {\n\tconst method = detectInstallMethod();\n\tswitch (method) {\n\t\tcase \"bun-binary\":\n\t\t\treturn `Download from: https://github.com/draht-dev/draht/releases/latest`;\n\t\tcase \"pnpm\":\n\t\t\treturn `Run: pnpm install -g ${packageName}`;\n\t\tcase \"yarn\":\n\t\t\treturn `Run: yarn global add ${packageName}`;\n\t\tcase \"bun\":\n\t\t\treturn `Run: bun add -g ${packageName}`;\n\t\tcase \"npm\":\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t\tdefault:\n\t\t\treturn `Run: bun add -g ${packageName}`;\n\t}\n}\n\n// =============================================================================\n// Package Asset Paths (shipped with executable)\n// =============================================================================\n\n/**\n * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).\n * - For Bun binary: returns the directory containing the executable\n * - For Node.js (dist/): returns __dirname (the dist/ directory)\n * - For tsx (src/): returns parent directory (the package root)\n */\nexport function getPackageDir(): string {\n\t// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)\n\tconst envDir = process.env.DRAHT_PACKAGE_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\n\tif (isBunBinary) {\n\t\t// Bun binary: process.execPath points to the compiled executable\n\t\treturn dirname(process.execPath);\n\t}\n\t// Node.js: walk up from __dirname until we find package.json\n\tlet dir = __dirname;\n\twhile (dir !== dirname(dir)) {\n\t\tif (existsSync(join(dir, \"package.json\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\t// Fallback (shouldn't happen)\n\treturn __dirname;\n}\n\n/**\n * Get path to built-in themes directory (shipped with package)\n * - For Bun binary: theme/ next to executable\n * - For Node.js (dist/): dist/modes/interactive/theme/\n * - For tsx (src/): src/modes/interactive/theme/\n */\nexport function getThemesDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"theme\");\n\t}\n\t// Theme is in modes/interactive/theme/ relative to src/ or dist/\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\n\n/**\n * Get path to HTML export template directory (shipped with package)\n * - For Bun binary: export-html/ next to executable\n * - For Node.js (dist/): dist/core/export-html/\n * - For tsx (src/): src/core/export-html/\n */\nexport function getExportTemplateDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"export-html\");\n\t}\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"core\", \"export-html\");\n}\n\n/** Get path to package.json */\nexport function getPackageJsonPath(): string {\n\treturn join(getPackageDir(), \"package.json\");\n}\n\n/** Get path to README.md */\nexport function getReadmePath(): string {\n\treturn resolve(join(getPackageDir(), \"README.md\"));\n}\n\n/** Get path to docs directory */\nexport function getDocsPath(): string {\n\treturn resolve(join(getPackageDir(), \"docs\"));\n}\n\n/** Get path to examples directory */\nexport function getExamplesPath(): string {\n\treturn resolve(join(getPackageDir(), \"examples\"));\n}\n\n/** Get path to CHANGELOG.md */\nexport function getChangelogPath(): string {\n\treturn resolve(join(getPackageDir(), \"CHANGELOG.md\"));\n}\n\n// =============================================================================\n// App Config (from package.json drahtConfig)\n// =============================================================================\n\nconst pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n\nexport const APP_NAME: string = pkg.drahtConfig?.name || \"draht\";\nexport const CONFIG_DIR_NAME: string = pkg.drahtConfig?.configDir || \".draht\";\nexport const LEGACY_CONFIG_DIR_NAME = \".pi\";\nexport const VERSION: string = existsSync(join(getPackageDir(), \".dev\")) ? \"dev\" : pkg.version;\n\n/**\n * Resolve the project config directory. Prefers `CONFIG_DIR_NAME` (`.draht`),\n * falls back to `LEGACY_CONFIG_DIR_NAME` (`.pi`) if the primary doesn't exist\n * but the legacy one does.\n */\nexport function getProjectConfigDir(cwd: string): string {\n\tconst primary = join(cwd, CONFIG_DIR_NAME);\n\tif (existsSync(primary)) return primary;\n\tconst legacy = join(cwd, LEGACY_CONFIG_DIR_NAME);\n\tif (existsSync(legacy)) return legacy;\n\treturn primary; // default to primary even if it doesn't exist yet\n}\n\n// e.g., DRAHT_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR\nexport const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\n\nconst DEFAULT_SHARE_VIEWER_URL = \"https://draht.dev/session/\";\n\n/** Get the share viewer URL for a gist ID */\nexport function getShareViewerUrl(gistId: string): string {\n\tconst baseUrl = process.env.DRAHT_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n\treturn `${baseUrl}#${gistId}`;\n}\n\n// =============================================================================\n// User Config Paths (~/.draht/agent/*)\n// =============================================================================\n\n/** Get the agent config directory (e.g., ~/.draht/agent/) */\nexport function getAgentDir(): string {\n\tconst envDir = process.env[ENV_AGENT_DIR];\n\tif (envDir) {\n\t\t// Expand tilde to home directory\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\n/** Get path to user's custom themes directory */\nexport function getCustomThemesDir(): string {\n\treturn join(getAgentDir(), \"themes\");\n}\n\n/** Get path to models.json */\nexport function getModelsPath(): string {\n\treturn join(getAgentDir(), \"models.json\");\n}\n\n/** Get path to auth.json */\nexport function getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/** Get path to settings.json */\nexport function getSettingsPath(): string {\n\treturn join(getAgentDir(), \"settings.json\");\n}\n\n/** Get path to tools directory */\nexport function getToolsDir(): string {\n\treturn join(getAgentDir(), \"tools\");\n}\n\n/** Get path to managed binaries directory (fd, rg) */\nexport function getBinDir(): string {\n\treturn join(getAgentDir(), \"bin\");\n}\n\n/** Get path to prompt templates directory */\nexport function getPromptsDir(): string {\n\treturn join(getAgentDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped prompt templates (bundled with the package).\n * - For Bun binary: prompts/ next to executable\n * - For Node.js: prompts/ at package root\n */\nexport function getShippedPromptsDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"prompts\");\n\t}\n\treturn join(getPackageDir(), \"prompts\");\n}\n\n/**\n * Get path to shipped hooks (bundled with the package).\n */\nexport function getShippedHooksDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"hooks\");\n\t}\n\treturn join(getPackageDir(), \"hooks\");\n}\n\n/** Get path to sessions directory */\nexport function getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\n/** Get path to debug log file */\nexport function getDebugLogPath(): string {\n\treturn join(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n"]}