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,277 +0,0 @@
1
- /**
2
- * Write-Pass (W-PASS) primitive · v0.9 S6 · the WRITE counterpart to S1's
3
- * context-source READ primitive.
4
- *
5
- * Demo v12 lines 2030-2050. Every time an agent wants to make a stateful
6
- * call to a third-party tool (Linear status update, GitHub PR comment,
7
- * Notion page edit, etc.) it emits a `WritePassIntent`. Codehere mediates:
8
- *
9
- * 1. Intent · agent → codehere · {target, method, payload, reason}
10
- * 2. Approval · user → codehere · approve / edit / cancel
11
- * 3. Mediated send · codehere → third-party · captures response
12
- * 4. Audit · chained entry for each step
13
- *
14
- * Why this primitive exists: AI 2027 forecasts agentic AI doing autonomous
15
- * multi-tool writes by mid-2027. Without W-PASS we either (a) hand the
16
- * agent raw API keys + tokens — every write is invisible to the human,
17
- * audit-impossible — or (b) ban writes entirely and lose half the value.
18
- * W-PASS is the middle path: writes happen, but every payload is human-
19
- * mediated and chain-recorded.
20
- *
21
- * This file is PURE LOGIC · no fs, no fetch. CLI + HTTP + UI wrap it.
22
- */
23
- import { randomUUID, createHash } from 'crypto';
24
- /** Errors raised by W-PASS primitive functions. */
25
- export class WritePassError extends Error {
26
- code;
27
- constructor(code, message) {
28
- super(`[w-pass] ${code}: ${message}`);
29
- this.code = code;
30
- }
31
- }
32
- /* ──────────────────────────────────────────────────────────────────────── */
33
- /* Pure helpers */
34
- /* ──────────────────────────────────────────────────────────────────────── */
35
- /** Generate a fresh W-PASS id · stable across the intent → decision → send cycle. */
36
- export function newPassId() {
37
- return randomUUID();
38
- }
39
- /** Allowed URL schemes for W-PASS targets · matches context-source's namespace
40
- * (we want symmetry: read via context-source, write via write-pass, same identifiers). */
41
- const ALLOWED_SCHEMES = new Set(['linear', 'github', 'figma', 'drawio', 'notion']);
42
- /**
43
- * Validate that an intent is well-formed before showing it to the user.
44
- * Refuse anything we can't audit (unknown scheme, unsupported method, empty
45
- * reason, etc.). Throws WritePassError with a precise code.
46
- */
47
- export function validateIntent(intent) {
48
- if (typeof intent !== 'object' || intent === null) {
49
- throw new WritePassError('invalid_intent', 'intent must be an object');
50
- }
51
- const it = intent;
52
- if (typeof it.id !== 'string' || it.id.length === 0) {
53
- throw new WritePassError('invalid_intent', 'id required');
54
- }
55
- if (typeof it.sessionId !== 'string' || it.sessionId.length === 0) {
56
- throw new WritePassError('invalid_intent', 'sessionId required');
57
- }
58
- if (typeof it.target !== 'string' || it.target.length === 0) {
59
- throw new WritePassError('invalid_intent', 'target required');
60
- }
61
- const schemeMatch = it.target.match(/^([a-z][a-z0-9+.-]*):\/\//);
62
- if (!schemeMatch) {
63
- throw new WritePassError('invalid_intent', `target must be a URL with a scheme · got "${it.target}"`);
64
- }
65
- if (!ALLOWED_SCHEMES.has(schemeMatch[1])) {
66
- throw new WritePassError('unsupported_target', `scheme "${schemeMatch[1]}" not allowed · supported: ${[...ALLOWED_SCHEMES].sort().join(', ')}`);
67
- }
68
- if (typeof it.method !== 'string') {
69
- throw new WritePassError('invalid_intent', 'method required');
70
- }
71
- const m = it.method.toUpperCase();
72
- if (m !== 'POST' && m !== 'PUT' && m !== 'PATCH' && m !== 'DELETE') {
73
- throw new WritePassError('unsupported_method', `method "${it.method}" not allowed for W-PASS (use context-source for GET)`);
74
- }
75
- if (typeof it.reason !== 'string' || it.reason.trim().length === 0) {
76
- throw new WritePassError('invalid_intent', 'reason required · must be a non-empty one-line "why"');
77
- }
78
- if (typeof it.emittedAt !== 'number' || !Number.isFinite(it.emittedAt)) {
79
- throw new WritePassError('invalid_intent', 'emittedAt required (epoch ms)');
80
- }
81
- // payload may be any JSON value · we don't constrain shape here · the user
82
- // sees it verbatim and decides.
83
- return {
84
- id: it.id,
85
- sessionId: it.sessionId,
86
- target: it.target,
87
- method: m,
88
- payload: it.payload,
89
- reason: it.reason,
90
- emittedAt: it.emittedAt,
91
- emittedBy: typeof it.emittedBy === 'string' ? it.emittedBy : undefined,
92
- };
93
- }
94
- /** Validate a decision belongs to its intent and carries the fields required for its kind. */
95
- export function validateDecision(decision, intent) {
96
- if (typeof decision !== 'object' || decision === null) {
97
- throw new WritePassError('invalid_decision', 'decision must be an object');
98
- }
99
- const d = decision;
100
- if (d.passId !== intent.id) {
101
- throw new WritePassError('invalid_decision', `decision.passId "${d.passId}" doesn't match intent.id "${intent.id}"`);
102
- }
103
- const kind = d.kind;
104
- if (kind !== 'approve' && kind !== 'edit' && kind !== 'cancel') {
105
- throw new WritePassError('invalid_decision', `kind must be approve | edit | cancel · got "${d.kind}"`);
106
- }
107
- if (kind === 'edit' && d.editedPayload === undefined) {
108
- throw new WritePassError('invalid_decision', 'edit requires editedPayload');
109
- }
110
- if (typeof d.decidedAt !== 'number' || !Number.isFinite(d.decidedAt)) {
111
- throw new WritePassError('invalid_decision', 'decidedAt required (epoch ms)');
112
- }
113
- return {
114
- passId: intent.id,
115
- kind,
116
- editedPayload: kind === 'edit' ? d.editedPayload : undefined,
117
- note: typeof d.note === 'string' ? d.note : undefined,
118
- decidedAt: d.decidedAt,
119
- };
120
- }
121
- /**
122
- * Apply a decision to an intent and produce the next status.
123
- * Pure · no I/O. The caller (daemon route) does the network call and produces
124
- * a `WritePassResponse` which then transitions 'approved'/'edited' → 'sent'.
125
- */
126
- export function applyDecision(intent, decision) {
127
- if (decision.kind === 'cancel') {
128
- return { kind: 'cancelled', intent, decision };
129
- }
130
- if (decision.kind === 'edit') {
131
- return { kind: 'edited', intent, decision, effectivePayload: decision.editedPayload };
132
- }
133
- return { kind: 'approved', intent, decision };
134
- }
135
- /**
136
- * After codehere does the mediated send, record the response and transition
137
- * to 'sent' (2xx/3xx) or 'failed' (everything else).
138
- */
139
- export function applyResponse(status, response) {
140
- const effectivePayload = status.kind === 'edited' ? status.effectivePayload : status.intent.payload;
141
- const ok = response.status >= 200 && response.status < 400;
142
- return ok
143
- ? { kind: 'sent', intent: status.intent, decision: status.decision, effectivePayload, response }
144
- : { kind: 'failed', intent: status.intent, decision: status.decision, effectivePayload, response };
145
- }
146
- /* ──────────────────────────────────────────────────────────────────────── */
147
- /* Audit-line shaping */
148
- /* ──────────────────────────────────────────────────────────────────────── */
149
- /**
150
- * Deterministic JSON for hashing into the audit chain. Same canonical-form
151
- * rules as thread-export's canonicalize · keys sorted, undefined dropped,
152
- * non-finite numbers refused. We want two machines that re-serialize the
153
- * same intent to compute the same hash.
154
- */
155
- export function canonicalizeForAudit(value) {
156
- if (value === null)
157
- return 'null';
158
- if (typeof value === 'number') {
159
- if (!Number.isFinite(value))
160
- throw new Error(`cannot canonicalize non-finite number: ${value}`);
161
- return JSON.stringify(value);
162
- }
163
- if (typeof value === 'string' || typeof value === 'boolean')
164
- return JSON.stringify(value);
165
- if (Array.isArray(value)) {
166
- return '[' + value.map(canonicalizeForAudit).join(',') + ']';
167
- }
168
- if (typeof value === 'object') {
169
- const obj = value;
170
- const keys = Object.keys(obj).sort();
171
- const parts = keys
172
- .filter((k) => obj[k] !== undefined)
173
- .map((k) => JSON.stringify(k) + ':' + canonicalizeForAudit(obj[k]));
174
- return '{' + parts.join(',') + '}';
175
- }
176
- if (value === undefined)
177
- return 'null';
178
- throw new Error(`cannot canonicalize type: ${typeof value}`);
179
- }
180
- /** SHA-256 hash of canonicalize(value) · 16-char hex prefix for inline display. */
181
- export function shortContentHash(value) {
182
- return createHash('sha256').update(canonicalizeForAudit(value)).digest('hex').slice(0, 16);
183
- }
184
- /** Render a status transition as an audit-chain entry. Caller appends it. */
185
- export function statusToAuditLine(s) {
186
- const sessionId = s.intent.sessionId;
187
- const timestamp = new Date('response' in s ? s.response.receivedAt : 'decision' in s ? s.decision.decidedAt : s.intent.emittedAt).toISOString();
188
- const baseSummary = {
189
- passId: s.intent.id,
190
- target: s.intent.target,
191
- method: s.intent.method,
192
- reason: s.intent.reason,
193
- payloadHash: shortContentHash(s.intent.payload),
194
- };
195
- switch (s.kind) {
196
- case 'pending':
197
- return {
198
- toolName: 'WritePass.intent',
199
- toolInput: canonicalizeForAudit(baseSummary),
200
- riskScore: 0,
201
- blocked: false,
202
- findings: 0,
203
- criticalFindings: 0,
204
- sessionId,
205
- timestamp,
206
- };
207
- case 'approved':
208
- return {
209
- toolName: 'WritePass.approved',
210
- toolInput: canonicalizeForAudit({ ...baseSummary, note: s.decision.note }),
211
- riskScore: 0,
212
- blocked: false,
213
- findings: 0,
214
- criticalFindings: 0,
215
- sessionId,
216
- timestamp,
217
- };
218
- case 'edited':
219
- return {
220
- toolName: 'WritePass.edited',
221
- toolInput: canonicalizeForAudit({
222
- ...baseSummary,
223
- editedPayloadHash: shortContentHash(s.effectivePayload),
224
- note: s.decision.note,
225
- }),
226
- riskScore: 0,
227
- blocked: false,
228
- findings: 0,
229
- criticalFindings: 0,
230
- sessionId,
231
- timestamp,
232
- };
233
- case 'cancelled':
234
- return {
235
- toolName: 'WritePass.cancelled',
236
- toolInput: canonicalizeForAudit({ ...baseSummary, note: s.decision.note }),
237
- riskScore: 0,
238
- blocked: true,
239
- findings: 0,
240
- criticalFindings: 0,
241
- sessionId,
242
- timestamp,
243
- };
244
- case 'sent':
245
- return {
246
- toolName: 'WritePass.sent',
247
- toolInput: canonicalizeForAudit({
248
- ...baseSummary,
249
- effectivePayloadHash: shortContentHash(s.effectivePayload),
250
- responseStatus: s.response.status,
251
- }),
252
- riskScore: 0,
253
- blocked: false,
254
- findings: 0,
255
- criticalFindings: 0,
256
- sessionId,
257
- timestamp,
258
- };
259
- case 'failed':
260
- return {
261
- toolName: 'WritePass.failed',
262
- toolInput: canonicalizeForAudit({
263
- ...baseSummary,
264
- effectivePayloadHash: shortContentHash(s.effectivePayload),
265
- responseStatus: s.response.status,
266
- error: s.response.error,
267
- }),
268
- riskScore: 0,
269
- blocked: false,
270
- findings: 1,
271
- criticalFindings: 0,
272
- sessionId,
273
- timestamp,
274
- };
275
- }
276
- }
277
- //# sourceMappingURL=write-pass.js.map
@@ -1,61 +0,0 @@
1
- /**
2
- * Domain Entity: CodehereTask
3
- * Task and workflow entities for the 4-mode interaction model
4
- *
5
- * Phase 1: v0.5.0-alpha
6
- * See: .internal/ARCHITECTURE.md (internal docs)
7
- */
8
- /**
9
- * Task Mode - The interaction mode that created this task
10
- */
11
- export var TaskMode;
12
- (function (TaskMode) {
13
- TaskMode["SUGGEST"] = "suggest";
14
- TaskMode["PLAN"] = "plan";
15
- TaskMode["RUN"] = "run";
16
- TaskMode["REVIEW"] = "review";
17
- })(TaskMode || (TaskMode = {}));
18
- /**
19
- * Task Status - Current lifecycle state
20
- */
21
- export var TaskStatus;
22
- (function (TaskStatus) {
23
- TaskStatus["CREATED"] = "created";
24
- TaskStatus["PLANNED"] = "planned";
25
- TaskStatus["RUNNING"] = "running";
26
- TaskStatus["COMPLETED"] = "completed";
27
- TaskStatus["FAILED"] = "failed";
28
- TaskStatus["NEEDS_REVIEW"] = "needs_review";
29
- TaskStatus["APPROVED"] = "approved";
30
- TaskStatus["REJECTED"] = "rejected";
31
- TaskStatus["CANCELLED"] = "cancelled";
32
- })(TaskStatus || (TaskStatus = {}));
33
- /**
34
- * Risk Tier - Risk level for operation
35
- */
36
- export var RiskTier;
37
- (function (RiskTier) {
38
- RiskTier["T1"] = "t1";
39
- RiskTier["T2"] = "t2";
40
- RiskTier["T3"] = "t3";
41
- })(RiskTier || (RiskTier = {}));
42
- /**
43
- * Environment Mode - Data access boundaries
44
- */
45
- export var EnvironmentMode;
46
- (function (EnvironmentMode) {
47
- EnvironmentMode["LOCAL"] = "local";
48
- EnvironmentMode["ORG"] = "org";
49
- EnvironmentMode["INTERNET"] = "internet";
50
- })(EnvironmentMode || (EnvironmentMode = {}));
51
- /**
52
- * Review Status
53
- */
54
- export var ReviewStatus;
55
- (function (ReviewStatus) {
56
- ReviewStatus["NOT_REQUIRED"] = "not_required";
57
- ReviewStatus["PENDING"] = "pending";
58
- ReviewStatus["APPROVED"] = "approved";
59
- ReviewStatus["REJECTED"] = "rejected";
60
- })(ReviewStatus || (ReviewStatus = {}));
61
- //# sourceMappingURL=task.js.map
@@ -1,91 +0,0 @@
1
- /**
2
- * Domain Service: CodebaseDetector
3
- * Detects and identifies codebase root directory
4
- */
5
- import { existsSync } from 'fs';
6
- import { join, dirname, resolve } from 'path';
7
- /**
8
- * Find codebase root (git root, package.json parent, or current directory)
9
- */
10
- export function findCodebaseRoot(startPath = process.cwd()) {
11
- const resolvedStart = resolve(startPath);
12
- const currentDir = resolvedStart;
13
- // Try to find git root first
14
- const gitRoot = findGitRoot(currentDir);
15
- if (gitRoot) {
16
- return {
17
- rootPath: gitRoot,
18
- codebaseId: generateCodebaseId(gitRoot),
19
- type: 'git',
20
- };
21
- }
22
- // Try to find package.json
23
- const packageRoot = findPackageRoot(currentDir);
24
- if (packageRoot) {
25
- return {
26
- rootPath: packageRoot,
27
- codebaseId: generateCodebaseId(packageRoot),
28
- type: 'package',
29
- };
30
- }
31
- // Fallback to current directory
32
- return {
33
- rootPath: currentDir,
34
- codebaseId: generateCodebaseId(currentDir),
35
- type: 'directory',
36
- };
37
- }
38
- /**
39
- * Generate stable codebase ID from path
40
- * Uses absolute path normalized for cross-platform compatibility
41
- */
42
- function generateCodebaseId(path) {
43
- // Normalize path (handle Windows/Unix differences)
44
- const normalized = resolve(path).replace(/\\/g, '/');
45
- // Use path as ID (stable identifier)
46
- // For production, could hash this for shorter IDs
47
- return normalized;
48
- }
49
- /**
50
- * Find git root directory
51
- */
52
- function findGitRoot(startPath) {
53
- let currentDir = startPath;
54
- const root = currentDir.split(/[/\\]/)[0];
55
- while (currentDir !== root) {
56
- if (existsSync(join(currentDir, '.git'))) {
57
- return currentDir;
58
- }
59
- const parentDir = dirname(currentDir);
60
- if (parentDir === currentDir) {
61
- break;
62
- }
63
- currentDir = parentDir;
64
- }
65
- return null;
66
- }
67
- /**
68
- * Find package.json root directory
69
- */
70
- function findPackageRoot(startPath) {
71
- let currentDir = startPath;
72
- const root = currentDir.split(/[/\\]/)[0];
73
- while (currentDir !== root) {
74
- if (existsSync(join(currentDir, 'package.json'))) {
75
- return currentDir;
76
- }
77
- const parentDir = dirname(currentDir);
78
- if (parentDir === currentDir) {
79
- break;
80
- }
81
- currentDir = parentDir;
82
- }
83
- return null;
84
- }
85
- /**
86
- * Get codebase info for a given file path
87
- */
88
- export function getCodebaseForFile(filepath) {
89
- return findCodebaseRoot(dirname(filepath));
90
- }
91
- //# sourceMappingURL=codebase-detector.js.map
@@ -1,251 +0,0 @@
1
- /**
2
- * Enterprise-Grade Error Handling & Recovery System
3
- * Ensures 24/7 operation with automatic recovery
4
- */
5
- export var ErrorType;
6
- (function (ErrorType) {
7
- ErrorType["RETRYABLE"] = "RETRYABLE";
8
- ErrorType["FATAL"] = "FATAL";
9
- ErrorType["RATE_LIMIT"] = "RATE_LIMIT";
10
- ErrorType["NETWORK"] = "NETWORK";
11
- ErrorType["API_ERROR"] = "API_ERROR";
12
- ErrorType["VALIDATION"] = "VALIDATION";
13
- ErrorType["POLICY"] = "POLICY";
14
- })(ErrorType || (ErrorType = {}));
15
- export class EnterpriseError extends Error {
16
- errorType;
17
- context;
18
- retryable;
19
- constructor(message, errorType, context, retryable = false) {
20
- super(message);
21
- this.errorType = errorType;
22
- this.context = context;
23
- this.retryable = retryable;
24
- this.name = 'EnterpriseError';
25
- }
26
- }
27
- /**
28
- * Classify error type for appropriate handling
29
- */
30
- export function classifyError(error) {
31
- if (error instanceof EnterpriseError) {
32
- return error.errorType;
33
- }
34
- // Check for 429 status code directly (Cohere SDK errors)
35
- if (error && typeof error === 'object') {
36
- const err = error;
37
- if (err.statusCode === 429 || err.status === 429) {
38
- return ErrorType.RATE_LIMIT;
39
- }
40
- // Check error name/class
41
- const errorName = err.constructor?.name || err.name || '';
42
- if (errorName.includes('TooManyRequests') || errorName === 'TooManyRequestsError') {
43
- return ErrorType.RATE_LIMIT;
44
- }
45
- // Check body/message for trial key quota messages
46
- const body = err.body || err.message || '';
47
- if (typeof body === 'string' && body.includes('Trial key') && body.includes('1000 API calls')) {
48
- return ErrorType.RATE_LIMIT;
49
- }
50
- }
51
- const errorMessage = error instanceof Error ? error.message : String(error);
52
- const lowerMessage = errorMessage.toLowerCase();
53
- // Rate limiting - check message content
54
- if (lowerMessage.includes('rate limit') ||
55
- lowerMessage.includes('429') ||
56
- lowerMessage.includes('too many requests') ||
57
- lowerMessage.includes('toomanyrequests') ||
58
- (lowerMessage.includes('trial key') && lowerMessage.includes('1000'))) {
59
- return ErrorType.RATE_LIMIT;
60
- }
61
- // Network errors
62
- if (lowerMessage.includes('network') || lowerMessage.includes('timeout') || lowerMessage.includes('econnrefused')) {
63
- return ErrorType.NETWORK;
64
- }
65
- // API errors
66
- if (lowerMessage.includes('api') || lowerMessage.includes('cohere')) {
67
- return ErrorType.API_ERROR;
68
- }
69
- // Validation errors
70
- if (lowerMessage.includes('validation') || lowerMessage.includes('invalid')) {
71
- return ErrorType.VALIDATION;
72
- }
73
- // Default to retryable
74
- return ErrorType.RETRYABLE;
75
- }
76
- /**
77
- * Check if error is retryable
78
- * Rate limit errors (429) should NOT be retried - they indicate quota exceeded
79
- */
80
- export function isRetryable(error) {
81
- // Check for 429 status code directly - don't retry monthly quota limits
82
- if (error && typeof error === 'object') {
83
- const err = error;
84
- // Cohere SDK error structure
85
- if (err.statusCode === 429 || err.status === 429) {
86
- return false; // Monthly quota exceeded - retrying won't help
87
- }
88
- // Check error name/class (Cohere SDK uses TooManyRequestsError)
89
- const errorName = err.constructor?.name || err.name || '';
90
- if (errorName.includes('TooManyRequests') || errorName === 'TooManyRequestsError') {
91
- return false;
92
- }
93
- // Check error message for trial key limit message
94
- const errorMsg = err.message || String(err);
95
- if (errorMsg.includes('Trial key') && errorMsg.includes('1000 API calls')) {
96
- return false; // Monthly quota exceeded
97
- }
98
- }
99
- const errorType = classifyError(error);
100
- // Don't retry rate limit errors - they indicate quota/limit exceeded
101
- if (errorType === ErrorType.RATE_LIMIT) {
102
- return false;
103
- }
104
- return [ErrorType.RETRYABLE, ErrorType.NETWORK, ErrorType.API_ERROR].includes(errorType);
105
- }
106
- /**
107
- * Calculate exponential backoff delay
108
- */
109
- export function calculateBackoff(attempt, baseDelay = 1000, maxDelay = 60000) {
110
- const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
111
- // Add jitter to prevent thundering herd
112
- const jitter = Math.random() * 0.3 * delay;
113
- return Math.floor(delay + jitter);
114
- }
115
- /**
116
- * Retry with exponential backoff
117
- */
118
- export async function retryWithBackoff(operation, options = {}) {
119
- const { maxRetries = 5, baseDelay = 1000, maxDelay = 60000, operationName = 'operation', onRetry } = options;
120
- let lastError;
121
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
122
- try {
123
- return await operation();
124
- }
125
- catch (error) {
126
- lastError = error;
127
- // Don't retry on fatal errors
128
- if (!isRetryable(error)) {
129
- throw new EnterpriseError(`Fatal error in ${operationName}: ${error instanceof Error ? error.message : String(error)}`, classifyError(error), {
130
- operation: operationName,
131
- attempt,
132
- maxRetries,
133
- timestamp: new Date().toISOString(),
134
- errorType: classifyError(error),
135
- originalError: error instanceof Error ? error : new Error(String(error)),
136
- }, false);
137
- }
138
- // Last attempt, throw error
139
- if (attempt === maxRetries) {
140
- break;
141
- }
142
- // Calculate delay and wait
143
- const delay = calculateBackoff(attempt, baseDelay, maxDelay);
144
- if (onRetry) {
145
- onRetry(attempt + 1, error);
146
- }
147
- await new Promise((resolve) => setTimeout(resolve, delay));
148
- }
149
- }
150
- // All retries exhausted
151
- throw new EnterpriseError(`Operation ${operationName} failed after ${maxRetries} retries: ${lastError instanceof Error ? lastError.message : String(lastError)}`, classifyError(lastError), {
152
- operation: operationName,
153
- attempt: maxRetries,
154
- maxRetries,
155
- timestamp: new Date().toISOString(),
156
- errorType: classifyError(lastError),
157
- originalError: lastError instanceof Error ? lastError : new Error(String(lastError)),
158
- }, false);
159
- }
160
- /**
161
- * Circuit breaker pattern for API calls
162
- */
163
- export class CircuitBreaker {
164
- threshold;
165
- timeout;
166
- resetTimeout;
167
- failures = 0;
168
- lastFailureTime = 0;
169
- state = 'CLOSED';
170
- constructor(threshold = 5, timeout = 60000, // 1 minute
171
- resetTimeout = 30000) {
172
- this.threshold = threshold;
173
- this.timeout = timeout;
174
- this.resetTimeout = resetTimeout;
175
- }
176
- async execute(operation) {
177
- // Check if circuit should be reset
178
- if (this.state === 'OPEN') {
179
- const timeSinceLastFailure = Date.now() - this.lastFailureTime;
180
- if (timeSinceLastFailure > this.resetTimeout) {
181
- this.state = 'HALF_OPEN';
182
- }
183
- else {
184
- throw new EnterpriseError('Circuit breaker is OPEN. Service unavailable.', ErrorType.API_ERROR, {
185
- operation: 'circuit_breaker',
186
- timestamp: new Date().toISOString(),
187
- errorType: ErrorType.API_ERROR,
188
- originalError: new Error('Circuit breaker open'),
189
- }, false);
190
- }
191
- }
192
- try {
193
- const result = await operation();
194
- // Success - reset failures if in HALF_OPEN
195
- if (this.state === 'HALF_OPEN') {
196
- this.state = 'CLOSED';
197
- this.failures = 0;
198
- }
199
- else if (this.failures > 0) {
200
- this.failures = 0;
201
- }
202
- return result;
203
- }
204
- catch (error) {
205
- this.failures++;
206
- this.lastFailureTime = Date.now();
207
- // Open circuit if threshold exceeded
208
- if (this.failures >= this.threshold) {
209
- this.state = 'OPEN';
210
- }
211
- throw error;
212
- }
213
- }
214
- getState() {
215
- return this.state;
216
- }
217
- reset() {
218
- this.failures = 0;
219
- this.state = 'CLOSED';
220
- this.lastFailureTime = 0;
221
- }
222
- }
223
- /**
224
- * Global circuit breaker for Cohere API
225
- */
226
- export const cohereCircuitBreaker = new CircuitBreaker(5, 60000, 30000);
227
- /**
228
- * Graceful error handler with recovery strategies
229
- */
230
- export function handleError(error, context) {
231
- const errorType = classifyError(error);
232
- const errorMessage = error instanceof Error ? error.message : String(error);
233
- const fullContext = {
234
- operation: context.operation || 'unknown',
235
- filepath: context.filepath,
236
- attempt: context.attempt,
237
- maxRetries: context.maxRetries,
238
- timestamp: new Date().toISOString(),
239
- errorType,
240
- originalError: error instanceof Error ? error : new Error(errorMessage),
241
- metadata: context.metadata,
242
- };
243
- // Log error with full context
244
- console.error('Enterprise Error:', {
245
- message: errorMessage,
246
- type: errorType,
247
- context: fullContext,
248
- });
249
- throw new EnterpriseError(errorMessage, errorType, fullContext, isRetryable(error));
250
- }
251
- //# sourceMappingURL=error-handler.js.map