@ascenda-one/history-import 0.1.13 → 0.1.15
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 +11 -3
- package/dist/cli.js +327 -17
- package/dist/cli.js.map +1 -1
- package/dist/extractors/claudeCode.js +105 -4
- package/dist/extractors/claudeCode.js.map +1 -1
- package/dist/extractors/cursor.js +97 -4
- package/dist/extractors/cursor.js.map +1 -1
- package/dist/extractors/vscode.js +95 -2
- package/dist/extractors/vscode.js.map +1 -1
- package/dist/localHandoff.js +15 -1
- package/dist/localHandoff.js.map +1 -1
- package/dist/ship.js +18 -2
- package/dist/ship.js.map +1 -1
- package/dist/toolName.js +33 -0
- package/dist/toolName.js.map +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,8 +30,15 @@ command (same pattern as hooks pairing) and this CLI does the reading.
|
|
|
30
30
|
4. **Metrics only by default.** Prompt/response text, thinking blocks and
|
|
31
31
|
file contents never leave the machine. Content-level ingestion, if it ever
|
|
32
32
|
ships, is a separate explicit opt-in — not this package's default path.
|
|
33
|
-
5. **Aggregate before shipping
|
|
34
|
-
per bubble — a single machine's stores hold
|
|
33
|
+
5. **Aggregate before shipping, unless a reader counts the rows.** Per-session
|
|
34
|
+
/ per-day events, not one event per bubble — a single machine's stores hold
|
|
35
|
+
tens of thousands of them. The one deliberate exception is
|
|
36
|
+
`ai_tool_call_started`: the backend's work-demand rail derives
|
|
37
|
+
`toolCallCount` by counting rows of that type and reads no `toolCallCount`
|
|
38
|
+
key off metadata, so a session-level aggregate would ship, store, and be
|
|
39
|
+
counted by nothing. Per-call events also place the work in the right hour,
|
|
40
|
+
which a session spanning six of them cannot. Expect an order of magnitude
|
|
41
|
+
more events than a session-only import, and an `events.jsonl` to match.
|
|
35
42
|
6. **Provenance is data.** Every event carries `historical_direct`,
|
|
36
43
|
`historical_derived` or `historical_unparsed` — never the live
|
|
37
44
|
`ai_work_telemetry` provenance — so no chart can pass history off as
|
|
@@ -46,6 +53,7 @@ command (same pattern as hooks pairing) and this CLI does the reading.
|
|
|
46
53
|
| Staging/snapshot (copy-then-parse, WAL-aware, **torn down by the run that makes it**) | implemented |
|
|
47
54
|
| `archive` (durable content-addressed copy, dedup, verify, restore, prune) | **implemented, verified on a real 4.1 GB store** |
|
|
48
55
|
| **Claude Code extractor** (human-prompt/tool-result split, session folds incl. recursive subagent transcripts, after-hours, compaction, tool failures, context-window peak, human-corrected edits, correction cadence, gap-split active minutes, epoch marker) | **implemented, verified live** |
|
|
56
|
+
| **Tool-call counting, all three stores** (`tool_use` items / `toolFormerData` / `toolInvocationSerialized`, one `ai_tool_call_started` per call) | **implemented; exercised end to end against all three stores on a developer machine** |
|
|
49
57
|
| **Batch shipper** (`POST /v1/tool-events/batch`, salted hashes, stable importKey) | **implemented, verified live** |
|
|
50
58
|
| **Cursor extractor** (composerHeaders + bubble aggregation via SQL-side `json_extract`, prompt text never parsed into the process, subagent-composer folding, epoch marker) | **implemented, verified live** |
|
|
51
59
|
| **VS Code extractor** (Timeline-history Chat-Edit day×workspace aggregation, Copilot chatSessions folding, workspace identity via `workspace.json` longest-prefix match, epoch marker) | **implemented, verified live** |
|
|
@@ -119,7 +127,7 @@ ascenda-history-import archive # the durable copy; --verify / --list / -
|
|
|
119
127
|
### Staging is scaffolding; `archive` is the copy
|
|
120
128
|
|
|
121
129
|
`import` snapshots each store, extracts, and **deletes the snapshot in a
|
|
122
|
-
`finally`** — success or failure — keeping only
|
|
130
|
+
`finally`** — success or failure — keeping only `events.jsonl`.
|
|
123
131
|
It also sweeps snapshots left by earlier runs. This is not tidiness: nineteen
|
|
124
132
|
runs once left 254 GB on a 926 GB disk and took free space to 279 MB, and the
|
|
125
133
|
first thing to notice was unrelated tooling failing with `ENOSPC`.
|
package/dist/cli.js
CHANGED
|
@@ -377,12 +377,155 @@ var require_payload = __commonJS({
|
|
|
377
377
|
}
|
|
378
378
|
});
|
|
379
379
|
|
|
380
|
+
// ../packages/tool-contract/out/metricKeys.js
|
|
381
|
+
var require_metricKeys = __commonJS({
|
|
382
|
+
"../packages/tool-contract/out/metricKeys.js"(exports) {
|
|
383
|
+
"use strict";
|
|
384
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
385
|
+
exports.METRIC_KEYS = void 0;
|
|
386
|
+
exports.backendMetricKeys = backendMetricKeys;
|
|
387
|
+
var CONTEXT_WINDOW_CANONICAL_ALIASES = [
|
|
388
|
+
"contextWindowPeakPct",
|
|
389
|
+
"context_window_peak_pct",
|
|
390
|
+
"contextWindowPct",
|
|
391
|
+
"context_window_pct"
|
|
392
|
+
];
|
|
393
|
+
var CONTEXT_WINDOW_CURSOR_PERCENT_ALIASES = ["contextUsagePercent"];
|
|
394
|
+
exports.METRIC_KEYS = {
|
|
395
|
+
// ── Read by a backend reader ────────────────────────────────────────────
|
|
396
|
+
contextWindowPeakPct: {
|
|
397
|
+
readBy: ["backend", "handoff"],
|
|
398
|
+
backendAliases: CONTEXT_WINDOW_CANONICAL_ALIASES,
|
|
399
|
+
unit: "fraction of the context window (0\u20131; uncapped for >200k contexts)",
|
|
400
|
+
note: "Claude Code reports a true per-session peak. Cursor reports its composer's last known occupancy under the same key \u2014 the closest its store can answer, and not the same measurement."
|
|
401
|
+
},
|
|
402
|
+
contextUsagePercent: {
|
|
403
|
+
readBy: ["backend", "handoff"],
|
|
404
|
+
backendAliases: CONTEXT_WINDOW_CURSOR_PERCENT_ALIASES,
|
|
405
|
+
unit: "percent (0\u2013100)",
|
|
406
|
+
note: "Cursor's own column name. Superseded by contextWindowPeakPct on the wire; kept because the handoff reads it and imported rows carry it. Unit-explicit on the backend: always divided by 100, never put through the fraction-or-percent heuristic."
|
|
407
|
+
},
|
|
408
|
+
promptCount: { readBy: ["backend", "handoff"], backendAliases: ["promptCount", "prompt_count"] },
|
|
409
|
+
sessionMinutes: { readBy: ["backend"], backendAliases: ["sessionMinutes", "session_minutes"], unit: "minutes" },
|
|
410
|
+
durationBucket: { readBy: ["backend", "handoff"], backendAliases: ["durationBucket", "duration_bucket"] },
|
|
411
|
+
afterHoursPrompts: { readBy: ["backend", "handoff"], backendAliases: ["afterHoursPrompts", "after_hours_prompts"] },
|
|
412
|
+
inputTokens: { readBy: ["backend"], backendAliases: ["inputTokens", "input_tokens"], unit: "tokens" },
|
|
413
|
+
outputTokens: { readBy: ["backend"], backendAliases: ["outputTokens", "output_tokens"], unit: "tokens" },
|
|
414
|
+
cacheReadTokens: { readBy: ["backend"], backendAliases: ["cacheReadTokens", "cache_read_tokens"], unit: "tokens" },
|
|
415
|
+
queuedPrompts: { readBy: ["backend"], backendAliases: ["queuedPrompts", "queued_prompts"] },
|
|
416
|
+
linesChangedBucket: { readBy: ["backend"], backendAliases: ["linesChangedBucket", "lines_changed_bucket"] },
|
|
417
|
+
// ── Read by the local handoff only ──────────────────────────────────────
|
|
418
|
+
activeMinutes: { readBy: ["handoff"], unit: "minutes" },
|
|
419
|
+
afterHoursRequests: { readBy: ["handoff"] },
|
|
420
|
+
approximateLintErrorsCount: { readBy: ["handoff"] },
|
|
421
|
+
canceledCount: { readBy: ["handoff"] },
|
|
422
|
+
chatEditCount: { readBy: ["handoff"] },
|
|
423
|
+
compactionCount: {
|
|
424
|
+
readBy: ["handoff"],
|
|
425
|
+
note: "The backend counts context_compression_* event rows, not this key. Both are emitted; this one is for the handoff."
|
|
426
|
+
},
|
|
427
|
+
contextWindowPeakTokens: {
|
|
428
|
+
readBy: ["handoff"],
|
|
429
|
+
unit: "tokens",
|
|
430
|
+
note: "The measured quantity, with no assumed denominator. Prefer this to the ratio for any within-person baseline."
|
|
431
|
+
},
|
|
432
|
+
date: { readBy: ["handoff"] },
|
|
433
|
+
errorCount: { readBy: ["handoff"] },
|
|
434
|
+
filesChangedCount: { readBy: ["handoff"] },
|
|
435
|
+
humanChangesCount: { readBy: ["handoff"] },
|
|
436
|
+
linesAdded: { readBy: ["handoff"] },
|
|
437
|
+
linesRemoved: { readBy: ["handoff"] },
|
|
438
|
+
primaryModel: { readBy: ["handoff"] },
|
|
439
|
+
requestCount: { readBy: ["handoff"] },
|
|
440
|
+
sessionStartedAt: { readBy: ["handoff"] },
|
|
441
|
+
subagentComposers: { readBy: ["handoff"] },
|
|
442
|
+
subagentToolCallCount: {
|
|
443
|
+
readBy: ["handoff"],
|
|
444
|
+
note: "Claude Code only: calls made inside subagent transcripts, kept out of toolCallCount so the main-loop count matches what the wire events carry."
|
|
445
|
+
},
|
|
446
|
+
subagentTranscripts: { readBy: ["handoff"] },
|
|
447
|
+
toolCallCount: {
|
|
448
|
+
readBy: ["handoff"],
|
|
449
|
+
note: "The backend counts ai_tool_call_started event rows, not this key \u2014 same split as compactionCount. Deduplicated on the tool-call id; see each extractor for what one call means in its store."
|
|
450
|
+
},
|
|
451
|
+
toolCallsUndated: {
|
|
452
|
+
readBy: ["handoff"],
|
|
453
|
+
note: "Cursor only: calls whose every record carries an empty createdAt. Counted in toolCallCount, but no event exists for them \u2014 the wire total is smaller than this session count by exactly this number."
|
|
454
|
+
},
|
|
455
|
+
toolFailureCount: { readBy: ["handoff"] },
|
|
456
|
+
totalEntryCount: { readBy: ["handoff"] },
|
|
457
|
+
userModifiedEditCount: {
|
|
458
|
+
readBy: ["handoff"],
|
|
459
|
+
note: "Null, never 0 \u2014 Claude Code never sets userModified true, so 0 would assert 'no AI edit was ever corrected by hand'."
|
|
460
|
+
},
|
|
461
|
+
// ── Diagnostic: read by nobody, on purpose ──────────────────────────────
|
|
462
|
+
abandonedPromptCount: { readBy: ["diagnostic"] },
|
|
463
|
+
// Epoch-marker metrics. The marker is local-only and never reaches the wire
|
|
464
|
+
// (see EXTRACTION_EPOCH_KIND), but it travels as a NormalizedHistoricalEvent
|
|
465
|
+
// and so is keyed by the same vocabulary.
|
|
466
|
+
windowOldest: { readBy: ["handoff"], note: "Oldest event the extraction saw \u2014 the marker's left edge." },
|
|
467
|
+
windowNewest: { readBy: ["handoff"], note: "Newest event the extraction saw \u2014 the marker's right edge." },
|
|
468
|
+
projectsWithNoReadableTranscript: { readBy: ["diagnostic"] },
|
|
469
|
+
unparsedComposerHeaders: { readBy: ["diagnostic"] },
|
|
470
|
+
unknownComposerHeaderTypes: { readBy: ["diagnostic"] },
|
|
471
|
+
orphanedBubbles: { readBy: ["diagnostic"] },
|
|
472
|
+
orphanedSubagentBubbles: { readBy: ["diagnostic"] },
|
|
473
|
+
sessionsWithoutTimeline: { readBy: ["diagnostic"] },
|
|
474
|
+
emptyComposers: { readBy: ["diagnostic"] },
|
|
475
|
+
apiErrorCount: { readBy: ["diagnostic"] },
|
|
476
|
+
assistantTurns: { readBy: ["diagnostic"] },
|
|
477
|
+
compactionAutoCount: { readBy: ["diagnostic"] },
|
|
478
|
+
compactionManualCount: { readBy: ["diagnostic"] },
|
|
479
|
+
editDayCount: { readBy: ["diagnostic"] },
|
|
480
|
+
emptyChatSessions: { readBy: ["diagnostic"] },
|
|
481
|
+
gitBranch: { readBy: ["diagnostic"] },
|
|
482
|
+
linesChanged: { readBy: ["diagnostic"] },
|
|
483
|
+
malformedChatSessionLines: { readBy: ["diagnostic"] },
|
|
484
|
+
malformedHistoryEntries: { readBy: ["diagnostic"] },
|
|
485
|
+
mode: { readBy: ["diagnostic"] },
|
|
486
|
+
modelCount: { readBy: ["diagnostic"] },
|
|
487
|
+
modelSwitchCount: { readBy: ["diagnostic"] },
|
|
488
|
+
rapidRepromptCount: { readBy: ["diagnostic"] },
|
|
489
|
+
schemaUnreadable: { readBy: ["diagnostic"] },
|
|
490
|
+
sessionCount: { readBy: ["diagnostic"] },
|
|
491
|
+
sessionsFromBubbleTimeline: { readBy: ["diagnostic"] },
|
|
492
|
+
sessionsFromCheckpointTimeline: { readBy: ["diagnostic"] },
|
|
493
|
+
sessionsFromRecencyTimeline: { readBy: ["diagnostic"] },
|
|
494
|
+
subagentAssistantTurns: { readBy: ["diagnostic"] },
|
|
495
|
+
subagentPrompts: { readBy: ["diagnostic"] },
|
|
496
|
+
subagentTokensTotal: { readBy: ["diagnostic"] },
|
|
497
|
+
toolName: {
|
|
498
|
+
readBy: ["diagnostic"],
|
|
499
|
+
note: "Set per ai_tool_call_started event by #43's extractors and shipped in wire metadata, but no reader resolves it server-side yet (the backend's ToolName column is MCP audit, not telemetry). Registered after the fact: #38 and #43 merged past each other, and the union caught it on the next compile \u2014 metaLines all over again."
|
|
500
|
+
},
|
|
501
|
+
toolResultCount: { readBy: ["diagnostic"] },
|
|
502
|
+
toolResultErrorCount: { readBy: ["diagnostic"] },
|
|
503
|
+
unknownBubbles: { readBy: ["diagnostic"] },
|
|
504
|
+
unknownLines: { readBy: ["diagnostic"] },
|
|
505
|
+
metaLines: {
|
|
506
|
+
readBy: ["diagnostic"],
|
|
507
|
+
note: 'Recognised-but-skipped transcript machinery (file-history-snapshot, queued-command, \u2026). Split out of unknownLines by #43 so that number keeps meaning "a type nobody has looked at". Registered here after the fact: #41 and #43 merged past each other, and the union caught it on the next compile \u2014 which is this module doing its job.'
|
|
508
|
+
},
|
|
509
|
+
unparsedBubbles: { readBy: ["diagnostic"] },
|
|
510
|
+
unparsedChatSessionFiles: { readBy: ["diagnostic"] },
|
|
511
|
+
unparsedHistoryFiles: { readBy: ["diagnostic"] },
|
|
512
|
+
unparsedLines: { readBy: ["diagnostic"] },
|
|
513
|
+
unreadableChatSessionFiles: { readBy: ["diagnostic"] },
|
|
514
|
+
unreadableHistoryFiles: { readBy: ["diagnostic"] },
|
|
515
|
+
unrecognisedChatSessionFiles: { readBy: ["diagnostic"] }
|
|
516
|
+
};
|
|
517
|
+
function backendMetricKeys() {
|
|
518
|
+
return Object.entries(exports.METRIC_KEYS).filter(([, spec]) => spec.readBy.includes("backend")).map(([key, spec]) => [key, spec.backendAliases ?? [key]]);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
380
523
|
// ../packages/tool-contract/out/index.js
|
|
381
524
|
var require_out = __commonJS({
|
|
382
525
|
"../packages/tool-contract/out/index.js"(exports) {
|
|
383
526
|
"use strict";
|
|
384
527
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
385
|
-
exports.ASCENDA_SEMANTIC_PROVENANCE = exports.ASCENDA_HISTORICAL_CONSENT_SCOPE = exports.ASCENDA_COLLABORATION_CONSENT_SCOPE = exports.ASCENDA_SEMANTIC_CONSENT_SCOPE = exports.ASCENDA_PROVENANCE = exports.ASCENDA_CONSENT_SCOPE = exports.EVENT_WORKLOAD_CATEGORY = exports.COLLABORATION_EVENT_TYPES = exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = void 0;
|
|
528
|
+
exports.backendMetricKeys = exports.METRIC_KEYS = exports.ASCENDA_SEMANTIC_PROVENANCE = exports.ASCENDA_HISTORICAL_CONSENT_SCOPE = exports.ASCENDA_COLLABORATION_CONSENT_SCOPE = exports.ASCENDA_SEMANTIC_CONSENT_SCOPE = exports.ASCENDA_PROVENANCE = exports.ASCENDA_CONSENT_SCOPE = exports.EVENT_WORKLOAD_CATEGORY = exports.COLLABORATION_EVENT_TYPES = exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = void 0;
|
|
386
529
|
exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = [
|
|
387
530
|
"approach_churn_detected",
|
|
388
531
|
"goal_drift_detected",
|
|
@@ -441,6 +584,13 @@ var require_out = __commonJS({
|
|
|
441
584
|
exports.ASCENDA_COLLABORATION_CONSENT_SCOPE = "workflow_telemetry";
|
|
442
585
|
exports.ASCENDA_HISTORICAL_CONSENT_SCOPE = "historical_import";
|
|
443
586
|
exports.ASCENDA_SEMANTIC_PROVENANCE = "semantic_work_signals";
|
|
587
|
+
var metricKeys_1 = require_metricKeys();
|
|
588
|
+
Object.defineProperty(exports, "METRIC_KEYS", { enumerable: true, get: function() {
|
|
589
|
+
return metricKeys_1.METRIC_KEYS;
|
|
590
|
+
} });
|
|
591
|
+
Object.defineProperty(exports, "backendMetricKeys", { enumerable: true, get: function() {
|
|
592
|
+
return metricKeys_1.backendMetricKeys;
|
|
593
|
+
} });
|
|
444
594
|
}
|
|
445
595
|
});
|
|
446
596
|
|
|
@@ -675,6 +825,7 @@ var require_tokenStore = __commonJS({
|
|
|
675
825
|
};
|
|
676
826
|
}();
|
|
677
827
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
828
|
+
exports.ascendaHome = ascendaHome;
|
|
678
829
|
exports.defaultTokenFilePath = defaultTokenFilePath2;
|
|
679
830
|
exports.persistEventWriteToken = persistEventWriteToken;
|
|
680
831
|
exports.readTokenFile = readTokenFile2;
|
|
@@ -682,8 +833,11 @@ var require_tokenStore = __commonJS({
|
|
|
682
833
|
var fs10 = __importStar(__require("fs"));
|
|
683
834
|
var os3 = __importStar(__require("os"));
|
|
684
835
|
var path10 = __importStar(__require("path"));
|
|
836
|
+
function ascendaHome() {
|
|
837
|
+
return process.env.ASCENDA_HOME ?? path10.join(os3.homedir(), ".ascenda");
|
|
838
|
+
}
|
|
685
839
|
function defaultTokenFilePath2(toolInstallationId) {
|
|
686
|
-
return path10.join(
|
|
840
|
+
return path10.join(ascendaHome(), "tokens", sanitizeFilePart(toolInstallationId));
|
|
687
841
|
}
|
|
688
842
|
function persistEventWriteToken(tokenFilePath, token) {
|
|
689
843
|
const dir = path10.dirname(tokenFilePath);
|
|
@@ -1642,6 +1796,7 @@ var require_liveBus = __commonJS({
|
|
|
1642
1796
|
var path10 = __importStar(__require("path"));
|
|
1643
1797
|
var WRITE_TIMEOUT_MS = 50;
|
|
1644
1798
|
var APP_BUNDLE_ID2 = "one.ascenda.ascendaMissionControl";
|
|
1799
|
+
var SAVER_HOST_BUNDLE_ID = "com.apple.ScreenSaver.Engine.legacyScreenSaver";
|
|
1645
1800
|
function liveBusSocketCandidates() {
|
|
1646
1801
|
const override = process.env.ASCENDA_LIVE_BUS_SOCKET;
|
|
1647
1802
|
if (override)
|
|
@@ -1649,7 +1804,8 @@ var require_liveBus = __commonJS({
|
|
|
1649
1804
|
const home = os3.homedir();
|
|
1650
1805
|
return [
|
|
1651
1806
|
path10.join(home, ".ascenda", "live.sock"),
|
|
1652
|
-
path10.join(home, "Library", "Containers", APP_BUNDLE_ID2, "Data", ".ascenda", "live.sock")
|
|
1807
|
+
path10.join(home, "Library", "Containers", APP_BUNDLE_ID2, "Data", ".ascenda", "live.sock"),
|
|
1808
|
+
path10.join(home, "Library", "Containers", SAVER_HOST_BUNDLE_ID, "Data", "l.sock")
|
|
1653
1809
|
];
|
|
1654
1810
|
}
|
|
1655
1811
|
function liveBusSocketPath() {
|
|
@@ -1721,8 +1877,8 @@ var require_out2 = __commonJS({
|
|
|
1721
1877
|
"../packages/tool-kit/out/index.js"(exports) {
|
|
1722
1878
|
"use strict";
|
|
1723
1879
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1724
|
-
exports.
|
|
1725
|
-
exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = exports.postToolEvent = exports.renewToolToken = exports.getPairingStatus = exports.createPairingSession = exports.AscendaApiError = exports.liveBusSocketCandidates = exports.liveBusSocketPath = exports.bucketPromptSize = exports.emitLiveSignal = void 0;
|
|
1880
|
+
exports.readWorkContextRegistry = exports.recordWorkContextAlias = exports.recordWorkContext = exports.deriveWorkContext = exports.hashWithMachineSalt = exports.readOrCreateMachineSalt = exports.machineSaltFilePath = exports.markFailureNotified = exports.shouldAnnounceFailure = exports.recordSendOutcome = exports.readCollectorState = exports.defaultStateFilePath = exports.readTokenFile = exports.persistEventWriteToken = exports.defaultTokenFilePath = exports.ascendaHome = exports.recordTurnStart = exports.consumeTurnDurationMs = exports.resolveContextHashes = exports.loadCliAgentConfig = exports.deliverHookEvents = exports.DEFAULT_API_BASE_URL = exports.resolveEventLogPath = exports.expandUserPath = exports.appendEventLog = exports.EVENT_LOG_ENV_VAR = exports.buildEventPayload = exports.AscendaSemanticEventError = exports.AscendaEventSender = exports.looksLikeCorrection = exports.outcomeForHook = exports.inferOutcome = exports.getNestedNumber = exports.getNestedString = exports.getNested = exports.getNumber = exports.getString = exports.localHourAt = exports.utcOffsetMinutesAt = exports.BUSINESS_DAY = exports.isOutsideBusinessHours = exports.isAfterHours = exports.bucketDurationMs = exports.bucketLinesChanged = exports.invitesDebrief = exports.classifyWorkMilestone = exports.isReworkGitAction = exports.classifyGitAction = exports.isVerificationCommand = exports.classifyCommand = void 0;
|
|
1881
|
+
exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = exports.postToolEvent = exports.renewToolToken = exports.getPairingStatus = exports.createPairingSession = exports.AscendaApiError = exports.liveBusSocketCandidates = exports.liveBusSocketPath = exports.bucketPromptSize = exports.emitLiveSignal = exports.workContextRegistryFilePath = void 0;
|
|
1726
1882
|
var commandClassifier_1 = require_commandClassifier();
|
|
1727
1883
|
Object.defineProperty(exports, "classifyCommand", { enumerable: true, get: function() {
|
|
1728
1884
|
return commandClassifier_1.classifyCommand;
|
|
@@ -1836,6 +1992,9 @@ var require_out2 = __commonJS({
|
|
|
1836
1992
|
return turnState_1.recordTurnStart;
|
|
1837
1993
|
} });
|
|
1838
1994
|
var tokenStore_1 = require_tokenStore();
|
|
1995
|
+
Object.defineProperty(exports, "ascendaHome", { enumerable: true, get: function() {
|
|
1996
|
+
return tokenStore_1.ascendaHome;
|
|
1997
|
+
} });
|
|
1839
1998
|
Object.defineProperty(exports, "defaultTokenFilePath", { enumerable: true, get: function() {
|
|
1840
1999
|
return tokenStore_1.defaultTokenFilePath;
|
|
1841
2000
|
} });
|
|
@@ -2366,6 +2525,12 @@ var HISTORICAL_PROVENANCE = {
|
|
|
2366
2525
|
var HISTORICAL_CONSENT_SCOPE = import_tool_contract.ASCENDA_HISTORICAL_CONSENT_SCOPE;
|
|
2367
2526
|
var EXTRACTION_EPOCH_KIND = "extraction_epoch";
|
|
2368
2527
|
|
|
2528
|
+
// src/toolName.ts
|
|
2529
|
+
function sanitizeToolName(toolName) {
|
|
2530
|
+
if (!toolName) return "unknown";
|
|
2531
|
+
return toolName.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 40) || "unknown";
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2369
2534
|
// src/daySlice.ts
|
|
2370
2535
|
var LOCAL_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
|
|
2371
2536
|
function localDayKey(t) {
|
|
@@ -2423,6 +2588,19 @@ var KNOWN_CLAUDE_LINE_TYPES = [
|
|
|
2423
2588
|
"last-prompt",
|
|
2424
2589
|
"custom-title"
|
|
2425
2590
|
];
|
|
2591
|
+
var META_CLAUDE_LINE_TYPES = /* @__PURE__ */ new Set([
|
|
2592
|
+
"ai-title",
|
|
2593
|
+
"mode",
|
|
2594
|
+
"pr-link",
|
|
2595
|
+
"worktree-state",
|
|
2596
|
+
"relocated",
|
|
2597
|
+
"create",
|
|
2598
|
+
"file",
|
|
2599
|
+
"directory",
|
|
2600
|
+
"image",
|
|
2601
|
+
"file-history-snapshot",
|
|
2602
|
+
"summary"
|
|
2603
|
+
]);
|
|
2426
2604
|
function sniffClaudeLine(line) {
|
|
2427
2605
|
const trimmed = line.trim();
|
|
2428
2606
|
if (trimmed === "") return { kind: "unparsed", raw: line };
|
|
@@ -2439,7 +2617,7 @@ function sniffClaudeLine(line) {
|
|
|
2439
2617
|
const type = record.type;
|
|
2440
2618
|
if (typeof type !== "string") return { kind: "unparsed", raw: line };
|
|
2441
2619
|
if (!KNOWN_CLAUDE_LINE_TYPES.includes(type)) {
|
|
2442
|
-
return { kind: "unknown", type };
|
|
2620
|
+
return META_CLAUDE_LINE_TYPES.has(type) ? { kind: "meta", type } : { kind: "unknown", type };
|
|
2443
2621
|
}
|
|
2444
2622
|
const message = record.message;
|
|
2445
2623
|
return {
|
|
@@ -2469,6 +2647,19 @@ function isToolFailureLine(record) {
|
|
|
2469
2647
|
(item) => typeof item === "object" && item !== null && item.type === "tool_result" && item.is_error === true
|
|
2470
2648
|
);
|
|
2471
2649
|
}
|
|
2650
|
+
function toolUseNamesOf(record) {
|
|
2651
|
+
const message = record.message;
|
|
2652
|
+
const content = message?.content;
|
|
2653
|
+
if (!Array.isArray(content)) return [];
|
|
2654
|
+
const names = [];
|
|
2655
|
+
for (const item of content) {
|
|
2656
|
+
if (typeof item !== "object" || item === null) continue;
|
|
2657
|
+
const entry = item;
|
|
2658
|
+
if (entry.type !== "tool_use") continue;
|
|
2659
|
+
names.push(sanitizeToolName(typeof entry.name === "string" ? entry.name : void 0));
|
|
2660
|
+
}
|
|
2661
|
+
return names;
|
|
2662
|
+
}
|
|
2472
2663
|
function countChangedLines(structuredPatch) {
|
|
2473
2664
|
let count = 0;
|
|
2474
2665
|
for (const hunk of structuredPatch) {
|
|
@@ -2499,6 +2690,7 @@ function newFold(sessionId, projectSlug) {
|
|
|
2499
2690
|
toolResults: 0,
|
|
2500
2691
|
queuedPrompts: 0,
|
|
2501
2692
|
unknownLines: 0,
|
|
2693
|
+
metaLines: 0,
|
|
2502
2694
|
unparsedLines: 0,
|
|
2503
2695
|
inputTokens: 0,
|
|
2504
2696
|
outputTokens: 0,
|
|
@@ -2515,10 +2707,13 @@ function newFold(sessionId, projectSlug) {
|
|
|
2515
2707
|
userModifiedEditCount: 0,
|
|
2516
2708
|
linesChangedTotal: 0,
|
|
2517
2709
|
abandonedPromptCount: 0,
|
|
2710
|
+
toolCallCount: 0,
|
|
2518
2711
|
subagentTranscripts: 0,
|
|
2519
2712
|
subagentPrompts: 0,
|
|
2520
2713
|
subagentAssistantTurns: 0,
|
|
2521
2714
|
subagentTokensTotal: 0,
|
|
2715
|
+
subagentToolCallCount: 0,
|
|
2716
|
+
toolCalls: [],
|
|
2522
2717
|
timelinePoints: [],
|
|
2523
2718
|
humanPromptTimestamps: []
|
|
2524
2719
|
};
|
|
@@ -2572,6 +2767,10 @@ async function foldLinesInto(fold, filePath, opts) {
|
|
|
2572
2767
|
if (line.trim() !== "") fold.unparsedLines += 1;
|
|
2573
2768
|
continue;
|
|
2574
2769
|
}
|
|
2770
|
+
if (sniffed.kind === "meta") {
|
|
2771
|
+
fold.metaLines += 1;
|
|
2772
|
+
continue;
|
|
2773
|
+
}
|
|
2575
2774
|
if (sniffed.kind === "unknown") {
|
|
2576
2775
|
fold.unknownLines += 1;
|
|
2577
2776
|
continue;
|
|
@@ -2618,6 +2817,16 @@ async function foldLinesInto(fold, filePath, opts) {
|
|
|
2618
2817
|
case "assistant": {
|
|
2619
2818
|
const record = JSON.parse(line);
|
|
2620
2819
|
const usage = record.message?.usage;
|
|
2820
|
+
const toolNames = toolUseNamesOf(record);
|
|
2821
|
+
if (toolNames.length > 0) {
|
|
2822
|
+
if (opts.isSidechain) fold.subagentToolCallCount += toolNames.length;
|
|
2823
|
+
else fold.toolCallCount += toolNames.length;
|
|
2824
|
+
if (sniffed.occurredAt) {
|
|
2825
|
+
for (const name of toolNames) {
|
|
2826
|
+
fold.toolCalls.push({ at: sniffed.occurredAt, name });
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2621
2830
|
if (opts.isSidechain) {
|
|
2622
2831
|
fold.subagentAssistantTurns += 1;
|
|
2623
2832
|
if (usage) {
|
|
@@ -2776,11 +2985,25 @@ async function* extractClaudeCode(snapshotDir, extractionId) {
|
|
|
2776
2985
|
extractionId
|
|
2777
2986
|
};
|
|
2778
2987
|
}
|
|
2988
|
+
for (const call of fold.toolCalls) {
|
|
2989
|
+
yield {
|
|
2990
|
+
occurredAt: call.at,
|
|
2991
|
+
store: "claude_code",
|
|
2992
|
+
sourceVersion: fold.sourceVersion,
|
|
2993
|
+
sessionRef: fold.sessionId,
|
|
2994
|
+
repoRef: fold.cwd ?? fold.projectSlug,
|
|
2995
|
+
eventKind: "ai_tool_call_started",
|
|
2996
|
+
metrics: { toolName: call.name },
|
|
2997
|
+
provenance: HISTORICAL_PROVENANCE.direct,
|
|
2998
|
+
extractionId
|
|
2999
|
+
};
|
|
3000
|
+
}
|
|
2779
3001
|
const durationMs = sessionDurationMs(fold);
|
|
2780
3002
|
const toolFailureCount = fold.toolResultErrorCount + fold.apiErrorCount;
|
|
2781
3003
|
const sessionMetrics = {
|
|
2782
3004
|
promptCount: fold.humanPrompts,
|
|
2783
3005
|
assistantTurns: fold.assistantTurns,
|
|
3006
|
+
toolCallCount: fold.toolCallCount,
|
|
2784
3007
|
toolResultCount: fold.toolResults,
|
|
2785
3008
|
queuedPrompts: fold.queuedPrompts,
|
|
2786
3009
|
inputTokens: fold.inputTokens,
|
|
@@ -2789,6 +3012,7 @@ async function* extractClaudeCode(snapshotDir, extractionId) {
|
|
|
2789
3012
|
durationBucket: durationBucketOf(fold),
|
|
2790
3013
|
afterHoursPrompts: fold.afterHoursPrompts,
|
|
2791
3014
|
unknownLines: fold.unknownLines,
|
|
3015
|
+
metaLines: fold.metaLines,
|
|
2792
3016
|
unparsedLines: fold.unparsedLines,
|
|
2793
3017
|
modelCount: fold.models.size,
|
|
2794
3018
|
modelSwitchCount: fold.modelSwitchCount,
|
|
@@ -2809,7 +3033,8 @@ async function* extractClaudeCode(snapshotDir, extractionId) {
|
|
|
2809
3033
|
subagentTranscripts: fold.subagentTranscripts,
|
|
2810
3034
|
subagentPrompts: fold.subagentPrompts,
|
|
2811
3035
|
subagentAssistantTurns: fold.subagentAssistantTurns,
|
|
2812
|
-
subagentTokensTotal: fold.subagentTokensTotal
|
|
3036
|
+
subagentTokensTotal: fold.subagentTokensTotal,
|
|
3037
|
+
subagentToolCallCount: fold.subagentToolCallCount
|
|
2813
3038
|
};
|
|
2814
3039
|
if (durationMs !== null) sessionMetrics.sessionMinutes = Math.round(durationMs / 6e4);
|
|
2815
3040
|
sessionMetrics.sessionStartedAt = fold.firstTs;
|
|
@@ -2975,7 +3200,9 @@ SELECT
|
|
|
2975
3200
|
json_extract(value,'$.tokenCount.outputTokens') AS outputTokens,
|
|
2976
3201
|
coalesce(json_array_length(value,'$.humanChanges'),0) AS humanChangesCount,
|
|
2977
3202
|
coalesce(json_array_length(value,'$.approximateLintErrors'),0) AS lintErrorsCount,
|
|
2978
|
-
json_extract(value,'$.modelInfo.modelName') AS modelName
|
|
3203
|
+
json_extract(value,'$.modelInfo.modelName') AS modelName,
|
|
3204
|
+
json_extract(value,'$.toolFormerData.toolCallId') AS toolCallId,
|
|
3205
|
+
json_extract(value,'$.toolFormerData.name') AS toolName
|
|
2979
3206
|
FROM cursorDiskKV WHERE key LIKE 'bubbleId:%';
|
|
2980
3207
|
`;
|
|
2981
3208
|
function repoInfoOf(row) {
|
|
@@ -3036,9 +3263,22 @@ function sniffCursorBubbleRow(row) {
|
|
|
3036
3263
|
humanChangesCount: asNumber2(row.humanChangesCount),
|
|
3037
3264
|
lintErrorsCount: asNumber2(row.lintErrorsCount),
|
|
3038
3265
|
modelName: row.modelName,
|
|
3039
|
-
sourceVersion: String(row.v)
|
|
3266
|
+
sourceVersion: String(row.v),
|
|
3267
|
+
toolCallId: row.toolCallId,
|
|
3268
|
+
toolName: row.toolName
|
|
3040
3269
|
};
|
|
3041
3270
|
}
|
|
3271
|
+
function foldToolCall(fold, sniffed) {
|
|
3272
|
+
const id = sniffed.toolCallId;
|
|
3273
|
+
if (!id) return;
|
|
3274
|
+
const at = sniffed.createdAt && sniffed.createdAt.length > 0 ? sniffed.createdAt : null;
|
|
3275
|
+
const known = fold.toolCallFirstSeen.get(id);
|
|
3276
|
+
if (known === void 0) fold.toolCallFirstSeen.set(id, at);
|
|
3277
|
+
else if (at !== null && (known === null || at < known)) fold.toolCallFirstSeen.set(id, at);
|
|
3278
|
+
if (sniffed.toolName && !fold.toolCallNames.has(id)) {
|
|
3279
|
+
fold.toolCallNames.set(id, sanitizeToolName(sniffed.toolName));
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3042
3282
|
function newFold2(row, sniffed) {
|
|
3043
3283
|
return {
|
|
3044
3284
|
composerId: row.composerId,
|
|
@@ -3067,6 +3307,8 @@ function newFold2(row, sniffed) {
|
|
|
3067
3307
|
models: /* @__PURE__ */ new Map(),
|
|
3068
3308
|
bubbleVersions: /* @__PURE__ */ new Map(),
|
|
3069
3309
|
humanPromptTimestamps: [],
|
|
3310
|
+
toolCallFirstSeen: /* @__PURE__ */ new Map(),
|
|
3311
|
+
toolCallNames: /* @__PURE__ */ new Map(),
|
|
3070
3312
|
subagentComposerIds: /* @__PURE__ */ new Set(),
|
|
3071
3313
|
subagentPromptCount: 0,
|
|
3072
3314
|
subagentAssistantTurns: 0,
|
|
@@ -3190,6 +3432,7 @@ async function* extractCursor(snapshotDir, extractionId) {
|
|
|
3190
3432
|
ownFold.lastBubbleMs = ms;
|
|
3191
3433
|
}
|
|
3192
3434
|
}
|
|
3435
|
+
foldToolCall(ownFold, sniffed);
|
|
3193
3436
|
if (sniffed.kind === "user") {
|
|
3194
3437
|
ownFold.humanPrompts += 1;
|
|
3195
3438
|
if (sniffed.createdAt && (0, import_tool_kit2.isAfterHours)(new Date(sniffed.createdAt))) {
|
|
@@ -3214,6 +3457,7 @@ async function* extractCursor(snapshotDir, extractionId) {
|
|
|
3214
3457
|
}
|
|
3215
3458
|
parentFold.subagentComposerIds.add(sniffed.composerId);
|
|
3216
3459
|
parentFold.subagentTokensTotal += sniffed.inputTokens + sniffed.outputTokens;
|
|
3460
|
+
foldToolCall(parentFold, sniffed);
|
|
3217
3461
|
if (sniffed.kind === "user") {
|
|
3218
3462
|
parentFold.subagentPromptCount += 1;
|
|
3219
3463
|
} else {
|
|
@@ -3260,8 +3504,30 @@ async function* extractCursor(snapshotDir, extractionId) {
|
|
|
3260
3504
|
extractionId
|
|
3261
3505
|
};
|
|
3262
3506
|
}
|
|
3507
|
+
let toolCallsUndated = 0;
|
|
3508
|
+
for (const [id, at] of [...fold.toolCallFirstSeen].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
3509
|
+
if (at === null) {
|
|
3510
|
+
toolCallsUndated += 1;
|
|
3511
|
+
continue;
|
|
3512
|
+
}
|
|
3513
|
+
yield {
|
|
3514
|
+
occurredAt: at,
|
|
3515
|
+
store: "cursor",
|
|
3516
|
+
sourceVersion,
|
|
3517
|
+
sessionRef: fold.composerId,
|
|
3518
|
+
repoRef: fold.repoRef,
|
|
3519
|
+
eventKind: "ai_tool_call_started",
|
|
3520
|
+
metrics: { toolName: fold.toolCallNames.get(id) ?? "unknown" },
|
|
3521
|
+
provenance: HISTORICAL_PROVENANCE.direct,
|
|
3522
|
+
extractionId
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3263
3525
|
const durationMs = sessionDurationMs2(fold);
|
|
3264
3526
|
const sessionMetrics = {
|
|
3527
|
+
toolCallCount: fold.toolCallFirstSeen.size,
|
|
3528
|
+
// The gap between the count and the events above, stated rather than
|
|
3529
|
+
// left to be inferred from a shortfall.
|
|
3530
|
+
toolCallsUndated,
|
|
3265
3531
|
promptCount: fold.humanPrompts,
|
|
3266
3532
|
assistantTurns: fold.assistantTurns,
|
|
3267
3533
|
inputTokens: fold.inputTokens,
|
|
@@ -3286,6 +3552,7 @@ async function* extractCursor(snapshotDir, extractionId) {
|
|
|
3286
3552
|
if (fold.mode) sessionMetrics.mode = fold.mode;
|
|
3287
3553
|
if (fold.contextUsagePercent !== null) {
|
|
3288
3554
|
sessionMetrics.contextUsagePercent = Math.round(fold.contextUsagePercent * 100) / 100;
|
|
3555
|
+
sessionMetrics.contextWindowPeakPct = Math.round(fold.contextUsagePercent * 100) / 1e4;
|
|
3289
3556
|
}
|
|
3290
3557
|
const primaryModel = pickTop(fold.models);
|
|
3291
3558
|
if (primaryModel) sessionMetrics.primaryModel = primaryModel;
|
|
@@ -3474,6 +3741,22 @@ async function foldEditDays(historyDir, index) {
|
|
|
3474
3741
|
}
|
|
3475
3742
|
return result;
|
|
3476
3743
|
}
|
|
3744
|
+
function toolInvocationsOf(request) {
|
|
3745
|
+
const response = request.response;
|
|
3746
|
+
if (!Array.isArray(response)) return [];
|
|
3747
|
+
const calls = [];
|
|
3748
|
+
for (const part of response) {
|
|
3749
|
+
if (typeof part !== "object" || part === null) continue;
|
|
3750
|
+
const entry = part;
|
|
3751
|
+
if (entry.kind !== "toolInvocationSerialized") continue;
|
|
3752
|
+
if (typeof entry.toolCallId !== "string" || entry.toolCallId.length === 0) continue;
|
|
3753
|
+
calls.push({
|
|
3754
|
+
id: entry.toolCallId,
|
|
3755
|
+
name: sanitizeToolName(typeof entry.toolId === "string" ? entry.toolId : void 0)
|
|
3756
|
+
});
|
|
3757
|
+
}
|
|
3758
|
+
return calls;
|
|
3759
|
+
}
|
|
3477
3760
|
var JSONL_KIND_HEADER = 0;
|
|
3478
3761
|
var JSONL_KIND_SET = 1;
|
|
3479
3762
|
var JSONL_KIND_SPLICE = 2;
|
|
@@ -3635,7 +3918,8 @@ async function foldChatSessions(workspaceStorageDir) {
|
|
|
3635
3918
|
canceledCount: 0,
|
|
3636
3919
|
errorCount: 0,
|
|
3637
3920
|
models: /* @__PURE__ */ new Map(),
|
|
3638
|
-
requestTimestamps: []
|
|
3921
|
+
requestTimestamps: [],
|
|
3922
|
+
toolCalls: /* @__PURE__ */ new Map()
|
|
3639
3923
|
};
|
|
3640
3924
|
for (const r of requests) {
|
|
3641
3925
|
if (typeof r !== "object" || r === null) continue;
|
|
@@ -3654,6 +3938,9 @@ async function foldChatSessions(workspaceStorageDir) {
|
|
|
3654
3938
|
if (typeof req.modelId === "string") {
|
|
3655
3939
|
fold.models.set(req.modelId, (fold.models.get(req.modelId) ?? 0) + 1);
|
|
3656
3940
|
}
|
|
3941
|
+
for (const call of toolInvocationsOf(req)) {
|
|
3942
|
+
if (!fold.toolCalls.has(call.id)) fold.toolCalls.set(call.id, { at: iso, name: call.name });
|
|
3943
|
+
}
|
|
3657
3944
|
}
|
|
3658
3945
|
if (fold.requestCount > 0) result.sessions.push(fold);
|
|
3659
3946
|
}
|
|
@@ -3707,8 +3994,22 @@ async function* extractVsCode(source, extractionId) {
|
|
|
3707
3994
|
extractionId
|
|
3708
3995
|
};
|
|
3709
3996
|
}
|
|
3997
|
+
for (const call of fold.toolCalls.values()) {
|
|
3998
|
+
yield {
|
|
3999
|
+
occurredAt: call.at,
|
|
4000
|
+
store: "vscode",
|
|
4001
|
+
sourceVersion: String(KNOWN_CHAT_SESSION_VERSION),
|
|
4002
|
+
sessionRef: fold.sessionId,
|
|
4003
|
+
repoRef: fold.workspaceRoot,
|
|
4004
|
+
eventKind: "ai_tool_call_started",
|
|
4005
|
+
metrics: { toolName: call.name },
|
|
4006
|
+
provenance: HISTORICAL_PROVENANCE.derived,
|
|
4007
|
+
extractionId
|
|
4008
|
+
};
|
|
4009
|
+
}
|
|
3710
4010
|
const durationMs = Date.parse(fold.lastTs) - Date.parse(fold.firstTs);
|
|
3711
4011
|
const sessionMetrics = {
|
|
4012
|
+
toolCallCount: fold.toolCalls.size,
|
|
3712
4013
|
requestCount: fold.requestCount,
|
|
3713
4014
|
afterHoursRequests: fold.afterHoursRequests,
|
|
3714
4015
|
canceledCount: fold.canceledCount,
|
|
@@ -4134,7 +4435,7 @@ function importKeyOf(event, ordinal) {
|
|
|
4134
4435
|
[event.store, event.sessionRef ?? "", event.eventKind, event.occurredAt, String(ordinal)].join(
|
|
4135
4436
|
"|"
|
|
4136
4437
|
)
|
|
4137
|
-
).digest("hex")
|
|
4438
|
+
).digest("hex");
|
|
4138
4439
|
}
|
|
4139
4440
|
var workContextMemo = /* @__PURE__ */ new Map();
|
|
4140
4441
|
function workContextOf(repoRef) {
|
|
@@ -4297,7 +4598,7 @@ import * as fs8 from "node:fs/promises";
|
|
|
4297
4598
|
import * as os2 from "node:os";
|
|
4298
4599
|
import * as path8 from "node:path";
|
|
4299
4600
|
var APP_BUNDLE_ID = "one.ascenda.ascendaMissionControl";
|
|
4300
|
-
var HANDOFF_SCHEMA =
|
|
4601
|
+
var HANDOFF_SCHEMA = 3;
|
|
4301
4602
|
function handoffDir(home = os2.homedir()) {
|
|
4302
4603
|
return path8.join(home, "Library", "Containers", APP_BUNDLE_ID, "Data", ".ascenda", "history-import");
|
|
4303
4604
|
}
|
|
@@ -4345,6 +4646,8 @@ function buildHandoff(events, extractionId, generatedAt) {
|
|
|
4345
4646
|
// counting it in case upstream starts populating it, and the handoff
|
|
4346
4647
|
// reports the count only when it is non-zero.
|
|
4347
4648
|
userModifiedEditCount: Number(event.metrics.userModifiedEditCount ?? 0) > 0 ? Number(event.metrics.userModifiedEditCount) : null,
|
|
4649
|
+
toolCallCount: Number(event.metrics.toolCallCount ?? 0),
|
|
4650
|
+
subagentToolCallCount: Number(event.metrics.subagentToolCallCount ?? 0),
|
|
4348
4651
|
subagentTranscripts: Number(event.metrics.subagentTranscripts ?? 0),
|
|
4349
4652
|
days: event.dayBreakdown ?? [],
|
|
4350
4653
|
provenance: event.provenance
|
|
@@ -4390,6 +4693,8 @@ function buildCursorHandoff(events, extractionId, generatedAt) {
|
|
|
4390
4693
|
contextUsagePercent: typeof event.metrics.contextUsagePercent === "number" ? event.metrics.contextUsagePercent : null,
|
|
4391
4694
|
humanChangesCount: Number(event.metrics.humanChangesCount ?? 0),
|
|
4392
4695
|
approximateLintErrorsCount: Number(event.metrics.approximateLintErrorsCount ?? 0),
|
|
4696
|
+
toolCallCount: Number(event.metrics.toolCallCount ?? 0),
|
|
4697
|
+
toolCallsUndated: Number(event.metrics.toolCallsUndated ?? 0),
|
|
4393
4698
|
subagentComposers: Number(event.metrics.subagentComposers ?? 0),
|
|
4394
4699
|
days: event.dayBreakdown ?? [],
|
|
4395
4700
|
provenance: event.provenance
|
|
@@ -4442,6 +4747,7 @@ function buildVsCodeHandoff(events, extractionId, generatedAt) {
|
|
|
4442
4747
|
primaryModel: typeof event.metrics.primaryModel === "string" ? event.metrics.primaryModel : null,
|
|
4443
4748
|
canceledCount: Number(event.metrics.canceledCount ?? 0),
|
|
4444
4749
|
errorCount: Number(event.metrics.errorCount ?? 0),
|
|
4750
|
+
toolCallCount: Number(event.metrics.toolCallCount ?? 0),
|
|
4445
4751
|
days: event.dayBreakdown ?? [],
|
|
4446
4752
|
provenance: event.provenance
|
|
4447
4753
|
});
|
|
@@ -4503,8 +4809,6 @@ async function safeScan(store, rootPath, scan) {
|
|
|
4503
4809
|
}
|
|
4504
4810
|
}
|
|
4505
4811
|
var READ_FAILURE_METRICS = [
|
|
4506
|
-
"unparsedFiles",
|
|
4507
|
-
"unreadableFiles",
|
|
4508
4812
|
"unparsedHistoryFiles",
|
|
4509
4813
|
"unreadableHistoryFiles",
|
|
4510
4814
|
"malformedHistoryEntries",
|
|
@@ -4513,7 +4817,10 @@ var READ_FAILURE_METRICS = [
|
|
|
4513
4817
|
"unrecognisedChatSessionFiles",
|
|
4514
4818
|
"malformedChatSessionLines",
|
|
4515
4819
|
"unparsedLines",
|
|
4516
|
-
|
|
4820
|
+
// Projects, not files — the total is a count of things this run could not
|
|
4821
|
+
// read, and the warning wording ("file(s)/record(s)") is looser than the
|
|
4822
|
+
// set it sums.
|
|
4823
|
+
"projectsWithNoReadableTranscript"
|
|
4517
4824
|
];
|
|
4518
4825
|
function readFailuresOf(events) {
|
|
4519
4826
|
let total = 0;
|
|
@@ -4526,6 +4833,9 @@ function readFailuresOf(events) {
|
|
|
4526
4833
|
}
|
|
4527
4834
|
return total;
|
|
4528
4835
|
}
|
|
4836
|
+
function appendAll(target, source) {
|
|
4837
|
+
for (const item of source) target.push(item);
|
|
4838
|
+
}
|
|
4529
4839
|
async function runSource(outcomes, store, inventory, allEvents, extract, buildStoreHandoff, scanError = null) {
|
|
4530
4840
|
if (scanError !== null) {
|
|
4531
4841
|
process.stdout.write(`${inventory.store} FAILED to scan: ${scanError}
|
|
@@ -4547,7 +4857,7 @@ async function runSource(outcomes, store, inventory, allEvents, extract, buildSt
|
|
|
4547
4857
|
kindCounts[event.eventKind] = (kindCounts[event.eventKind] ?? 0) + 1;
|
|
4548
4858
|
});
|
|
4549
4859
|
} catch (error) {
|
|
4550
|
-
allEvents
|
|
4860
|
+
appendAll(allEvents, events);
|
|
4551
4861
|
outcomes.push({
|
|
4552
4862
|
store,
|
|
4553
4863
|
status: "failed",
|
|
@@ -4560,7 +4870,7 @@ async function runSource(outcomes, store, inventory, allEvents, extract, buildSt
|
|
|
4560
4870
|
`);
|
|
4561
4871
|
return;
|
|
4562
4872
|
}
|
|
4563
|
-
allEvents
|
|
4873
|
+
appendAll(allEvents, events);
|
|
4564
4874
|
process.stdout.write(`${store} extracted: ${events.length.toLocaleString("en-US")} events
|
|
4565
4875
|
`);
|
|
4566
4876
|
for (const [kind, n] of Object.entries(kindCounts)) {
|