codehere 0.8.0 → 1.0.2

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 (119) hide show
  1. package/README.md +37 -184
  2. package/dist/application/use-cases/check-claimed-tests.js +81 -0
  3. package/dist/application/use-cases/detect-test-weakening.js +237 -0
  4. package/dist/application/use-cases/rerun-tests.js +329 -0
  5. package/dist/index.js +74 -1004
  6. package/dist/infrastructure/orchestration/artifacts-extractor.js +2 -265
  7. package/dist/presentation/cli/commands/check-command.js +251 -0
  8. package/dist/presentation/cli/commands/help-command.js +22 -286
  9. package/dist/ui.js +19 -438
  10. package/dist/utils/version.js +0 -12
  11. package/package.json +18 -27
  12. package/dist/application/use-cases/domain-trust.js +0 -110
  13. package/dist/application/use-cases/generate-final-report.js +0 -134
  14. package/dist/application/use-cases/generate-narration.js +0 -128
  15. package/dist/application/use-cases/generate-thread-title.js +0 -178
  16. package/dist/application/use-cases/narrator-prompt-template.js +0 -158
  17. package/dist/application/use-cases/thread-export.js +0 -155
  18. package/dist/application/use-cases/verify-claim.js +0 -274
  19. package/dist/application/use-cases/write-pass.js +0 -277
  20. package/dist/domain/entities/task.js +0 -61
  21. package/dist/domain/services/codebase-detector.js +0 -91
  22. package/dist/error-handler.js +0 -251
  23. package/dist/infrastructure/completion/bash-completion.js +0 -25
  24. package/dist/infrastructure/completion/fish-completion.js +0 -22
  25. package/dist/infrastructure/completion/zsh-completion.js +0 -30
  26. package/dist/infrastructure/config/config-manager.js +0 -173
  27. package/dist/infrastructure/config/product-context.js +0 -67
  28. package/dist/infrastructure/context/adapters/drawio-source.js +0 -157
  29. package/dist/infrastructure/context/adapters/figma-source.js +0 -163
  30. package/dist/infrastructure/context/adapters/github-issue-source.js +0 -159
  31. package/dist/infrastructure/context/adapters/linear-source.js +0 -190
  32. package/dist/infrastructure/context/context-resolver.js +0 -144
  33. package/dist/infrastructure/context/context-source.js +0 -114
  34. package/dist/infrastructure/context/oauth-flow.js +0 -207
  35. package/dist/infrastructure/context/oauth-store.js +0 -119
  36. package/dist/infrastructure/context/registry-bootstrap.js +0 -99
  37. package/dist/infrastructure/context/write-pass-resolver.js +0 -106
  38. package/dist/infrastructure/cost/budget-config.js +0 -113
  39. package/dist/infrastructure/cost/cost-router.js +0 -104
  40. package/dist/infrastructure/cost/spend-aggregator.js +0 -147
  41. package/dist/infrastructure/hooks/claude-sdk-hook.js +0 -888
  42. package/dist/infrastructure/hooks/hook-mode.js +0 -71
  43. package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +0 -43
  44. package/dist/infrastructure/hooks/pre-prompt-scan.js +0 -122
  45. package/dist/infrastructure/hooks/session-analyzer.js +0 -177
  46. package/dist/infrastructure/observability/execution-tracer.js +0 -227
  47. package/dist/infrastructure/orchestration/agent-adapter.js +0 -13
  48. package/dist/infrastructure/orchestration/agent-installer.js +0 -101
  49. package/dist/infrastructure/orchestration/agents-config-seed.js +0 -56
  50. package/dist/infrastructure/orchestration/aider-adapter.js +0 -447
  51. package/dist/infrastructure/orchestration/cassette-recorder.js +0 -120
  52. package/dist/infrastructure/orchestration/claude-code-adapter.js +0 -478
  53. package/dist/infrastructure/orchestration/codex-adapter.js +0 -538
  54. package/dist/infrastructure/orchestration/conductor-adapter.js +0 -377
  55. package/dist/infrastructure/orchestration/context-handoff.js +0 -144
  56. package/dist/infrastructure/orchestration/control/codex-control-surface.js +0 -99
  57. package/dist/infrastructure/orchestration/control/control-surface.js +0 -15
  58. package/dist/infrastructure/orchestration/failover-classifier.js +0 -151
  59. package/dist/infrastructure/orchestration/failover-config.js +0 -77
  60. package/dist/infrastructure/orchestration/failover-policy.js +0 -106
  61. package/dist/infrastructure/orchestration/gemini-adapter.js +0 -583
  62. package/dist/infrastructure/orchestration/generic-cli-adapter.js +0 -558
  63. package/dist/infrastructure/orchestration/graphify-context.js +0 -254
  64. package/dist/infrastructure/orchestration/memory-injector.js +0 -380
  65. package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +0 -233
  66. package/dist/infrastructure/orchestration/mocks/mock-codex-app-server.js +0 -73
  67. package/dist/infrastructure/orchestration/mocks/mock-synthesis.js +0 -83
  68. package/dist/infrastructure/orchestration/mocks/resolve-agent-spawn.js +0 -37
  69. package/dist/infrastructure/orchestration/opencode-adapter.js +0 -510
  70. package/dist/infrastructure/orchestration/progress-aggregator.js +0 -689
  71. package/dist/infrastructure/orchestration/readiness.js +0 -103
  72. package/dist/infrastructure/orchestration/session-manager.js +0 -1091
  73. package/dist/infrastructure/orchestration/session-persistence.js +0 -258
  74. package/dist/infrastructure/orchestration/thread-key-store.js +0 -127
  75. package/dist/infrastructure/orchestration/write-pass-store.js +0 -46
  76. package/dist/infrastructure/protocols/cloud-sync.js +0 -207
  77. package/dist/infrastructure/protocols/mcp-helpers.js +0 -25
  78. package/dist/infrastructure/protocols/mcp-server-impl.js +0 -2853
  79. package/dist/infrastructure/protocols/probe-port.js +0 -36
  80. package/dist/infrastructure/protocols/thread-phase.js +0 -105
  81. package/dist/infrastructure/protocols/ui-page-v2.js +0 -4418
  82. package/dist/infrastructure/protocols/ui-page.js +0 -2377
  83. package/dist/infrastructure/protocols/verify-page.js +0 -983
  84. package/dist/infrastructure/security/file-collection.js +0 -118
  85. package/dist/infrastructure/security/input-validator.js +0 -152
  86. package/dist/infrastructure/security/permissions-config.js +0 -234
  87. package/dist/infrastructure/security/trust-scorer.js +0 -657
  88. package/dist/infrastructure/storage/cross-tool-agents.js +0 -268
  89. package/dist/infrastructure/storage/embeddings-path.js +0 -37
  90. package/dist/infrastructure/storage/project-thread-migration.js +0 -237
  91. package/dist/infrastructure/storage/project-thread-mirror.js +0 -524
  92. package/dist/infrastructure/storage/project-thread-reader.js +0 -172
  93. package/dist/infrastructure/storage/project-thread-title-backfill.js +0 -214
  94. package/dist/infrastructure/storage/task-repository.js +0 -206
  95. package/dist/monitoring.js +0 -212
  96. package/dist/presentation/cli/commands/audit-command.js +0 -126
  97. package/dist/presentation/cli/commands/budget-command.js +0 -79
  98. package/dist/presentation/cli/commands/config-command.js +0 -125
  99. package/dist/presentation/cli/commands/context-source-command.js +0 -198
  100. package/dist/presentation/cli/commands/hook-command.js +0 -265
  101. package/dist/presentation/cli/commands/init-command.js +0 -578
  102. package/dist/presentation/cli/commands/memory-command.js +0 -1031
  103. package/dist/presentation/cli/commands/narrator-command.js +0 -101
  104. package/dist/presentation/cli/commands/permission-command.js +0 -116
  105. package/dist/presentation/cli/commands/protocols-builder.js +0 -254
  106. package/dist/presentation/cli/commands/protocols-command.js +0 -84
  107. package/dist/presentation/cli/commands/repo-map-builder.js +0 -247
  108. package/dist/presentation/cli/commands/report-command.js +0 -387
  109. package/dist/presentation/cli/commands/scan-tool-command.js +0 -94
  110. package/dist/presentation/cli/commands/setup-command.js +0 -307
  111. package/dist/presentation/cli/commands/status-command.js +0 -661
  112. package/dist/presentation/cli/commands/thread-command.js +0 -288
  113. package/dist/presentation/cli/commands/trust-command.js +0 -306
  114. package/dist/presentation/cli/commands/verify-command.js +0 -233
  115. package/dist/presentation/cli/error-display.js +0 -336
  116. package/dist/presentation/cli/repl.js +0 -797
  117. package/dist/presentation/cli/task-deliverable.js +0 -127
  118. package/dist/testing/cassette.js +0 -125
  119. package/dist/testing/replay-adapter.js +0 -166
@@ -1,126 +0,0 @@
1
- /**
2
- * CLI: `codehere audit`
3
- *
4
- * F-05 of the demo-v12 backlog · expose the hash-chained audit log verifier
5
- * + a "show" subcommand for forensic inspection. The chain is the source of
6
- * truth, NOT codehere itself · this command lets reviewers and CI verify it
7
- * without trusting our daemon.
8
- *
9
- * Subcommands:
10
- * codehere audit verify [--json] Walk the chain · report intact/tampered
11
- * + entry counts + every break point.
12
- * Exit 0 = valid, 1 = invalid.
13
- * codehere audit show <seq> [--json]
14
- * Print one entry by sequence number.
15
- *
16
- * Default audit file: ~/.codehere/audit/hook-events.jsonl
17
- * Override via CODEHERE_AUDIT_FILE env var (mirrors the hook's own resolution).
18
- */
19
- import { existsSync, readFileSync } from 'fs';
20
- import { colors, symbols } from '../../../ui.js';
21
- import { AUDIT_FILE, verifyAuditChain } from '../../../infrastructure/hooks/claude-sdk-hook.js';
22
- export function executeAuditCommand(sub, arg, options = {}) {
23
- if (!sub || sub === 'verify')
24
- return verify(options.json ?? false);
25
- if (sub === 'show')
26
- return show(arg, options.json ?? false);
27
- process.stderr.write(colors.error(`${symbols.error} Unknown audit subcommand: ${sub}\n`) +
28
- colors.dim('Try: codehere audit verify | codehere audit show <seq>\n'));
29
- return 2;
30
- }
31
- /* ──────────────────────────────────────────────────────────────────────── */
32
- /* verify · the F-05 headline */
33
- /* ──────────────────────────────────────────────────────────────────────── */
34
- function verify(json) {
35
- const result = verifyAuditChain(AUDIT_FILE);
36
- if (json) {
37
- process.stdout.write(JSON.stringify({
38
- path: AUDIT_FILE,
39
- valid: result.valid,
40
- totalEntries: result.totalEntries,
41
- chainedEntries: result.chainedEntries,
42
- legacyEntries: result.legacyEntries,
43
- errors: result.errors,
44
- }, null, 2) + '\n');
45
- return result.valid ? 0 : 1;
46
- }
47
- // Human output · header, verdict line, counts, then errors if any.
48
- process.stdout.write('\n' + colors.dim('audit log: ') + colors.gray(AUDIT_FILE) + '\n\n');
49
- if (result.totalEntries === 0) {
50
- process.stdout.write(colors.gray(`${symbols.dot} No audit entries yet.`) +
51
- colors.dim(' Install the hook first: ') +
52
- colors.bold('codehere hook install') +
53
- '\n\n');
54
- return 0;
55
- }
56
- if (result.valid) {
57
- process.stdout.write(colors.green(`${symbols.success} Chain intact`) +
58
- colors.dim(' every entry verified against its predecessor hash.') +
59
- '\n\n');
60
- }
61
- else {
62
- process.stdout.write(colors.error(`${symbols.error} Chain BROKEN`) +
63
- colors.dim(` ${result.errors.length} break point${result.errors.length === 1 ? '' : 's'} detected.`) +
64
- '\n\n');
65
- }
66
- process.stdout.write(colors.bold('Counts:\n'));
67
- process.stdout.write(` ${result.totalEntries.toString().padStart(6)} total entries\n`);
68
- process.stdout.write(` ${result.chainedEntries.toString().padStart(6)} hash-chained (verifiable)\n`);
69
- process.stdout.write(` ${result.legacyEntries.toString().padStart(6)} legacy pre-chain (un-verifiable)\n\n`);
70
- if (result.errors.length > 0) {
71
- process.stdout.write(colors.bold('Break points:\n'));
72
- for (const err of result.errors) {
73
- process.stdout.write(' ' +
74
- colors.error(`line ${err.lineNumber}`) +
75
- colors.dim(' ') +
76
- colors.gray(err.reason) +
77
- colors.dim(' ') +
78
- err.detail +
79
- '\n');
80
- }
81
- process.stdout.write('\n');
82
- }
83
- return result.valid ? 0 : 1;
84
- }
85
- function show(seqStr, json) {
86
- if (!seqStr || !/^\d+$/.test(seqStr)) {
87
- process.stderr.write(colors.error(`${symbols.error} Need a numeric sequence: codehere audit show <seq>\n`));
88
- return 2;
89
- }
90
- const target = parseInt(seqStr, 10);
91
- if (!existsSync(AUDIT_FILE)) {
92
- process.stderr.write(colors.gray(`${symbols.dot} No audit log yet.\n`));
93
- return 2;
94
- }
95
- const lines = readFileSync(AUDIT_FILE, 'utf-8').split('\n').filter(Boolean);
96
- for (const line of lines) {
97
- let entry;
98
- try {
99
- entry = JSON.parse(line);
100
- }
101
- catch {
102
- continue;
103
- }
104
- if (entry.seq !== target)
105
- continue;
106
- if (json) {
107
- process.stdout.write(JSON.stringify(entry, null, 2) + '\n');
108
- }
109
- else {
110
- process.stdout.write('\n' +
111
- colors.bold(`Entry #${target}`) +
112
- (entry.ts ? colors.dim(' ' + new Date(entry.ts).toISOString()) : '') +
113
- '\n\n');
114
- for (const [k, v] of Object.entries(entry)) {
115
- const val = typeof v === 'string' && v.length > 120 ? v.slice(0, 117) + '...' : JSON.stringify(v);
116
- process.stdout.write(` ${colors.dim(k.padEnd(12))} ${val}\n`);
117
- }
118
- process.stdout.write('\n');
119
- }
120
- return 0;
121
- }
122
- process.stderr.write(colors.error(`${symbols.error} No entry with seq=${target}.\n`) +
123
- colors.dim(' Tip: run `codehere audit verify` to see the chained-entry count.\n'));
124
- return 2;
125
- }
126
- //# sourceMappingURL=audit-command.js.map
@@ -1,79 +0,0 @@
1
- /**
2
- * `codehere budget` — read or set the daily-spend budget.
3
- *
4
- * Subcommands:
5
- * show — print current ceiling, today's spend, % used
6
- * set <usd> — set daily ceiling in USD (e.g. `codehere budget set 5`)
7
- * off — disable the budget (omits daily_usd from yaml)
8
- *
9
- * Reads + writes ~/.codehere/budget.yaml via budget-config.ts. Per
10
- * claim_user_persona HIGH the YAML is hand-editable; the CLI is the
11
- * fast path for users who want one number, one command.
12
- */
13
- import { loadBudget, saveBudget, budgetUsedPct, isOverBudget } from '../../../infrastructure/cost/budget-config.js';
14
- import { computeSpendToday } from '../../../infrastructure/cost/spend-aggregator.js';
15
- import { success, error, info, newline } from '../../../ui.js';
16
- export async function executeBudgetCommand(subcommand, value) {
17
- const sub = subcommand ?? 'show';
18
- switch (sub) {
19
- case 'show':
20
- return showBudget();
21
- case 'set':
22
- if (!value) {
23
- console.error(error('Usage:'), 'codehere budget set <amount-in-usd> e.g. codehere budget set 5');
24
- process.exit(1);
25
- }
26
- return setBudget(value);
27
- case 'off':
28
- return disableBudget();
29
- default:
30
- console.error(error('Unknown subcommand:'), sub);
31
- console.error(info('Try:'), 'codehere budget [show | set <usd> | off]');
32
- process.exit(1);
33
- }
34
- }
35
- function fmtUsd(n) {
36
- return n >= 0.01 ? `$${n.toFixed(2)}` : `$${n.toFixed(3)}`;
37
- }
38
- function showBudget() {
39
- const cfg = loadBudget();
40
- const spend = computeSpendToday();
41
- newline();
42
- console.log(info("Today's estimated spend:"), fmtUsd(spend.totalUsd), `(${spend.sessionCount} session${spend.sessionCount === 1 ? '' : 's'})`);
43
- if (cfg.dailyUsd === null) {
44
- console.log(info('Daily budget:'), 'none — no enforcement');
45
- console.log(info('Set one with:'), 'codehere budget set 5');
46
- }
47
- else {
48
- const pct = budgetUsedPct(spend.totalUsd, cfg) ?? 0;
49
- const over = isOverBudget(spend.totalUsd, cfg);
50
- console.log(info('Daily budget:'), fmtUsd(cfg.dailyUsd), `(${pct}% used)`);
51
- if (over) {
52
- console.log(error('Over budget.'), 'New spawns are blocked until midnight or the budget is raised.');
53
- }
54
- else if (pct >= cfg.warnAtPct) {
55
- console.log(info('Approaching limit.'), `Warn threshold is ${cfg.warnAtPct}%.`);
56
- }
57
- }
58
- newline();
59
- }
60
- function setBudget(value) {
61
- const n = Number(value.replace(/[$,]/g, ''));
62
- if (!Number.isFinite(n) || n <= 0) {
63
- console.error(error('Invalid amount:'), value, '— expected a positive USD number.');
64
- process.exit(1);
65
- }
66
- const cfg = loadBudget();
67
- cfg.dailyUsd = n;
68
- saveBudget(cfg);
69
- console.log(success('Daily budget set to'), fmtUsd(n));
70
- console.log(info("Spawns will be blocked once today's estimated spend reaches this amount."));
71
- console.log(info('Disable with:'), 'codehere budget off');
72
- }
73
- function disableBudget() {
74
- const cfg = loadBudget();
75
- cfg.dailyUsd = null;
76
- saveBudget(cfg);
77
- console.log(success('Daily budget disabled.'), 'No enforcement on spawns.');
78
- }
79
- //# sourceMappingURL=budget-command.js.map
@@ -1,125 +0,0 @@
1
- /**
2
- * Config Command
3
- * Manage Codehere configuration and preferences
4
- */
5
- import { colors, separator, newline, sectionHeader, success, error, createTable, isMinimalStyle } from '../../../ui.js';
6
- import { getConfigManager } from '../../../infrastructure/config/config-manager.js';
7
- import { executionTracer } from '../../../infrastructure/observability/execution-tracer.js';
8
- import { findCodebaseRoot } from '../../../domain/services/codebase-detector.js';
9
- /**
10
- * Display current configuration
11
- */
12
- function displayConfig(config) {
13
- sectionHeader('Current Configuration');
14
- const configRows = [
15
- ['Preference', 'Value'],
16
- ['Auto Commit', config.preferences.autoCommit ? 'Yes' : 'No'],
17
- ['Ask Before Destructive', config.preferences.askBeforeDestructive ? 'Yes' : 'No'],
18
- ['Cross-Team Learning', config.preferences.enableCrossTeamLearning ? 'Enabled' : 'Disabled'],
19
- ['Default Model', config.preferences.defaultModel || 'auto (detects from API key)'],
20
- ['Max Tokens', String(config.preferences.maxTokens || 4096)],
21
- ['Temperature', String(config.preferences.temperature || 0.3)],
22
- ['Streaming', config.preferences.enableStreaming ? 'Enabled' : 'Disabled'],
23
- ['Output Format', config.ui.outputFormat || 'full'],
24
- ['Show Progress', config.ui.showProgress ? 'Yes' : 'No'],
25
- ['Show Summary', config.ui.showSummary ? 'Yes' : 'No'],
26
- ];
27
- if (config.codebase.root) {
28
- configRows.push(['Codebase Root', config.codebase.root]);
29
- if (config.codebase.lastIndexed) {
30
- const date = new Date(config.codebase.lastIndexed);
31
- configRows.push(['Last Indexed', date.toLocaleString()]);
32
- }
33
- }
34
- const table = createTable(['Preference', 'Value'], configRows.slice(1));
35
- console.log(table.toString());
36
- newline();
37
- console.log(colors.dim(`Config file: ${getConfigManager().getConfigPath()}`));
38
- newline();
39
- }
40
- /**
41
- * Execute config command
42
- */
43
- export async function executeConfigCommand(action, key, value) {
44
- // Start execution tracing
45
- const codebaseInfo = findCodebaseRoot(process.cwd());
46
- executionTracer.startRun('config', {
47
- codebaseId: codebaseInfo?.rootPath || process.cwd(),
48
- });
49
- try {
50
- if (!isMinimalStyle()) {
51
- newline();
52
- console.log(separator('═', 80));
53
- console.log(colors.bold('Codehere - Configuration Manager'));
54
- console.log(separator('═', 80));
55
- newline();
56
- }
57
- const configManager = getConfigManager();
58
- const config = configManager.getAll();
59
- // No action - show current config
60
- if (!action || action === 'show' || action === 'list') {
61
- displayConfig(config);
62
- return;
63
- }
64
- // Get value
65
- if (action === 'get' && key) {
66
- const preference = configManager.getPreference(key);
67
- if (preference !== undefined) {
68
- console.log(preference);
69
- }
70
- else {
71
- console.error(error(`Preference '${key}' not found.`));
72
- process.exit(1);
73
- }
74
- return;
75
- }
76
- // Set value
77
- if (action === 'set' && key && value !== undefined) {
78
- try {
79
- // Parse value (boolean, number, or string)
80
- let parsedValue = value;
81
- if (value.toLowerCase() === 'true')
82
- parsedValue = true;
83
- else if (value.toLowerCase() === 'false')
84
- parsedValue = false;
85
- else if (!isNaN(Number(value)))
86
- parsedValue = Number(value);
87
- configManager.setPreference(key, parsedValue);
88
- configManager.saveConfig();
89
- console.log(success(`Set ${key} = ${parsedValue}`));
90
- }
91
- catch (err) {
92
- console.error(error(`Failed to set preference: ${err instanceof Error ? err.message : String(err)}`));
93
- process.exit(1);
94
- }
95
- return;
96
- }
97
- // Reset to defaults
98
- if (action === 'reset') {
99
- configManager.reset();
100
- console.log(success('Configuration reset to defaults'));
101
- newline();
102
- displayConfig(configManager.getAll());
103
- return;
104
- }
105
- // Invalid action
106
- console.error(error(`Unknown action: ${action}`));
107
- newline();
108
- console.log(colors.bold('Usage:'));
109
- console.log(colors.cyan(' codehere config Show current configuration'));
110
- console.log(colors.cyan(' codehere config get <key> Get a preference value'));
111
- console.log(colors.cyan(' codehere config set <key> <value> Set a preference value'));
112
- console.log(colors.cyan(' codehere config reset Reset to defaults'));
113
- newline();
114
- console.log(colors.bold('Examples:'));
115
- console.log(colors.dim(' codehere config set autoCommit true'));
116
- console.log(colors.dim(' codehere config set temperature 0.5'));
117
- console.log(colors.dim(' codehere config get defaultModel'));
118
- newline();
119
- process.exit(1);
120
- }
121
- finally {
122
- executionTracer.endRun();
123
- }
124
- }
125
- //# sourceMappingURL=config-command.js.map
@@ -1,198 +0,0 @@
1
- /**
2
- * CLI: `codehere context-source` · v0.8 S2.5
3
- *
4
- * Subcommands:
5
- * list · show every registered provider + connection status
6
- * connect <provider> · open the browser to begin OAuth · prints URL
7
- * disconnect <provider> · clear the stored OAuth token
8
- *
9
- * Talks to the running daemon at 127.0.0.1:3773. If the daemon isn't running,
10
- * we print a clear message rather than starting one silently.
11
- */
12
- import { colors, symbols } from '../../../ui.js';
13
- import { spawn } from 'child_process';
14
- const DAEMON_BASE = process.env.CODEHERE_DAEMON_URL || 'http://127.0.0.1:3773';
15
- export async function executeContextSourceCommand(sub, arg, options = {}) {
16
- switch (sub) {
17
- case undefined:
18
- case 'list':
19
- return list(options.json ?? false);
20
- case 'connect':
21
- return connect(arg, options.json ?? false, options.open !== false);
22
- case 'disconnect':
23
- return disconnect(arg, options.json ?? false);
24
- default:
25
- process.stderr.write(colors.error(`${symbols.error} Unknown subcommand: ${sub}\n`) +
26
- colors.dim('Try: codehere context-source list | connect <provider> | disconnect <provider>\n'));
27
- return 2;
28
- }
29
- }
30
- async function fetchJson(path, init = {}) {
31
- try {
32
- const r = await fetch(DAEMON_BASE + path, init);
33
- if (!r.ok) {
34
- const text = await r.text();
35
- return { ok: false, status: r.status, error: text };
36
- }
37
- return { ok: true, status: r.status, data: (await r.json()) };
38
- }
39
- catch (err) {
40
- return { ok: false, status: 0, error: err instanceof Error ? err.message : String(err) };
41
- }
42
- }
43
- function daemonUnreachableNote(err) {
44
- return (colors.error(`${symbols.error} Daemon not reachable at ${DAEMON_BASE}.\n`) +
45
- colors.dim(` Start it with: `) +
46
- colors.bold('codehere start') +
47
- '\n' +
48
- colors.dim(` Detail: ${err}\n`));
49
- }
50
- /* ──────────────────────────────────────────────────────────────────────── */
51
- /* list */
52
- /* ──────────────────────────────────────────────────────────────────────── */
53
- async function list(json) {
54
- const r = await fetchJson('/api/context-sources');
55
- if (!r.ok) {
56
- if (json) {
57
- process.stdout.write(JSON.stringify({ error: 'daemon_unreachable', detail: r.error }, null, 2) + '\n');
58
- }
59
- else {
60
- process.stderr.write(daemonUnreachableNote(r.error ?? ''));
61
- }
62
- return 2;
63
- }
64
- const items = r.data?.providers ?? [];
65
- if (json) {
66
- process.stdout.write(JSON.stringify({ providers: items }, null, 2) + '\n');
67
- return 0;
68
- }
69
- process.stdout.write('\n' + colors.bold('Context sources') + '\n\n');
70
- if (!items.length) {
71
- process.stdout.write(colors.dim(' (no providers registered)\n\n'));
72
- return 0;
73
- }
74
- for (const p of items) {
75
- const tag = statusTag(p.status);
76
- const who = p.userLabel ? colors.gray('· ' + p.userLabel) : '';
77
- process.stdout.write(` ${tag} ${colors.bold(p.label.padEnd(10))} ${colors.dim(p.scheme + '://')} ${who}\n`);
78
- if (!p.clientIdConfigured) {
79
- process.stdout.write(' ' + colors.warning(`set CODEHERE_${p.id.toUpperCase()}_CLIENT_ID before connect()`) + '\n');
80
- }
81
- }
82
- process.stdout.write('\n' + colors.dim('Connect: ') + colors.bold('codehere context-source connect <provider>') + '\n\n');
83
- return 0;
84
- }
85
- function statusTag(s) {
86
- switch (s) {
87
- case 'connected':
88
- return colors.green('● connected ');
89
- case 'expired':
90
- return colors.warning('● expired ');
91
- case 'manual':
92
- return colors.gray('● manual ');
93
- case 'disconnected':
94
- return colors.gray('○ disconnected');
95
- }
96
- }
97
- /* ──────────────────────────────────────────────────────────────────────── */
98
- /* connect */
99
- /* ──────────────────────────────────────────────────────────────────────── */
100
- async function connect(providerArg, json, openBrowser) {
101
- if (!providerArg) {
102
- process.stderr.write(colors.error(`${symbols.error} Need a provider id: codehere context-source connect <id>\n`));
103
- return 2;
104
- }
105
- const r = await fetchJson(`/api/context-sources/${encodeURIComponent(providerArg)}/connect`, { method: 'POST' });
106
- if (!r.ok) {
107
- let detail = null;
108
- try {
109
- detail = JSON.parse(r.error ?? '{}');
110
- }
111
- catch {
112
- /* ignore */
113
- }
114
- if (detail?.error === 'provider_not_registered') {
115
- const envVar = detail.envVar ?? `CODEHERE_${providerArg.toUpperCase()}_CLIENT_ID`;
116
- if (json) {
117
- process.stdout.write(JSON.stringify({ error: 'provider_not_registered', envVar, message: detail.message }, null, 2) + '\n');
118
- }
119
- else {
120
- process.stderr.write(colors.error(`${symbols.error} ${providerArg} OAuth app not registered.\n`) +
121
- colors.dim(` ${detail.message ?? ''}\n`) +
122
- colors.dim(` Set the env var: `) +
123
- colors.bold(envVar) +
124
- '\n');
125
- }
126
- return 2;
127
- }
128
- if (json) {
129
- process.stdout.write(JSON.stringify({ error: 'connect_failed', detail: r.error }, null, 2) + '\n');
130
- }
131
- else {
132
- process.stderr.write(daemonUnreachableNote(r.error ?? ''));
133
- }
134
- return 2;
135
- }
136
- const url = r.data?.authorizeUrl;
137
- if (!url) {
138
- process.stderr.write(colors.error(`${symbols.error} Daemon did not return an authorize URL.\n`));
139
- return 1;
140
- }
141
- if (json) {
142
- process.stdout.write(JSON.stringify({ authorizeUrl: url }, null, 2) + '\n');
143
- return 0;
144
- }
145
- process.stdout.write('\n' +
146
- colors.bold(`Opening ${providerArg} OAuth flow`) +
147
- '\n\n' +
148
- colors.dim(' URL: ') +
149
- url +
150
- '\n\n' +
151
- colors.dim(' Codehere will store the token at ~/.codehere/context-sources.json.\n') +
152
- colors.dim(' You can close the browser tab when it says "connected".\n\n'));
153
- if (openBrowser) {
154
- openInBrowser(url);
155
- }
156
- return 0;
157
- }
158
- function openInBrowser(url) {
159
- const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
160
- try {
161
- const child = spawn(cmd, [url], { detached: true, stdio: 'ignore' });
162
- child.unref();
163
- }
164
- catch {
165
- // best-effort · the URL is already printed
166
- }
167
- }
168
- /* ──────────────────────────────────────────────────────────────────────── */
169
- /* disconnect */
170
- /* ──────────────────────────────────────────────────────────────────────── */
171
- async function disconnect(providerArg, json) {
172
- if (!providerArg) {
173
- process.stderr.write(colors.error(`${symbols.error} Need a provider id: codehere context-source disconnect <id>\n`));
174
- return 2;
175
- }
176
- const r = await fetchJson(`/api/context-sources/${encodeURIComponent(providerArg)}/disconnect`, { method: 'POST' });
177
- if (!r.ok) {
178
- if (json) {
179
- process.stdout.write(JSON.stringify({ error: 'disconnect_failed', detail: r.error }, null, 2) + '\n');
180
- }
181
- else {
182
- process.stderr.write(daemonUnreachableNote(r.error ?? ''));
183
- }
184
- return 2;
185
- }
186
- if (json) {
187
- process.stdout.write(JSON.stringify(r.data) + '\n');
188
- return 0;
189
- }
190
- if (r.data?.ok) {
191
- process.stdout.write(colors.green(`${symbols.success} disconnected ${providerArg}\n`));
192
- }
193
- else {
194
- process.stdout.write(colors.gray(`${symbols.dot} ${providerArg} was not connected\n`));
195
- }
196
- return 0;
197
- }
198
- //# sourceMappingURL=context-source-command.js.map