codehere 1.0.1 → 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.
- package/README.md +36 -192
- package/dist/application/use-cases/check-claimed-tests.js +81 -0
- package/dist/application/use-cases/detect-test-weakening.js +237 -0
- package/dist/application/use-cases/rerun-tests.js +110 -7
- package/dist/index.js +38 -1212
- package/dist/infrastructure/orchestration/artifacts-extractor.js +2 -323
- package/dist/presentation/cli/commands/check-command.js +178 -23
- package/dist/presentation/cli/commands/help-command.js +21 -285
- package/dist/ui.js +5 -236
- package/dist/utils/version.js +0 -6
- package/package.json +9 -38
- package/dist/application/services/verdict-service.js +0 -154
- package/dist/application/use-cases/assess-cross-vendor.js +0 -126
- package/dist/application/use-cases/build-cross-vendor-verdict.js +0 -118
- package/dist/application/use-cases/domain-trust.js +0 -110
- package/dist/application/use-cases/export-aat.js +0 -107
- package/dist/application/use-cases/generate-acceptance-criteria.js +0 -223
- package/dist/application/use-cases/generate-final-report.js +0 -259
- package/dist/application/use-cases/generate-narration.js +0 -130
- package/dist/application/use-cases/generate-thread-title.js +0 -181
- package/dist/application/use-cases/narrator-prompt-template.js +0 -158
- package/dist/application/use-cases/plan-auto-review.js +0 -57
- package/dist/application/use-cases/reconcile-audit.js +0 -100
- package/dist/application/use-cases/search-sessions.js +0 -70
- package/dist/application/use-cases/should-auto-review.js +0 -71
- package/dist/application/use-cases/thread-export.js +0 -245
- package/dist/application/use-cases/verify-claim.js +0 -456
- package/dist/application/use-cases/write-pass.js +0 -277
- package/dist/domain/audit.js +0 -11
- package/dist/domain/services/codebase-detector.js +0 -85
- package/dist/domain/task.js +0 -91
- package/dist/error-handler.js +0 -139
- package/dist/infrastructure/completion/bash-completion.js +0 -29
- package/dist/infrastructure/completion/fish-completion.js +0 -17
- package/dist/infrastructure/completion/zsh-completion.js +0 -25
- package/dist/infrastructure/config/config-manager.js +0 -174
- package/dist/infrastructure/config/product-context.js +0 -49
- package/dist/infrastructure/context/adapters/drawio-source.js +0 -157
- package/dist/infrastructure/context/adapters/figma-source.js +0 -198
- package/dist/infrastructure/context/adapters/github-issue-source.js +0 -160
- package/dist/infrastructure/context/adapters/linear-source.js +0 -190
- package/dist/infrastructure/context/context-resolver.js +0 -144
- package/dist/infrastructure/context/context-source.js +0 -114
- package/dist/infrastructure/context/github-api.js +0 -110
- package/dist/infrastructure/context/github-device-flow.js +0 -65
- package/dist/infrastructure/context/oauth-flow.js +0 -207
- package/dist/infrastructure/context/oauth-store.js +0 -122
- package/dist/infrastructure/context/registry-bootstrap.js +0 -95
- package/dist/infrastructure/context/write-pass-resolver.js +0 -106
- package/dist/infrastructure/cost/budget-config.js +0 -114
- package/dist/infrastructure/cost/cost-router.js +0 -97
- package/dist/infrastructure/cost/spend-aggregator.js +0 -222
- package/dist/infrastructure/cost/team-ledger.js +0 -355
- package/dist/infrastructure/discovery/discovery-log.js +0 -85
- package/dist/infrastructure/hooks/audit-tip-signature.js +0 -336
- package/dist/infrastructure/hooks/claude-sdk-hook.js +0 -1018
- package/dist/infrastructure/hooks/hook-mode.js +0 -87
- package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +0 -49
- package/dist/infrastructure/hooks/pre-prompt-scan.js +0 -122
- package/dist/infrastructure/hooks/session-analyzer.js +0 -177
- package/dist/infrastructure/observability/execution-tracer.js +0 -227
- package/dist/infrastructure/orchestration/agent-adapter.js +0 -13
- package/dist/infrastructure/orchestration/agent-installer.js +0 -101
- package/dist/infrastructure/orchestration/agents-config-seed.js +0 -68
- package/dist/infrastructure/orchestration/aider-adapter.js +0 -611
- package/dist/infrastructure/orchestration/cassette-recorder.js +0 -120
- package/dist/infrastructure/orchestration/claude-code-adapter.js +0 -592
- package/dist/infrastructure/orchestration/codex-adapter.js +0 -574
- package/dist/infrastructure/orchestration/conductor-adapter.js +0 -416
- package/dist/infrastructure/orchestration/context-handoff.js +0 -162
- package/dist/infrastructure/orchestration/control/codex-control-surface.js +0 -99
- package/dist/infrastructure/orchestration/control/control-surface.js +0 -15
- package/dist/infrastructure/orchestration/detect-ollama.js +0 -75
- package/dist/infrastructure/orchestration/failover-classifier.js +0 -151
- package/dist/infrastructure/orchestration/failover-config.js +0 -67
- package/dist/infrastructure/orchestration/failover-policy.js +0 -106
- package/dist/infrastructure/orchestration/gemini-adapter.js +0 -663
- package/dist/infrastructure/orchestration/generic-cli-adapter.js +0 -689
- package/dist/infrastructure/orchestration/graphify-context.js +0 -209
- package/dist/infrastructure/orchestration/memory-injector.js +0 -380
- package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +0 -388
- package/dist/infrastructure/orchestration/mocks/mock-codex-app-server.js +0 -73
- package/dist/infrastructure/orchestration/mocks/mock-synthesis.js +0 -83
- package/dist/infrastructure/orchestration/mocks/resolve-agent-spawn.js +0 -37
- package/dist/infrastructure/orchestration/opencode-adapter.js +0 -580
- package/dist/infrastructure/orchestration/progress-aggregator.js +0 -906
- package/dist/infrastructure/orchestration/readiness.js +0 -103
- package/dist/infrastructure/orchestration/session-manager.js +0 -1590
- package/dist/infrastructure/orchestration/session-persistence.js +0 -394
- package/dist/infrastructure/orchestration/thread-key-store.js +0 -127
- package/dist/infrastructure/orchestration/write-pass-store.js +0 -38
- package/dist/infrastructure/protocols/cloud-sync.js +0 -207
- package/dist/infrastructure/protocols/mcp-helpers.js +0 -25
- package/dist/infrastructure/protocols/mcp-server-impl.js +0 -3935
- package/dist/infrastructure/protocols/mcp-tools.js +0 -401
- package/dist/infrastructure/protocols/probe-port.js +0 -36
- package/dist/infrastructure/protocols/thread-phase.js +0 -105
- package/dist/infrastructure/protocols/ui/app-script-artifacts.js +0 -121
- package/dist/infrastructure/protocols/ui/app-script-audit-footer.js +0 -44
- package/dist/infrastructure/protocols/ui/app-script-audit-verify.js +0 -56
- package/dist/infrastructure/protocols/ui/app-script-composer-cost.js +0 -588
- package/dist/infrastructure/protocols/ui/app-script-context-sources.js +0 -168
- package/dist/infrastructure/protocols/ui/app-script-conversation.js +0 -67
- package/dist/infrastructure/protocols/ui/app-script-drawer.js +0 -115
- package/dist/infrastructure/protocols/ui/app-script-failover.js +0 -133
- package/dist/infrastructure/protocols/ui/app-script-github.js +0 -113
- package/dist/infrastructure/protocols/ui/app-script-observer.js +0 -104
- package/dist/infrastructure/protocols/ui/app-script-onboarding.js +0 -80
- package/dist/infrastructure/protocols/ui/app-script-overlay.js +0 -203
- package/dist/infrastructure/protocols/ui/app-script-recovery.js +0 -136
- package/dist/infrastructure/protocols/ui/app-script-render.js +0 -166
- package/dist/infrastructure/protocols/ui/app-script-share.js +0 -78
- package/dist/infrastructure/protocols/ui/app-script-sidebar.js +0 -194
- package/dist/infrastructure/protocols/ui/app-script-tour.js +0 -78
- package/dist/infrastructure/protocols/ui/app-script-wpass.js +0 -312
- package/dist/infrastructure/protocols/ui/app-script.js +0 -2998
- package/dist/infrastructure/protocols/ui/font-faces.js +0 -7
- package/dist/infrastructure/protocols/ui/styles.js +0 -2147
- package/dist/infrastructure/protocols/ui/tokens.js +0 -96
- package/dist/infrastructure/protocols/ui-page-v2.js +0 -320
- package/dist/infrastructure/protocols/verify-page.js +0 -1677
- package/dist/infrastructure/security/file-collection.js +0 -118
- package/dist/infrastructure/security/fix-code.js +0 -144
- package/dist/infrastructure/security/fix-secret.js +0 -89
- package/dist/infrastructure/security/permissions-config.js +0 -235
- package/dist/infrastructure/security/scan-types.js +0 -10
- package/dist/infrastructure/security/ship-scan.js +0 -195
- package/dist/infrastructure/security/trust-scorer.js +0 -724
- package/dist/infrastructure/security/vibe-checks.js +0 -99
- package/dist/infrastructure/storage/atomic-write.js +0 -86
- package/dist/infrastructure/storage/cross-tool-agents.js +0 -268
- package/dist/infrastructure/storage/project-thread-migration.js +0 -237
- package/dist/infrastructure/storage/project-thread-mirror.js +0 -671
- package/dist/infrastructure/storage/project-thread-reader.js +0 -409
- package/dist/infrastructure/storage/project-thread-title-backfill.js +0 -214
- package/dist/monitoring.js +0 -212
- package/dist/presentation/cli/commands/audit-command.js +0 -201
- package/dist/presentation/cli/commands/budget-command.js +0 -79
- package/dist/presentation/cli/commands/config-command.js +0 -125
- package/dist/presentation/cli/commands/context-source-command.js +0 -217
- package/dist/presentation/cli/commands/hook-command.js +0 -265
- package/dist/presentation/cli/commands/init-command.js +0 -590
- package/dist/presentation/cli/commands/memory-command.js +0 -1031
- package/dist/presentation/cli/commands/narrator-command.js +0 -101
- package/dist/presentation/cli/commands/permission-command.js +0 -105
- package/dist/presentation/cli/commands/protocols-builder.js +0 -254
- package/dist/presentation/cli/commands/protocols-command.js +0 -84
- package/dist/presentation/cli/commands/repo-map-builder.js +0 -247
- package/dist/presentation/cli/commands/report-command.js +0 -403
- package/dist/presentation/cli/commands/scan-command.js +0 -52
- package/dist/presentation/cli/commands/scan-tool-command.js +0 -110
- package/dist/presentation/cli/commands/search-command.js +0 -51
- package/dist/presentation/cli/commands/setup-command.js +0 -330
- package/dist/presentation/cli/commands/status-command.js +0 -614
- package/dist/presentation/cli/commands/team-command.js +0 -256
- package/dist/presentation/cli/commands/thread-command.js +0 -370
- package/dist/presentation/cli/commands/trust-command.js +0 -328
- package/dist/presentation/cli/commands/verify-command.js +0 -298
- package/dist/presentation/cli/error-display.js +0 -328
- package/dist/presentation/cli/repl.js +0 -805
- package/dist/presentation/cli/task-deliverable.js +0 -153
- package/dist/testing/cassette.js +0 -125
- package/dist/testing/replay-adapter.js +0 -147
package/dist/monitoring.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enterprise Monitoring & Health Check System
|
|
3
|
-
* Ensures 24/7 operation visibility
|
|
4
|
-
*/
|
|
5
|
-
import { existsSync, mkdirSync } from 'fs';
|
|
6
|
-
import { join, dirname } from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { cohereCircuitBreaker } from './error-handler.js';
|
|
9
|
-
class MetricsCollector {
|
|
10
|
-
operations = {
|
|
11
|
-
total: 0,
|
|
12
|
-
successful: 0,
|
|
13
|
-
failed: 0,
|
|
14
|
-
retries: 0,
|
|
15
|
-
};
|
|
16
|
-
performance = {
|
|
17
|
-
responseTimes: [],
|
|
18
|
-
retryTimes: [],
|
|
19
|
-
apiCalls: 0,
|
|
20
|
-
cacheHits: 0,
|
|
21
|
-
};
|
|
22
|
-
errors = {
|
|
23
|
-
byType: {},
|
|
24
|
-
recent: [],
|
|
25
|
-
};
|
|
26
|
-
recordOperation(success, responseTime, retries) {
|
|
27
|
-
this.operations.total++;
|
|
28
|
-
if (success) {
|
|
29
|
-
this.operations.successful++;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
this.operations.failed++;
|
|
33
|
-
}
|
|
34
|
-
if (retries) {
|
|
35
|
-
this.operations.retries += retries;
|
|
36
|
-
}
|
|
37
|
-
if (responseTime) {
|
|
38
|
-
this.performance.responseTimes.push(responseTime);
|
|
39
|
-
// Keep only last 1000 measurements
|
|
40
|
-
if (this.performance.responseTimes.length > 1000) {
|
|
41
|
-
this.performance.responseTimes.shift();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
recordApiCall() {
|
|
46
|
-
this.performance.apiCalls++;
|
|
47
|
-
}
|
|
48
|
-
recordCacheHit() {
|
|
49
|
-
this.performance.cacheHits++;
|
|
50
|
-
}
|
|
51
|
-
recordError(type, message) {
|
|
52
|
-
this.errors.byType[type] = (this.errors.byType[type] || 0) + 1;
|
|
53
|
-
this.errors.recent.push({
|
|
54
|
-
timestamp: new Date().toISOString(),
|
|
55
|
-
type,
|
|
56
|
-
message,
|
|
57
|
-
});
|
|
58
|
-
// Keep only last 100 errors
|
|
59
|
-
if (this.errors.recent.length > 100) {
|
|
60
|
-
this.errors.recent.shift();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
getMetrics() {
|
|
64
|
-
const avgResponseTime = this.performance.responseTimes.length > 0
|
|
65
|
-
? this.performance.responseTimes.reduce((a, b) => a + b, 0) / this.performance.responseTimes.length
|
|
66
|
-
: 0;
|
|
67
|
-
const avgRetryTime = this.performance.retryTimes.length > 0
|
|
68
|
-
? this.performance.retryTimes.reduce((a, b) => a + b, 0) / this.performance.retryTimes.length
|
|
69
|
-
: 0;
|
|
70
|
-
return {
|
|
71
|
-
operations: { ...this.operations },
|
|
72
|
-
performance: {
|
|
73
|
-
avgResponseTime,
|
|
74
|
-
avgRetryTime,
|
|
75
|
-
apiCalls: this.performance.apiCalls,
|
|
76
|
-
cacheHits: this.performance.cacheHits,
|
|
77
|
-
},
|
|
78
|
-
errors: {
|
|
79
|
-
byType: { ...this.errors.byType },
|
|
80
|
-
recent: [...this.errors.recent],
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
reset() {
|
|
85
|
-
this.operations = { total: 0, successful: 0, failed: 0, retries: 0 };
|
|
86
|
-
this.performance = { responseTimes: [], retryTimes: [], apiCalls: 0, cacheHits: 0 };
|
|
87
|
-
this.errors = { byType: {}, recent: [] };
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
export const metricsCollector = new MetricsCollector();
|
|
91
|
-
/**
|
|
92
|
-
* Check API health
|
|
93
|
-
*/
|
|
94
|
-
function checkApi() {
|
|
95
|
-
const circuitState = cohereCircuitBreaker.getState();
|
|
96
|
-
if (circuitState === 'OPEN') {
|
|
97
|
-
return { status: 'circuit_open', message: 'API circuit breaker is OPEN - too many failures' };
|
|
98
|
-
}
|
|
99
|
-
if (circuitState === 'HALF_OPEN') {
|
|
100
|
-
return { status: 'error', message: 'API circuit breaker is HALF_OPEN - recovering' };
|
|
101
|
-
}
|
|
102
|
-
// Check if any API key is configured
|
|
103
|
-
const hasKey = !!(process.env.ANTHROPIC_API_KEY ||
|
|
104
|
-
process.env.OPENAI_API_KEY ||
|
|
105
|
-
process.env.COHERE_API_KEY ||
|
|
106
|
-
process.env.OPENROUTER_API_KEY);
|
|
107
|
-
if (!hasKey) {
|
|
108
|
-
return { status: 'error', message: 'No API key configured' };
|
|
109
|
-
}
|
|
110
|
-
return { status: 'ok', message: 'API accessible' };
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Check filesystem health
|
|
114
|
-
*/
|
|
115
|
-
function checkFilesystem() {
|
|
116
|
-
try {
|
|
117
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
118
|
-
const __dirname = dirname(__filename);
|
|
119
|
-
const agentDir = join(__dirname, '..');
|
|
120
|
-
const dataDir = join(agentDir, 'data');
|
|
121
|
-
// Check if data directory exists or can be created
|
|
122
|
-
if (!existsSync(dataDir)) {
|
|
123
|
-
// Try to create it
|
|
124
|
-
try {
|
|
125
|
-
mkdirSync(dataDir, { recursive: true });
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return { status: 'error', message: 'Cannot create data directory' };
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return { status: 'ok', message: 'Filesystem accessible' };
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
return {
|
|
135
|
-
status: 'error',
|
|
136
|
-
message: `Filesystem check failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Check memory usage
|
|
142
|
-
*/
|
|
143
|
-
function checkMemory() {
|
|
144
|
-
try {
|
|
145
|
-
const usage = process.memoryUsage();
|
|
146
|
-
const heapUsedMB = usage.heapUsed / 1024 / 1024;
|
|
147
|
-
const heapTotalMB = usage.heapTotal / 1024 / 1024;
|
|
148
|
-
const usagePercent = (heapUsedMB / heapTotalMB) * 100;
|
|
149
|
-
if (usagePercent > 90) {
|
|
150
|
-
return {
|
|
151
|
-
status: 'warning',
|
|
152
|
-
message: `High memory usage: ${usagePercent.toFixed(1)}%`,
|
|
153
|
-
usage: usagePercent,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
status: 'ok',
|
|
158
|
-
message: `Memory usage: ${usagePercent.toFixed(1)}%`,
|
|
159
|
-
usage: usagePercent,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
catch {
|
|
163
|
-
return {
|
|
164
|
-
status: 'ok',
|
|
165
|
-
message: 'Memory check unavailable',
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Perform health check
|
|
171
|
-
*/
|
|
172
|
-
export function performHealthCheck() {
|
|
173
|
-
const apiCheck = checkApi();
|
|
174
|
-
const fsCheck = checkFilesystem();
|
|
175
|
-
const memCheck = checkMemory();
|
|
176
|
-
const checks = {
|
|
177
|
-
api: apiCheck,
|
|
178
|
-
filesystem: fsCheck,
|
|
179
|
-
memory: memCheck,
|
|
180
|
-
};
|
|
181
|
-
let status = 'healthy';
|
|
182
|
-
if (apiCheck.status === 'circuit_open' || fsCheck.status === 'error') {
|
|
183
|
-
status = 'unhealthy';
|
|
184
|
-
}
|
|
185
|
-
else if (apiCheck.status === 'error' || memCheck.status === 'warning') {
|
|
186
|
-
status = 'degraded';
|
|
187
|
-
}
|
|
188
|
-
return {
|
|
189
|
-
status,
|
|
190
|
-
timestamp: new Date().toISOString(),
|
|
191
|
-
checks,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Get current metrics
|
|
196
|
-
*/
|
|
197
|
-
export function getMetrics() {
|
|
198
|
-
return metricsCollector.getMetrics();
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Format health status for display
|
|
202
|
-
*/
|
|
203
|
-
export function formatHealthStatus(health) {
|
|
204
|
-
const statusIcon = health.status === 'healthy' ? '✓' : health.status === 'degraded' ? '!' : '✕';
|
|
205
|
-
let output = ` ${statusIcon} ${health.status.toUpperCase()}\n\n`;
|
|
206
|
-
for (const [component, check] of Object.entries(health.checks)) {
|
|
207
|
-
const icon = check.status === 'ok' ? '✓' : check.status === 'warning' ? '!' : '✕';
|
|
208
|
-
output += ` ${icon} ${component.padEnd(12)} ${check.message}\n`;
|
|
209
|
-
}
|
|
210
|
-
return output;
|
|
211
|
-
}
|
|
212
|
-
//# sourceMappingURL=monitoring.js.map
|
|
@@ -1,201 +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
|
-
import { verifyAuditTip, tipBlocksVerification } from '../../../infrastructure/hooks/audit-tip-signature.js';
|
|
23
|
-
import { exportAat, aatToJsonl } from '../../../application/use-cases/export-aat.js';
|
|
24
|
-
import { writeFileSync as writeFileSyncFs } from 'fs';
|
|
25
|
-
import { trustedKeySet } from '../../../infrastructure/orchestration/thread-key-store.js';
|
|
26
|
-
export function executeAuditCommand(sub, arg, options = {}) {
|
|
27
|
-
if (!sub || sub === 'verify')
|
|
28
|
-
return verify(options.json ?? false);
|
|
29
|
-
if (sub === 'show')
|
|
30
|
-
return show(arg, options.json ?? false);
|
|
31
|
-
if (sub === 'export')
|
|
32
|
-
return exportAatCmd(arg);
|
|
33
|
-
process.stderr.write(colors.error(`${symbols.error} Unknown audit subcommand: ${sub}\n`) +
|
|
34
|
-
colors.dim('Try: codehere audit verify | codehere audit show <seq> | codehere audit export [out.jsonl]\n'));
|
|
35
|
-
return 2;
|
|
36
|
-
}
|
|
37
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
38
|
-
/* verify · the F-05 headline */
|
|
39
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
40
|
-
function verify(json) {
|
|
41
|
-
const result = verifyAuditChain(AUDIT_FILE);
|
|
42
|
-
// R2 · the tip signature catches a re-walked forgery the hash chain alone
|
|
43
|
-
// can't (a determined edit + recomputed hashes verifies green, but the signed
|
|
44
|
-
// entry's hash changes). ANCESTOR check: honest appends since signing are
|
|
45
|
-
// expected and pass; an edit at/below the signed seq, truncation, an untrusted
|
|
46
|
-
// re-sign, or a deleted .tipsig on a previously-signed chain all fail.
|
|
47
|
-
const tip = verifyAuditTip(AUDIT_FILE, trustedKeySet());
|
|
48
|
-
const tipTampered = tipBlocksVerification(tip);
|
|
49
|
-
// An empty or missing log has nothing to verify, and a chain walk over zero entries
|
|
50
|
-
// trivially succeeds. Reporting that as valid:true is the failure this product exists to
|
|
51
|
-
// catch: deleting the audit log is exactly the attack the hash chain is meant to detect,
|
|
52
|
-
// and the machine interface was answering "intact" to a machine that asked. The human
|
|
53
|
-
// path already says "No audit entries yet" and claims nothing, so only --json was lying.
|
|
54
|
-
// "Is my chain intact?" over no chain is not answered by yes.
|
|
55
|
-
const verifiable = result.totalEntries > 0;
|
|
56
|
-
const ok = verifiable && result.valid && !tipTampered;
|
|
57
|
-
if (json) {
|
|
58
|
-
process.stdout.write(JSON.stringify({
|
|
59
|
-
path: AUDIT_FILE,
|
|
60
|
-
valid: ok,
|
|
61
|
-
verifiable,
|
|
62
|
-
...(verifiable ? {} : { reason: 'no audit entries — nothing to verify (is the hook installed?)' }),
|
|
63
|
-
chainHashesValid: result.valid,
|
|
64
|
-
writerMix: result.writerMix,
|
|
65
|
-
tipSignature: {
|
|
66
|
-
present: tip.present,
|
|
67
|
-
expectedButMissing: tip.expectedButMissing,
|
|
68
|
-
signatureValid: tip.signatureValid,
|
|
69
|
-
ancestorIntact: tip.ancestorIntact,
|
|
70
|
-
matchesTip: tip.matchesTip,
|
|
71
|
-
trusted: tip.trusted,
|
|
72
|
-
signer: tip.signerKeyB64,
|
|
73
|
-
reason: tip.reason,
|
|
74
|
-
},
|
|
75
|
-
totalEntries: result.totalEntries,
|
|
76
|
-
chainedEntries: result.chainedEntries,
|
|
77
|
-
legacyEntries: result.legacyEntries,
|
|
78
|
-
errors: result.errors,
|
|
79
|
-
}, null, 2) + '\n');
|
|
80
|
-
return ok ? 0 : 1;
|
|
81
|
-
}
|
|
82
|
-
// Human output · header, verdict line, counts, then errors if any.
|
|
83
|
-
process.stdout.write('\n' + colors.dim('audit log: ') + colors.gray(AUDIT_FILE) + '\n\n');
|
|
84
|
-
if (result.totalEntries === 0) {
|
|
85
|
-
process.stdout.write(colors.gray(`${symbols.dot} No audit entries yet.`) +
|
|
86
|
-
colors.dim(' Install the hook first: ') +
|
|
87
|
-
colors.bold('codehere hook install') +
|
|
88
|
-
'\n\n');
|
|
89
|
-
return 0;
|
|
90
|
-
}
|
|
91
|
-
if (result.valid) {
|
|
92
|
-
process.stdout.write(colors.green(`${symbols.success} Chain intact`) +
|
|
93
|
-
colors.dim(' every entry verified against its predecessor hash.') +
|
|
94
|
-
'\n\n');
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
process.stdout.write(colors.error(`${symbols.error} Chain BROKEN`) +
|
|
98
|
-
colors.dim(` ${result.errors.length} break point${result.errors.length === 1 ? '' : 's'} detected.`) +
|
|
99
|
-
'\n\n');
|
|
100
|
-
}
|
|
101
|
-
// R1.5 · writer-provenance mix — honest about WHO wrote the entries. The
|
|
102
|
-
// verify surface must never imply everything went through the daemon when
|
|
103
|
-
// some entries are the hook's direct fallback or predate provenance.
|
|
104
|
-
const wm = result.writerMix;
|
|
105
|
-
if (result.chainedEntries > 0) {
|
|
106
|
-
process.stdout.write(colors.dim(` written by: ${wm.daemon} daemon \u00B7 ${wm.hookDirect} hook-direct (no daemon reachable) \u00B7 ${wm.unattributed} unattributed (no writer field)\n\n`));
|
|
107
|
-
}
|
|
108
|
-
// R2 · tip-signature line — catches a re-walked forgery the hash chain can't.
|
|
109
|
-
if (tip.present && tip.signatureValid && tip.ancestorIntact && tip.trusted) {
|
|
110
|
-
process.stdout.write(colors.green(`${symbols.success} Chain signed`) +
|
|
111
|
-
colors.dim(tip.matchesTip
|
|
112
|
-
? " by a trusted key · no edits by anyone without this machine's key."
|
|
113
|
-
: ' by a trusted key · the signed prefix is intact (the chain has grown since).') +
|
|
114
|
-
'\n\n');
|
|
115
|
-
}
|
|
116
|
-
else if (tipTampered) {
|
|
117
|
-
process.stdout.write(colors.error(`${symbols.error} Tip signature FAILED`) + colors.dim(` ${tip.reason}.`) + '\n\n');
|
|
118
|
-
}
|
|
119
|
-
process.stdout.write(colors.bold('Counts:\n'));
|
|
120
|
-
process.stdout.write(` ${result.totalEntries.toString().padStart(6)} total entries\n`);
|
|
121
|
-
process.stdout.write(` ${result.chainedEntries.toString().padStart(6)} hash-chained (verifiable)\n`);
|
|
122
|
-
process.stdout.write(` ${result.legacyEntries.toString().padStart(6)} legacy pre-chain (un-verifiable)\n\n`);
|
|
123
|
-
if (result.errors.length > 0) {
|
|
124
|
-
process.stdout.write(colors.bold('Break points:\n'));
|
|
125
|
-
for (const err of result.errors) {
|
|
126
|
-
process.stdout.write(' ' +
|
|
127
|
-
colors.error(`line ${err.lineNumber}`) +
|
|
128
|
-
colors.dim(' ') +
|
|
129
|
-
colors.gray(err.reason) +
|
|
130
|
-
colors.dim(' ') +
|
|
131
|
-
err.detail +
|
|
132
|
-
'\n');
|
|
133
|
-
}
|
|
134
|
-
process.stdout.write('\n');
|
|
135
|
-
}
|
|
136
|
-
return ok ? 0 : 1;
|
|
137
|
-
}
|
|
138
|
-
function show(seqStr, json) {
|
|
139
|
-
if (!seqStr || !/^\d+$/.test(seqStr)) {
|
|
140
|
-
process.stderr.write(colors.error(`${symbols.error} Need a numeric sequence: codehere audit show <seq>\n`));
|
|
141
|
-
return 2;
|
|
142
|
-
}
|
|
143
|
-
const target = parseInt(seqStr, 10);
|
|
144
|
-
if (!existsSync(AUDIT_FILE)) {
|
|
145
|
-
process.stderr.write(colors.gray(`${symbols.dot} No audit log yet.\n`));
|
|
146
|
-
return 2;
|
|
147
|
-
}
|
|
148
|
-
const lines = readFileSync(AUDIT_FILE, 'utf-8').split('\n').filter(Boolean);
|
|
149
|
-
for (const line of lines) {
|
|
150
|
-
let entry;
|
|
151
|
-
try {
|
|
152
|
-
entry = JSON.parse(line);
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (entry.seq !== target)
|
|
158
|
-
continue;
|
|
159
|
-
if (json) {
|
|
160
|
-
process.stdout.write(JSON.stringify(entry, null, 2) + '\n');
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
process.stdout.write('\n' +
|
|
164
|
-
colors.bold(`Entry #${target}`) +
|
|
165
|
-
(entry.ts ? colors.dim(' ' + new Date(entry.ts).toISOString()) : '') +
|
|
166
|
-
'\n\n');
|
|
167
|
-
for (const [k, v] of Object.entries(entry)) {
|
|
168
|
-
const val = typeof v === 'string' && v.length > 120 ? v.slice(0, 117) + '...' : JSON.stringify(v);
|
|
169
|
-
process.stdout.write(` ${colors.dim(k.padEnd(12))} ${val}\n`);
|
|
170
|
-
}
|
|
171
|
-
process.stdout.write('\n');
|
|
172
|
-
}
|
|
173
|
-
return 0;
|
|
174
|
-
}
|
|
175
|
-
process.stderr.write(colors.error(`${symbols.error} No entry with seq=${target}.\n`) +
|
|
176
|
-
colors.dim(' Tip: run `codehere audit verify` to see the chained-entry count.\n'));
|
|
177
|
-
return 2;
|
|
178
|
-
}
|
|
179
|
-
/* ──────────────────────────────────────────────────────────────────────── */
|
|
180
|
-
/** R-AAT · export the chain as IETF draft-sharif-agent-audit-trail-00 JSONL.
|
|
181
|
-
* The header line carries the honest scope notes (L0 trust level, codehere
|
|
182
|
-
* canonicalization, hashed inputs) so the FILE can't claim more than it is. */
|
|
183
|
-
function exportAatCmd(outPath) {
|
|
184
|
-
const exp = exportAat(AUDIT_FILE);
|
|
185
|
-
const target = outPath && outPath.trim() ? outPath.trim() : 'codehere-audit-aat.jsonl';
|
|
186
|
-
try {
|
|
187
|
-
writeFileSyncFs(target, aatToJsonl(exp), 'utf-8');
|
|
188
|
-
}
|
|
189
|
-
catch (e) {
|
|
190
|
-
process.stderr.write(colors.error(`${symbols.error} Could not write ${target}: ${e instanceof Error ? e.message : String(e)}\n`));
|
|
191
|
-
return 2;
|
|
192
|
-
}
|
|
193
|
-
process.stdout.write(colors.green(`${symbols.success} Exported ${exp.header.record_count} records`) +
|
|
194
|
-
colors.dim(` › ${target} (AAT draft-00 JSONL)\n`) +
|
|
195
|
-
(exp.skippedLegacy > 0
|
|
196
|
-
? colors.dim(` ${exp.skippedLegacy} legacy pre-chain entries skipped (no hash-chained position to export)\n`)
|
|
197
|
-
: '') +
|
|
198
|
-
colors.dim(' trust_level=L0 throughout · agents carry no cryptographic identity; the daemon signs the chain tip (recorder identity). Details in the header line.\n'));
|
|
199
|
-
return 0;
|
|
200
|
-
}
|
|
201
|
-
//# 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
|