vouchington-tooling 0.20.0 → 0.22.0
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 +73 -10
- package/dist/agent-blackboard/snapshot-partition-format.mjs +2 -72
- package/dist/agent-blackboard/snapshot-partition-guards.d.mts +3 -0
- package/dist/agent-blackboard/snapshot-partition-guards.mjs +9 -0
- package/dist/agent-blackboard/snapshot-partition-predicates.d.mts +3 -0
- package/dist/agent-blackboard/snapshot-partition-predicates.mjs +65 -0
- package/dist/api-contract-discovery/header-contract-parser.d.mts +3 -0
- package/dist/api-contract-discovery/header-contract-parser.mjs +93 -0
- package/dist/api-contract-discovery/header-contract-registry.d.mts +3 -0
- package/dist/api-contract-discovery/header-contract-registry.mjs +38 -0
- package/dist/api-contract-discovery/header-contract-types.d.mts +19 -0
- package/dist/api-contract-discovery/header-contract-types.mjs +1 -0
- package/dist/api-contract-discovery/index.d.mts +31 -0
- package/dist/api-contract-discovery/index.mjs +26 -0
- package/dist/api-contract-discovery/query-contract-extraction.d.mts +3 -0
- package/dist/api-contract-discovery/query-contract-extraction.mjs +65 -0
- package/dist/api-contract-discovery/query-contract-literals.d.mts +8 -0
- package/dist/api-contract-discovery/query-contract-literals.mjs +54 -0
- package/dist/api-contract-discovery/query-contract-registry.d.mts +3 -0
- package/dist/api-contract-discovery/query-contract-registry.mjs +68 -0
- package/dist/api-contract-discovery/query-contract-types.d.mts +8 -0
- package/dist/api-contract-discovery/query-contract-types.mjs +1 -0
- package/dist/api-contract-discovery/registered-route-catalog.d.mts +10 -0
- package/dist/api-contract-discovery/registered-route-catalog.mjs +81 -0
- package/dist/api-contract-discovery/registered-route-handler-analysis.d.mts +2 -0
- package/dist/api-contract-discovery/registered-route-handler-analysis.mjs +74 -0
- package/dist/api-contract-discovery/request-contract-implicit.d.mts +17 -0
- package/dist/api-contract-discovery/request-contract-implicit.mjs +73 -0
- package/dist/api-contract-discovery/request-contract-lenient.d.mts +28 -0
- package/dist/api-contract-discovery/request-contract-lenient.mjs +59 -0
- package/dist/api-contract-discovery/request-contract-registry.d.mts +14 -0
- package/dist/api-contract-discovery/request-contract-registry.mjs +61 -0
- package/dist/api-contract-discovery/request-contract-route-analysis.d.mts +25 -0
- package/dist/api-contract-discovery/request-contract-route-analysis.mjs +68 -0
- package/dist/api-contract-discovery/request-contract-types.d.mts +12 -0
- package/dist/api-contract-discovery/request-contract-types.mjs +1 -0
- package/dist/api-contract-discovery/response-contract-ctx-analysis.d.mts +7 -0
- package/dist/api-contract-discovery/response-contract-ctx-analysis.mjs +28 -0
- package/dist/api-contract-discovery/response-contract-error-branch.d.mts +15 -0
- package/dist/api-contract-discovery/response-contract-error-branch.mjs +47 -0
- package/dist/api-contract-discovery/response-contract-implicit-sources.test-helpers.d.mts +145 -0
- package/dist/api-contract-discovery/response-contract-implicit-sources.test-helpers.mjs +145 -0
- package/dist/api-contract-discovery/response-contract-implicit.d.mts +5 -0
- package/dist/api-contract-discovery/response-contract-implicit.mjs +110 -0
- package/dist/api-contract-discovery/response-contract-lenient.d.mts +23 -0
- package/dist/api-contract-discovery/response-contract-lenient.mjs +52 -0
- package/dist/api-contract-discovery/response-contract-media.d.mts +3 -0
- package/dist/api-contract-discovery/response-contract-media.mjs +46 -0
- package/dist/api-contract-discovery/response-contract-registration.d.mts +11 -0
- package/dist/api-contract-discovery/response-contract-registration.mjs +61 -0
- package/dist/api-contract-discovery/response-contract-registry.d.mts +7 -0
- package/dist/api-contract-discovery/response-contract-registry.mjs +76 -0
- package/dist/api-contract-discovery/response-contract-route-analysis.d.mts +13 -0
- package/dist/api-contract-discovery/response-contract-route-analysis.mjs +144 -0
- package/dist/api-contract-discovery/response-contract-status.d.mts +27 -0
- package/dist/api-contract-discovery/response-contract-status.mjs +80 -0
- package/dist/api-contract-discovery/response-contract-types.d.mts +16 -0
- package/dist/api-contract-discovery/response-contract-types.mjs +1 -0
- package/dist/api-contract-discovery/test-setup.test-helpers.d.mts +3 -0
- package/dist/api-contract-discovery/test-setup.test-helpers.mjs +2 -0
- package/dist/ast-grep-examples/companion-parity-compare.d.mts +3 -0
- package/dist/ast-grep-examples/companion-parity-compare.mjs +58 -0
- package/dist/ast-grep-examples/companion-parity.d.mts +2 -1
- package/dist/ast-grep-examples/companion-parity.mjs +2 -58
- package/dist/browser-session-runner/attempt.mjs +29 -48
- package/dist/browser-session-runner/termination.d.mts +11 -0
- package/dist/browser-session-runner/termination.mjs +34 -0
- package/dist/cli/parse-direct-options.d.mts +26 -0
- package/dist/cli/parse-direct-options.mjs +72 -0
- package/dist/cli/parse-forwarded-commands.d.mts +42 -0
- package/dist/cli/parse-forwarded-commands.mjs +29 -0
- package/dist/cli/parse-options.d.mts +1 -2
- package/dist/cli/parse-options.mjs +2 -72
- package/dist/cli/parse.mjs +4 -26
- package/dist/compiler-build/freshness.d.mts +27 -0
- package/dist/compiler-build/freshness.mjs +116 -0
- package/dist/compiler-build/index.d.mts +2 -0
- package/dist/compiler-build/index.mjs +2 -0
- package/dist/compiler-build/settlement.d.mts +10 -0
- package/dist/compiler-build/settlement.mjs +14 -0
- package/dist/config-inventory/call-arguments.d.mts +1 -0
- package/dist/config-inventory/call-arguments.mjs +30 -0
- package/dist/config-inventory/collect.d.mts +3 -0
- package/dist/config-inventory/collect.mjs +43 -0
- package/dist/config-inventory/dynamic-configs.d.mts +2 -0
- package/dist/config-inventory/dynamic-configs.mjs +9 -0
- package/dist/config-inventory/env-expression-readers.d.mts +3 -0
- package/dist/config-inventory/env-expression-readers.mjs +117 -0
- package/dist/config-inventory/env-prefix-readers.d.mts +2 -0
- package/dist/config-inventory/env-prefix-readers.mjs +14 -0
- package/dist/config-inventory/env-reference-matchers.d.mts +3 -0
- package/dist/config-inventory/env-reference-matchers.mjs +9 -0
- package/dist/config-inventory/env-var-accumulator.d.mts +6 -0
- package/dist/config-inventory/env-var-accumulator.mjs +82 -0
- package/dist/config-inventory/env-vars.d.mts +4 -0
- package/dist/config-inventory/env-vars.mjs +108 -0
- package/dist/config-inventory/format.d.mts +2 -0
- package/dist/config-inventory/format.mjs +69 -0
- package/dist/config-inventory/index.d.mts +3 -0
- package/dist/config-inventory/index.mjs +2 -0
- package/dist/config-inventory/package-gates.d.mts +2 -0
- package/dist/config-inventory/package-gates.mjs +54 -0
- package/dist/config-inventory/shared.d.mts +3 -0
- package/dist/config-inventory/shared.mjs +7 -0
- package/dist/config-inventory/types.d.mts +96 -0
- package/dist/config-inventory/types.mjs +1 -0
- package/dist/contract-schema/contract-schema-bounded-array.d.mts +15 -0
- package/dist/contract-schema/contract-schema-bounded-array.mjs +32 -0
- package/dist/contract-schema/contract-schema-type-extractor.d.mts +2 -8
- package/dist/contract-schema/contract-schema-type-extractor.mjs +2 -31
- package/dist/coverage-transport/control-v2-parse-object.d.mts +12 -0
- package/dist/coverage-transport/control-v2-parse-object.mjs +28 -0
- package/dist/coverage-transport/control-v2.mjs +2 -27
- package/dist/dependency-license-policy/audit-directory.d.mts +28 -0
- package/dist/dependency-license-policy/audit-directory.mjs +115 -0
- package/dist/dependency-license-policy/audit-signals.d.mts +12 -0
- package/dist/dependency-license-policy/audit-signals.mjs +44 -0
- package/dist/dependency-license-policy/audit-store.d.mts +12 -0
- package/dist/dependency-license-policy/audit-store.mjs +32 -0
- package/dist/dependency-license-policy/collect.d.mts +3 -1
- package/dist/dependency-license-policy/collect.mjs +16 -21
- package/dist/dependency-license-policy/execute-pnpm.d.mts +10 -0
- package/dist/dependency-license-policy/execute-pnpm.mjs +83 -0
- package/dist/dependency-license-policy/types.d.mts +11 -9
- package/dist/dependency-license-policy/workspace.d.mts +3 -1
- package/dist/dependency-license-policy/workspace.mjs +12 -5
- package/dist/gh-api-shell-quoting/argument-scan.d.mts +7 -0
- package/dist/gh-api-shell-quoting/argument-scan.mjs +35 -0
- package/dist/gh-api-shell-quoting/logical-line.d.mts +3 -0
- package/dist/gh-api-shell-quoting/logical-line.mjs +90 -0
- package/dist/gh-api-shell-quoting/scan.d.mts +2 -4
- package/dist/gh-api-shell-quoting/scan.mjs +1 -119
- package/dist/gh-cli/diff.d.mts +24 -4
- package/dist/gh-cli/diff.mjs +111 -4
- package/dist/gh-cli/index.d.mts +2 -1
- package/dist/gh-cli/index.mjs +1 -1
- package/dist/gha-workspace-policy/docker-options.d.mts +4 -0
- package/dist/gha-workspace-policy/docker-options.mjs +93 -0
- package/dist/gha-workspace-policy/docker-workspace-user.mjs +1 -168
- package/dist/gha-workspace-policy/shell-token-modes.d.mts +10 -0
- package/dist/gha-workspace-policy/shell-token-modes.mjs +31 -0
- package/dist/gha-workspace-policy/shell-tokens.d.mts +1 -0
- package/dist/gha-workspace-policy/shell-tokens.mjs +65 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +1 -1
- package/dist/openapi-document/contract-schema-types.d.mts +1 -1
- package/dist/openapi-document/openapi-types.d.mts +1 -1
- package/dist/pnpm-install/native-family.d.mts +3 -0
- package/dist/pnpm-install/native-family.mjs +31 -0
- package/dist/pnpm-install/native-health.d.mts +1 -4
- package/dist/pnpm-install/native-health.mjs +2 -31
- package/dist/retrospective-facts/local-merge.d.mts +2 -0
- package/dist/retrospective-facts/local-merge.mjs +21 -0
- package/dist/retrospective-facts/local.mjs +1 -21
- package/dist/retrospective-transcript/claude-blocks.d.mts +3 -0
- package/dist/retrospective-transcript/claude-blocks.mjs +38 -0
- package/dist/retrospective-transcript/claude.mjs +4 -34
- package/dist/retrospective-transcript/codex-payload.d.mts +2 -0
- package/dist/retrospective-transcript/codex-payload.mjs +51 -0
- package/dist/retrospective-transcript/codex-records.d.mts +2 -0
- package/dist/retrospective-transcript/codex-records.mjs +95 -0
- package/dist/retrospective-transcript/codex.mjs +2 -144
- package/dist/retrospective-transcript/index.d.mts +3 -16
- package/dist/retrospective-transcript/index.mjs +4 -48
- package/dist/retrospective-transcript/resolve-transcript-file.d.mts +19 -0
- package/dist/retrospective-transcript/resolve-transcript-file.mjs +50 -0
- package/dist/session-friction/command-segments.d.mts +3 -0
- package/dist/session-friction/command-segments.mjs +94 -0
- package/dist/session-friction/log-file.d.mts +7 -0
- package/dist/session-friction/log-file.mjs +83 -0
- package/dist/session-friction/log.mjs +3 -83
- package/dist/session-friction/normalize.mjs +1 -94
- package/dist/sql-scanner/comments.d.mts +1 -0
- package/dist/sql-scanner/comments.mjs +101 -0
- package/dist/sql-scanner/index.d.mts +1 -1
- package/dist/sql-scanner/index.mjs +1 -100
- package/dist/sql-scanner/literals.mjs +1 -35
- package/dist/sql-scanner/quote-decode.d.mts +2 -0
- package/dist/sql-scanner/quote-decode.mjs +35 -0
- package/dist/vitest-diagnostics/index.d.mts +7 -0
- package/dist/vitest-diagnostics/index.mjs +4 -0
- package/dist/vitest-diagnostics/vitest-fork-exit-error-detail.d.mts +7 -0
- package/dist/vitest-diagnostics/vitest-fork-exit-error-detail.mjs +26 -0
- package/dist/vitest-diagnostics/vitest-fork-exit-records.d.mts +26 -0
- package/dist/vitest-diagnostics/vitest-fork-exit-records.mjs +161 -0
- package/dist/vitest-diagnostics/vitest-fork-exit-sentinel.d.mts +14 -0
- package/dist/vitest-diagnostics/vitest-fork-exit-sentinel.mjs +131 -0
- package/dist/vitest-diagnostics/vitest-fork-leak-detection.d.mts +26 -0
- package/dist/vitest-diagnostics/vitest-fork-leak-detection.mjs +96 -0
- package/dist/vitest-diagnostics/vitest-fork-leak-diagnostics.d.mts +3 -0
- package/dist/vitest-diagnostics/vitest-fork-leak-diagnostics.mjs +14 -0
- package/dist/vitest-diagnostics/vitest-fork-leak-episode.d.mts +37 -0
- package/dist/vitest-diagnostics/vitest-fork-leak-episode.mjs +118 -0
- package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-errors.d.mts +2 -0
- package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-errors.mjs +42 -0
- package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-reporter.d.mts +12 -0
- package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-reporter.mjs +142 -0
- package/dist/workflow-policy/concurrency-scope.d.mts +4 -0
- package/dist/workflow-policy/concurrency-scope.mjs +66 -0
- package/dist/workflow-policy/concurrency.d.mts +10 -0
- package/dist/workflow-policy/concurrency.mjs +77 -0
- package/dist/workflow-policy/condition-entailment.d.mts +20 -0
- package/dist/workflow-policy/condition-entailment.mjs +132 -0
- package/dist/workflow-policy/condition-split.d.mts +15 -0
- package/dist/workflow-policy/condition-split.mjs +71 -0
- package/dist/workflow-policy/graph.d.mts +2 -0
- package/dist/workflow-policy/graph.mjs +138 -0
- package/dist/workflow-policy/index.d.mts +7 -0
- package/dist/workflow-policy/index.mjs +6 -0
- package/dist/workflow-policy/permission-mismatches.d.mts +3 -0
- package/dist/workflow-policy/permission-mismatches.mjs +52 -0
- package/dist/workflow-policy/permissions.d.mts +16 -0
- package/dist/workflow-policy/permissions.mjs +83 -0
- package/dist/workflow-policy/secret-readiness.d.mts +18 -0
- package/dist/workflow-policy/secret-readiness.mjs +163 -0
- package/dist/workflow-policy/shell-comments.d.mts +7 -0
- package/dist/workflow-policy/shell-comments.mjs +28 -0
- package/dist/workflow-policy/types.d.mts +90 -0
- package/dist/workflow-policy/types.mjs +1 -0
- package/dist/workspace-gates/manifest-version-parser.mjs +1 -52
- package/dist/workspace-gates/manifest-version-skips.d.mts +1 -0
- package/dist/workspace-gates/manifest-version-skips.mjs +52 -0
- package/docs/workflow-and-compiler.md +74 -0
- package/package.json +26 -2
- package/skills/agent-workflow/SKILL.md +4 -4
- package/skills/agent-workflow/references/review-response.md +47 -44
- package/skills/backend-vitest-test-authoring/SKILL.md +9 -6
- package/skills/blackboard/SKILL.md +8 -8
- package/skills/dependabot/SKILL.md +68 -67
- package/skills/dotnet-test-authoring/SKILL.md +11 -12
- package/skills/git-commit-checklist/SKILL.md +3 -3
- package/skills/github-actions-authoring/SKILL.md +40 -38
- package/skills/github-actions-checklist/SKILL.md +93 -85
- package/skills/github-issue/SKILL.md +82 -78
- package/skills/nextjs-vitest-test-authoring/SKILL.md +8 -6
- package/skills/npm-publishing/SKILL.md +42 -38
- package/skills/organize-github-issues/SKILL.md +18 -22
- package/skills/package-json-checklist/SKILL.md +5 -5
- package/skills/planning/SKILL.md +3 -3
- package/skills/playwright-authoring/SKILL.md +10 -9
- package/skills/postgres-node-performance-tuning/SKILL.md +10 -6
- package/skills/postgres-partitioning-uuid-v7/SKILL.md +10 -7
- package/skills/pr-description/SKILL.md +4 -3
- package/skills/retrospective/SKILL.md +14 -15
- package/skills/retrospective-distill/SKILL.md +14 -14
- package/skills/review-ci-logs/SKILL.md +18 -19
- package/skills/review-github-issue-taxonomy/SKILL.md +21 -18
- package/skills/revisit-followups/SKILL.md +3 -3
- package/skills/stacked-prs/SKILL.md +30 -61
- package/skills/static-analysis-checklist/SKILL.md +6 -4
- package/skills/storybook-authoring/SKILL.md +9 -9
- package/skills/swift-test-authoring/SKILL.md +10 -9
- package/skills/test-authoring/SKILL.md +14 -14
- package/skills/test-authoring/references/core-practice.md +12 -11
- package/skills/test-authoring/references/dependency-boundaries.md +36 -35
- package/skills/test-authoring/references/tautological-tests.md +45 -44
- package/skills/vitest-test-authoring/SKILL.md +9 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asRecord, emptyFacts, parseLines } from './shared.mjs';
|
|
2
|
+
import { applyAssistantUsage, applyToolBlocks } from './claude-blocks.mjs';
|
|
2
3
|
function hasPromptContent(content) {
|
|
3
4
|
if (typeof content === 'string')
|
|
4
5
|
return true;
|
|
@@ -27,39 +28,8 @@ export function computeClaude(lines) {
|
|
|
27
28
|
record.isMeta !== true &&
|
|
28
29
|
record.isCompactSummary !== true)
|
|
29
30
|
facts.userPrompts++;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
facts.assistantResponses++;
|
|
33
|
-
const usage = asRecord(message?.usage);
|
|
34
|
-
const totals = subagent ? facts.subagentTokens : facts.tokens;
|
|
35
|
-
totals.input += asNumber(usage?.input_tokens);
|
|
36
|
-
totals.output += asNumber(usage?.output_tokens);
|
|
37
|
-
totals.cacheRead += asNumber(usage?.cache_read_input_tokens);
|
|
38
|
-
totals.cacheCreation += asNumber(usage?.cache_creation_input_tokens);
|
|
39
|
-
}
|
|
40
|
-
const blocks = Array.isArray(message?.content) ? message.content : [];
|
|
41
|
-
for (const block of blocks) {
|
|
42
|
-
const value = asRecord(block);
|
|
43
|
-
if (!value)
|
|
44
|
-
continue;
|
|
45
|
-
if (value.type === 'tool_use' || value.type === 'server_tool_use') {
|
|
46
|
-
facts.toolCalls++;
|
|
47
|
-
if (subagent)
|
|
48
|
-
facts.subagentToolCalls++;
|
|
49
|
-
if (value.name === 'advisor' && typeof value.id === 'string')
|
|
50
|
-
advisorIds.add(value.id);
|
|
51
|
-
if (value.name === 'Bash' || value.name === 'bash') {
|
|
52
|
-
const command = asRecord(value.input)?.command;
|
|
53
|
-
if (typeof command === 'string')
|
|
54
|
-
applyCommand(command, facts);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else if ((value.type === 'tool_result' && value.is_error === true) ||
|
|
58
|
-
(typeof value.type === 'string' && value.type.endsWith('_tool_result_error')))
|
|
59
|
-
facts.failedToolCalls++;
|
|
60
|
-
else if (value.type === 'advisor_tool_result' && typeof value.tool_use_id === 'string')
|
|
61
|
-
advisorIds.add(value.tool_use_id);
|
|
62
|
-
}
|
|
31
|
+
applyAssistantUsage(record, message, subagent, facts);
|
|
32
|
+
applyToolBlocks(message, subagent, facts, advisorIds);
|
|
63
33
|
}
|
|
64
34
|
}
|
|
65
35
|
facts.advisorCalls = advisorIds.size;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { customExecCommands } from './javascript-command.mjs';
|
|
2
|
+
import { asRecord } from './shared.mjs';
|
|
3
|
+
export function commands(payload) {
|
|
4
|
+
const raw = payload.type === 'function_call' ? payload.arguments : payload.input;
|
|
5
|
+
if (payload.type === 'local_shell_call') {
|
|
6
|
+
const input = asRecord(raw);
|
|
7
|
+
const value = asRecord(input?.action)?.command ?? input?.command;
|
|
8
|
+
if (typeof value === 'string')
|
|
9
|
+
return [value];
|
|
10
|
+
if (!Array.isArray(value))
|
|
11
|
+
return [];
|
|
12
|
+
return value.every((item) => typeof item === 'string') ? [value.join(' ')] : [];
|
|
13
|
+
}
|
|
14
|
+
const customExec = payload.type === 'custom_tool_call' && payload.name === 'exec';
|
|
15
|
+
if (!customExec && !['exec_command', 'bash', 'shell', 'Bash'].includes(String(payload.name)))
|
|
16
|
+
return [];
|
|
17
|
+
if (typeof raw !== 'string')
|
|
18
|
+
return [];
|
|
19
|
+
if (customExec)
|
|
20
|
+
return customExecCommands(raw);
|
|
21
|
+
try {
|
|
22
|
+
const value = asRecord(JSON.parse(raw));
|
|
23
|
+
const candidate = value?.cmd ?? value?.command;
|
|
24
|
+
return typeof candidate === 'string' ? [candidate] : [];
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function hasFailedOutcome(value) {
|
|
31
|
+
if (Array.isArray(value))
|
|
32
|
+
return value.some(hasFailedOutcome);
|
|
33
|
+
const payload = asRecord(value);
|
|
34
|
+
if (!payload)
|
|
35
|
+
return false;
|
|
36
|
+
if (payload.type === 'input_text' && typeof payload.text === 'string') {
|
|
37
|
+
try {
|
|
38
|
+
return hasFailedOutcome(JSON.parse(payload.text));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (payload.status === 'failed' || payload.status === 'error' || payload.is_error === true)
|
|
45
|
+
return true;
|
|
46
|
+
if ((typeof payload.exit_code === 'number' && payload.exit_code !== 0) ||
|
|
47
|
+
(typeof payload.exitCode === 'number' && payload.exitCode !== 0) ||
|
|
48
|
+
payload.success === false)
|
|
49
|
+
return true;
|
|
50
|
+
return [payload.output, payload.result, payload.metadata].some(hasFailedOutcome);
|
|
51
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { CodexMessageCounter } from './codex-messages.mjs';
|
|
2
|
+
import { commands, hasFailedOutcome } from './codex-payload.mjs';
|
|
3
|
+
import { applyCommand, asNumber, asRecord, emptyTokens, } from './shared.mjs';
|
|
4
|
+
function usage(record) {
|
|
5
|
+
const payload = asRecord(record.payload);
|
|
6
|
+
const totals = asRecord(asRecord(payload?.info)?.total_token_usage);
|
|
7
|
+
if (record.type !== 'event_msg' || payload?.type !== 'token_count' || !totals)
|
|
8
|
+
return undefined;
|
|
9
|
+
return {
|
|
10
|
+
input: asNumber(totals.input_tokens),
|
|
11
|
+
output: asNumber(totals.output_tokens),
|
|
12
|
+
cacheRead: asNumber(totals.cached_input_tokens),
|
|
13
|
+
cacheCreation: 0,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function isCall(payload) {
|
|
17
|
+
return (['function_call', 'custom_tool_call'].includes(String(payload.type)) ||
|
|
18
|
+
(typeof payload.type === 'string' && payload.type.endsWith('_call')));
|
|
19
|
+
}
|
|
20
|
+
function isCallOutcome(payload) {
|
|
21
|
+
return typeof payload.type === 'string' && payload.type.endsWith('_call_output');
|
|
22
|
+
}
|
|
23
|
+
function addDelta(current, previous, target) {
|
|
24
|
+
target.input += Math.max(0, current.input - previous.input);
|
|
25
|
+
target.output += Math.max(0, current.output - previous.output);
|
|
26
|
+
target.cacheRead += Math.max(0, current.cacheRead - previous.cacheRead);
|
|
27
|
+
return {
|
|
28
|
+
input: Math.max(current.input, previous.input),
|
|
29
|
+
output: Math.max(current.output, previous.output),
|
|
30
|
+
cacheRead: Math.max(current.cacheRead, previous.cacheRead),
|
|
31
|
+
cacheCreation: 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function applyRecords(records, facts, subagent, baseline = emptyTokens()) {
|
|
35
|
+
let previous = baseline;
|
|
36
|
+
const calls = new Set();
|
|
37
|
+
const failed = new Set();
|
|
38
|
+
const messages = new CodexMessageCounter();
|
|
39
|
+
let anonymousFailures = 0;
|
|
40
|
+
let previousCompaction;
|
|
41
|
+
for (const record of records) {
|
|
42
|
+
const payload = asRecord(record.payload);
|
|
43
|
+
if (!subagent)
|
|
44
|
+
messages.add(record, payload);
|
|
45
|
+
const compaction = record.type === 'compacted'
|
|
46
|
+
? 'top-level'
|
|
47
|
+
: record.type === 'event_msg' && payload?.type === 'context_compacted'
|
|
48
|
+
? 'context-event'
|
|
49
|
+
: undefined;
|
|
50
|
+
if (compaction && previousCompaction !== undefined && previousCompaction !== compaction)
|
|
51
|
+
previousCompaction = undefined;
|
|
52
|
+
else if (compaction) {
|
|
53
|
+
facts.compactions++;
|
|
54
|
+
previousCompaction = compaction;
|
|
55
|
+
}
|
|
56
|
+
else
|
|
57
|
+
previousCompaction = undefined;
|
|
58
|
+
const totals = usage(record);
|
|
59
|
+
if (totals) {
|
|
60
|
+
previous = addDelta(totals, previous, subagent ? facts.subagentTokens : facts.tokens);
|
|
61
|
+
}
|
|
62
|
+
if (record.type !== 'response_item' || !payload)
|
|
63
|
+
continue;
|
|
64
|
+
const id = typeof payload.call_id === 'string'
|
|
65
|
+
? payload.call_id
|
|
66
|
+
: typeof payload.id === 'string'
|
|
67
|
+
? payload.id
|
|
68
|
+
: undefined;
|
|
69
|
+
if (isCall(payload)) {
|
|
70
|
+
if (!id || !calls.has(id)) {
|
|
71
|
+
facts.toolCalls++;
|
|
72
|
+
if (subagent)
|
|
73
|
+
facts.subagentToolCalls++;
|
|
74
|
+
if (id)
|
|
75
|
+
calls.add(id);
|
|
76
|
+
if (payload.name === 'advisor')
|
|
77
|
+
facts.advisorCalls++;
|
|
78
|
+
for (const rawCommand of commands(payload))
|
|
79
|
+
applyCommand(rawCommand, facts);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if ((isCall(payload) || isCallOutcome(payload)) && hasFailedOutcome(payload)) {
|
|
83
|
+
if (id)
|
|
84
|
+
failed.add(id);
|
|
85
|
+
else
|
|
86
|
+
anonymousFailures++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!subagent) {
|
|
90
|
+
const [userPrompts, assistantResponses] = messages.totals();
|
|
91
|
+
facts.userPrompts += userPrompts;
|
|
92
|
+
facts.assistantResponses += assistantResponses;
|
|
93
|
+
}
|
|
94
|
+
facts.failedToolCalls += [...failed].filter((id) => calls.has(id)).length + anonymousFailures;
|
|
95
|
+
}
|
|
@@ -1,147 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { customExecCommands } from './javascript-command.mjs';
|
|
4
|
-
function usage(record) {
|
|
5
|
-
const payload = asRecord(record.payload);
|
|
6
|
-
const totals = asRecord(asRecord(payload?.info)?.total_token_usage);
|
|
7
|
-
if (record.type !== 'event_msg' || payload?.type !== 'token_count' || !totals)
|
|
8
|
-
return undefined;
|
|
9
|
-
return {
|
|
10
|
-
input: asNumber(totals.input_tokens),
|
|
11
|
-
output: asNumber(totals.output_tokens),
|
|
12
|
-
cacheRead: asNumber(totals.cached_input_tokens),
|
|
13
|
-
cacheCreation: 0,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function commands(payload) {
|
|
17
|
-
const raw = payload.type === 'function_call' ? payload.arguments : payload.input;
|
|
18
|
-
if (payload.type === 'local_shell_call') {
|
|
19
|
-
const input = asRecord(raw);
|
|
20
|
-
const value = asRecord(input?.action)?.command ?? input?.command;
|
|
21
|
-
if (typeof value === 'string')
|
|
22
|
-
return [value];
|
|
23
|
-
if (!Array.isArray(value))
|
|
24
|
-
return [];
|
|
25
|
-
return value.every((item) => typeof item === 'string') ? [value.join(' ')] : [];
|
|
26
|
-
}
|
|
27
|
-
const customExec = payload.type === 'custom_tool_call' && payload.name === 'exec';
|
|
28
|
-
if (!customExec && !['exec_command', 'bash', 'shell', 'Bash'].includes(String(payload.name)))
|
|
29
|
-
return [];
|
|
30
|
-
if (typeof raw !== 'string')
|
|
31
|
-
return [];
|
|
32
|
-
if (customExec)
|
|
33
|
-
return customExecCommands(raw);
|
|
34
|
-
try {
|
|
35
|
-
const value = asRecord(JSON.parse(raw));
|
|
36
|
-
const candidate = value?.cmd ?? value?.command;
|
|
37
|
-
return typeof candidate === 'string' ? [candidate] : [];
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return [];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function hasFailedOutcome(value) {
|
|
44
|
-
if (Array.isArray(value))
|
|
45
|
-
return value.some(hasFailedOutcome);
|
|
46
|
-
const payload = asRecord(value);
|
|
47
|
-
if (!payload)
|
|
48
|
-
return false;
|
|
49
|
-
if (payload.type === 'input_text' && typeof payload.text === 'string') {
|
|
50
|
-
try {
|
|
51
|
-
return hasFailedOutcome(JSON.parse(payload.text));
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (payload.status === 'failed' || payload.status === 'error' || payload.is_error === true)
|
|
58
|
-
return true;
|
|
59
|
-
if ((typeof payload.exit_code === 'number' && payload.exit_code !== 0) ||
|
|
60
|
-
(typeof payload.exitCode === 'number' && payload.exitCode !== 0) ||
|
|
61
|
-
payload.success === false)
|
|
62
|
-
return true;
|
|
63
|
-
return [payload.output, payload.result, payload.metadata].some(hasFailedOutcome);
|
|
64
|
-
}
|
|
65
|
-
function isCall(payload) {
|
|
66
|
-
return (['function_call', 'custom_tool_call'].includes(String(payload.type)) ||
|
|
67
|
-
(typeof payload.type === 'string' && payload.type.endsWith('_call')));
|
|
68
|
-
}
|
|
69
|
-
function isCallOutcome(payload) {
|
|
70
|
-
return typeof payload.type === 'string' && payload.type.endsWith('_call_output');
|
|
71
|
-
}
|
|
72
|
-
function addDelta(current, previous, target) {
|
|
73
|
-
target.input += Math.max(0, current.input - previous.input);
|
|
74
|
-
target.output += Math.max(0, current.output - previous.output);
|
|
75
|
-
target.cacheRead += Math.max(0, current.cacheRead - previous.cacheRead);
|
|
76
|
-
return {
|
|
77
|
-
input: Math.max(current.input, previous.input),
|
|
78
|
-
output: Math.max(current.output, previous.output),
|
|
79
|
-
cacheRead: Math.max(current.cacheRead, previous.cacheRead),
|
|
80
|
-
cacheCreation: 0,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function applyRecords(records, facts, subagent, baseline = emptyTokens()) {
|
|
84
|
-
let previous = baseline;
|
|
85
|
-
const calls = new Set();
|
|
86
|
-
const failed = new Set();
|
|
87
|
-
const messages = new CodexMessageCounter();
|
|
88
|
-
let anonymousFailures = 0;
|
|
89
|
-
let previousCompaction;
|
|
90
|
-
for (const record of records) {
|
|
91
|
-
const payload = asRecord(record.payload);
|
|
92
|
-
if (!subagent)
|
|
93
|
-
messages.add(record, payload);
|
|
94
|
-
const compaction = record.type === 'compacted'
|
|
95
|
-
? 'top-level'
|
|
96
|
-
: record.type === 'event_msg' && payload?.type === 'context_compacted'
|
|
97
|
-
? 'context-event'
|
|
98
|
-
: undefined;
|
|
99
|
-
if (compaction && previousCompaction !== undefined && previousCompaction !== compaction)
|
|
100
|
-
previousCompaction = undefined;
|
|
101
|
-
else if (compaction) {
|
|
102
|
-
facts.compactions++;
|
|
103
|
-
previousCompaction = compaction;
|
|
104
|
-
}
|
|
105
|
-
else
|
|
106
|
-
previousCompaction = undefined;
|
|
107
|
-
const totals = usage(record);
|
|
108
|
-
if (totals) {
|
|
109
|
-
previous = addDelta(totals, previous, subagent ? facts.subagentTokens : facts.tokens);
|
|
110
|
-
}
|
|
111
|
-
if (record.type !== 'response_item' || !payload)
|
|
112
|
-
continue;
|
|
113
|
-
const id = typeof payload.call_id === 'string'
|
|
114
|
-
? payload.call_id
|
|
115
|
-
: typeof payload.id === 'string'
|
|
116
|
-
? payload.id
|
|
117
|
-
: undefined;
|
|
118
|
-
if (isCall(payload)) {
|
|
119
|
-
if (!id || !calls.has(id)) {
|
|
120
|
-
facts.toolCalls++;
|
|
121
|
-
if (subagent)
|
|
122
|
-
facts.subagentToolCalls++;
|
|
123
|
-
if (id)
|
|
124
|
-
calls.add(id);
|
|
125
|
-
if (payload.name === 'advisor')
|
|
126
|
-
facts.advisorCalls++;
|
|
127
|
-
for (const rawCommand of commands(payload))
|
|
128
|
-
applyCommand(rawCommand, facts);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if ((isCall(payload) || isCallOutcome(payload)) && hasFailedOutcome(payload)) {
|
|
132
|
-
if (id)
|
|
133
|
-
failed.add(id);
|
|
134
|
-
else
|
|
135
|
-
anonymousFailures++;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (!subagent) {
|
|
139
|
-
const [userPrompts, assistantResponses] = messages.totals();
|
|
140
|
-
facts.userPrompts += userPrompts;
|
|
141
|
-
facts.assistantResponses += assistantResponses;
|
|
142
|
-
}
|
|
143
|
-
facts.failedToolCalls += [...failed].filter((id) => calls.has(id)).length + anonymousFailures;
|
|
144
|
-
}
|
|
1
|
+
import { asRecord, emptyFacts, parseLines, } from './shared.mjs';
|
|
2
|
+
import { applyRecords } from './codex-records.mjs';
|
|
145
3
|
export function codexChildren(lines, ownerPath = '/root') {
|
|
146
4
|
const direct = new Map();
|
|
147
5
|
const base = ownerPath.replace(/\/$/, '');
|
|
@@ -1,22 +1,9 @@
|
|
|
1
|
+
import { type ResolveOptions } from './resolve-transcript-file.mts';
|
|
1
2
|
import { type CodexSegment, type TranscriptFacts } from './shared.mts';
|
|
2
3
|
export type { TokenTotals, TranscriptFacts } from './shared.mts';
|
|
3
4
|
export { codexChildren, codexIdentity } from './codex.mts';
|
|
4
5
|
export { formatTranscriptFacts, formatUnavailable } from './format.mts';
|
|
5
|
-
export type ResolveOptions
|
|
6
|
-
|
|
7
|
-
jsonlPath?: string;
|
|
8
|
-
projectsDir?: string;
|
|
9
|
-
codexSessionsDir?: string;
|
|
10
|
-
grokSessionsDir?: string;
|
|
11
|
-
cwd?: string;
|
|
12
|
-
env?: NodeJS.ProcessEnv;
|
|
13
|
-
};
|
|
14
|
-
type TranscriptResolution = {
|
|
15
|
-
path: string;
|
|
16
|
-
sessionId: string;
|
|
17
|
-
} | {
|
|
18
|
-
error: string;
|
|
19
|
-
};
|
|
20
|
-
export declare function resolveTranscriptFile(options: ResolveOptions): TranscriptResolution;
|
|
6
|
+
export type { ResolveOptions } from './resolve-transcript-file.mts';
|
|
7
|
+
export { resolveTranscriptFile } from './resolve-transcript-file.mts';
|
|
21
8
|
export declare function computeTranscriptFacts(lines: string[], subagents?: Array<string[] | CodexSegment>): TranscriptFacts;
|
|
22
9
|
export declare function runRetrospectiveTranscript(options: ResolveOptions): Promise<string>;
|
|
@@ -1,61 +1,17 @@
|
|
|
1
|
-
import { existsSync
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { basename, dirname, join } from 'node:path';
|
|
5
|
-
import { inspectHarnessEnvironment, selectHarnessSession, } from '../agent-harness-identity/index.mjs';
|
|
6
5
|
import { codexChildren, codexIdentity, computeCodex } from './codex.mjs';
|
|
7
6
|
import { segmentCodex } from './codex-segment.mjs';
|
|
8
7
|
import { computeClaude } from './claude.mjs';
|
|
9
|
-
import { formatTranscriptFacts, formatUnavailable
|
|
8
|
+
import { formatTranscriptFacts, formatUnavailable } from './format.mjs';
|
|
9
|
+
import { globFrom, resolveTranscriptFile, SESSION_ID, } from './resolve-transcript-file.mjs';
|
|
10
10
|
import { emptyFacts, hasMalformedInteriorRecord, parseLines, } from './shared.mjs';
|
|
11
11
|
export { codexChildren, codexIdentity } from './codex.mjs';
|
|
12
12
|
export { formatTranscriptFacts, formatUnavailable } from './format.mjs';
|
|
13
|
-
|
|
13
|
+
export { resolveTranscriptFile } from './resolve-transcript-file.mjs';
|
|
14
14
|
const MALFORMED_INTERIOR = 'malformed interior transcript record';
|
|
15
|
-
function globFrom(root, pattern) {
|
|
16
|
-
return globSync(pattern, { cwd: root }).map((path) => join(root, path));
|
|
17
|
-
}
|
|
18
|
-
export function resolveTranscriptFile(options) {
|
|
19
|
-
if (options.sessionId && !SESSION_ID.test(options.sessionId))
|
|
20
|
-
return { error: 'invalid session id format' };
|
|
21
|
-
if (options.jsonlPath) {
|
|
22
|
-
const filename = basename(options.jsonlPath, '.jsonl');
|
|
23
|
-
const fileSessionId = filename.slice(-36);
|
|
24
|
-
return {
|
|
25
|
-
path: options.jsonlPath,
|
|
26
|
-
sessionId: options.sessionId?.toLowerCase() ??
|
|
27
|
-
(SESSION_ID.test(fileSessionId) ? fileSessionId.toLowerCase() : sessionLabel(filename)),
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
const env = options.env ?? process.env;
|
|
31
|
-
const sessionId = options.sessionId ??
|
|
32
|
-
selectHarnessSession(inspectHarnessEnvironment(env), ['codex', 'claude', 'cursor', 'grok'])
|
|
33
|
-
?.sessionId;
|
|
34
|
-
if (!sessionId)
|
|
35
|
-
return {
|
|
36
|
-
error: 'no session id (pass --session-id or set CODEX_THREAD_ID, CLAUDE_CODE_SESSION_ID, CURSOR_SESSION_ID, or GROK_SESSION_ID)',
|
|
37
|
-
};
|
|
38
|
-
if (!SESSION_ID.test(sessionId))
|
|
39
|
-
return { error: 'invalid session id format' };
|
|
40
|
-
const normalizedSessionId = sessionId.toLowerCase();
|
|
41
|
-
const codex = options.codexSessionsDir ?? join(env.CODEX_HOME || join(homedir(), '.codex'), 'sessions');
|
|
42
|
-
const claude = options.projectsDir ?? join(env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude'), 'projects');
|
|
43
|
-
const grokHome = env.GROK_HOME || join(homedir(), '.grok');
|
|
44
|
-
const grok = options.grokSessionsDir ?? join(grokHome, 'sessions');
|
|
45
|
-
const encodedCwd = encodeURIComponent(options.cwd ?? process.cwd());
|
|
46
|
-
const grokExact = join(grok, encodedCwd, normalizedSessionId, 'updates.jsonl');
|
|
47
|
-
const grokPaths = existsSync(grokExact)
|
|
48
|
-
? [grokExact]
|
|
49
|
-
: globFrom(grok, `*/${normalizedSessionId}/updates.jsonl`);
|
|
50
|
-
const codexPaths = globFrom(codex, `**/rollout-*-${normalizedSessionId}.jsonl`);
|
|
51
|
-
const claudePaths = globFrom(claude, `*/${normalizedSessionId}.jsonl`);
|
|
52
|
-
const paths = [...grokPaths, ...codexPaths, ...claudePaths].sort();
|
|
53
|
-
if (paths.length > 1)
|
|
54
|
-
return { error: `multiple transcripts found for session ${normalizedSessionId}` };
|
|
55
|
-
return paths[0]
|
|
56
|
-
? { path: paths[0], sessionId: normalizedSessionId }
|
|
57
|
-
: { error: `no transcript found for session ${normalizedSessionId}` };
|
|
58
|
-
}
|
|
59
15
|
function schema(lines) {
|
|
60
16
|
const records = parseLines(lines);
|
|
61
17
|
const kinds = new Set(records
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ResolveOptions = {
|
|
2
|
+
sessionId?: string;
|
|
3
|
+
jsonlPath?: string;
|
|
4
|
+
projectsDir?: string;
|
|
5
|
+
codexSessionsDir?: string;
|
|
6
|
+
grokSessionsDir?: string;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
};
|
|
10
|
+
export declare const SESSION_ID: RegExp;
|
|
11
|
+
type TranscriptResolution = {
|
|
12
|
+
path: string;
|
|
13
|
+
sessionId: string;
|
|
14
|
+
} | {
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function globFrom(root: string, pattern: string): string[];
|
|
18
|
+
export declare function resolveTranscriptFile(options: ResolveOptions): TranscriptResolution;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, globSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
|
+
import { inspectHarnessEnvironment, selectHarnessSession, } from '../agent-harness-identity/index.mjs';
|
|
5
|
+
import { sessionLabel } from './format.mjs';
|
|
6
|
+
export const SESSION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7
|
+
export function globFrom(root, pattern) {
|
|
8
|
+
return globSync(pattern, { cwd: root }).map((path) => join(root, path));
|
|
9
|
+
}
|
|
10
|
+
export function resolveTranscriptFile(options) {
|
|
11
|
+
if (options.sessionId && !SESSION_ID.test(options.sessionId))
|
|
12
|
+
return { error: 'invalid session id format' };
|
|
13
|
+
if (options.jsonlPath) {
|
|
14
|
+
const filename = basename(options.jsonlPath, '.jsonl');
|
|
15
|
+
const fileSessionId = filename.slice(-36);
|
|
16
|
+
return {
|
|
17
|
+
path: options.jsonlPath,
|
|
18
|
+
sessionId: options.sessionId?.toLowerCase() ??
|
|
19
|
+
(SESSION_ID.test(fileSessionId) ? fileSessionId.toLowerCase() : sessionLabel(filename)),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const env = options.env ?? process.env;
|
|
23
|
+
const sessionId = options.sessionId ??
|
|
24
|
+
selectHarnessSession(inspectHarnessEnvironment(env), ['codex', 'claude', 'cursor', 'grok'])
|
|
25
|
+
?.sessionId;
|
|
26
|
+
if (!sessionId)
|
|
27
|
+
return {
|
|
28
|
+
error: 'no session id (pass --session-id or set CODEX_THREAD_ID, CLAUDE_CODE_SESSION_ID, CURSOR_SESSION_ID, or GROK_SESSION_ID)',
|
|
29
|
+
};
|
|
30
|
+
if (!SESSION_ID.test(sessionId))
|
|
31
|
+
return { error: 'invalid session id format' };
|
|
32
|
+
const normalizedSessionId = sessionId.toLowerCase();
|
|
33
|
+
const codex = options.codexSessionsDir ?? join(env.CODEX_HOME || join(homedir(), '.codex'), 'sessions');
|
|
34
|
+
const claude = options.projectsDir ?? join(env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude'), 'projects');
|
|
35
|
+
const grokHome = env.GROK_HOME || join(homedir(), '.grok');
|
|
36
|
+
const grok = options.grokSessionsDir ?? join(grokHome, 'sessions');
|
|
37
|
+
const encodedCwd = encodeURIComponent(options.cwd ?? process.cwd());
|
|
38
|
+
const grokExact = join(grok, encodedCwd, normalizedSessionId, 'updates.jsonl');
|
|
39
|
+
const grokPaths = existsSync(grokExact)
|
|
40
|
+
? [grokExact]
|
|
41
|
+
: globFrom(grok, `*/${normalizedSessionId}/updates.jsonl`);
|
|
42
|
+
const codexPaths = globFrom(codex, `**/rollout-*-${normalizedSessionId}.jsonl`);
|
|
43
|
+
const claudePaths = globFrom(claude, `*/${normalizedSessionId}.jsonl`);
|
|
44
|
+
const paths = [...grokPaths, ...codexPaths, ...claudePaths].sort();
|
|
45
|
+
if (paths.length > 1)
|
|
46
|
+
return { error: `multiple transcripts found for session ${normalizedSessionId}` };
|
|
47
|
+
return paths[0]
|
|
48
|
+
? { path: paths[0], sessionId: normalizedSessionId }
|
|
49
|
+
: { error: `no transcript found for session ${normalizedSessionId}` };
|
|
50
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export const REDACTED_TOKEN = '[REDACTED]';
|
|
2
|
+
const ENV_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
3
|
+
const ENV_OPTIONS_WITH_ARGS = new Set(['-C', '--chdir', '-S', '--split-string', '-u', '--unset']);
|
|
4
|
+
const ENV_OPTIONS_WITHOUT_ARGS = new Set([
|
|
5
|
+
'-i',
|
|
6
|
+
'--ignore-environment',
|
|
7
|
+
'-0',
|
|
8
|
+
'--null',
|
|
9
|
+
'-v',
|
|
10
|
+
'--debug',
|
|
11
|
+
]);
|
|
12
|
+
export function splitCommand(command) {
|
|
13
|
+
const result = [];
|
|
14
|
+
let segment = [];
|
|
15
|
+
let word = '';
|
|
16
|
+
let quote;
|
|
17
|
+
let escaped = false;
|
|
18
|
+
const flushWord = () => {
|
|
19
|
+
if (word)
|
|
20
|
+
segment.push(word);
|
|
21
|
+
word = '';
|
|
22
|
+
};
|
|
23
|
+
const flushSegment = () => {
|
|
24
|
+
flushWord();
|
|
25
|
+
if (segment.length)
|
|
26
|
+
result.push(segment);
|
|
27
|
+
segment = [];
|
|
28
|
+
};
|
|
29
|
+
for (const char of command) {
|
|
30
|
+
if (escaped) {
|
|
31
|
+
word += char;
|
|
32
|
+
escaped = false;
|
|
33
|
+
}
|
|
34
|
+
else if (char === '\\' && quote !== "'") {
|
|
35
|
+
escaped = true;
|
|
36
|
+
}
|
|
37
|
+
else if (quote) {
|
|
38
|
+
if (char === quote)
|
|
39
|
+
quote = undefined;
|
|
40
|
+
else
|
|
41
|
+
word += char;
|
|
42
|
+
}
|
|
43
|
+
else if (char === '"' || char === "'")
|
|
44
|
+
quote = char;
|
|
45
|
+
else if (';&|<>\n\r'.includes(char))
|
|
46
|
+
flushSegment();
|
|
47
|
+
else if (/\s/.test(char))
|
|
48
|
+
flushWord();
|
|
49
|
+
else
|
|
50
|
+
word += char;
|
|
51
|
+
}
|
|
52
|
+
if (escaped)
|
|
53
|
+
word += '\\';
|
|
54
|
+
flushSegment();
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
export function stripAssignments(tokens) {
|
|
58
|
+
let index = 0;
|
|
59
|
+
while (index < tokens.length && ENV_ASSIGNMENT.test(tokens[index]))
|
|
60
|
+
index++;
|
|
61
|
+
const wrapper = tokens[index];
|
|
62
|
+
// Assignments without an executable are represented by a safe sentinel.
|
|
63
|
+
if (wrapper !== 'env' && !wrapper?.endsWith('/env'))
|
|
64
|
+
return index < tokens.length ? tokens.slice(index) : index ? [REDACTED_TOKEN] : tokens;
|
|
65
|
+
index++;
|
|
66
|
+
while (index < tokens.length) {
|
|
67
|
+
const option = tokens[index];
|
|
68
|
+
if (option === '--') {
|
|
69
|
+
index++;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
const optionName = option.split('=', 1)[0];
|
|
73
|
+
const splitStringOption = optionName === '-S' || (optionName.length >= 5 && '--split-string'.startsWith(optionName));
|
|
74
|
+
if (splitStringOption)
|
|
75
|
+
return [REDACTED_TOKEN];
|
|
76
|
+
const abbreviatedArgument = optionName.length >= 5 && '--chdir'.startsWith(optionName);
|
|
77
|
+
if (ENV_OPTIONS_WITH_ARGS.has(optionName) || abbreviatedArgument) {
|
|
78
|
+
index += option.includes('=') ? 1 : 2;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (ENV_OPTIONS_WITHOUT_ARGS.has(option)) {
|
|
82
|
+
index++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (option.startsWith('-'))
|
|
86
|
+
return [REDACTED_TOKEN];
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
while (index < tokens.length && ENV_ASSIGNMENT.test(tokens[index]))
|
|
90
|
+
index++;
|
|
91
|
+
if (index < tokens.length)
|
|
92
|
+
return tokens.slice(index);
|
|
93
|
+
return tokens.some((token) => ENV_ASSIGNMENT.test(token)) ? [REDACTED_TOKEN] : [];
|
|
94
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FrictionEvent } from './types.mts';
|
|
2
|
+
export declare const LOG_MAX_BYTES = 2000000;
|
|
3
|
+
export declare function validEvent(value: unknown): value is FrictionEvent;
|
|
4
|
+
export declare function openLogFile(path: string, flags: number): number;
|
|
5
|
+
export declare function readLogContent(descriptor: number): string;
|
|
6
|
+
export declare function atEventLimit(content: string, limit: number): boolean;
|
|
7
|
+
export declare function writeAll(descriptor: number, value: string): void;
|