selftune 0.1.4 → 0.2.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/.claude/agents/diagnosis-analyst.md +156 -0
- package/.claude/agents/evolution-reviewer.md +180 -0
- package/.claude/agents/integration-guide.md +212 -0
- package/.claude/agents/pattern-analyst.md +160 -0
- package/CHANGELOG.md +46 -1
- package/README.md +105 -257
- package/apps/local-dashboard/dist/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/apps/local-dashboard/dist/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/apps/local-dashboard/dist/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/apps/local-dashboard/dist/assets/index-C4EOTFZ2.js +15 -0
- package/apps/local-dashboard/dist/assets/index-bl-Webyd.css +1 -0
- package/apps/local-dashboard/dist/assets/vendor-react-U7zYD9Rg.js +60 -0
- package/apps/local-dashboard/dist/assets/vendor-table-B7VF2Ipl.js +26 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-D7_zX_qy.js +346 -0
- package/apps/local-dashboard/dist/favicon.png +0 -0
- package/apps/local-dashboard/dist/index.html +17 -0
- package/apps/local-dashboard/dist/logo.png +0 -0
- package/apps/local-dashboard/dist/logo.svg +9 -0
- package/assets/BeforeAfter.gif +0 -0
- package/assets/FeedbackLoop.gif +0 -0
- package/assets/logo.svg +9 -0
- package/assets/skill-health-badge.svg +20 -0
- package/cli/selftune/activation-rules.ts +171 -0
- package/cli/selftune/badge/badge-data.ts +108 -0
- package/cli/selftune/badge/badge-svg.ts +212 -0
- package/cli/selftune/badge/badge.ts +99 -0
- package/cli/selftune/canonical-export.ts +183 -0
- package/cli/selftune/constants.ts +103 -1
- package/cli/selftune/contribute/bundle.ts +314 -0
- package/cli/selftune/contribute/contribute.ts +214 -0
- package/cli/selftune/contribute/sanitize.ts +162 -0
- package/cli/selftune/cron/setup.ts +266 -0
- package/cli/selftune/dashboard-contract.ts +202 -0
- package/cli/selftune/dashboard-server.ts +1049 -0
- package/cli/selftune/dashboard.ts +43 -156
- package/cli/selftune/eval/baseline.ts +248 -0
- package/cli/selftune/eval/composability-v2.ts +273 -0
- package/cli/selftune/eval/composability.ts +117 -0
- package/cli/selftune/eval/generate-unit-tests.ts +143 -0
- package/cli/selftune/eval/hooks-to-evals.ts +101 -16
- package/cli/selftune/eval/import-skillsbench.ts +221 -0
- package/cli/selftune/eval/synthetic-evals.ts +172 -0
- package/cli/selftune/eval/unit-test-cli.ts +152 -0
- package/cli/selftune/eval/unit-test.ts +196 -0
- package/cli/selftune/evolution/deploy-proposal.ts +142 -1
- package/cli/selftune/evolution/evidence.ts +26 -0
- package/cli/selftune/evolution/evolve-body.ts +586 -0
- package/cli/selftune/evolution/evolve.ts +825 -116
- package/cli/selftune/evolution/extract-patterns.ts +105 -16
- package/cli/selftune/evolution/pareto.ts +314 -0
- package/cli/selftune/evolution/propose-body.ts +171 -0
- package/cli/selftune/evolution/propose-description.ts +100 -2
- package/cli/selftune/evolution/propose-routing.ts +166 -0
- package/cli/selftune/evolution/refine-body.ts +141 -0
- package/cli/selftune/evolution/rollback.ts +21 -4
- package/cli/selftune/evolution/validate-body.ts +254 -0
- package/cli/selftune/evolution/validate-proposal.ts +257 -35
- package/cli/selftune/evolution/validate-routing.ts +177 -0
- package/cli/selftune/grading/auto-grade.ts +200 -0
- package/cli/selftune/grading/grade-session.ts +513 -42
- package/cli/selftune/grading/pre-gates.ts +104 -0
- package/cli/selftune/grading/results.ts +42 -0
- package/cli/selftune/hooks/auto-activate.ts +185 -0
- package/cli/selftune/hooks/evolution-guard.ts +165 -0
- package/cli/selftune/hooks/prompt-log.ts +172 -2
- package/cli/selftune/hooks/session-stop.ts +123 -3
- package/cli/selftune/hooks/skill-change-guard.ts +112 -0
- package/cli/selftune/hooks/skill-eval.ts +119 -3
- package/cli/selftune/index.ts +415 -48
- package/cli/selftune/ingestors/claude-replay.ts +377 -0
- package/cli/selftune/ingestors/codex-rollout.ts +345 -46
- package/cli/selftune/ingestors/codex-wrapper.ts +207 -39
- package/cli/selftune/ingestors/openclaw-ingest.ts +573 -0
- package/cli/selftune/ingestors/opencode-ingest.ts +193 -17
- package/cli/selftune/init.ts +376 -16
- package/cli/selftune/last.ts +14 -5
- package/cli/selftune/localdb/db.ts +63 -0
- package/cli/selftune/localdb/materialize.ts +428 -0
- package/cli/selftune/localdb/queries.ts +376 -0
- package/cli/selftune/localdb/schema.ts +204 -0
- package/cli/selftune/memory/writer.ts +447 -0
- package/cli/selftune/monitoring/watch.ts +90 -16
- package/cli/selftune/normalization.ts +682 -0
- package/cli/selftune/observability.ts +19 -44
- package/cli/selftune/orchestrate.ts +1073 -0
- package/cli/selftune/quickstart.ts +203 -0
- package/cli/selftune/repair/skill-usage.ts +576 -0
- package/cli/selftune/schedule.ts +561 -0
- package/cli/selftune/status.ts +59 -33
- package/cli/selftune/sync.ts +627 -0
- package/cli/selftune/types.ts +525 -5
- package/cli/selftune/utils/canonical-log.ts +45 -0
- package/cli/selftune/utils/frontmatter.ts +217 -0
- package/cli/selftune/utils/hooks.ts +41 -0
- package/cli/selftune/utils/html.ts +27 -0
- package/cli/selftune/utils/llm-call.ts +103 -19
- package/cli/selftune/utils/math.ts +10 -0
- package/cli/selftune/utils/query-filter.ts +139 -0
- package/cli/selftune/utils/skill-discovery.ts +340 -0
- package/cli/selftune/utils/skill-log.ts +68 -0
- package/cli/selftune/utils/skill-usage-confidence.ts +18 -0
- package/cli/selftune/utils/transcript.ts +307 -26
- package/cli/selftune/utils/trigger-check.ts +89 -0
- package/cli/selftune/utils/tui.ts +156 -0
- package/cli/selftune/workflows/discover.ts +254 -0
- package/cli/selftune/workflows/skill-md-writer.ts +288 -0
- package/cli/selftune/workflows/workflows.ts +188 -0
- package/package.json +28 -11
- package/packages/telemetry-contract/README.md +11 -0
- package/packages/telemetry-contract/fixtures/golden.json +87 -0
- package/packages/telemetry-contract/fixtures/golden.test.ts +42 -0
- package/packages/telemetry-contract/index.ts +1 -0
- package/packages/telemetry-contract/package.json +19 -0
- package/packages/telemetry-contract/src/index.ts +2 -0
- package/packages/telemetry-contract/src/types.ts +163 -0
- package/packages/telemetry-contract/src/validators.ts +109 -0
- package/skill/SKILL.md +180 -33
- package/skill/Workflows/AutoActivation.md +145 -0
- package/skill/Workflows/Badge.md +124 -0
- package/skill/Workflows/Baseline.md +144 -0
- package/skill/Workflows/Composability.md +107 -0
- package/skill/Workflows/Contribute.md +94 -0
- package/skill/Workflows/Cron.md +132 -0
- package/skill/Workflows/Dashboard.md +214 -0
- package/skill/Workflows/Doctor.md +63 -14
- package/skill/Workflows/Evals.md +110 -18
- package/skill/Workflows/EvolutionMemory.md +154 -0
- package/skill/Workflows/Evolve.md +181 -21
- package/skill/Workflows/EvolveBody.md +159 -0
- package/skill/Workflows/Grade.md +36 -31
- package/skill/Workflows/ImportSkillsBench.md +117 -0
- package/skill/Workflows/Ingest.md +142 -21
- package/skill/Workflows/Initialize.md +91 -23
- package/skill/Workflows/Orchestrate.md +139 -0
- package/skill/Workflows/Replay.md +91 -0
- package/skill/Workflows/Rollback.md +23 -4
- package/skill/Workflows/Schedule.md +61 -0
- package/skill/Workflows/Sync.md +88 -0
- package/skill/Workflows/UnitTest.md +150 -0
- package/skill/Workflows/Watch.md +33 -1
- package/skill/Workflows/Workflows.md +129 -0
- package/skill/assets/activation-rules-default.json +26 -0
- package/skill/assets/multi-skill-settings.json +63 -0
- package/skill/assets/single-skill-settings.json +57 -0
- package/skill/references/invocation-taxonomy.md +2 -2
- package/skill/references/logs.md +164 -2
- package/skill/references/setup-patterns.md +65 -0
- package/skill/references/version-history.md +40 -0
- package/skill/settings_snippet.json +23 -0
- package/templates/activation-rules-default.json +27 -0
- package/templates/multi-skill-settings.json +64 -0
- package/templates/single-skill-settings.json +58 -0
- package/dashboard/index.html +0 -1119
|
@@ -17,35 +17,59 @@
|
|
|
17
17
|
* ~/.claude/skill_usage_log.jsonl
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
21
20
|
import { homedir } from "node:os";
|
|
22
21
|
import { join } from "node:path";
|
|
23
|
-
import { QUERY_LOG, SKILL_LOG, TELEMETRY_LOG } from "../constants.js";
|
|
24
|
-
import
|
|
22
|
+
import { CANONICAL_LOG, QUERY_LOG, SKILL_LOG, TELEMETRY_LOG } from "../constants.js";
|
|
23
|
+
import {
|
|
24
|
+
appendCanonicalRecords,
|
|
25
|
+
buildCanonicalExecutionFact,
|
|
26
|
+
buildCanonicalPrompt,
|
|
27
|
+
buildCanonicalSession,
|
|
28
|
+
buildCanonicalSkillInvocation,
|
|
29
|
+
type CanonicalBaseInput,
|
|
30
|
+
deriveInvocationMode,
|
|
31
|
+
derivePromptId,
|
|
32
|
+
deriveSkillInvocationId,
|
|
33
|
+
} from "../normalization.js";
|
|
34
|
+
import type {
|
|
35
|
+
CanonicalRecord,
|
|
36
|
+
QueryLogRecord,
|
|
37
|
+
SessionTelemetryRecord,
|
|
38
|
+
SkillUsageRecord,
|
|
39
|
+
} from "../types.js";
|
|
25
40
|
import { appendJsonl } from "../utils/jsonl.js";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
import {
|
|
42
|
+
classifySkillPath,
|
|
43
|
+
containsWholeSkillMention,
|
|
44
|
+
extractExplicitSkillMentions,
|
|
45
|
+
extractSkillNamesFromInstructions,
|
|
46
|
+
findInstalledSkillNames,
|
|
47
|
+
findInstalledSkillPath,
|
|
48
|
+
findRepositorySkillDirs,
|
|
49
|
+
} from "../utils/skill-discovery.js";
|
|
50
|
+
|
|
51
|
+
const SKILL_NAME_CACHE = new Map<string, Set<string>>();
|
|
31
52
|
|
|
32
53
|
/** Return the set of skill names installed in Codex skill directories. */
|
|
33
|
-
export function findCodexSkillNames(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
export function findCodexSkillNames(
|
|
55
|
+
cwd: string = process.cwd(),
|
|
56
|
+
homeDir: string = homedir(),
|
|
57
|
+
adminDir: string = "/etc/codex/skills",
|
|
58
|
+
codexHome: string = process.env.CODEX_HOME ?? join(homeDir, ".codex"),
|
|
59
|
+
): Set<string> {
|
|
60
|
+
const cacheKey = [cwd, homeDir, adminDir, codexHome].join("\u0000");
|
|
61
|
+
const cached = SKILL_NAME_CACHE.get(cacheKey);
|
|
62
|
+
if (cached) return new Set(cached);
|
|
63
|
+
|
|
64
|
+
const names = findInstalledSkillNames([
|
|
65
|
+
...findRepositorySkillDirs(cwd),
|
|
66
|
+
join(homeDir, ".agents", "skills"),
|
|
67
|
+
adminDir,
|
|
68
|
+
join(codexHome, "skills"),
|
|
69
|
+
join(codexHome, "skills", ".system"),
|
|
70
|
+
]);
|
|
71
|
+
SKILL_NAME_CACHE.set(cacheKey, names);
|
|
72
|
+
return new Set(names);
|
|
49
73
|
}
|
|
50
74
|
|
|
51
75
|
/**
|
|
@@ -84,12 +108,29 @@ export function parseJsonlStream(lines: string[], skillNames: Set<string>): Pars
|
|
|
84
108
|
let inputTokens = 0;
|
|
85
109
|
let outputTokens = 0;
|
|
86
110
|
const agentMessages: string[] = [];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
const sessionSkillNames = new Set(skillNames);
|
|
112
|
+
const rememberSessionSkillNames = (text: unknown): void => {
|
|
113
|
+
if (typeof text !== "string" || !text) return;
|
|
114
|
+
for (const skillName of extractSkillNamesFromInstructions(text, sessionSkillNames)) {
|
|
115
|
+
sessionSkillNames.add(skillName);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const detectTriggeredSkills = (text: unknown): void => {
|
|
119
|
+
if (typeof text !== "string" || !text) return;
|
|
120
|
+
for (const skillName of sessionSkillNames) {
|
|
121
|
+
if (containsWholeSkillMention(text, skillName) && !skillsTriggered.includes(skillName)) {
|
|
122
|
+
skillsTriggered.push(skillName);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const detectExplicitPromptSkillMentions = (text: unknown): void => {
|
|
127
|
+
if (typeof text !== "string" || !text) return;
|
|
128
|
+
for (const skillName of extractExplicitSkillMentions(text, sessionSkillNames)) {
|
|
129
|
+
if (!skillsTriggered.includes(skillName)) {
|
|
130
|
+
skillsTriggered.push(skillName);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
93
134
|
|
|
94
135
|
for (const rawLine of lines) {
|
|
95
136
|
const line = rawLine.trim();
|
|
@@ -106,6 +147,12 @@ export function parseJsonlStream(lines: string[], skillNames: Set<string>): Pars
|
|
|
106
147
|
|
|
107
148
|
if (etype === "thread.started") {
|
|
108
149
|
threadId = (event.thread_id as string) ?? "unknown";
|
|
150
|
+
} else if (etype === "session_meta") {
|
|
151
|
+
const payload = (event.payload as Record<string, unknown>) ?? {};
|
|
152
|
+
rememberSessionSkillNames(payload.instructions);
|
|
153
|
+
rememberSessionSkillNames(
|
|
154
|
+
(payload.base_instructions as Record<string, unknown> | undefined)?.text,
|
|
155
|
+
);
|
|
109
156
|
} else if (etype === "turn.started") {
|
|
110
157
|
turns += 1;
|
|
111
158
|
} else if (etype === "turn.completed") {
|
|
@@ -137,6 +184,7 @@ export function parseJsonlStream(lines: string[], skillNames: Set<string>): Pars
|
|
|
137
184
|
} else if (itemType === "agent_message") {
|
|
138
185
|
const text = (item.text as string) ?? "";
|
|
139
186
|
if (text) agentMessages.push(text.slice(0, 500));
|
|
187
|
+
detectTriggeredSkills(text);
|
|
140
188
|
} else if (itemType === "reasoning") {
|
|
141
189
|
toolCalls.reasoning = (toolCalls.reasoning ?? 0) + 1;
|
|
142
190
|
}
|
|
@@ -144,14 +192,32 @@ export function parseJsonlStream(lines: string[], skillNames: Set<string>): Pars
|
|
|
144
192
|
|
|
145
193
|
// Detect skill names in text on completed events (whole-word match)
|
|
146
194
|
const textContent = ((item.text as string) ?? "") + ((item.command as string) ?? "");
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
195
|
+
if (etype === "item.completed") {
|
|
196
|
+
detectTriggeredSkills(textContent);
|
|
197
|
+
}
|
|
198
|
+
} else if (etype === "response_item") {
|
|
199
|
+
const payload = (event.payload as Record<string, unknown>) ?? {};
|
|
200
|
+
const itemType = (payload.type as string) ?? "";
|
|
201
|
+
if (itemType === "function_call") {
|
|
202
|
+
detectTriggeredSkills(payload.arguments);
|
|
203
|
+
} else if (itemType === "message") {
|
|
204
|
+
const content = Array.isArray(payload.content)
|
|
205
|
+
? payload.content
|
|
206
|
+
.map((part) =>
|
|
207
|
+
typeof part === "object" && part
|
|
208
|
+
? (((part as Record<string, unknown>).text as string | undefined) ?? "")
|
|
209
|
+
: "",
|
|
210
|
+
)
|
|
211
|
+
.join("\n")
|
|
212
|
+
: "";
|
|
213
|
+
rememberSessionSkillNames(content);
|
|
214
|
+
if ((payload.role as string) === "assistant") {
|
|
215
|
+
detectTriggeredSkills(content);
|
|
216
|
+
} else if ((payload.role as string) === "user") {
|
|
217
|
+
detectExplicitPromptSkillMentions(content);
|
|
154
218
|
}
|
|
219
|
+
} else if (itemType === "agent_reasoning") {
|
|
220
|
+
detectTriggeredSkills(payload.text);
|
|
155
221
|
}
|
|
156
222
|
} else if (etype === "error") {
|
|
157
223
|
errors += 1;
|
|
@@ -210,13 +276,25 @@ export function logSkillTrigger(
|
|
|
210
276
|
skillName: string,
|
|
211
277
|
prompt: string,
|
|
212
278
|
sessionId: string,
|
|
279
|
+
cwd: string = process.cwd(),
|
|
213
280
|
logPath: string = SKILL_LOG,
|
|
281
|
+
homeDir: string = homedir(),
|
|
282
|
+
codexHome: string = process.env.CODEX_HOME ?? join(homeDir, ".codex"),
|
|
214
283
|
): void {
|
|
284
|
+
const skillPath =
|
|
285
|
+
findInstalledSkillPath(skillName, [
|
|
286
|
+
...findRepositorySkillDirs(cwd),
|
|
287
|
+
join(homeDir, ".agents", "skills"),
|
|
288
|
+
"/etc/codex/skills",
|
|
289
|
+
join(codexHome, "skills"),
|
|
290
|
+
join(codexHome, "skills", ".system"),
|
|
291
|
+
]) ?? `(codex:${skillName})`;
|
|
215
292
|
const record: SkillUsageRecord = {
|
|
216
293
|
timestamp: new Date().toISOString(),
|
|
217
294
|
session_id: sessionId,
|
|
218
295
|
skill_name: skillName,
|
|
219
|
-
skill_path:
|
|
296
|
+
skill_path: skillPath,
|
|
297
|
+
...classifySkillPath(skillPath, homeDir, codexHome),
|
|
220
298
|
query: prompt,
|
|
221
299
|
triggered: true,
|
|
222
300
|
source: "codex",
|
|
@@ -224,6 +302,92 @@ export function logSkillTrigger(
|
|
|
224
302
|
appendJsonl(logPath, record);
|
|
225
303
|
}
|
|
226
304
|
|
|
305
|
+
/** Build canonical records from a wrapper session. */
|
|
306
|
+
export function buildCanonicalRecordsFromWrapper(
|
|
307
|
+
metrics: ParsedCodexStream,
|
|
308
|
+
prompt: string,
|
|
309
|
+
sessionId: string,
|
|
310
|
+
cwd: string,
|
|
311
|
+
): CanonicalRecord[] {
|
|
312
|
+
const records: CanonicalRecord[] = [];
|
|
313
|
+
const now = new Date().toISOString();
|
|
314
|
+
const baseInput: CanonicalBaseInput = {
|
|
315
|
+
platform: "codex",
|
|
316
|
+
capture_mode: "wrapper",
|
|
317
|
+
source_session_kind: "interactive",
|
|
318
|
+
session_id: sessionId,
|
|
319
|
+
raw_source_ref: { event_type: "codex_wrapper" },
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
records.push(
|
|
323
|
+
buildCanonicalSession({
|
|
324
|
+
...baseInput,
|
|
325
|
+
started_at: now,
|
|
326
|
+
workspace_path: cwd || undefined,
|
|
327
|
+
}),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
const promptEmitted = Boolean(prompt && prompt.length >= 4);
|
|
331
|
+
const promptId = promptEmitted ? derivePromptId(sessionId, 0) : undefined;
|
|
332
|
+
|
|
333
|
+
if (promptId) {
|
|
334
|
+
records.push(
|
|
335
|
+
buildCanonicalPrompt({
|
|
336
|
+
...baseInput,
|
|
337
|
+
prompt_id: promptId,
|
|
338
|
+
occurred_at: now,
|
|
339
|
+
prompt_text: prompt,
|
|
340
|
+
prompt_index: 0,
|
|
341
|
+
}),
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
for (let i = 0; i < metrics.skills_triggered.length; i++) {
|
|
346
|
+
const skillName = metrics.skills_triggered[i];
|
|
347
|
+
const { invocation_mode, confidence } = deriveInvocationMode({
|
|
348
|
+
is_text_mention_only: true,
|
|
349
|
+
});
|
|
350
|
+
records.push(
|
|
351
|
+
buildCanonicalSkillInvocation({
|
|
352
|
+
...baseInput,
|
|
353
|
+
skill_invocation_id: deriveSkillInvocationId(sessionId, skillName, i),
|
|
354
|
+
occurred_at: now,
|
|
355
|
+
matched_prompt_id: promptId,
|
|
356
|
+
skill_name: skillName,
|
|
357
|
+
skill_path: `(codex:${skillName})`,
|
|
358
|
+
invocation_mode,
|
|
359
|
+
triggered: true,
|
|
360
|
+
confidence,
|
|
361
|
+
}),
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
records.push(
|
|
366
|
+
buildCanonicalExecutionFact({
|
|
367
|
+
...baseInput,
|
|
368
|
+
occurred_at: now,
|
|
369
|
+
prompt_id: promptId,
|
|
370
|
+
tool_calls_json: metrics.tool_calls,
|
|
371
|
+
total_tool_calls: metrics.total_tool_calls,
|
|
372
|
+
bash_commands_redacted: metrics.bash_commands,
|
|
373
|
+
assistant_turns: metrics.assistant_turns,
|
|
374
|
+
errors_encountered: metrics.errors_encountered,
|
|
375
|
+
input_tokens: metrics.input_tokens ?? undefined,
|
|
376
|
+
output_tokens: metrics.output_tokens ?? undefined,
|
|
377
|
+
}),
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
return records;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** Write canonical records to appropriate log files. */
|
|
384
|
+
export function logCanonicalRecords(
|
|
385
|
+
records: CanonicalRecord[],
|
|
386
|
+
canonicalLogPath: string = CANONICAL_LOG,
|
|
387
|
+
): void {
|
|
388
|
+
appendCanonicalRecords(records, canonicalLogPath);
|
|
389
|
+
}
|
|
390
|
+
|
|
227
391
|
// --- CLI main ---
|
|
228
392
|
export async function cliMain(): Promise<void> {
|
|
229
393
|
const extraArgs = process.argv.slice(2);
|
|
@@ -308,9 +472,13 @@ export async function cliMain(): Promise<void> {
|
|
|
308
472
|
logTelemetry(metricsWithoutThread, prompt, sessionId, cwd);
|
|
309
473
|
|
|
310
474
|
for (const skillName of metrics.skills_triggered) {
|
|
311
|
-
logSkillTrigger(skillName, prompt, sessionId);
|
|
475
|
+
logSkillTrigger(skillName, prompt, sessionId, cwd);
|
|
312
476
|
}
|
|
313
477
|
|
|
478
|
+
// Emit canonical records (additive)
|
|
479
|
+
const canonical = buildCanonicalRecordsFromWrapper(metrics, prompt, sessionId, cwd);
|
|
480
|
+
logCanonicalRecords(canonical);
|
|
481
|
+
|
|
314
482
|
process.exit(proc.exitCode ?? 0);
|
|
315
483
|
} catch (e) {
|
|
316
484
|
if (e instanceof Error && e.message.includes("ENOENT")) {
|