sentinelayer-cli 0.6.2 → 0.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/README.md +1009 -996
- package/bin/create-sentinelayer.js +5 -5
- package/bin/sentinelayer-cli.js +4 -4
- package/bin/sl.js +5 -5
- package/package.json +64 -63
- package/src/agents/ai-governance/index.js +12 -0
- package/src/agents/ai-governance/tools/base.js +171 -0
- package/src/agents/ai-governance/tools/eval-regression.js +47 -0
- package/src/agents/ai-governance/tools/hitl-audit.js +81 -0
- package/src/agents/ai-governance/tools/index.js +52 -0
- package/src/agents/ai-governance/tools/prompt-drift.js +42 -0
- package/src/agents/ai-governance/tools/provenance-check.js +69 -0
- package/src/agents/backend/index.js +12 -0
- package/src/agents/backend/tools/base.js +189 -0
- package/src/agents/backend/tools/circuit-breaker-check.js +123 -0
- package/src/agents/backend/tools/idempotency-audit.js +105 -0
- package/src/agents/backend/tools/index.js +87 -0
- package/src/agents/backend/tools/retry-audit.js +132 -0
- package/src/agents/backend/tools/timeout-audit.js +144 -0
- package/src/agents/code-quality/index.js +12 -0
- package/src/agents/code-quality/tools/base.js +159 -0
- package/src/agents/code-quality/tools/complexity-measure.js +197 -0
- package/src/agents/code-quality/tools/coupling-analysis.js +81 -0
- package/src/agents/code-quality/tools/cycle-detect.js +49 -0
- package/src/agents/code-quality/tools/dep-graph.js +196 -0
- package/src/agents/code-quality/tools/index.js +89 -0
- package/src/agents/data-layer/index.js +12 -0
- package/src/agents/data-layer/tools/base.js +181 -0
- package/src/agents/data-layer/tools/index-audit.js +165 -0
- package/src/agents/data-layer/tools/index.js +83 -0
- package/src/agents/data-layer/tools/migration-scan.js +135 -0
- package/src/agents/data-layer/tools/query-explain.js +120 -0
- package/src/agents/data-layer/tools/tenancy-scan.js +166 -0
- package/src/agents/documentation/index.js +12 -0
- package/src/agents/documentation/tools/api-diff.js +91 -0
- package/src/agents/documentation/tools/base.js +151 -0
- package/src/agents/documentation/tools/dead-link-check.js +58 -0
- package/src/agents/documentation/tools/docstring-coverage.js +78 -0
- package/src/agents/documentation/tools/index.js +52 -0
- package/src/agents/documentation/tools/readme-freshness.js +61 -0
- package/src/agents/envelope/fix-cycle.js +45 -0
- package/src/agents/envelope/index.js +31 -0
- package/src/agents/envelope/loop.js +150 -0
- package/src/agents/envelope/pulse.js +18 -0
- package/src/agents/envelope/stream.js +40 -0
- package/src/agents/infrastructure/index.js +12 -0
- package/src/agents/infrastructure/tools/base.js +171 -0
- package/src/agents/infrastructure/tools/checkov-run.js +32 -0
- package/src/agents/infrastructure/tools/drift-detect.js +59 -0
- package/src/agents/infrastructure/tools/iam-least-priv-check.js +78 -0
- package/src/agents/infrastructure/tools/index.js +52 -0
- package/src/agents/infrastructure/tools/tflint-run.js +31 -0
- package/src/agents/jules/config/definition.js +160 -160
- package/src/agents/jules/config/system-prompt.js +182 -182
- package/src/agents/jules/error-intake.js +51 -51
- package/src/agents/jules/fix-cycle.js +17 -17
- package/src/agents/jules/loop.js +460 -450
- package/src/agents/jules/pulse.js +10 -10
- package/src/agents/jules/stream.js +187 -186
- package/src/agents/jules/swarm/file-scanner.js +74 -74
- package/src/agents/jules/swarm/index.js +11 -11
- package/src/agents/jules/swarm/orchestrator.js +362 -362
- package/src/agents/jules/swarm/pattern-hunter.js +123 -123
- package/src/agents/jules/swarm/sub-agent.js +315 -309
- package/src/agents/jules/tools/aidenid-email.js +189 -189
- package/src/agents/jules/tools/auth-audit.js +1708 -1691
- package/src/agents/jules/tools/dispatch.js +340 -335
- package/src/agents/jules/tools/file-edit.js +2 -2
- package/src/agents/jules/tools/file-read.js +2 -2
- package/src/agents/jules/tools/frontend-analyze.js +570 -570
- package/src/agents/jules/tools/glob.js +2 -2
- package/src/agents/jules/tools/grep.js +2 -2
- package/src/agents/jules/tools/index.js +29 -29
- package/src/agents/jules/tools/path-guards.js +2 -2
- package/src/agents/jules/tools/runtime-audit.js +507 -507
- package/src/agents/jules/tools/shell.js +2 -2
- package/src/agents/jules/tools/url-policy.js +100 -100
- package/src/agents/mode.js +113 -0
- package/src/agents/observability/index.js +12 -0
- package/src/agents/observability/tools/alert-audit.js +39 -0
- package/src/agents/observability/tools/base.js +181 -0
- package/src/agents/observability/tools/dashboard-gap.js +42 -0
- package/src/agents/observability/tools/index.js +54 -0
- package/src/agents/observability/tools/log-schema-check.js +74 -0
- package/src/agents/observability/tools/span-coverage.js +74 -0
- package/src/agents/persona-visuals.js +102 -61
- package/src/agents/release/index.js +12 -0
- package/src/agents/release/tools/base.js +181 -0
- package/src/agents/release/tools/changelog-diff.js +86 -0
- package/src/agents/release/tools/feature-flag-audit.js +126 -0
- package/src/agents/release/tools/index.js +61 -0
- package/src/agents/release/tools/rollback-verify.js +129 -0
- package/src/agents/release/tools/semver-check.js +109 -0
- package/src/agents/reliability/index.js +12 -0
- package/src/agents/reliability/tools/backpressure-check.js +129 -0
- package/src/agents/reliability/tools/base.js +181 -0
- package/src/agents/reliability/tools/chaos-probe.js +109 -0
- package/src/agents/reliability/tools/graceful-degradation-check.js +114 -0
- package/src/agents/reliability/tools/health-check-audit.js +111 -0
- package/src/agents/reliability/tools/index.js +87 -0
- package/src/agents/run-persona.js +109 -0
- package/src/agents/security/index.js +12 -0
- package/src/agents/security/tools/authz-audit.js +134 -0
- package/src/agents/security/tools/base.js +190 -0
- package/src/agents/security/tools/crypto-review.js +175 -0
- package/src/agents/security/tools/index.js +97 -0
- package/src/agents/security/tools/sast-scan.js +175 -0
- package/src/agents/security/tools/secrets-scan.js +216 -0
- package/src/agents/shared-tools/dispatch-core.js +320 -315
- package/src/agents/shared-tools/file-edit.js +180 -180
- package/src/agents/shared-tools/file-read.js +100 -100
- package/src/agents/shared-tools/glob.js +168 -168
- package/src/agents/shared-tools/grep.js +228 -228
- package/src/agents/shared-tools/index.js +46 -46
- package/src/agents/shared-tools/path-guards.js +161 -161
- package/src/agents/shared-tools/shell.js +383 -383
- package/src/agents/supply-chain/index.js +12 -0
- package/src/agents/supply-chain/tools/attestation-check.js +42 -0
- package/src/agents/supply-chain/tools/base.js +151 -0
- package/src/agents/supply-chain/tools/index.js +52 -0
- package/src/agents/supply-chain/tools/lockfile-integrity.js +73 -0
- package/src/agents/supply-chain/tools/package-verify.js +56 -0
- package/src/agents/supply-chain/tools/sbom-diff.js +34 -0
- package/src/agents/testing/index.js +12 -0
- package/src/agents/testing/tools/base.js +202 -0
- package/src/agents/testing/tools/coverage-gap.js +144 -0
- package/src/agents/testing/tools/flake-detect.js +125 -0
- package/src/agents/testing/tools/index.js +85 -0
- package/src/agents/testing/tools/mutation-test.js +143 -0
- package/src/agents/testing/tools/snapshot-diff.js +103 -0
- package/src/ai/aidenid.js +1021 -1009
- package/src/ai/client.js +553 -553
- package/src/ai/domain-target-store.js +268 -268
- package/src/ai/identity-store.js +270 -270
- package/src/ai/proxy.js +137 -137
- package/src/ai/site-store.js +145 -145
- package/src/audit/agents/architecture.js +180 -180
- package/src/audit/agents/compliance.js +179 -179
- package/src/audit/agents/documentation.js +165 -165
- package/src/audit/agents/performance.js +145 -145
- package/src/audit/agents/security.js +215 -215
- package/src/audit/agents/testing.js +172 -172
- package/src/audit/orchestrator.js +557 -557
- package/src/audit/package.js +204 -204
- package/src/audit/registry.js +284 -284
- package/src/audit/replay.js +103 -103
- package/src/auth/gate.js +428 -371
- package/src/auth/http.js +681 -611
- package/src/auth/service.js +1106 -1106
- package/src/auth/session-store.js +813 -813
- package/src/cli.js +257 -252
- package/src/commands/ai/identity-lifecycle.js +1338 -1338
- package/src/commands/ai/provision-governance.js +1272 -1272
- package/src/commands/ai/shared.js +147 -147
- package/src/commands/ai.js +11 -11
- package/src/commands/apply.js +12 -12
- package/src/commands/audit.js +1171 -1166
- package/src/commands/auth.js +419 -419
- package/src/commands/chat.js +184 -191
- package/src/commands/config.js +184 -184
- package/src/commands/cost.js +311 -311
- package/src/commands/daemon/core.js +850 -850
- package/src/commands/daemon/extended.js +1048 -1048
- package/src/commands/daemon/shared.js +213 -213
- package/src/commands/daemon.js +11 -11
- package/src/commands/guide.js +174 -174
- package/src/commands/ingest.js +58 -58
- package/src/commands/init.js +55 -55
- package/src/commands/legacy-args.js +20 -10
- package/src/commands/mcp.js +461 -461
- package/src/commands/omargate.js +63 -29
- package/src/commands/persona.js +65 -20
- package/src/commands/plugin.js +260 -260
- package/src/commands/policy.js +132 -132
- package/src/commands/prompt.js +238 -238
- package/src/commands/review.js +704 -704
- package/src/commands/scan.js +865 -872
- package/src/commands/session.js +1238 -0
- package/src/commands/spec.js +771 -716
- package/src/commands/swarm.js +651 -651
- package/src/commands/telemetry.js +202 -202
- package/src/commands/watch.js +511 -511
- package/src/config/agent-dictionary.js +182 -182
- package/src/config/io.js +56 -56
- package/src/config/paths.js +18 -18
- package/src/config/schema.js +55 -55
- package/src/config/service.js +184 -184
- package/src/coord/events-log.js +141 -0
- package/src/coord/handshake.js +719 -0
- package/src/coord/index.js +35 -0
- package/src/coord/paths.js +84 -0
- package/src/coord/priority.js +62 -0
- package/src/coord/tarjan.js +157 -0
- package/src/cost/budget.js +235 -235
- package/src/cost/history.js +188 -188
- package/src/cost/tokenizer.js +160 -0
- package/src/cost/tracker.js +232 -171
- package/src/daemon/artifact-lineage.js +896 -534
- package/src/daemon/assignment-ledger.js +1083 -770
- package/src/daemon/ast-drift.js +496 -0
- package/src/daemon/ast-parser-layer.js +258 -258
- package/src/daemon/budget-governor.js +633 -633
- package/src/daemon/callgraph-overlay.js +646 -646
- package/src/daemon/error-worker.js +1209 -626
- package/src/daemon/fix-cycle.js +384 -377
- package/src/daemon/hybrid-mapper.js +929 -929
- package/src/daemon/ingest-refresh.js +79 -11
- package/src/daemon/jira-lifecycle.js +767 -632
- package/src/daemon/operator-control.js +657 -657
- package/src/daemon/pulse.js +327 -327
- package/src/daemon/reliability-lane.js +471 -471
- package/src/daemon/scope-engine.js +1068 -0
- package/src/daemon/watchdog.js +971 -971
- package/src/events/schema.js +190 -0
- package/src/guide/generator.js +316 -316
- package/src/ingest/engine.js +933 -918
- package/src/ingest/ownership.js +380 -0
- package/src/interactive/index.js +97 -97
- package/src/legacy-cli.js +3228 -2994
- package/src/mcp/registry.js +695 -695
- package/src/memory/blackboard.js +301 -301
- package/src/memory/retrieval.js +581 -581
- package/src/orchestrator/kai-chen.js +126 -0
- package/src/plugin/manifest.js +553 -553
- package/src/policy/packs.js +144 -144
- package/src/prompt/generator.js +136 -118
- package/src/review/ai-review.js +672 -679
- package/src/review/compliance-pack.js +389 -0
- package/src/review/investor-dd-config.js +54 -0
- package/src/review/investor-dd-file-loop.js +303 -0
- package/src/review/investor-dd-file-router.js +406 -0
- package/src/review/investor-dd-html-report.js +233 -0
- package/src/review/investor-dd-notification.js +120 -0
- package/src/review/investor-dd-orchestrator.js +405 -0
- package/src/review/investor-dd-persona-runner.js +275 -0
- package/src/review/live-validator.js +253 -0
- package/src/review/local-review.js +1351 -1305
- package/src/review/omargate-interactive.js +68 -68
- package/src/review/omargate-orchestrator.js +492 -300
- package/src/review/persona-prompts.js +484 -296
- package/src/review/reconciliation-rules.js +329 -0
- package/src/review/replay.js +235 -235
- package/src/review/report.js +664 -664
- package/src/review/reproducibility-chain.js +136 -0
- package/src/review/scan-modes.js +147 -42
- package/src/review/spec-binding.js +487 -487
- package/src/scaffold/generator.js +67 -67
- package/src/scaffold/templates.js +150 -150
- package/src/scan/generator.js +418 -418
- package/src/scan/gh-secrets.js +107 -107
- package/src/session/agent-registry.js +359 -0
- package/src/session/analytics.js +479 -0
- package/src/session/daemon.js +1396 -0
- package/src/session/file-locks.js +666 -0
- package/src/session/paths.js +37 -0
- package/src/session/recap.js +567 -0
- package/src/session/redact.js +82 -0
- package/src/session/runtime-bridge.js +762 -0
- package/src/session/scoring.js +406 -0
- package/src/session/setup-guides.js +304 -0
- package/src/session/store.js +704 -0
- package/src/session/stream.js +333 -0
- package/src/session/sync.js +753 -0
- package/src/session/tasks.js +1054 -0
- package/src/session/templates.js +188 -0
- package/src/spec/generator.js +619 -519
- package/src/spec/regenerate.js +237 -237
- package/src/spec/templates.js +91 -91
- package/src/swarm/dashboard.js +247 -247
- package/src/swarm/factory.js +363 -363
- package/src/swarm/pentest.js +934 -934
- package/src/swarm/registry.js +419 -419
- package/src/swarm/report.js +158 -158
- package/src/swarm/runtime.js +569 -576
- package/src/swarm/scenario-dsl.js +272 -272
- package/src/telemetry/ledger.js +302 -302
- package/src/telemetry/session-tracker.js +234 -234
- package/src/telemetry/sync.js +203 -203
- package/src/ui/command-hints.js +13 -13
- package/src/ui/markdown.js +220 -220
|
@@ -1,202 +1,202 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import pc from "picocolors";
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
appendRunEvent,
|
|
7
|
-
loadRunEvents,
|
|
8
|
-
summarizeRunEvents,
|
|
9
|
-
RUN_EVENT_TYPES,
|
|
10
|
-
STOP_CLASSES,
|
|
11
|
-
} from "../telemetry/ledger.js";
|
|
12
|
-
|
|
13
|
-
function shouldEmitJson(options, command) {
|
|
14
|
-
const local = Boolean(options && options.json);
|
|
15
|
-
const globalFromCommand =
|
|
16
|
-
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
17
|
-
return local || globalFromCommand;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function parseNonNegativeNumber(rawValue, field) {
|
|
21
|
-
const normalized = Number(rawValue || 0);
|
|
22
|
-
if (!Number.isFinite(normalized) || normalized < 0) {
|
|
23
|
-
throw new Error(`${field} must be a non-negative number.`);
|
|
24
|
-
}
|
|
25
|
-
return normalized;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function parseReasonCodes(rawValue) {
|
|
29
|
-
if (rawValue === undefined || rawValue === null) {
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
return String(rawValue)
|
|
33
|
-
.split(",")
|
|
34
|
-
.map((item) => item.trim().toUpperCase())
|
|
35
|
-
.filter(Boolean);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function parseMetadata(rawValue) {
|
|
39
|
-
if (!rawValue) {
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
const parsed = JSON.parse(String(rawValue));
|
|
43
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
44
|
-
throw new Error("metadataJson must parse to an object.");
|
|
45
|
-
}
|
|
46
|
-
return parsed;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function runShow({ targetPath, outputDir, emitJson }) {
|
|
50
|
-
const { filePath, events } = await loadRunEvents({
|
|
51
|
-
targetPath,
|
|
52
|
-
outputDirOverride: outputDir,
|
|
53
|
-
});
|
|
54
|
-
const summary = summarizeRunEvents(events);
|
|
55
|
-
const payload = {
|
|
56
|
-
command: "telemetry show",
|
|
57
|
-
targetPath,
|
|
58
|
-
filePath,
|
|
59
|
-
summary,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
if (emitJson) {
|
|
63
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
console.log(pc.bold("Telemetry summary"));
|
|
68
|
-
console.log(pc.gray(`File: ${filePath}`));
|
|
69
|
-
console.log(
|
|
70
|
-
pc.gray(
|
|
71
|
-
`Events=${summary.eventCount}, Sessions=${summary.sessionCount}, Runs=${summary.runCount}`
|
|
72
|
-
)
|
|
73
|
-
);
|
|
74
|
-
console.log(
|
|
75
|
-
pc.gray(
|
|
76
|
-
`Usage totals: input=${summary.usageTotals.inputTokens}, output=${summary.usageTotals.outputTokens}, cost=$${summary.usageTotals.costUsd.toFixed(6)}, durationMs=${summary.usageTotals.durationMs}, toolCalls=${summary.usageTotals.toolCalls}`
|
|
77
|
-
)
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function registerTelemetryCommand(program) {
|
|
82
|
-
const telemetry = program
|
|
83
|
-
.command("telemetry")
|
|
84
|
-
.description("Track run events, usage telemetry, and stop-class outcomes");
|
|
85
|
-
|
|
86
|
-
telemetry
|
|
87
|
-
.option("--path <path>", "Target workspace path", ".")
|
|
88
|
-
.option("--output-dir <path>", "Optional output dir override for telemetry files")
|
|
89
|
-
.option("--json", "Emit machine-readable output")
|
|
90
|
-
.action(async (options, command) => {
|
|
91
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
92
|
-
await runShow({
|
|
93
|
-
targetPath,
|
|
94
|
-
outputDir: options.outputDir,
|
|
95
|
-
emitJson: shouldEmitJson(options, command),
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
telemetry
|
|
100
|
-
.command("show")
|
|
101
|
-
.description("Show telemetry summary from the local run-event ledger")
|
|
102
|
-
.option("--path <path>", "Target workspace path", ".")
|
|
103
|
-
.option("--output-dir <path>", "Optional output dir override for telemetry files")
|
|
104
|
-
.option("--json", "Emit machine-readable output")
|
|
105
|
-
.action(async (options, command) => {
|
|
106
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
107
|
-
await runShow({
|
|
108
|
-
targetPath,
|
|
109
|
-
outputDir: options.outputDir,
|
|
110
|
-
emitJson: shouldEmitJson(options, command),
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
telemetry
|
|
115
|
-
.command("record")
|
|
116
|
-
.description("Record a telemetry event in the local run-event ledger")
|
|
117
|
-
.option("--path <path>", "Target workspace path", ".")
|
|
118
|
-
.option("--output-dir <path>", "Optional output dir override for telemetry files")
|
|
119
|
-
.option("--session-id <id>", "Session identifier", "default")
|
|
120
|
-
.option("--run-id <id>", "Run identifier", "default")
|
|
121
|
-
.option(
|
|
122
|
-
"--event-type <type>",
|
|
123
|
-
`Event type (${RUN_EVENT_TYPES.join(", ")})`,
|
|
124
|
-
"run_step"
|
|
125
|
-
)
|
|
126
|
-
.option("--input-tokens <n>", "Input token count", "0")
|
|
127
|
-
.option("--output-tokens <n>", "Output token count", "0")
|
|
128
|
-
.option("--cache-read-tokens <n>", "Cache read token count", "0")
|
|
129
|
-
.option("--cache-write-tokens <n>", "Cache write token count", "0")
|
|
130
|
-
.option("--cost-usd <amount>", "Usage cost in USD", "0")
|
|
131
|
-
.option("--duration-ms <n>", "Event duration in milliseconds", "0")
|
|
132
|
-
.option("--tool-calls <n>", "Tool calls consumed by this event", "0")
|
|
133
|
-
.option(
|
|
134
|
-
"--stop-class <class>",
|
|
135
|
-
`Stop class (${STOP_CLASSES.join(", ")})`,
|
|
136
|
-
"NONE"
|
|
137
|
-
)
|
|
138
|
-
.option("--blocking", "Mark the stop state as blocking")
|
|
139
|
-
.option("--reason-codes <codes>", "Comma-separated stop reason codes")
|
|
140
|
-
.option("--metadata-json <json>", "Optional metadata object as JSON string")
|
|
141
|
-
.option("--json", "Emit machine-readable output")
|
|
142
|
-
.action(async (options, command) => {
|
|
143
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
144
|
-
const reasonCodes = parseReasonCodes(options.reasonCodes);
|
|
145
|
-
const stopClass = String(options.stopClass || "NONE").trim().toUpperCase() || "NONE";
|
|
146
|
-
const stop =
|
|
147
|
-
stopClass !== "NONE" || options.blocking || reasonCodes.length > 0
|
|
148
|
-
? {
|
|
149
|
-
stopClass,
|
|
150
|
-
blocking: Boolean(options.blocking),
|
|
151
|
-
reasonCodes,
|
|
152
|
-
}
|
|
153
|
-
: null;
|
|
154
|
-
|
|
155
|
-
const appended = await appendRunEvent(
|
|
156
|
-
{
|
|
157
|
-
targetPath,
|
|
158
|
-
outputDirOverride: options.outputDir,
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
sessionId: options.sessionId,
|
|
162
|
-
runId: options.runId,
|
|
163
|
-
eventType: String(options.eventType || "run_step").trim(),
|
|
164
|
-
usage: {
|
|
165
|
-
inputTokens: parseNonNegativeNumber(options.inputTokens, "inputTokens"),
|
|
166
|
-
outputTokens: parseNonNegativeNumber(options.outputTokens, "outputTokens"),
|
|
167
|
-
cacheReadTokens: parseNonNegativeNumber(options.cacheReadTokens, "cacheReadTokens"),
|
|
168
|
-
cacheWriteTokens: parseNonNegativeNumber(options.cacheWriteTokens, "cacheWriteTokens"),
|
|
169
|
-
costUsd: parseNonNegativeNumber(options.costUsd, "costUsd"),
|
|
170
|
-
durationMs: parseNonNegativeNumber(options.durationMs, "durationMs"),
|
|
171
|
-
toolCalls: parseNonNegativeNumber(options.toolCalls, "toolCalls"),
|
|
172
|
-
},
|
|
173
|
-
stop,
|
|
174
|
-
metadata: parseMetadata(options.metadataJson),
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
const payload = {
|
|
179
|
-
command: "telemetry record",
|
|
180
|
-
targetPath,
|
|
181
|
-
filePath: appended.filePath,
|
|
182
|
-
event: appended.event,
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
if (shouldEmitJson(options, command)) {
|
|
186
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
187
|
-
} else {
|
|
188
|
-
console.log(pc.bold("Telemetry event recorded"));
|
|
189
|
-
console.log(pc.gray(`File: ${appended.filePath}`));
|
|
190
|
-
console.log(
|
|
191
|
-
pc.gray(
|
|
192
|
-
`Event=${appended.event.eventType}, session=${appended.event.sessionId}, run=${appended.event.runId}, stopClass=${appended.event.stop?.stopClass || "NONE"}`
|
|
193
|
-
)
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (appended.event.stop?.blocking) {
|
|
198
|
-
process.exitCode = 2;
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
appendRunEvent,
|
|
7
|
+
loadRunEvents,
|
|
8
|
+
summarizeRunEvents,
|
|
9
|
+
RUN_EVENT_TYPES,
|
|
10
|
+
STOP_CLASSES,
|
|
11
|
+
} from "../telemetry/ledger.js";
|
|
12
|
+
|
|
13
|
+
function shouldEmitJson(options, command) {
|
|
14
|
+
const local = Boolean(options && options.json);
|
|
15
|
+
const globalFromCommand =
|
|
16
|
+
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
17
|
+
return local || globalFromCommand;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseNonNegativeNumber(rawValue, field) {
|
|
21
|
+
const normalized = Number(rawValue || 0);
|
|
22
|
+
if (!Number.isFinite(normalized) || normalized < 0) {
|
|
23
|
+
throw new Error(`${field} must be a non-negative number.`);
|
|
24
|
+
}
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseReasonCodes(rawValue) {
|
|
29
|
+
if (rawValue === undefined || rawValue === null) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
return String(rawValue)
|
|
33
|
+
.split(",")
|
|
34
|
+
.map((item) => item.trim().toUpperCase())
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseMetadata(rawValue) {
|
|
39
|
+
if (!rawValue) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
const parsed = JSON.parse(String(rawValue));
|
|
43
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
44
|
+
throw new Error("metadataJson must parse to an object.");
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function runShow({ targetPath, outputDir, emitJson }) {
|
|
50
|
+
const { filePath, events } = await loadRunEvents({
|
|
51
|
+
targetPath,
|
|
52
|
+
outputDirOverride: outputDir,
|
|
53
|
+
});
|
|
54
|
+
const summary = summarizeRunEvents(events);
|
|
55
|
+
const payload = {
|
|
56
|
+
command: "telemetry show",
|
|
57
|
+
targetPath,
|
|
58
|
+
filePath,
|
|
59
|
+
summary,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (emitJson) {
|
|
63
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(pc.bold("Telemetry summary"));
|
|
68
|
+
console.log(pc.gray(`File: ${filePath}`));
|
|
69
|
+
console.log(
|
|
70
|
+
pc.gray(
|
|
71
|
+
`Events=${summary.eventCount}, Sessions=${summary.sessionCount}, Runs=${summary.runCount}`
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
console.log(
|
|
75
|
+
pc.gray(
|
|
76
|
+
`Usage totals: input=${summary.usageTotals.inputTokens}, output=${summary.usageTotals.outputTokens}, cost=$${summary.usageTotals.costUsd.toFixed(6)}, durationMs=${summary.usageTotals.durationMs}, toolCalls=${summary.usageTotals.toolCalls}`
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function registerTelemetryCommand(program) {
|
|
82
|
+
const telemetry = program
|
|
83
|
+
.command("telemetry")
|
|
84
|
+
.description("Track run events, usage telemetry, and stop-class outcomes");
|
|
85
|
+
|
|
86
|
+
telemetry
|
|
87
|
+
.option("--path <path>", "Target workspace path", ".")
|
|
88
|
+
.option("--output-dir <path>", "Optional output dir override for telemetry files")
|
|
89
|
+
.option("--json", "Emit machine-readable output")
|
|
90
|
+
.action(async (options, command) => {
|
|
91
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
92
|
+
await runShow({
|
|
93
|
+
targetPath,
|
|
94
|
+
outputDir: options.outputDir,
|
|
95
|
+
emitJson: shouldEmitJson(options, command),
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
telemetry
|
|
100
|
+
.command("show")
|
|
101
|
+
.description("Show telemetry summary from the local run-event ledger")
|
|
102
|
+
.option("--path <path>", "Target workspace path", ".")
|
|
103
|
+
.option("--output-dir <path>", "Optional output dir override for telemetry files")
|
|
104
|
+
.option("--json", "Emit machine-readable output")
|
|
105
|
+
.action(async (options, command) => {
|
|
106
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
107
|
+
await runShow({
|
|
108
|
+
targetPath,
|
|
109
|
+
outputDir: options.outputDir,
|
|
110
|
+
emitJson: shouldEmitJson(options, command),
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
telemetry
|
|
115
|
+
.command("record")
|
|
116
|
+
.description("Record a telemetry event in the local run-event ledger")
|
|
117
|
+
.option("--path <path>", "Target workspace path", ".")
|
|
118
|
+
.option("--output-dir <path>", "Optional output dir override for telemetry files")
|
|
119
|
+
.option("--session-id <id>", "Session identifier", "default")
|
|
120
|
+
.option("--run-id <id>", "Run identifier", "default")
|
|
121
|
+
.option(
|
|
122
|
+
"--event-type <type>",
|
|
123
|
+
`Event type (${RUN_EVENT_TYPES.join(", ")})`,
|
|
124
|
+
"run_step"
|
|
125
|
+
)
|
|
126
|
+
.option("--input-tokens <n>", "Input token count", "0")
|
|
127
|
+
.option("--output-tokens <n>", "Output token count", "0")
|
|
128
|
+
.option("--cache-read-tokens <n>", "Cache read token count", "0")
|
|
129
|
+
.option("--cache-write-tokens <n>", "Cache write token count", "0")
|
|
130
|
+
.option("--cost-usd <amount>", "Usage cost in USD", "0")
|
|
131
|
+
.option("--duration-ms <n>", "Event duration in milliseconds", "0")
|
|
132
|
+
.option("--tool-calls <n>", "Tool calls consumed by this event", "0")
|
|
133
|
+
.option(
|
|
134
|
+
"--stop-class <class>",
|
|
135
|
+
`Stop class (${STOP_CLASSES.join(", ")})`,
|
|
136
|
+
"NONE"
|
|
137
|
+
)
|
|
138
|
+
.option("--blocking", "Mark the stop state as blocking")
|
|
139
|
+
.option("--reason-codes <codes>", "Comma-separated stop reason codes")
|
|
140
|
+
.option("--metadata-json <json>", "Optional metadata object as JSON string")
|
|
141
|
+
.option("--json", "Emit machine-readable output")
|
|
142
|
+
.action(async (options, command) => {
|
|
143
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
144
|
+
const reasonCodes = parseReasonCodes(options.reasonCodes);
|
|
145
|
+
const stopClass = String(options.stopClass || "NONE").trim().toUpperCase() || "NONE";
|
|
146
|
+
const stop =
|
|
147
|
+
stopClass !== "NONE" || options.blocking || reasonCodes.length > 0
|
|
148
|
+
? {
|
|
149
|
+
stopClass,
|
|
150
|
+
blocking: Boolean(options.blocking),
|
|
151
|
+
reasonCodes,
|
|
152
|
+
}
|
|
153
|
+
: null;
|
|
154
|
+
|
|
155
|
+
const appended = await appendRunEvent(
|
|
156
|
+
{
|
|
157
|
+
targetPath,
|
|
158
|
+
outputDirOverride: options.outputDir,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
sessionId: options.sessionId,
|
|
162
|
+
runId: options.runId,
|
|
163
|
+
eventType: String(options.eventType || "run_step").trim(),
|
|
164
|
+
usage: {
|
|
165
|
+
inputTokens: parseNonNegativeNumber(options.inputTokens, "inputTokens"),
|
|
166
|
+
outputTokens: parseNonNegativeNumber(options.outputTokens, "outputTokens"),
|
|
167
|
+
cacheReadTokens: parseNonNegativeNumber(options.cacheReadTokens, "cacheReadTokens"),
|
|
168
|
+
cacheWriteTokens: parseNonNegativeNumber(options.cacheWriteTokens, "cacheWriteTokens"),
|
|
169
|
+
costUsd: parseNonNegativeNumber(options.costUsd, "costUsd"),
|
|
170
|
+
durationMs: parseNonNegativeNumber(options.durationMs, "durationMs"),
|
|
171
|
+
toolCalls: parseNonNegativeNumber(options.toolCalls, "toolCalls"),
|
|
172
|
+
},
|
|
173
|
+
stop,
|
|
174
|
+
metadata: parseMetadata(options.metadataJson),
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const payload = {
|
|
179
|
+
command: "telemetry record",
|
|
180
|
+
targetPath,
|
|
181
|
+
filePath: appended.filePath,
|
|
182
|
+
event: appended.event,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
if (shouldEmitJson(options, command)) {
|
|
186
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
187
|
+
} else {
|
|
188
|
+
console.log(pc.bold("Telemetry event recorded"));
|
|
189
|
+
console.log(pc.gray(`File: ${appended.filePath}`));
|
|
190
|
+
console.log(
|
|
191
|
+
pc.gray(
|
|
192
|
+
`Event=${appended.event.eventType}, session=${appended.event.sessionId}, run=${appended.event.runId}, stopClass=${appended.event.stop?.stopClass || "NONE"}`
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (appended.event.stop?.blocking) {
|
|
198
|
+
process.exitCode = 2;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|