claude-cli-advanced-starter-pack 1.1.0 ā 1.8.1
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/OVERVIEW.md +5 -1
- package/README.md +241 -132
- package/bin/gtask.js +53 -0
- package/package.json +1 -1
- package/src/cli/menu.js +27 -0
- package/src/commands/explore-mcp/mcp-registry.js +99 -0
- package/src/commands/init.js +339 -351
- package/src/commands/install-panel-hook.js +108 -0
- package/src/commands/install-scripts.js +232 -0
- package/src/commands/install-skill.js +220 -0
- package/src/commands/panel.js +297 -0
- package/src/commands/setup-wizard.js +4 -3
- package/src/commands/test-setup.js +4 -5
- package/src/data/releases.json +164 -0
- package/src/panel/queue.js +188 -0
- package/templates/commands/ask-claude.template.md +118 -0
- package/templates/commands/ccasp-panel.template.md +72 -0
- package/templates/commands/ccasp-setup.template.md +470 -79
- package/templates/commands/create-smoke-test.template.md +186 -0
- package/templates/commands/project-impl.template.md +9 -113
- package/templates/commands/refactor-check.template.md +112 -0
- package/templates/commands/refactor-cleanup.template.md +144 -0
- package/templates/commands/refactor-prep.template.md +192 -0
- package/templates/docs/AI_ARCHITECTURE_CONSTITUTION.template.md +198 -0
- package/templates/docs/DETAILED_GOTCHAS.template.md +347 -0
- package/templates/docs/PHASE-DEV-CHECKLIST.template.md +241 -0
- package/templates/docs/PROGRESS_JSON_TEMPLATE.json +117 -0
- package/templates/docs/background-agent.template.md +264 -0
- package/templates/hooks/autonomous-decision-logger.template.js +207 -0
- package/templates/hooks/branch-merge-checker.template.js +272 -0
- package/templates/hooks/git-commit-tracker.template.js +267 -0
- package/templates/hooks/issue-completion-detector.template.js +205 -0
- package/templates/hooks/panel-queue-reader.template.js +83 -0
- package/templates/hooks/phase-validation-gates.template.js +307 -0
- package/templates/hooks/session-id-generator.template.js +236 -0
- package/templates/hooks/token-usage-monitor.template.js +193 -0
- package/templates/patterns/README.md +129 -0
- package/templates/patterns/l1-l2-orchestration.md +189 -0
- package/templates/patterns/multi-phase-orchestration.md +258 -0
- package/templates/patterns/two-tier-query-pipeline.md +192 -0
- package/templates/scripts/README.md +109 -0
- package/templates/scripts/analyze-delegation-log.js +299 -0
- package/templates/scripts/autonomous-decision-logger.js +277 -0
- package/templates/scripts/git-history-analyzer.py +269 -0
- package/templates/scripts/phase-validation-gates.js +307 -0
- package/templates/scripts/poll-deployment-status.js +260 -0
- package/templates/scripts/roadmap-scanner.js +263 -0
- package/templates/scripts/validate-deployment.js +293 -0
- package/templates/skills/agent-creator/skill.json +18 -0
- package/templates/skills/agent-creator/skill.md +335 -0
- package/templates/skills/hook-creator/skill.json +18 -0
- package/templates/skills/hook-creator/skill.md +318 -0
- package/templates/skills/panel/skill.json +18 -0
- package/templates/skills/panel/skill.md +90 -0
- package/templates/skills/rag-agent-creator/skill.json +18 -0
- package/templates/skills/rag-agent-creator/skill.md +307 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Analyze Delegation Log
|
|
4
|
+
*
|
|
5
|
+
* Analyzes Claude Code delegation logs to understand model usage,
|
|
6
|
+
* token consumption, and agent patterns.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node analyze-delegation-log.js ~/.claude/logs/delegation.jsonl
|
|
10
|
+
* node analyze-delegation-log.js log.jsonl --cost-estimate
|
|
11
|
+
* node analyze-delegation-log.js log.jsonl --output json
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { readFileSync, existsSync } from 'fs';
|
|
15
|
+
|
|
16
|
+
// Approximate costs per 1M tokens (as of 2025)
|
|
17
|
+
const MODEL_COSTS = {
|
|
18
|
+
'claude-opus-4-5': { input: 15.00, output: 75.00 },
|
|
19
|
+
'claude-sonnet-4': { input: 3.00, output: 15.00 },
|
|
20
|
+
'claude-haiku': { input: 0.25, output: 1.25 },
|
|
21
|
+
'default': { input: 3.00, output: 15.00 },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
class DelegationAnalyzer {
|
|
25
|
+
constructor(logPath, options = {}) {
|
|
26
|
+
this.logPath = logPath;
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.entries = [];
|
|
29
|
+
this.analysis = {
|
|
30
|
+
models: {},
|
|
31
|
+
agents: {},
|
|
32
|
+
tools: {},
|
|
33
|
+
sessions: {},
|
|
34
|
+
timeline: [],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async analyze() {
|
|
39
|
+
console.log(`\nš Analyzing delegation log: ${this.logPath}\n`);
|
|
40
|
+
|
|
41
|
+
if (!existsSync(this.logPath)) {
|
|
42
|
+
console.error(`Error: File not found: ${this.logPath}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await this.parseLog();
|
|
47
|
+
await this.computeMetrics();
|
|
48
|
+
|
|
49
|
+
if (this.options.output === 'json') {
|
|
50
|
+
this.outputJson();
|
|
51
|
+
} else {
|
|
52
|
+
this.outputText();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async parseLog() {
|
|
57
|
+
const content = readFileSync(this.logPath, 'utf8');
|
|
58
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
59
|
+
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
try {
|
|
62
|
+
const entry = JSON.parse(line);
|
|
63
|
+
this.entries.push(entry);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
// Skip invalid lines
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log(`Parsed ${this.entries.length} log entries\n`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async computeMetrics() {
|
|
73
|
+
for (const entry of this.entries) {
|
|
74
|
+
// Track by model
|
|
75
|
+
const model = entry.model || 'unknown';
|
|
76
|
+
if (!this.analysis.models[model]) {
|
|
77
|
+
this.analysis.models[model] = {
|
|
78
|
+
calls: 0,
|
|
79
|
+
inputTokens: 0,
|
|
80
|
+
outputTokens: 0,
|
|
81
|
+
errors: 0,
|
|
82
|
+
avgLatency: 0,
|
|
83
|
+
latencies: [],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const modelStats = this.analysis.models[model];
|
|
88
|
+
modelStats.calls++;
|
|
89
|
+
modelStats.inputTokens += entry.inputTokens || 0;
|
|
90
|
+
modelStats.outputTokens += entry.outputTokens || 0;
|
|
91
|
+
if (entry.error) modelStats.errors++;
|
|
92
|
+
if (entry.latencyMs) modelStats.latencies.push(entry.latencyMs);
|
|
93
|
+
|
|
94
|
+
// Track by agent type
|
|
95
|
+
const agentType = entry.agentType || entry.subagentType || 'main';
|
|
96
|
+
if (!this.analysis.agents[agentType]) {
|
|
97
|
+
this.analysis.agents[agentType] = {
|
|
98
|
+
invocations: 0,
|
|
99
|
+
totalTokens: 0,
|
|
100
|
+
avgTokensPerCall: 0,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const agentStats = this.analysis.agents[agentType];
|
|
105
|
+
agentStats.invocations++;
|
|
106
|
+
agentStats.totalTokens += (entry.inputTokens || 0) + (entry.outputTokens || 0);
|
|
107
|
+
|
|
108
|
+
// Track by tool
|
|
109
|
+
if (entry.tool) {
|
|
110
|
+
if (!this.analysis.tools[entry.tool]) {
|
|
111
|
+
this.analysis.tools[entry.tool] = { calls: 0, errors: 0 };
|
|
112
|
+
}
|
|
113
|
+
this.analysis.tools[entry.tool].calls++;
|
|
114
|
+
if (entry.error) this.analysis.tools[entry.tool].errors++;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Track by session
|
|
118
|
+
const sessionId = entry.sessionId || 'default';
|
|
119
|
+
if (!this.analysis.sessions[sessionId]) {
|
|
120
|
+
this.analysis.sessions[sessionId] = {
|
|
121
|
+
calls: 0,
|
|
122
|
+
tokens: 0,
|
|
123
|
+
start: entry.timestamp,
|
|
124
|
+
end: entry.timestamp,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const session = this.analysis.sessions[sessionId];
|
|
129
|
+
session.calls++;
|
|
130
|
+
session.tokens += (entry.inputTokens || 0) + (entry.outputTokens || 0);
|
|
131
|
+
if (entry.timestamp > session.end) session.end = entry.timestamp;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Compute averages
|
|
135
|
+
for (const model of Object.keys(this.analysis.models)) {
|
|
136
|
+
const stats = this.analysis.models[model];
|
|
137
|
+
if (stats.latencies.length > 0) {
|
|
138
|
+
stats.avgLatency = Math.round(
|
|
139
|
+
stats.latencies.reduce((a, b) => a + b, 0) / stats.latencies.length
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
delete stats.latencies;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (const agent of Object.keys(this.analysis.agents)) {
|
|
146
|
+
const stats = this.analysis.agents[agent];
|
|
147
|
+
stats.avgTokensPerCall = Math.round(stats.totalTokens / stats.invocations);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
estimateCost() {
|
|
152
|
+
let totalCost = 0;
|
|
153
|
+
const breakdown = {};
|
|
154
|
+
|
|
155
|
+
for (const [model, stats] of Object.entries(this.analysis.models)) {
|
|
156
|
+
const costs = MODEL_COSTS[model] || MODEL_COSTS['default'];
|
|
157
|
+
const inputCost = (stats.inputTokens / 1_000_000) * costs.input;
|
|
158
|
+
const outputCost = (stats.outputTokens / 1_000_000) * costs.output;
|
|
159
|
+
const modelCost = inputCost + outputCost;
|
|
160
|
+
|
|
161
|
+
breakdown[model] = {
|
|
162
|
+
inputCost: inputCost.toFixed(4),
|
|
163
|
+
outputCost: outputCost.toFixed(4),
|
|
164
|
+
totalCost: modelCost.toFixed(4),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
totalCost += modelCost;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { breakdown, totalCost: totalCost.toFixed(4) };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
outputText() {
|
|
174
|
+
console.log('='.repeat(70));
|
|
175
|
+
console.log(' DELEGATION LOG ANALYSIS');
|
|
176
|
+
console.log('='.repeat(70));
|
|
177
|
+
|
|
178
|
+
// Model usage
|
|
179
|
+
console.log('\nš Model Usage\n');
|
|
180
|
+
console.log('Model Calls Input Tokens Output Tokens Errors');
|
|
181
|
+
console.log('-'.repeat(70));
|
|
182
|
+
|
|
183
|
+
for (const [model, stats] of Object.entries(this.analysis.models)) {
|
|
184
|
+
const modelName = model.padEnd(24);
|
|
185
|
+
const calls = stats.calls.toString().padStart(6);
|
|
186
|
+
const input = stats.inputTokens.toLocaleString().padStart(15);
|
|
187
|
+
const output = stats.outputTokens.toLocaleString().padStart(16);
|
|
188
|
+
const errors = stats.errors.toString().padStart(8);
|
|
189
|
+
console.log(`${modelName}${calls}${input}${output}${errors}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Agent usage
|
|
193
|
+
console.log('\nš¤ Agent Types\n');
|
|
194
|
+
console.log('Agent Type Invocations Total Tokens Avg Tokens/Call');
|
|
195
|
+
console.log('-'.repeat(70));
|
|
196
|
+
|
|
197
|
+
for (const [agent, stats] of Object.entries(this.analysis.agents)) {
|
|
198
|
+
const agentName = agent.padEnd(22);
|
|
199
|
+
const invocations = stats.invocations.toString().padStart(12);
|
|
200
|
+
const tokens = stats.totalTokens.toLocaleString().padStart(15);
|
|
201
|
+
const avg = stats.avgTokensPerCall.toLocaleString().padStart(17);
|
|
202
|
+
console.log(`${agentName}${invocations}${tokens}${avg}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Tool usage (top 10)
|
|
206
|
+
const toolEntries = Object.entries(this.analysis.tools)
|
|
207
|
+
.sort((a, b) => b[1].calls - a[1].calls)
|
|
208
|
+
.slice(0, 10);
|
|
209
|
+
|
|
210
|
+
if (toolEntries.length > 0) {
|
|
211
|
+
console.log('\nš§ Top 10 Tools\n');
|
|
212
|
+
console.log('Tool Calls Errors');
|
|
213
|
+
console.log('-'.repeat(50));
|
|
214
|
+
|
|
215
|
+
for (const [tool, stats] of toolEntries) {
|
|
216
|
+
const toolName = tool.padEnd(30);
|
|
217
|
+
const calls = stats.calls.toString().padStart(6);
|
|
218
|
+
const errors = stats.errors.toString().padStart(9);
|
|
219
|
+
console.log(`${toolName}${calls}${errors}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Cost estimate
|
|
224
|
+
if (this.options.costEstimate) {
|
|
225
|
+
const cost = this.estimateCost();
|
|
226
|
+
|
|
227
|
+
console.log('\nš° Cost Estimate\n');
|
|
228
|
+
console.log('Model Input Cost Output Cost Total Cost');
|
|
229
|
+
console.log('-'.repeat(70));
|
|
230
|
+
|
|
231
|
+
for (const [model, costs] of Object.entries(cost.breakdown)) {
|
|
232
|
+
const modelName = model.padEnd(26);
|
|
233
|
+
const input = `$${costs.inputCost}`.padStart(12);
|
|
234
|
+
const output = `$${costs.outputCost}`.padStart(14);
|
|
235
|
+
const total = `$${costs.totalCost}`.padStart(13);
|
|
236
|
+
console.log(`${modelName}${input}${output}${total}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log('-'.repeat(70));
|
|
240
|
+
console.log(`${'TOTAL'.padEnd(26)}${''.padStart(26)}$${cost.totalCost}`.padStart(13));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Summary
|
|
244
|
+
const totalCalls = Object.values(this.analysis.models)
|
|
245
|
+
.reduce((acc, m) => acc + m.calls, 0);
|
|
246
|
+
const totalTokens = Object.values(this.analysis.models)
|
|
247
|
+
.reduce((acc, m) => acc + m.inputTokens + m.outputTokens, 0);
|
|
248
|
+
const totalErrors = Object.values(this.analysis.models)
|
|
249
|
+
.reduce((acc, m) => acc + m.errors, 0);
|
|
250
|
+
|
|
251
|
+
console.log('\n' + '='.repeat(70));
|
|
252
|
+
console.log('SUMMARY');
|
|
253
|
+
console.log('='.repeat(70));
|
|
254
|
+
console.log(`\n Total API Calls: ${totalCalls.toLocaleString()}`);
|
|
255
|
+
console.log(` Total Tokens: ${totalTokens.toLocaleString()}`);
|
|
256
|
+
console.log(` Error Rate: ${((totalErrors / totalCalls) * 100).toFixed(2)}%`);
|
|
257
|
+
console.log(` Sessions: ${Object.keys(this.analysis.sessions).length}`);
|
|
258
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
outputJson() {
|
|
262
|
+
const output = {
|
|
263
|
+
analyzedAt: new Date().toISOString(),
|
|
264
|
+
logPath: this.logPath,
|
|
265
|
+
totalEntries: this.entries.length,
|
|
266
|
+
analysis: this.analysis,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
if (this.options.costEstimate) {
|
|
270
|
+
output.costEstimate = this.estimateCost();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
console.log(JSON.stringify(output, null, 2));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// CLI entry point
|
|
278
|
+
async function main() {
|
|
279
|
+
const args = process.argv.slice(2);
|
|
280
|
+
|
|
281
|
+
if (args.length === 0 || args[0].startsWith('--')) {
|
|
282
|
+
console.error('Usage: node analyze-delegation-log.js <log-file> [options]');
|
|
283
|
+
console.error('Options:');
|
|
284
|
+
console.error(' --cost-estimate Include cost estimate');
|
|
285
|
+
console.error(' --output json Output as JSON');
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const logPath = args[0];
|
|
290
|
+
const options = {
|
|
291
|
+
costEstimate: args.includes('--cost-estimate'),
|
|
292
|
+
output: args.includes('--output') ? args[args.indexOf('--output') + 1] : 'text',
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const analyzer = new DelegationAnalyzer(logPath, options);
|
|
296
|
+
await analyzer.analyze();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Autonomous Decision Logger
|
|
4
|
+
*
|
|
5
|
+
* Creates JSONL audit trail for agent decisions.
|
|
6
|
+
* Tracks reasoning, confidence, and outcomes.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* // Import in your hook or script
|
|
10
|
+
* import { DecisionLogger } from './autonomous-decision-logger.js';
|
|
11
|
+
*
|
|
12
|
+
* const logger = new DecisionLogger('.claude/logs/decisions.jsonl');
|
|
13
|
+
* logger.logDecision({
|
|
14
|
+
* agent: 'deployment-checker',
|
|
15
|
+
* decision: 'deploy',
|
|
16
|
+
* reasoning: 'All tests passed, no conflicts',
|
|
17
|
+
* confidence: 0.95,
|
|
18
|
+
* });
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'fs';
|
|
22
|
+
import { dirname, resolve } from 'path';
|
|
23
|
+
|
|
24
|
+
export class DecisionLogger {
|
|
25
|
+
constructor(logPath = '.claude/logs/decisions.jsonl') {
|
|
26
|
+
this.logPath = resolve(process.cwd(), logPath);
|
|
27
|
+
this.sessionId = this.generateSessionId();
|
|
28
|
+
this.ensureLogDirectory();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
generateSessionId() {
|
|
32
|
+
const timestamp = Date.now().toString(36);
|
|
33
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
34
|
+
return `${timestamp}-${random}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ensureLogDirectory() {
|
|
38
|
+
const dir = dirname(this.logPath);
|
|
39
|
+
if (!existsSync(dir)) {
|
|
40
|
+
mkdirSync(dir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Log a decision with full context
|
|
46
|
+
*
|
|
47
|
+
* @param {Object} decision
|
|
48
|
+
* @param {string} decision.agent - Agent/component making decision
|
|
49
|
+
* @param {string} decision.decision - The decision made
|
|
50
|
+
* @param {string} decision.reasoning - Why this decision was made
|
|
51
|
+
* @param {number} decision.confidence - Confidence level 0-1
|
|
52
|
+
* @param {Object} [decision.context] - Additional context
|
|
53
|
+
* @param {string} [decision.outcome] - Result (success/failure/pending)
|
|
54
|
+
* @param {Array} [decision.alternatives] - Other options considered
|
|
55
|
+
*/
|
|
56
|
+
logDecision(decision) {
|
|
57
|
+
const entry = {
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
sessionId: this.sessionId,
|
|
60
|
+
pid: process.pid,
|
|
61
|
+
...decision,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
this.writeEntry(entry);
|
|
65
|
+
return entry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Log an action taken by an agent
|
|
70
|
+
*/
|
|
71
|
+
logAction(agent, action, details = {}) {
|
|
72
|
+
return this.logDecision({
|
|
73
|
+
agent,
|
|
74
|
+
type: 'action',
|
|
75
|
+
decision: action,
|
|
76
|
+
...details,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Log an observation or analysis
|
|
82
|
+
*/
|
|
83
|
+
logObservation(agent, observation, details = {}) {
|
|
84
|
+
return this.logDecision({
|
|
85
|
+
agent,
|
|
86
|
+
type: 'observation',
|
|
87
|
+
decision: observation,
|
|
88
|
+
...details,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Log an error or failure
|
|
94
|
+
*/
|
|
95
|
+
logError(agent, error, context = {}) {
|
|
96
|
+
return this.logDecision({
|
|
97
|
+
agent,
|
|
98
|
+
type: 'error',
|
|
99
|
+
decision: 'error',
|
|
100
|
+
reasoning: error.message || error,
|
|
101
|
+
outcome: 'failure',
|
|
102
|
+
context: {
|
|
103
|
+
...context,
|
|
104
|
+
stack: error.stack,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Log a phase transition
|
|
111
|
+
*/
|
|
112
|
+
logPhaseTransition(fromPhase, toPhase, reason, validation = {}) {
|
|
113
|
+
return this.logDecision({
|
|
114
|
+
agent: 'phase-controller',
|
|
115
|
+
type: 'phase_transition',
|
|
116
|
+
decision: `${fromPhase} -> ${toPhase}`,
|
|
117
|
+
reasoning: reason,
|
|
118
|
+
context: { fromPhase, toPhase, validation },
|
|
119
|
+
outcome: 'success',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Log agent spawn/delegation
|
|
125
|
+
*/
|
|
126
|
+
logDelegation(parentAgent, childAgent, task, options = {}) {
|
|
127
|
+
return this.logDecision({
|
|
128
|
+
agent: parentAgent,
|
|
129
|
+
type: 'delegation',
|
|
130
|
+
decision: `spawn:${childAgent}`,
|
|
131
|
+
reasoning: `Delegating: ${task}`,
|
|
132
|
+
context: {
|
|
133
|
+
childAgent,
|
|
134
|
+
task,
|
|
135
|
+
model: options.model,
|
|
136
|
+
runInBackground: options.runInBackground,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
writeEntry(entry) {
|
|
142
|
+
const line = JSON.stringify(entry) + '\n';
|
|
143
|
+
appendFileSync(this.logPath, line);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Read all decisions for current session
|
|
148
|
+
*/
|
|
149
|
+
getSessionDecisions() {
|
|
150
|
+
if (!existsSync(this.logPath)) return [];
|
|
151
|
+
|
|
152
|
+
const content = readFileSync(this.logPath, 'utf8');
|
|
153
|
+
return content
|
|
154
|
+
.split('\n')
|
|
155
|
+
.filter(line => line.trim())
|
|
156
|
+
.map(line => JSON.parse(line))
|
|
157
|
+
.filter(entry => entry.sessionId === this.sessionId);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get summary statistics
|
|
162
|
+
*/
|
|
163
|
+
getSummary() {
|
|
164
|
+
const decisions = this.getSessionDecisions();
|
|
165
|
+
|
|
166
|
+
const summary = {
|
|
167
|
+
sessionId: this.sessionId,
|
|
168
|
+
totalDecisions: decisions.length,
|
|
169
|
+
byType: {},
|
|
170
|
+
byAgent: {},
|
|
171
|
+
byOutcome: {},
|
|
172
|
+
avgConfidence: 0,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
let confidenceSum = 0;
|
|
176
|
+
let confidenceCount = 0;
|
|
177
|
+
|
|
178
|
+
for (const d of decisions) {
|
|
179
|
+
// Count by type
|
|
180
|
+
const type = d.type || 'decision';
|
|
181
|
+
summary.byType[type] = (summary.byType[type] || 0) + 1;
|
|
182
|
+
|
|
183
|
+
// Count by agent
|
|
184
|
+
summary.byAgent[d.agent] = (summary.byAgent[d.agent] || 0) + 1;
|
|
185
|
+
|
|
186
|
+
// Count by outcome
|
|
187
|
+
if (d.outcome) {
|
|
188
|
+
summary.byOutcome[d.outcome] = (summary.byOutcome[d.outcome] || 0) + 1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Average confidence
|
|
192
|
+
if (typeof d.confidence === 'number') {
|
|
193
|
+
confidenceSum += d.confidence;
|
|
194
|
+
confidenceCount++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (confidenceCount > 0) {
|
|
199
|
+
summary.avgConfidence = (confidenceSum / confidenceCount).toFixed(2);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return summary;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// CLI mode - print summary if run directly
|
|
207
|
+
async function main() {
|
|
208
|
+
const args = process.argv.slice(2);
|
|
209
|
+
const logPath = args[0] || '.claude/logs/decisions.jsonl';
|
|
210
|
+
|
|
211
|
+
if (!existsSync(logPath)) {
|
|
212
|
+
console.log(`No log file found at: ${logPath}`);
|
|
213
|
+
console.log('\nUsage: node autonomous-decision-logger.js [log-path]');
|
|
214
|
+
console.log('\nTo create logs, import DecisionLogger in your code:');
|
|
215
|
+
console.log(" import { DecisionLogger } from './autonomous-decision-logger.js';");
|
|
216
|
+
console.log(" const logger = new DecisionLogger();");
|
|
217
|
+
console.log(" logger.logDecision({ agent: 'my-agent', decision: 'proceed', confidence: 0.9 });");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Read and summarize log
|
|
222
|
+
const content = readFileSync(logPath, 'utf8');
|
|
223
|
+
const entries = content
|
|
224
|
+
.split('\n')
|
|
225
|
+
.filter(line => line.trim())
|
|
226
|
+
.map(line => JSON.parse(line));
|
|
227
|
+
|
|
228
|
+
console.log('\nš Decision Log Summary\n');
|
|
229
|
+
console.log(`Log file: ${logPath}`);
|
|
230
|
+
console.log(`Total entries: ${entries.length}`);
|
|
231
|
+
|
|
232
|
+
// Group by session
|
|
233
|
+
const sessions = {};
|
|
234
|
+
for (const entry of entries) {
|
|
235
|
+
const sid = entry.sessionId || 'unknown';
|
|
236
|
+
if (!sessions[sid]) {
|
|
237
|
+
sessions[sid] = [];
|
|
238
|
+
}
|
|
239
|
+
sessions[sid].push(entry);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log(`Sessions: ${Object.keys(sessions).length}`);
|
|
243
|
+
|
|
244
|
+
// Show last 10 decisions
|
|
245
|
+
console.log('\nš Last 10 Decisions:\n');
|
|
246
|
+
const recent = entries.slice(-10);
|
|
247
|
+
for (const entry of recent) {
|
|
248
|
+
const time = new Date(entry.timestamp).toLocaleTimeString();
|
|
249
|
+
const conf = entry.confidence ? ` (${(entry.confidence * 100).toFixed(0)}%)` : '';
|
|
250
|
+
console.log(` [${time}] ${entry.agent}: ${entry.decision}${conf}`);
|
|
251
|
+
if (entry.reasoning) {
|
|
252
|
+
console.log(` āā ${entry.reasoning.substring(0, 60)}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// By type
|
|
257
|
+
const typeCount = {};
|
|
258
|
+
for (const entry of entries) {
|
|
259
|
+
const type = entry.type || 'decision';
|
|
260
|
+
typeCount[type] = (typeCount[type] || 0) + 1;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
console.log('\nš By Type:');
|
|
264
|
+
for (const [type, count] of Object.entries(typeCount).sort((a, b) => b[1] - a[1])) {
|
|
265
|
+
console.log(` ${type}: ${count}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.log('');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Export for use as module
|
|
272
|
+
export default DecisionLogger;
|
|
273
|
+
|
|
274
|
+
// Run CLI if called directly
|
|
275
|
+
if (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}`) {
|
|
276
|
+
main().catch(console.error);
|
|
277
|
+
}
|