@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.9
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/CHANGELOG.md +25 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +4 -4
- package/dist/builtin/intercom/broker/broker.ts +617 -22
- package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
- package/dist/builtin/intercom/broker/client.ts +200 -10
- package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
- package/dist/builtin/intercom/broker/send-handler.ts +90 -36
- package/dist/builtin/intercom/broker/send-signature.ts +20 -8
- package/dist/builtin/intercom/group.ts +85 -0
- package/dist/builtin/intercom/index.bundle.mjs +746 -55
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/session-target.ts +54 -0
- package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
- package/dist/builtin/intercom/source-ownership.ts +31 -0
- package/dist/builtin/intercom/types.ts +115 -0
- package/dist/builtin/mcp/index.bundle.mjs +175 -37
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +239 -53
- package/dist/builtin/web-access/index.bundle.mjs +175 -37
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +15 -0
- package/dist/builtin/workflows/README.md +40 -37
- package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
- package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
- package/dist/builtin/workflows/builtin/chunk-17zk6ffd.js +69794 -0
- package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
- package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
- package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
- package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
- package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
- package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
- package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
- package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
- package/dist/builtin/workflows/builtin/chunk-8v8wmb7z.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-h5e65g7g.js +1080 -0
- package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
- package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
- package/dist/builtin/workflows/builtin/chunk-qe6bfpbd.js +1207 -0
- package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-rbnj9621.js +2447 -0
- package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
- package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
- package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
- package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
- package/dist/builtin/workflows/builtin/goal.js +16 -0
- package/dist/builtin/workflows/builtin/index.js +49 -0
- package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
- package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
- package/dist/builtin/workflows/builtin/ralph.js +16 -0
- package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
- package/dist/builtin/workflows/builtin/steering-context.js +7 -0
- package/dist/builtin/workflows/builtin/tournament.js +13 -0
- package/dist/builtin/workflows/package.json +10 -7
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1294 -430
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +1022 -429
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
- package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +12 -5
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +2 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtin-install-layout.d.ts +1 -1
- package/dist/core/builtin-install-layout.d.ts.map +1 -1
- package/dist/core/builtin-install-layout.js +1 -1
- package/dist/core/builtin-install-layout.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +10 -7
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.js +31 -13
- package/dist/core/codex-fast-mode.js.map +1 -1
- package/dist/core/extensions/agent-events.d.ts +15 -0
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/api-types.d.ts +3 -1
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +35 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/event-types.d.ts +2 -2
- package/dist/core/extensions/event-types.d.ts.map +1 -1
- package/dist/core/extensions/event-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +6 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +6 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +65 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +1 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +8 -0
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +2 -0
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +4 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +6 -1
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +8 -9
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +1 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +33 -5
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +8 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/extensions.md +19 -0
- package/docs/intercom.md +15 -6
- package/docs/packages.md +2 -2
- package/docs/providers.md +8 -3
- package/docs/quickstart.md +2 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +108 -239
- package/npm-shrinkwrap.json +32 -32
- package/package.json +9 -13
- package/dist/builtin/workflows/ambient.d.ts +0 -61
- package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
- package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
- package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
- package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
- package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
- package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
- package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
- package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
- package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
- package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
- package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
- package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
- package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
- package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
- package/dist/builtin/workflows/builtin/goal.ts +0 -78
- package/dist/builtin/workflows/builtin/index.ts +0 -16
- package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
- package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
- package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
- package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
- package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
- package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
- package/dist/builtin/workflows/builtin/ralph.ts +0 -82
- package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
- package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
- package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
- package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
- package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
- package/dist/builtin/workflows/builtin/tournament.ts +0 -73
- package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
- package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
- package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fold_usage
|
|
3
|
+
} from "./chunk-7at6dnkr.js";
|
|
4
|
+
import {
|
|
5
|
+
build_scoring_prompt,
|
|
6
|
+
scoring_prompt_reads,
|
|
7
|
+
warm_first_fan_out
|
|
8
|
+
} from "./chunk-7430zyas.js";
|
|
9
|
+
import {
|
|
10
|
+
stableArtifactRoot
|
|
11
|
+
} from "./chunk-wpckd35c.js";
|
|
12
|
+
import {
|
|
13
|
+
VERIFICATION_SCALE,
|
|
14
|
+
decide_verification,
|
|
15
|
+
normalize_criteria,
|
|
16
|
+
parse_rubric
|
|
17
|
+
} from "./chunk-cg9tmks0.js";
|
|
18
|
+
import {
|
|
19
|
+
workflow
|
|
20
|
+
} from "./chunk-bfkmzv9h.js";
|
|
21
|
+
import {
|
|
22
|
+
withSteeringPropagationContext
|
|
23
|
+
} from "./chunk-0x6e303p.js";
|
|
24
|
+
|
|
25
|
+
// dist/builtin/workflows/builtin/adversarial-verification.ts
|
|
26
|
+
import { Type as Type2 } from "typebox";
|
|
27
|
+
|
|
28
|
+
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
29
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
30
|
+
import { join } from "node:path";
|
|
31
|
+
import { Type } from "typebox";
|
|
32
|
+
|
|
33
|
+
// dist/builtin/workflows/builtin/adversarial-verification-prompts.ts
|
|
34
|
+
var GROUNDED_REPORTING = "Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.";
|
|
35
|
+
var READABLE_REPORT = "Lead with the outcome. Keep facts, decisions, caveats, and next steps; drop background and repetition. Use complete, readable sentences rather than compressed fragments.";
|
|
36
|
+
function renderWorkerPrompt(task) {
|
|
37
|
+
return `<role>
|
|
38
|
+
You produce a candidate solution for independent verification.
|
|
39
|
+
</role>
|
|
40
|
+
|
|
41
|
+
<success_criteria>
|
|
42
|
+
The task is complete and important claims have observable support. Preserve concrete evidence and state every validation performed.
|
|
43
|
+
</success_criteria>
|
|
44
|
+
|
|
45
|
+
<stop_rules>
|
|
46
|
+
Stop when the candidate is complete and validated where practical, or state the evidence still missing.
|
|
47
|
+
</stop_rules>
|
|
48
|
+
|
|
49
|
+
<output_format>
|
|
50
|
+
A self-contained candidate with actions taken, evidence, validation, and remaining risks. ${READABLE_REPORT}
|
|
51
|
+
${GROUNDED_REPORTING}
|
|
52
|
+
</output_format>
|
|
53
|
+
|
|
54
|
+
<objective>
|
|
55
|
+
${task}
|
|
56
|
+
</objective>`;
|
|
57
|
+
}
|
|
58
|
+
function renderConsolidatorPrompt(task, candidatePath, scorePaths, repairsCompleted, maxRepairs) {
|
|
59
|
+
return `<artifacts>
|
|
60
|
+
Candidate: ${candidatePath}
|
|
61
|
+
Confirmed criterion score reports: ${scorePaths.join(", ")}
|
|
62
|
+
</artifacts>
|
|
63
|
+
|
|
64
|
+
<role>
|
|
65
|
+
You consolidate confirmed verifier findings into actionable repair guidance. You do not decide whether verification is approved; the deterministic verification gate already made that decision.
|
|
66
|
+
</role>
|
|
67
|
+
|
|
68
|
+
<decision_rules>
|
|
69
|
+
Preserve every confirmed veto or blocking finding in remaining_work verbatim. Explain concrete repairs and validation steps. Repair budget: ${repairsCompleted}/${maxRepairs}.
|
|
70
|
+
</decision_rules>
|
|
71
|
+
|
|
72
|
+
<output_format>
|
|
73
|
+
Call structured_output with repair_guidance (a concise actionable repair plan) and remaining_work (the unresolved findings as strings). Never emit an approval or rejection decision. ${READABLE_REPORT}
|
|
74
|
+
${GROUNDED_REPORTING}
|
|
75
|
+
</output_format>
|
|
76
|
+
|
|
77
|
+
<objective>
|
|
78
|
+
Consolidate findings for the candidate produced for: ${task}
|
|
79
|
+
</objective>`;
|
|
80
|
+
}
|
|
81
|
+
function renderRepairPrompt(task, candidatePath, reviewPath) {
|
|
82
|
+
return `<artifacts>
|
|
83
|
+
Read the current candidate at ${candidatePath} and consolidated findings at ${reviewPath}.
|
|
84
|
+
</artifacts>
|
|
85
|
+
|
|
86
|
+
<role>
|
|
87
|
+
You repair a candidate using independent blocking findings.
|
|
88
|
+
</role>
|
|
89
|
+
|
|
90
|
+
<success_criteria>
|
|
91
|
+
Every actionable blocker is addressed, relevant validation is rerun, and valid prior work is retained.
|
|
92
|
+
</success_criteria>
|
|
93
|
+
|
|
94
|
+
<evidence_rules>
|
|
95
|
+
Do not dismiss a finding without contrary evidence. Report commands run, observed output, and file:line evidence where applicable. ${GROUNDED_REPORTING}
|
|
96
|
+
</evidence_rules>
|
|
97
|
+
|
|
98
|
+
<stop_rules>
|
|
99
|
+
Stop when all actionable blockers are repaired and validated, or list any blocker that remains with the missing evidence.
|
|
100
|
+
</stop_rules>
|
|
101
|
+
|
|
102
|
+
<output_format>
|
|
103
|
+
A complete replacement candidate with repair summary, evidence, validation, and remaining risks. ${READABLE_REPORT}
|
|
104
|
+
</output_format>
|
|
105
|
+
|
|
106
|
+
<objective>
|
|
107
|
+
Repair the candidate for: ${task}
|
|
108
|
+
</objective>`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
112
|
+
var DEFAULT_CRITERIA = {
|
|
113
|
+
task_fit: "The candidate satisfies the literal task.",
|
|
114
|
+
evidence: "Important claims cite observable evidence, and file findings cite file:line where applicable.",
|
|
115
|
+
completeness: "Relevant validation is executed and reported with commands run and observed output, and no blocking correctness, safety, or completeness gap remains."
|
|
116
|
+
};
|
|
117
|
+
var QUORUM_FRACTION = 1;
|
|
118
|
+
var criterionScoreSchema = Type.Object({
|
|
119
|
+
criterion_id: Type.String(),
|
|
120
|
+
score: VERIFICATION_SCALE.schema,
|
|
121
|
+
evidence: Type.Array(Type.String()),
|
|
122
|
+
findings: Type.Array(Type.Object({
|
|
123
|
+
finding: Type.String(),
|
|
124
|
+
severity: Type.Union([Type.Literal("veto"), Type.Literal("blocking"), Type.Literal("note")])
|
|
125
|
+
}, { additionalProperties: false }))
|
|
126
|
+
}, { additionalProperties: false });
|
|
127
|
+
var consolidatorSchema = Type.Object({
|
|
128
|
+
repair_guidance: Type.String(),
|
|
129
|
+
remaining_work: Type.Array(Type.String())
|
|
130
|
+
}, { additionalProperties: false });
|
|
131
|
+
function isRecord(value) {
|
|
132
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
133
|
+
}
|
|
134
|
+
function hasOnlyKeys(value, keys) {
|
|
135
|
+
const actual = Object.keys(value);
|
|
136
|
+
return actual.length === keys.length && keys.every((key) => (key in value));
|
|
137
|
+
}
|
|
138
|
+
function isStringArray(value) {
|
|
139
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
140
|
+
}
|
|
141
|
+
function isStringRecord(value) {
|
|
142
|
+
return isRecord(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
143
|
+
}
|
|
144
|
+
function isCriterionFinding(value) {
|
|
145
|
+
return isRecord(value) && hasOnlyKeys(value, ["finding", "severity"]) && typeof value.finding === "string" && (value.severity === "veto" || value.severity === "blocking" || value.severity === "note");
|
|
146
|
+
}
|
|
147
|
+
function isCriterionScore(value, criterionId) {
|
|
148
|
+
return value !== undefined && isRecord(value) && hasOnlyKeys(value, ["criterion_id", "score", "evidence", "findings"]) && value.criterion_id === criterionId && typeof value.score === "number" && Number.isInteger(value.score) && value.score >= VERIFICATION_SCALE.min && value.score <= VERIFICATION_SCALE.max && isStringArray(value.evidence) && Array.isArray(value.findings) && value.findings.every(isCriterionFinding);
|
|
149
|
+
}
|
|
150
|
+
function isConsolidatedReport(value) {
|
|
151
|
+
return value !== undefined && isRecord(value) && hasOnlyKeys(value, ["repair_guidance", "remaining_work"]) && typeof value.repair_guidance === "string" && isStringArray(value.remaining_work);
|
|
152
|
+
}
|
|
153
|
+
function structured(value, guard) {
|
|
154
|
+
return guard(value) ? value : undefined;
|
|
155
|
+
}
|
|
156
|
+
function resolveCriteria(value) {
|
|
157
|
+
if (value === undefined) {
|
|
158
|
+
return { groundTruthNote: "", criteria: normalize_criteria(DEFAULT_CRITERIA) };
|
|
159
|
+
}
|
|
160
|
+
if (typeof value === "string")
|
|
161
|
+
return parse_rubric(value);
|
|
162
|
+
if (isStringRecord(value))
|
|
163
|
+
return { groundTruthNote: "", criteria: normalize_criteria(value) };
|
|
164
|
+
throw new TypeError("criteria must be a criteria.md string or a record of criterion descriptions");
|
|
165
|
+
}
|
|
166
|
+
function renderCriteriaMarkdown(criteria) {
|
|
167
|
+
const lines = ["# Verification criteria"];
|
|
168
|
+
if (criteria.groundTruthNote.length > 0)
|
|
169
|
+
lines.push("## Ground Truth Note", criteria.groundTruthNote);
|
|
170
|
+
lines.push("## Criteria");
|
|
171
|
+
for (const item of criteria.criteria) {
|
|
172
|
+
lines.push(`### ${item.name} {#${item.id}}`, item.description);
|
|
173
|
+
}
|
|
174
|
+
return `${lines.join(`
|
|
175
|
+
|
|
176
|
+
`)}
|
|
177
|
+
`;
|
|
178
|
+
}
|
|
179
|
+
function meanScore(scores) {
|
|
180
|
+
if (scores.length === 0)
|
|
181
|
+
return 0;
|
|
182
|
+
return scores.reduce((total, score) => total + score.score, 0) / scores.length;
|
|
183
|
+
}
|
|
184
|
+
function toCriterionScore(report) {
|
|
185
|
+
return {
|
|
186
|
+
criterionId: report.criterion_id,
|
|
187
|
+
score: report.score,
|
|
188
|
+
evidence: report.evidence,
|
|
189
|
+
findings: report.findings
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function findingText(decision) {
|
|
193
|
+
return decision.findings.map((finding) => finding.finding);
|
|
194
|
+
}
|
|
195
|
+
function quorumEvidence(missing, invalidCount, expectedCount, reaskLimit) {
|
|
196
|
+
return `Quorum failure: ${missing} of ${expectedCount} criterion scores remain missing after ${reaskLimit} re-ask wave(s); ${invalidCount} report attempts were invalid or missing.`;
|
|
197
|
+
}
|
|
198
|
+
function stageName(cell, reaskWave) {
|
|
199
|
+
return reaskWave === 0 ? cell.name : `${cell.name}-reask-${reaskWave}`;
|
|
200
|
+
}
|
|
201
|
+
function verifierOutputFormat(criterionId) {
|
|
202
|
+
return `Call structured_output with criterion_id (set to ${criterionId}), score (1–20), evidence (string array), and findings containing finding and severity (veto, blocking, or note).`;
|
|
203
|
+
}
|
|
204
|
+
function scoreStep(cell, reaskWave, head, criteriaPath) {
|
|
205
|
+
const promptHead = {
|
|
206
|
+
...head,
|
|
207
|
+
outputFormat: verifierOutputFormat(cell.criterion.id)
|
|
208
|
+
};
|
|
209
|
+
return {
|
|
210
|
+
name: stageName(cell, reaskWave),
|
|
211
|
+
prompt: build_scoring_prompt(promptHead, cell.criterion),
|
|
212
|
+
context: "fresh",
|
|
213
|
+
reads: [criteriaPath, ...scoring_prompt_reads(promptHead)],
|
|
214
|
+
schema: criterionScoreSchema
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
async function writeInvalid(path, stage) {
|
|
218
|
+
const marker = { invalid: true, stage };
|
|
219
|
+
await writeFile(path, `${JSON.stringify(marker, null, 2)}
|
|
220
|
+
`);
|
|
221
|
+
}
|
|
222
|
+
async function runAdversarialVerification(ctx) {
|
|
223
|
+
const root = await stableArtifactRoot(ctx, "adversarial-verification");
|
|
224
|
+
const criteriaPath = join(root, "criteria.md");
|
|
225
|
+
const candidatePath = join(root, "candidate.md");
|
|
226
|
+
const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
|
|
227
|
+
await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
|
|
228
|
+
await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
|
|
229
|
+
const verifierCount = ctx.inputs.verifier_count ?? 3;
|
|
230
|
+
const maxRepairs = ctx.inputs.max_repairs ?? 2;
|
|
231
|
+
const acceptMean = ctx.inputs.accept_mean ?? 14;
|
|
232
|
+
const reaskLimit = Math.max(0, Math.floor(ctx.inputs.reask_limit ?? 1));
|
|
233
|
+
const expectedCount = resolvedCriteria.criteria.length * verifierCount;
|
|
234
|
+
let repairsCompleted = 0;
|
|
235
|
+
let consecutiveIndeterminate = 0;
|
|
236
|
+
let finalDecision;
|
|
237
|
+
let finalMean = 0;
|
|
238
|
+
let scoreTablePath;
|
|
239
|
+
let reviewReportPath;
|
|
240
|
+
let remainingWork = [];
|
|
241
|
+
for (let round = 0;; round += 1) {
|
|
242
|
+
const candidateBody = await readFile(candidatePath, "utf8");
|
|
243
|
+
const scoringHead = {
|
|
244
|
+
task: ctx.inputs.task,
|
|
245
|
+
groundTruthNote: resolvedCriteria.groundTruthNote,
|
|
246
|
+
candidates: [{ path: candidatePath, body: candidateBody }],
|
|
247
|
+
scaleAnchors: VERIFICATION_SCALE.anchors
|
|
248
|
+
};
|
|
249
|
+
const cells = [];
|
|
250
|
+
for (const criterion of resolvedCriteria.criteria) {
|
|
251
|
+
for (let index = 0;index < verifierCount; index += 1) {
|
|
252
|
+
const name = `verifier-${round}-${criterion.id}-${index + 1}`;
|
|
253
|
+
cells.push({
|
|
254
|
+
criterion,
|
|
255
|
+
verifierIndex: index + 1,
|
|
256
|
+
name,
|
|
257
|
+
artifactPath: join(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const runWave = async (pending2, reaskWave) => {
|
|
262
|
+
if (pending2.length === 0)
|
|
263
|
+
return { valid: [], invalid: [], results: [] };
|
|
264
|
+
const reports = await warm_first_fan_out(ctx, pending2.map((cell) => scoreStep(cell, reaskWave, scoringHead, criteriaPath)), () => scoringHead, { concurrency: Math.min(pending2.length, 4), failFast: false });
|
|
265
|
+
const byName = new Map;
|
|
266
|
+
for (const report of reports) {
|
|
267
|
+
const name = report.name ?? report.stageName;
|
|
268
|
+
if (name !== undefined)
|
|
269
|
+
byName.set(name, report);
|
|
270
|
+
}
|
|
271
|
+
const valid = [];
|
|
272
|
+
const invalid = [];
|
|
273
|
+
for (const cell of pending2) {
|
|
274
|
+
const report = byName.get(stageName(cell, reaskWave));
|
|
275
|
+
const artifactPath = reaskWave === 0 ? cell.artifactPath : cell.artifactPath.replace(/\.json$/, `-reask-${reaskWave}.json`);
|
|
276
|
+
if (isCriterionScore(report?.structured, cell.criterion.id)) {
|
|
277
|
+
await writeFile(artifactPath, `${JSON.stringify(report.structured, null, 2)}
|
|
278
|
+
`);
|
|
279
|
+
valid.push({ cell, report: report.structured, artifactPath });
|
|
280
|
+
} else {
|
|
281
|
+
await writeInvalid(artifactPath, stageName(cell, reaskWave));
|
|
282
|
+
invalid.push(cell);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return { valid, invalid, results: reports };
|
|
286
|
+
};
|
|
287
|
+
const roundResults = [];
|
|
288
|
+
let pending = [...cells];
|
|
289
|
+
const validResults = [];
|
|
290
|
+
let invalidCount = 0;
|
|
291
|
+
for (let reaskWave = 0;reaskWave <= reaskLimit; reaskWave += 1) {
|
|
292
|
+
const wave = await runWave(pending, reaskWave);
|
|
293
|
+
roundResults.push(...wave.results);
|
|
294
|
+
validResults.push(...wave.valid);
|
|
295
|
+
invalidCount += wave.invalid.length;
|
|
296
|
+
pending = [...wave.invalid];
|
|
297
|
+
if (pending.length === 0)
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
const validReportsByCell = new Map(validResults.map((item) => [item.cell.name, item.report]));
|
|
301
|
+
const scoreReports = cells.flatMap((cell) => {
|
|
302
|
+
const report = validReportsByCell.get(cell.name);
|
|
303
|
+
return report === undefined ? [] : [report];
|
|
304
|
+
});
|
|
305
|
+
const scores = scoreReports.map(toCriterionScore);
|
|
306
|
+
const roundResult = { scores, invalidCount, expectedCount };
|
|
307
|
+
const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
|
|
308
|
+
finalDecision = decision;
|
|
309
|
+
finalMean = meanScore(scoreReports);
|
|
310
|
+
scoreTablePath = join(root, `verification-summary-${round}.json`);
|
|
311
|
+
reviewReportPath = join(root, `review-${round}.json`);
|
|
312
|
+
const summary = {
|
|
313
|
+
scores: scoreReports,
|
|
314
|
+
mean: finalMean,
|
|
315
|
+
invalidCount,
|
|
316
|
+
decision,
|
|
317
|
+
usage: fold_usage(roundResults)
|
|
318
|
+
};
|
|
319
|
+
if (decision.kind === "accept") {
|
|
320
|
+
remainingWork = [];
|
|
321
|
+
await writeFile(scoreTablePath, `${JSON.stringify(summary, null, 2)}
|
|
322
|
+
`);
|
|
323
|
+
await writeFile(reviewReportPath, `${JSON.stringify({ decision, remaining_work: [] }, null, 2)}
|
|
324
|
+
`);
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
if (decision.kind === "indeterminate") {
|
|
328
|
+
consecutiveIndeterminate += 1;
|
|
329
|
+
remainingWork = [quorumEvidence(decision.missing, invalidCount, expectedCount, reaskLimit)];
|
|
330
|
+
await writeFile(scoreTablePath, `${JSON.stringify(summary, null, 2)}
|
|
331
|
+
`);
|
|
332
|
+
await writeFile(reviewReportPath, `${JSON.stringify({ decision, evidence: remainingWork, remaining_work: remainingWork }, null, 2)}
|
|
333
|
+
`);
|
|
334
|
+
if (consecutiveIndeterminate >= 2)
|
|
335
|
+
break;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
consecutiveIndeterminate = 0;
|
|
339
|
+
const confirmedFindings = findingText(decision);
|
|
340
|
+
const scorePaths = validResults.map((item) => item.artifactPath);
|
|
341
|
+
const consolidated = await ctx.task(`consolidate-findings-${round}`, {
|
|
342
|
+
prompt: renderConsolidatorPrompt(ctx.inputs.task, candidatePath, scorePaths, repairsCompleted, maxRepairs),
|
|
343
|
+
context: "fresh",
|
|
344
|
+
reads: [candidatePath, criteriaPath, ...scorePaths],
|
|
345
|
+
schema: consolidatorSchema
|
|
346
|
+
});
|
|
347
|
+
const fallbackRemaining = confirmedFindings.length > 0 ? confirmedFindings : [`Mean score ${decision.mean} is below the acceptance threshold ${acceptMean}.`];
|
|
348
|
+
const consolidatedReport = structured(consolidated.structured, isConsolidatedReport) ?? { repair_guidance: "Confirmed verifier findings require repair.", remaining_work: fallbackRemaining };
|
|
349
|
+
remainingWork = fallbackRemaining;
|
|
350
|
+
await writeFile(scoreTablePath, `${JSON.stringify(summary, null, 2)}
|
|
351
|
+
`);
|
|
352
|
+
await writeFile(reviewReportPath, `${JSON.stringify({ ...consolidatedReport, remaining_work: remainingWork }, null, 2)}
|
|
353
|
+
`);
|
|
354
|
+
if (repairsCompleted >= maxRepairs)
|
|
355
|
+
break;
|
|
356
|
+
repairsCompleted += 1;
|
|
357
|
+
await ctx.task(`repair-${repairsCompleted}`, {
|
|
358
|
+
prompt: renderRepairPrompt(ctx.inputs.task, candidatePath, reviewReportPath),
|
|
359
|
+
context: "fresh",
|
|
360
|
+
reads: [candidatePath, reviewReportPath],
|
|
361
|
+
output: candidatePath,
|
|
362
|
+
outputMode: "file-only"
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
approved: finalDecision.kind === "accept",
|
|
367
|
+
mean_score: finalMean,
|
|
368
|
+
score_table_path: scoreTablePath,
|
|
369
|
+
repairs_completed: repairsCompleted,
|
|
370
|
+
candidate_path: candidatePath,
|
|
371
|
+
review_report_path: reviewReportPath,
|
|
372
|
+
remaining_work: finalDecision.kind === "accept" ? [] : remainingWork
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// dist/builtin/workflows/builtin/adversarial-verification.ts
|
|
377
|
+
var adversarial_verification_default = workflow({
|
|
378
|
+
name: "adversarial-verification",
|
|
379
|
+
description: "Produce a candidate, score independent per-criterion verifier reports, and apply a deterministic mean-and-veto gate with bounded repairs.",
|
|
380
|
+
heartbeatIntervalMinutes: 15,
|
|
381
|
+
inputs: {
|
|
382
|
+
task: Type2.String({ description: "Task whose candidate result must be independently verified." }),
|
|
383
|
+
verifier_count: Type2.Integer({ minimum: 1, maximum: 5, default: 3, description: "Number of independent verifiers for each criterion per round." }),
|
|
384
|
+
max_repairs: Type2.Integer({ minimum: 0, maximum: 5, default: 2, description: "Maximum candidate repair rounds before rejection." }),
|
|
385
|
+
criteria: Type2.Union([
|
|
386
|
+
Type2.String(),
|
|
387
|
+
Type2.Record(Type2.String(), Type2.String())
|
|
388
|
+
], { default: DEFAULT_CRITERIA, description: "Criteria record of name-to-description entries, or criteria.md markdown." }),
|
|
389
|
+
accept_mean: Type2.Number({ default: 14, description: "Mean score required for acceptance on the 1–20 verification scale." }),
|
|
390
|
+
reask_limit: Type2.Integer({ minimum: 0, default: 1, description: "Maximum bounded re-ask waves for invalid criterion reports." })
|
|
391
|
+
},
|
|
392
|
+
outputs: {
|
|
393
|
+
approved: Type2.Boolean({ description: "Whether the deterministic mean-and-veto gate accepted the candidate." }),
|
|
394
|
+
mean_score: Type2.Number({ description: "Mean score of the final round's schema-valid criterion reports." }),
|
|
395
|
+
score_table_path: Type2.String({ description: "Path to the final round per-criterion score summary." }),
|
|
396
|
+
repairs_completed: Type2.Integer({ description: "Number of repair rounds performed." }),
|
|
397
|
+
candidate_path: Type2.String({ description: "Path to the final candidate artifact." }),
|
|
398
|
+
review_report_path: Type2.String({ description: "Path to the final consolidated findings or quorum report." }),
|
|
399
|
+
remaining_work: Type2.Array(Type2.String(), { description: "Unresolved findings or quorum evidence when not approved." })
|
|
400
|
+
},
|
|
401
|
+
run: async (ctx) => await runAdversarialVerification(withSteeringPropagationContext(ctx))
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
export { adversarial_verification_default };
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
APP_NAME,
|
|
3
|
+
SessionManager,
|
|
4
|
+
getExportTemplateDir,
|
|
5
|
+
getResolvedThemeColors,
|
|
6
|
+
getThemeExportColors,
|
|
7
|
+
normalizePath,
|
|
8
|
+
resolvePath
|
|
9
|
+
} from "./chunk-x2ghn0je.js";
|
|
10
|
+
import"./chunk-5wgwscd0.js";
|
|
11
|
+
|
|
12
|
+
// src/core/export-html/index.ts
|
|
13
|
+
import { existsSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
14
|
+
import { basename, join as join2 } from "path";
|
|
15
|
+
|
|
16
|
+
// src/core/export-html/template-script.ts
|
|
17
|
+
import { readFileSync } from "fs";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
var EXPORT_HTML_TEMPLATE_SCRIPT_CHUNKS = [
|
|
20
|
+
"data-tree.js",
|
|
21
|
+
"tree-filter-render.js",
|
|
22
|
+
"message-tools.js",
|
|
23
|
+
"entries-navigation.js",
|
|
24
|
+
"initialization.js"
|
|
25
|
+
];
|
|
26
|
+
function readExportHtmlTemplateScript(templateDir) {
|
|
27
|
+
return EXPORT_HTML_TEMPLATE_SCRIPT_CHUNKS.map((fileName) => readFileSync(join(templateDir, "template-js", fileName), "utf-8")).join("");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/core/export-html/index.ts
|
|
31
|
+
function parseColor(color) {
|
|
32
|
+
const hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);
|
|
33
|
+
if (hexMatch) {
|
|
34
|
+
return {
|
|
35
|
+
r: Number.parseInt(hexMatch[1], 16),
|
|
36
|
+
g: Number.parseInt(hexMatch[2], 16),
|
|
37
|
+
b: Number.parseInt(hexMatch[3], 16)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const rgbMatch = color.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);
|
|
41
|
+
if (rgbMatch) {
|
|
42
|
+
return {
|
|
43
|
+
r: Number.parseInt(rgbMatch[1], 10),
|
|
44
|
+
g: Number.parseInt(rgbMatch[2], 10),
|
|
45
|
+
b: Number.parseInt(rgbMatch[3], 10)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
function getLuminance(r, g, b) {
|
|
51
|
+
const toLinear = (c) => {
|
|
52
|
+
const s = c / 255;
|
|
53
|
+
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
54
|
+
};
|
|
55
|
+
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
56
|
+
}
|
|
57
|
+
function adjustBrightness(color, factor) {
|
|
58
|
+
const parsed = parseColor(color);
|
|
59
|
+
if (!parsed)
|
|
60
|
+
return color;
|
|
61
|
+
const adjust = (c) => Math.min(255, Math.max(0, Math.round(c * factor)));
|
|
62
|
+
return `rgb(${adjust(parsed.r)}, ${adjust(parsed.g)}, ${adjust(parsed.b)})`;
|
|
63
|
+
}
|
|
64
|
+
function deriveExportColors(baseColor) {
|
|
65
|
+
const parsed = parseColor(baseColor);
|
|
66
|
+
if (!parsed) {
|
|
67
|
+
return {
|
|
68
|
+
pageBg: "rgb(24, 24, 30)",
|
|
69
|
+
cardBg: "rgb(30, 30, 36)",
|
|
70
|
+
infoBg: "rgb(60, 55, 40)"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const luminance = getLuminance(parsed.r, parsed.g, parsed.b);
|
|
74
|
+
const isLight = luminance > 0.5;
|
|
75
|
+
if (isLight) {
|
|
76
|
+
return {
|
|
77
|
+
pageBg: adjustBrightness(baseColor, 0.96),
|
|
78
|
+
cardBg: baseColor,
|
|
79
|
+
infoBg: `rgb(${Math.min(255, parsed.r + 10)}, ${Math.min(255, parsed.g + 5)}, ${Math.max(0, parsed.b - 20)})`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
pageBg: adjustBrightness(baseColor, 0.7),
|
|
84
|
+
cardBg: adjustBrightness(baseColor, 0.85),
|
|
85
|
+
infoBg: `rgb(${Math.min(255, parsed.r + 20)}, ${Math.min(255, parsed.g + 15)}, ${parsed.b})`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function generateThemeVars(themeName) {
|
|
89
|
+
const colors = getResolvedThemeColors(themeName);
|
|
90
|
+
const lines = [];
|
|
91
|
+
for (const [key, value] of Object.entries(colors)) {
|
|
92
|
+
lines.push(`--${key}: ${value};`);
|
|
93
|
+
}
|
|
94
|
+
const themeExport = getThemeExportColors(themeName);
|
|
95
|
+
const userMessageBg = colors.userMessageBg || "#343541";
|
|
96
|
+
const derivedColors = deriveExportColors(userMessageBg);
|
|
97
|
+
lines.push(`--exportPageBg: ${themeExport.pageBg ?? derivedColors.pageBg};`);
|
|
98
|
+
lines.push(`--exportCardBg: ${themeExport.cardBg ?? derivedColors.cardBg};`);
|
|
99
|
+
lines.push(`--exportInfoBg: ${themeExport.infoBg ?? derivedColors.infoBg};`);
|
|
100
|
+
return lines.join(`
|
|
101
|
+
`);
|
|
102
|
+
}
|
|
103
|
+
function generateHtml(sessionData, themeName) {
|
|
104
|
+
const templateDir = getExportTemplateDir();
|
|
105
|
+
const template = readFileSync2(join2(templateDir, "template.html"), "utf-8");
|
|
106
|
+
const templateCss = readFileSync2(join2(templateDir, "template.css"), "utf-8");
|
|
107
|
+
const templateJs = readExportHtmlTemplateScript(templateDir);
|
|
108
|
+
const markedJs = readFileSync2(join2(templateDir, "vendor", "marked.min.js"), "utf-8");
|
|
109
|
+
const hljsJs = readFileSync2(join2(templateDir, "vendor", "highlight.min.js"), "utf-8");
|
|
110
|
+
const themeVars = generateThemeVars(themeName);
|
|
111
|
+
const colors = getResolvedThemeColors(themeName);
|
|
112
|
+
const themeExport = getThemeExportColors(themeName);
|
|
113
|
+
const derivedExportColors = deriveExportColors(colors.userMessageBg || "#343541");
|
|
114
|
+
const bodyBg = themeExport.pageBg ?? derivedExportColors.pageBg;
|
|
115
|
+
const containerBg = themeExport.cardBg ?? derivedExportColors.cardBg;
|
|
116
|
+
const infoBg = themeExport.infoBg ?? derivedExportColors.infoBg;
|
|
117
|
+
const sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toString("base64");
|
|
118
|
+
const css = templateCss.replace("{{THEME_VARS}}", themeVars).replace("{{BODY_BG}}", bodyBg).replace("{{CONTAINER_BG}}", containerBg).replace("{{INFO_BG}}", infoBg);
|
|
119
|
+
return template.replace("{{CSS}}", css).replace("{{JS}}", templateJs).replace("{{SESSION_DATA}}", sessionDataBase64).replace("{{MARKED_JS}}", markedJs).replace("{{HIGHLIGHT_JS}}", hljsJs);
|
|
120
|
+
}
|
|
121
|
+
var TEMPLATE_RENDERED_TOOLS = new Set(["bash", "read", "write", "edit", "ls"]);
|
|
122
|
+
function preRenderCustomTools(entries, toolRenderer) {
|
|
123
|
+
const renderedTools = {};
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (entry.type !== "message")
|
|
126
|
+
continue;
|
|
127
|
+
const msg = entry.message;
|
|
128
|
+
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
129
|
+
for (const block of msg.content) {
|
|
130
|
+
if (block.type === "toolCall" && !TEMPLATE_RENDERED_TOOLS.has(block.name)) {
|
|
131
|
+
const callHtml = toolRenderer.renderCall(block.id, block.name, block.arguments);
|
|
132
|
+
if (callHtml) {
|
|
133
|
+
renderedTools[block.id] = { callHtml };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (msg.role === "toolResult" && msg.toolCallId) {
|
|
139
|
+
const toolName = msg.toolName || "";
|
|
140
|
+
const existing = renderedTools[msg.toolCallId];
|
|
141
|
+
if (existing || !TEMPLATE_RENDERED_TOOLS.has(toolName)) {
|
|
142
|
+
const rendered = toolRenderer.renderResult(msg.toolCallId, toolName, msg.content, msg.details, msg.isError || false);
|
|
143
|
+
if (rendered) {
|
|
144
|
+
renderedTools[msg.toolCallId] = {
|
|
145
|
+
...existing,
|
|
146
|
+
resultHtmlCollapsed: rendered.collapsed,
|
|
147
|
+
resultHtmlExpanded: rendered.expanded
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return renderedTools;
|
|
154
|
+
}
|
|
155
|
+
async function exportSessionToHtml(sm, state, options) {
|
|
156
|
+
const opts = typeof options === "string" ? { outputPath: options } : options || {};
|
|
157
|
+
const sessionFile = sm.getSessionFile();
|
|
158
|
+
if (!sessionFile) {
|
|
159
|
+
throw new Error("Cannot export in-memory session to HTML");
|
|
160
|
+
}
|
|
161
|
+
if (!existsSync(sessionFile)) {
|
|
162
|
+
throw new Error("Nothing to export yet - start a conversation first");
|
|
163
|
+
}
|
|
164
|
+
const entries = sm.getEntries();
|
|
165
|
+
let renderedTools;
|
|
166
|
+
if (opts.toolRenderer) {
|
|
167
|
+
renderedTools = preRenderCustomTools(entries, opts.toolRenderer);
|
|
168
|
+
if (Object.keys(renderedTools).length === 0) {
|
|
169
|
+
renderedTools = undefined;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const sessionData = {
|
|
173
|
+
header: sm.getHeader(),
|
|
174
|
+
entries,
|
|
175
|
+
leafId: sm.getLeafId(),
|
|
176
|
+
systemPrompt: state?.systemPrompt,
|
|
177
|
+
tools: state?.tools?.map((t) => ({ name: t.name, description: t.description, parameters: t.parameters })),
|
|
178
|
+
renderedTools
|
|
179
|
+
};
|
|
180
|
+
const html = generateHtml(sessionData, opts.themeName);
|
|
181
|
+
let outputPath = opts.outputPath ? normalizePath(opts.outputPath) : undefined;
|
|
182
|
+
if (!outputPath) {
|
|
183
|
+
const sessionBasename = basename(sessionFile, ".jsonl");
|
|
184
|
+
outputPath = `${APP_NAME}-session-${sessionBasename}.html`;
|
|
185
|
+
}
|
|
186
|
+
writeFileSync(outputPath, html, "utf8");
|
|
187
|
+
return outputPath;
|
|
188
|
+
}
|
|
189
|
+
async function exportFromFile(inputPath, options) {
|
|
190
|
+
const opts = typeof options === "string" ? { outputPath: options } : options || {};
|
|
191
|
+
const resolvedInputPath = resolvePath(inputPath);
|
|
192
|
+
if (!existsSync(resolvedInputPath)) {
|
|
193
|
+
throw new Error(`File not found: ${resolvedInputPath}`);
|
|
194
|
+
}
|
|
195
|
+
const sm = SessionManager.open(resolvedInputPath);
|
|
196
|
+
const sessionData = {
|
|
197
|
+
header: sm.getHeader(),
|
|
198
|
+
entries: sm.getEntries(),
|
|
199
|
+
leafId: sm.getLeafId(),
|
|
200
|
+
systemPrompt: undefined,
|
|
201
|
+
tools: undefined
|
|
202
|
+
};
|
|
203
|
+
const html = generateHtml(sessionData, opts.themeName);
|
|
204
|
+
let outputPath = opts.outputPath ? normalizePath(opts.outputPath) : undefined;
|
|
205
|
+
if (!outputPath) {
|
|
206
|
+
const inputBasename = basename(resolvedInputPath, ".jsonl");
|
|
207
|
+
outputPath = `${APP_NAME}-session-${inputBasename}.html`;
|
|
208
|
+
}
|
|
209
|
+
writeFileSync(outputPath, html, "utf8");
|
|
210
|
+
return outputPath;
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
exportFromFile,
|
|
214
|
+
exportSessionToHtml
|
|
215
|
+
};
|