@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.8
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 +19 -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 +680 -53
- 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 +109 -35
- 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 +173 -51
- package/dist/builtin/web-access/index.bundle.mjs +109 -35
- 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-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-5n10x7j2.js +69730 -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-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -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-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -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/chunk-zf28603f.js +1080 -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 +1228 -428
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
- 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/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/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/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.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-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/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
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { mkdirSync } from "node:fs";
|
|
3
|
-
import { tmpdir, userInfo } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { Type } from "typebox";
|
|
6
|
-
import { createChildProcessEnvironment } from "@bastani/atomic";
|
|
7
|
-
import type { WorkflowTaskResult } from "../src/shared/types.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export const OUTPUT_TYPES = [
|
|
11
|
-
"prototype",
|
|
12
|
-
"wireframe",
|
|
13
|
-
"page",
|
|
14
|
-
"component",
|
|
15
|
-
"theme",
|
|
16
|
-
"tokens",
|
|
17
|
-
] as const;
|
|
18
|
-
export type OutputType = (typeof OUTPUT_TYPES)[number];
|
|
19
|
-
export const DEFAULT_OUTPUT_TYPE: OutputType = "prototype";
|
|
20
|
-
|
|
21
|
-
type PromptSection = readonly [tag: string, content: string];
|
|
22
|
-
|
|
23
|
-
export function taggedPrompt(sections: readonly PromptSection[]): string {
|
|
24
|
-
return sections
|
|
25
|
-
.map(([tag, content]) => {
|
|
26
|
-
const trimmed = content.trim();
|
|
27
|
-
return `<${tag}>\n${trimmed}\n</${tag}>`;
|
|
28
|
-
})
|
|
29
|
-
.join("\n\n");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export function normalizeOutputType(value: string | undefined): OutputType {
|
|
34
|
-
return value !== undefined &&
|
|
35
|
-
(OUTPUT_TYPES as readonly string[]).includes(value)
|
|
36
|
-
? (value as OutputType)
|
|
37
|
-
: DEFAULT_OUTPUT_TYPE;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function isUrl(value: string): boolean {
|
|
41
|
-
return /^https?:\/\//i.test(value.trim());
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function isFileLike(value: string): boolean {
|
|
45
|
-
const trimmed = value.trim();
|
|
46
|
-
return trimmed.length > 0 && !isUrl(trimmed);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Whether the browser-centric workflow should exit early instead of generating
|
|
51
|
-
* artifacts no one can review interactively. True only when the playwright-cli
|
|
52
|
-
* browser is unavailable AND we are not under the test harness (`NODE_ENV=test`,
|
|
53
|
-
* which always skips the global install and runs headlessly to completion).
|
|
54
|
-
*/
|
|
55
|
-
export function shouldEarlyExitForBrowser(
|
|
56
|
-
browserAvailable: boolean,
|
|
57
|
-
nodeEnv: string | undefined,
|
|
58
|
-
): boolean {
|
|
59
|
-
return !browserAvailable && nodeEnv !== "test";
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export type DiscoveryDecision = {
|
|
63
|
-
readonly brief: string;
|
|
64
|
-
readonly output_type: OutputType;
|
|
65
|
-
readonly references: readonly string[];
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const discoveryDecisionSchema = Type.Object(
|
|
69
|
-
{
|
|
70
|
-
brief: Type.String(),
|
|
71
|
-
output_type: Type.Union([...OUTPUT_TYPES].map((value) => Type.Literal(value))),
|
|
72
|
-
references: Type.Array(Type.String()),
|
|
73
|
-
},
|
|
74
|
-
{ additionalProperties: false },
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Parse the discovery stage's structured result, tolerating a missing/invalid
|
|
79
|
-
* structured payload (headless / mock runs) by falling back to the raw prompt as
|
|
80
|
-
* the brief, the default output type, and an empty reference list.
|
|
81
|
-
*/
|
|
82
|
-
export function discoveryDecisionFromResult(
|
|
83
|
-
result: WorkflowTaskResult,
|
|
84
|
-
fallbackBrief: string,
|
|
85
|
-
): DiscoveryDecision {
|
|
86
|
-
const decision = result.structured as Partial<DiscoveryDecision> | undefined;
|
|
87
|
-
const brief =
|
|
88
|
-
typeof decision?.brief === "string" && decision.brief.trim().length > 0
|
|
89
|
-
? decision.brief.trim()
|
|
90
|
-
: fallbackBrief;
|
|
91
|
-
const references = Array.isArray(decision?.references)
|
|
92
|
-
? decision.references
|
|
93
|
-
.filter((ref): ref is string => typeof ref === "string")
|
|
94
|
-
.map((ref) => ref.trim())
|
|
95
|
-
.filter((ref) => ref.length > 0)
|
|
96
|
-
: [];
|
|
97
|
-
return {
|
|
98
|
-
brief,
|
|
99
|
-
output_type: normalizeOutputType(decision?.output_type),
|
|
100
|
-
references,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function joinResults(results: readonly WorkflowTaskResult[]): string {
|
|
105
|
-
return results
|
|
106
|
-
.map((result) => `### ${result.name}\n\n${result.text}`)
|
|
107
|
-
.join("\n\n---\n\n");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Per-user tmpdir base for run artifacts. Namespacing by username avoids
|
|
112
|
-
* EACCES collisions on shared hosts where another user already owns a plain
|
|
113
|
-
* `<tmpdir>/open-claude-design` directory.
|
|
114
|
-
*/
|
|
115
|
-
function tmpArtifactBase(): string {
|
|
116
|
-
let user = "default";
|
|
117
|
-
try {
|
|
118
|
-
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
119
|
-
} catch {
|
|
120
|
-
// keep the "default" namespace when the username is unavailable
|
|
121
|
-
}
|
|
122
|
-
return join(tmpdir(), `open-claude-design-${user}`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Compute (and best-effort create) a per-run artifact directory.
|
|
127
|
-
* Prefers `<cwd>/.atomic/workflows/open-claude-design/<runId>` so the artifacts
|
|
128
|
-
* stay next to the project and are discoverable by pi. Falls back to a
|
|
129
|
-
* per-user OS tmpdir when the project tree is not writable (CI sandboxes,
|
|
130
|
-
* mocks, etc.).
|
|
131
|
-
*/
|
|
132
|
-
export function prepareArtifactDir(cwd = process.cwd()): {
|
|
133
|
-
readonly runId: string;
|
|
134
|
-
readonly artifactDir: string;
|
|
135
|
-
readonly previewPath: string;
|
|
136
|
-
readonly specPath: string;
|
|
137
|
-
} {
|
|
138
|
-
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
139
|
-
// Under automated tests, prefer the OS tmpdir so a full `d.run()` does not
|
|
140
|
-
// pollute the project's `specs/design/` tree with per-run artifact folders.
|
|
141
|
-
const tmpCandidates = [
|
|
142
|
-
join(tmpArtifactBase(), runId),
|
|
143
|
-
join(tmpdir(), "open-claude-design", runId),
|
|
144
|
-
];
|
|
145
|
-
const candidates =
|
|
146
|
-
process.env.NODE_ENV === "test"
|
|
147
|
-
? tmpCandidates
|
|
148
|
-
: [join(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
149
|
-
for (const candidate of candidates) {
|
|
150
|
-
try {
|
|
151
|
-
mkdirSync(candidate, { recursive: true });
|
|
152
|
-
return {
|
|
153
|
-
runId,
|
|
154
|
-
artifactDir: candidate,
|
|
155
|
-
previewPath: join(candidate, "preview.html"),
|
|
156
|
-
specPath: join(candidate, "spec.html"),
|
|
157
|
-
};
|
|
158
|
-
} catch {
|
|
159
|
-
// try next fallback
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// Last-resort: synthesize paths even if mkdir failed; downstream agents will
|
|
163
|
-
// recreate parents using their Write tool.
|
|
164
|
-
const fallback = join(tmpArtifactBase(), runId);
|
|
165
|
-
return {
|
|
166
|
-
runId,
|
|
167
|
-
artifactDir: fallback,
|
|
168
|
-
previewPath: join(fallback, "preview.html"),
|
|
169
|
-
specPath: join(fallback, "spec.html"),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export const HTML_PREVIEW_RULES = [
|
|
174
|
-
"Produce one self-contained HTML document: inline CSS in <style> and JS in <script>; make no external requests except explicitly required Google Fonts.",
|
|
175
|
-
"Use realistic brief-specific content, not Lorem ipsum or obvious placeholders.",
|
|
176
|
-
"Render well from 360px to 1440px with sensible container or media-query breakpoints.",
|
|
177
|
-
"Include default and hover/focus states for every interactive element, plus empty, loading, and error states where relevant.",
|
|
178
|
-
"Use semantic landmarks, labeled controls, WCAG AA contrast, visible focus, and prefers-reduced-motion.",
|
|
179
|
-
"Add HTML comments marking sections, states, and design-system token references for engineering handoff.",
|
|
180
|
-
].join("\n");
|
|
181
|
-
|
|
182
|
-
export const ANTI_SLOP_RULES = [
|
|
183
|
-
"Avoid generic AI palettes and structures: purple/indigo or blue-to-pink gradients, neon glassmorphism stacks, and nested card grids.",
|
|
184
|
-
"Avoid impeccable catalog clichés: gradient emphasis text, side-tab borders, three-font headers, and decorative shadows in flat-by-default systems.",
|
|
185
|
-
"Commit to a specific aesthetic rather than generic SaaS defaults.",
|
|
186
|
-
].join("\n");
|
|
187
|
-
|
|
188
|
-
/** Reference-import precedence note shared by import, generation, and refinement. */
|
|
189
|
-
export const REFERENCE_PRECEDENCE =
|
|
190
|
-
"User references in <reference_context> are the PRIMARY visual authority and override conflicting DESIGN.md/PRODUCT.md guidance. DESIGN.md governs uncovered design decisions; PRODUCT.md still governs strategic register/voice.";
|
|
191
|
-
|
|
192
|
-
export type PlaywrightCliStatus = {
|
|
193
|
-
/** Whether the `playwright-cli` command is expected to be available to downstream stages. */
|
|
194
|
-
readonly available: boolean;
|
|
195
|
-
/** True when the command was already on PATH and no install was attempted. */
|
|
196
|
-
readonly alreadyPresent: boolean;
|
|
197
|
-
/** True when this step installed the command via `npm install -g @playwright/cli@latest`. */
|
|
198
|
-
readonly installed: boolean;
|
|
199
|
-
/** Human-readable, single-line outcome surfaced as a workflow output. */
|
|
200
|
-
readonly summary: string;
|
|
201
|
-
/** Raw failure reason when the install could not complete; absent on success. */
|
|
202
|
-
readonly error?: string;
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Initial deterministic setup step (no LLM): ensure the playwright-cli skill's
|
|
207
|
-
* `playwright-cli` command is available before any design stage runs. Mirrors the
|
|
208
|
-
* playwright-cli skill's documented bootstrap (`npx --no-install playwright-cli
|
|
209
|
-
* --version` || `npm install -g @playwright/cli@latest`) but performs it once,
|
|
210
|
-
* deterministically, instead of relying on each stage to probe/install it.
|
|
211
|
-
* The PATH probe always runs, but the actual global install is skipped under
|
|
212
|
-
* automated tests (`NODE_ENV=test`) to avoid slow, networked, environment-
|
|
213
|
-
* mutating side effects.
|
|
214
|
-
*
|
|
215
|
-
* Best-effort by contract: it never throws and never blocks the workflow. When
|
|
216
|
-
* the command cannot be located or installed, downstream stages keep their graceful
|
|
217
|
-
* degradation path (surface the manual preview path / URL).
|
|
218
|
-
*/
|
|
219
|
-
export function ensurePlaywrightCli(): PlaywrightCliStatus {
|
|
220
|
-
const isWindows = process.platform === "win32";
|
|
221
|
-
const onPath = (): boolean => {
|
|
222
|
-
try {
|
|
223
|
-
const probe = spawnSync(isWindows ? "where" : "which", ["playwright-cli"], {
|
|
224
|
-
stdio: "ignore",
|
|
225
|
-
timeout: 15_000,
|
|
226
|
-
shell: isWindows,
|
|
227
|
-
env: createChildProcessEnvironment(),
|
|
228
|
-
});
|
|
229
|
-
return probe.status === 0;
|
|
230
|
-
} catch {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
if (onPath()) {
|
|
236
|
-
return {
|
|
237
|
-
available: true,
|
|
238
|
-
alreadyPresent: true,
|
|
239
|
-
installed: false,
|
|
240
|
-
summary: "playwright-cli already on PATH; skipped install.",
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Never perform a real global `npm install` during automated tests: it is
|
|
245
|
-
// slow, network-dependent, and would mutate the test runner's global
|
|
246
|
-
// environment. The PATH probe above and the prompt guidance below are still
|
|
247
|
-
// exercised; only the install side effect is skipped.
|
|
248
|
-
if (process.env.NODE_ENV === "test") {
|
|
249
|
-
return {
|
|
250
|
-
available: false,
|
|
251
|
-
alreadyPresent: false,
|
|
252
|
-
installed: false,
|
|
253
|
-
summary:
|
|
254
|
-
"playwright-cli not found; skipped global install under the test environment.",
|
|
255
|
-
error: "global install skipped during tests",
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
const install = spawnSync("npm", ["install", "-g", "@playwright/cli@latest"], {
|
|
261
|
-
stdio: "ignore",
|
|
262
|
-
timeout: 180_000,
|
|
263
|
-
shell: isWindows,
|
|
264
|
-
env: createChildProcessEnvironment(),
|
|
265
|
-
});
|
|
266
|
-
if (install.status === 0) {
|
|
267
|
-
return {
|
|
268
|
-
available: true,
|
|
269
|
-
alreadyPresent: false,
|
|
270
|
-
installed: true,
|
|
271
|
-
summary: "Installed playwright-cli via `npm install -g @playwright/cli@latest`.",
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
const reason =
|
|
275
|
-
install.error?.message ??
|
|
276
|
-
(typeof install.status === "number"
|
|
277
|
-
? `npm install -g @playwright/cli@latest exited with code ${install.status}`
|
|
278
|
-
: "npm install -g @playwright/cli@latest did not complete");
|
|
279
|
-
return {
|
|
280
|
-
available: false,
|
|
281
|
-
alreadyPresent: false,
|
|
282
|
-
installed: false,
|
|
283
|
-
summary: `Could not install playwright-cli (${reason}); stages will degrade gracefully.`,
|
|
284
|
-
error: reason,
|
|
285
|
-
};
|
|
286
|
-
} catch (error) {
|
|
287
|
-
const reason =
|
|
288
|
-
error instanceof Error ? error.message : String(error);
|
|
289
|
-
return {
|
|
290
|
-
available: false,
|
|
291
|
-
alreadyPresent: false,
|
|
292
|
-
installed: false,
|
|
293
|
-
summary: `Could not install playwright-cli (${reason}); stages will degrade gracefully.`,
|
|
294
|
-
error: reason,
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/** Build browser guidance for downstream stage prompts. */
|
|
300
|
-
export function buildPlaywrightCliBootstrapRules(status: PlaywrightCliStatus): string {
|
|
301
|
-
const probeRule = status.available
|
|
302
|
-
? "The playwright-cli skill's `playwright-cli` command is on PATH. Do not reinstall it unless a command reports it missing; then probe with `which playwright-cli` (or `npx --no-install playwright-cli --version`), run `npm install -g @playwright/cli@latest` once, and retry. Do not add project dependencies."
|
|
303
|
-
: `The playwright-cli skill's \`playwright-cli\` command failed setup: "${status.error ?? "unknown error"}". Probe with \`which playwright-cli\` (or \`npx --no-install playwright-cli --version\`) and retry once with \`npm install -g @playwright/cli@latest\`. For permission errors, use a user-writable global prefix; report missing npm/Node or network/registry errors plainly. If still unavailable, surface the manual file path / URL. Do not add project dependencies.`;
|
|
304
|
-
return [
|
|
305
|
-
probeRule,
|
|
306
|
-
"Use `playwright-cli open <url>` to show a local preview; use `playwright-cli snapshot` and `playwright-cli screenshot --filename=<file>` for review evidence.",
|
|
307
|
-
"If a `playwright-cli` command reports a missing browser executable, run `npx playwright install chromium` once and retry.",
|
|
308
|
-
"If `playwright-cli` is unavailable after three attempts or the browser runtime still fails, surface the manual file path / URL.",
|
|
309
|
-
].join("\n");
|
|
310
|
-
}
|
|
311
|
-
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builtin workflow: open-claude-design
|
|
3
|
-
*
|
|
4
|
-
* Adapts Atomic SDK's Claude Design workflow to the local workflow SDK:
|
|
5
|
-
* combined discovery/init, design-system/reference research, one generation,
|
|
6
|
-
* one live review session, export, and final display run through
|
|
7
|
-
* ctx.task()/ctx.parallel().
|
|
8
|
-
*
|
|
9
|
-
* Every stage prompt invokes the specific impeccable sub-skill that maps to
|
|
10
|
-
* its role (see https://github.com/pbakaus/impeccable/tree/main/site/content/skills):
|
|
11
|
-
*
|
|
12
|
-
* onboarding → impeccable `document` / `extract` / `audit`
|
|
13
|
-
* import → impeccable `extract`
|
|
14
|
-
* generate-1 → impeccable `craft` (HTML preview)
|
|
15
|
-
* live review → impeccable `live` (unbounded browser review session)
|
|
16
|
-
* exporter → impeccable `document` (rich HTML spec)
|
|
17
|
-
* final-display → opens/surfaces the exported HTML spec
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { Type } from "typebox";
|
|
21
|
-
import { workflow } from "../src/authoring/workflow.js";
|
|
22
|
-
import { withSteeringPropagationContext } from "./steering-context.js";
|
|
23
|
-
import { runOpenClaudeDesignWorkflow } from "./open-claude-design-runner.js";
|
|
24
|
-
|
|
25
|
-
export default workflow({
|
|
26
|
-
name: "open-claude-design",
|
|
27
|
-
description: "AI-powered design workflow: combined discovery/init → design-system/reference research → curated reference discovery → HTML generation → one live review session → rich HTML handoff. The discovery stage asks what to build, the output type, and which references to emulate, then runs impeccable init for PRODUCT.md/DESIGN.md (references take precedence over project context). The user reviews the generated HTML in one live session.",
|
|
28
|
-
// Disabled: this workflow is driven by the user reviewing generated HTML,
|
|
29
|
-
// so the parent chat is already the thing holding it to its goal. A periodic
|
|
30
|
-
// alignment steer would interrupt that review rather than inform it.
|
|
31
|
-
heartbeatIntervalMinutes: 0,
|
|
32
|
-
inputs: {
|
|
33
|
-
prompt: Type.String({
|
|
34
|
-
description: "What to design (for example, a dashboard, page, component, or prototype). The discovery stage refines this into a confirmed brief and asks for the output type and references.",
|
|
35
|
-
}),
|
|
36
|
-
discover_references: Type.Boolean({
|
|
37
|
-
default: true,
|
|
38
|
-
description:
|
|
39
|
-
"Discover beautiful, current reference designs from notable design websites (Awwwards, recent.design, Dribbble, Monet, Motionsites) and feed them to generation. Set false to skip the network/browser reference pass.",
|
|
40
|
-
}),
|
|
41
|
-
},
|
|
42
|
-
outputs: {
|
|
43
|
-
output_type: Type.Optional(Type.String({ description: "Kind of design artifact produced." })),
|
|
44
|
-
design_system: Type.Optional(Type.String({ description: "Design system source used for generation: the project-derived design system." })),
|
|
45
|
-
artifact: Type.Optional(Type.String({ description: "Latest final design summary from the final preview artifact." })),
|
|
46
|
-
handoff: Type.Optional(Type.String({ description: "Final rich HTML spec and implementation handoff summary." })),
|
|
47
|
-
import_context: Type.Optional(Type.String({ description: "Reference-import context used during generation." })),
|
|
48
|
-
run_id: Type.Optional(Type.String({ description: "Per-run design workflow artifact identifier." })),
|
|
49
|
-
artifact_dir: Type.Optional(Type.String({ description: "Directory containing preview and spec artifacts." })),
|
|
50
|
-
preview_path: Type.Optional(Type.String({ description: "Absolute path to the generated preview.html file." })),
|
|
51
|
-
preview_file_url: Type.Optional(Type.String({ description: "file:// URL for the generated preview.html file." })),
|
|
52
|
-
spec_path: Type.Optional(Type.String({ description: "Absolute path to the generated spec.html file." })),
|
|
53
|
-
spec_file_url: Type.Optional(Type.String({ description: "file:// URL for the generated spec.html file." })),
|
|
54
|
-
playwright_cli_status: Type.Optional(Type.String({ description: "Outcome of the initial deterministic step that ensures the playwright-cli skill's `playwright-cli` command is installed." })),
|
|
55
|
-
},
|
|
56
|
-
run: async (ctx) => await runOpenClaudeDesignWorkflow(withSteeringPropagationContext(ctx)),
|
|
57
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { mkdir } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import type { WorkflowRunContext } from "../src/shared/types.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Durable per-run artifact root under `<cwd>/.atomic/workflows/runs`.
|
|
8
|
-
*
|
|
9
|
-
* The random directory name is generated exactly once through `ctx.tool`, so
|
|
10
|
-
* a durable resume replays the original path instead of computing a fresh
|
|
11
|
-
* per-process root. Replayed stages therefore keep reading artifacts written
|
|
12
|
-
* before the interruption. The `mkdir` stays outside the durable checkpoint
|
|
13
|
-
* and is idempotent, so both fresh runs and resumes converge on an existing
|
|
14
|
-
* directory.
|
|
15
|
-
*/
|
|
16
|
-
export async function stableArtifactRoot(
|
|
17
|
-
ctx: Pick<WorkflowRunContext, "cwd" | "tool">,
|
|
18
|
-
workflowName: string,
|
|
19
|
-
): Promise<string> {
|
|
20
|
-
const cwd = ctx.cwd ?? process.cwd();
|
|
21
|
-
const artifactDir = await ctx.tool(
|
|
22
|
-
"artifact-root",
|
|
23
|
-
{ workflow: workflowName },
|
|
24
|
-
async () => join(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID()}`),
|
|
25
|
-
);
|
|
26
|
-
await mkdir(artifactDir, { recursive: true });
|
|
27
|
-
return artifactDir;
|
|
28
|
-
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Observation-grounded trajectory scoring and pure trend evidence.
|
|
3
|
-
*
|
|
4
|
-
* Progress is a monitoring magnitude only. The prompt asks about the supplied
|
|
5
|
-
* current state, and the trend result carries evidence without an action.
|
|
6
|
-
*/
|
|
7
|
-
import { Type } from "typebox";
|
|
8
|
-
import type { WorkflowRunContext, WorkflowSerializableObject, WorkflowSerializableValue } from "../src/shared/types.js";
|
|
9
|
-
import { VERIFICATION_SCALE } from "./verification-criteria.js";
|
|
10
|
-
|
|
11
|
-
export const DEFAULT_TREND_WINDOW = 3;
|
|
12
|
-
export const DEFAULT_RISE_DELTA = 1.5;
|
|
13
|
-
export const DEFAULT_FALL_DELTA = -1.5;
|
|
14
|
-
|
|
15
|
-
const DEFAULT_REPEATS = 1;
|
|
16
|
-
const CALIBRATION_RULES = [
|
|
17
|
-
"Trust observed output, not the agent's narration.",
|
|
18
|
-
"Effort and step count are NOT progress.",
|
|
19
|
-
'Agent declarations of success ("done!", "all tests pass") are ZERO evidence.',
|
|
20
|
-
"Scores may plateau or fall; wrong approaches plateau, and regressions decrease.",
|
|
21
|
-
] as const;
|
|
22
|
-
const PROGRESS_SCALE_ORIENTATION = `${VERIFICATION_SCALE.min} = certainly would not satisfy the acceptance criteria … ${VERIFICATION_SCALE.max} = verified satisfaction with observed output`;
|
|
23
|
-
|
|
24
|
-
export interface ProgressPromptInput {
|
|
25
|
-
readonly problem: string;
|
|
26
|
-
readonly steps: readonly string[];
|
|
27
|
-
readonly checkpoints: readonly number[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface ProgressScoreInput {
|
|
31
|
-
readonly problem: string;
|
|
32
|
-
readonly steps: readonly string[];
|
|
33
|
-
readonly checkpoints?: readonly number[];
|
|
34
|
-
readonly repeats?: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export type ProgressScoringContext = Pick<WorkflowRunContext, "task">;
|
|
38
|
-
|
|
39
|
-
export type ProgressCurve = {
|
|
40
|
-
checkpoints: number[];
|
|
41
|
-
scores: (number | null)[];
|
|
42
|
-
perRepeat: (number | null)[][];
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type TrendConfig = {
|
|
46
|
-
window?: number;
|
|
47
|
-
riseDelta?: number;
|
|
48
|
-
fallDelta?: number;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export type Trend = "rising" | "flat" | "regressing";
|
|
52
|
-
|
|
53
|
-
export type TrendResult = {
|
|
54
|
-
trend: Trend;
|
|
55
|
-
evidence: {
|
|
56
|
-
series: readonly number[];
|
|
57
|
-
window: number;
|
|
58
|
-
delta: number;
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const progressSchema = Type.Object({
|
|
63
|
-
scores: Type.Array(Type.Object({
|
|
64
|
-
checkpoint: Type.Integer({ minimum: 1 }),
|
|
65
|
-
score: VERIFICATION_SCALE.schema,
|
|
66
|
-
}, { additionalProperties: false })),
|
|
67
|
-
}, { additionalProperties: false });
|
|
68
|
-
|
|
69
|
-
type ProgressStructuredOutput = {
|
|
70
|
-
readonly scores: readonly WorkflowSerializableValue[];
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
function isRecord(value: WorkflowSerializableValue | undefined): value is WorkflowSerializableObject {
|
|
74
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function isProgressStructuredOutput(value: WorkflowSerializableValue | undefined): value is ProgressStructuredOutput {
|
|
78
|
-
if (!isRecord(value) || Object.keys(value).length !== 1 || !Object.hasOwn(value, "scores")) return false;
|
|
79
|
-
return Array.isArray(value.scores);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function nullScores(checkpointCount: number): (number | null)[] {
|
|
83
|
-
return Array.from({ length: checkpointCount }, () => null);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function defaultCheckpoints(stepCount: number): number[] {
|
|
87
|
-
const result: number[] = [];
|
|
88
|
-
for (let checkpoint = 2; checkpoint <= stepCount - 1; checkpoint += 1) result.push(checkpoint);
|
|
89
|
-
return result;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function validateCheckpoints(checkpoints: readonly number[], stepCount: number): void {
|
|
93
|
-
for (const checkpoint of checkpoints) {
|
|
94
|
-
if (!Number.isInteger(checkpoint) || checkpoint < 1 || checkpoint > stepCount) {
|
|
95
|
-
throw new RangeError(`Progress checkpoint ${checkpoint} is outside the step range 1..${stepCount}.`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function scoresFromStructured(
|
|
101
|
-
value: WorkflowSerializableValue | undefined,
|
|
102
|
-
checkpoints: readonly number[],
|
|
103
|
-
): (number | null)[] {
|
|
104
|
-
if (!isProgressStructuredOutput(value)) return nullScores(checkpoints.length);
|
|
105
|
-
const requested = new Set(checkpoints);
|
|
106
|
-
const seen = new Set<number>();
|
|
107
|
-
const scoresByCheckpoint = new Map<number, number>();
|
|
108
|
-
for (const candidate of value.scores) {
|
|
109
|
-
if (!isRecord(candidate) || Object.keys(candidate).length !== 2 ||
|
|
110
|
-
!Object.hasOwn(candidate, "checkpoint") || !Object.hasOwn(candidate, "score")) continue;
|
|
111
|
-
const checkpoint = candidate.checkpoint;
|
|
112
|
-
const score = candidate.score;
|
|
113
|
-
if (typeof checkpoint !== "number" || !Number.isInteger(checkpoint) || seen.has(checkpoint)) continue;
|
|
114
|
-
if (!requested.has(checkpoint) || typeof score !== "number" || !Number.isInteger(score) ||
|
|
115
|
-
score < VERIFICATION_SCALE.min || score > VERIFICATION_SCALE.max) continue;
|
|
116
|
-
seen.add(checkpoint);
|
|
117
|
-
scoresByCheckpoint.set(checkpoint, score);
|
|
118
|
-
}
|
|
119
|
-
return checkpoints.map((checkpoint) => scoresByCheckpoint.get(checkpoint) ?? null);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Score all requested checkpoints in one structured stage call for one repeat.
|
|
124
|
-
* A failed or malformed call is an invalid repeat and leaves every checkpoint
|
|
125
|
-
* in that repeat null.
|
|
126
|
-
*/
|
|
127
|
-
async function scoreRepeat(
|
|
128
|
-
ctx: ProgressScoringContext,
|
|
129
|
-
input: ProgressScoreInput,
|
|
130
|
-
checkpoints: readonly number[],
|
|
131
|
-
repeat: number,
|
|
132
|
-
): Promise<(number | null)[]> {
|
|
133
|
-
try {
|
|
134
|
-
const result = await ctx.task(`progress-score-${repeat + 1}`, {
|
|
135
|
-
prompt: build_progress_prompt({ ...input, checkpoints }),
|
|
136
|
-
context: "fresh",
|
|
137
|
-
schema: progressSchema,
|
|
138
|
-
});
|
|
139
|
-
return scoresFromStructured(result.structured, checkpoints);
|
|
140
|
-
} catch {
|
|
141
|
-
return nullScores(checkpoints.length);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** Score every requested checkpoint once per repeat, returning null-safe means. */
|
|
146
|
-
export async function score_progress(
|
|
147
|
-
ctx: ProgressScoringContext,
|
|
148
|
-
input: ProgressScoreInput,
|
|
149
|
-
): Promise<ProgressCurve> {
|
|
150
|
-
if (input.steps.length === 0) throw new RangeError("Progress scoring requires a non-empty step prefix.");
|
|
151
|
-
const checkpoints = Array.from(input.checkpoints ?? defaultCheckpoints(input.steps.length));
|
|
152
|
-
validateCheckpoints(checkpoints, input.steps.length);
|
|
153
|
-
const repeats = input.repeats ?? DEFAULT_REPEATS;
|
|
154
|
-
const perRepeat: (number | null)[][] = [];
|
|
155
|
-
for (let repeat = 0; repeat < repeats; repeat += 1) {
|
|
156
|
-
perRepeat.push(await scoreRepeat(ctx, input, checkpoints, repeat));
|
|
157
|
-
}
|
|
158
|
-
const scores = checkpoints.map((_, checkpointIndex) => {
|
|
159
|
-
const valid = perRepeat
|
|
160
|
-
.map((repeat) => repeat[checkpointIndex])
|
|
161
|
-
.filter((score): score is number => score !== null);
|
|
162
|
-
if (valid.length === 0) return null;
|
|
163
|
-
return valid.reduce((total, score) => total + score, 0) / valid.length;
|
|
164
|
-
});
|
|
165
|
-
return { checkpoints, scores, perRepeat };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Build a progress prompt with V3's shared-head/varying-tail layout. Steps are
|
|
170
|
-
* part of the cacheable head; only the requested checkpoint list varies at the
|
|
171
|
-
* tail.
|
|
172
|
-
*/
|
|
173
|
-
export function build_progress_prompt(input: ProgressPromptInput): string {
|
|
174
|
-
const numberedSteps = input.steps.map((step, index) => `${index + 1}. ${step}`);
|
|
175
|
-
const sharedHead = [
|
|
176
|
-
"<progress_head>",
|
|
177
|
-
"<problem>",
|
|
178
|
-
input.problem,
|
|
179
|
-
"</problem>",
|
|
180
|
-
"<steps>",
|
|
181
|
-
...numberedSteps,
|
|
182
|
-
"</steps>",
|
|
183
|
-
"<calibration>",
|
|
184
|
-
...CALIBRATION_RULES,
|
|
185
|
-
"</calibration>",
|
|
186
|
-
"<scale>",
|
|
187
|
-
`Use VERIFICATION_SCALE ${VERIFICATION_SCALE.min}..${VERIFICATION_SCALE.max} to answer: would the CURRENT state satisfy the acceptance criteria?`,
|
|
188
|
-
PROGRESS_SCALE_ORIENTATION,
|
|
189
|
-
"Score only the supplied current state from observed output.",
|
|
190
|
-
"</scale>",
|
|
191
|
-
"</progress_head>",
|
|
192
|
-
].join("\n");
|
|
193
|
-
const checkpointTail = [
|
|
194
|
-
"<checkpoints>",
|
|
195
|
-
"Score each listed 1-indexed checkpoint.",
|
|
196
|
-
...input.checkpoints.map((checkpoint) => `- ${checkpoint}`),
|
|
197
|
-
"</checkpoints>",
|
|
198
|
-
"<output_format>",
|
|
199
|
-
`Return structured_output with scores: [{ checkpoint, score }], using integer scores from ${VERIFICATION_SCALE.min} through ${VERIFICATION_SCALE.max}.`,
|
|
200
|
-
"</output_format>",
|
|
201
|
-
].join("\n");
|
|
202
|
-
return `${sharedHead}\n\n${checkpointTail}`;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function mean(values: readonly number[]): number {
|
|
206
|
-
if (values.length === 0) return 0;
|
|
207
|
-
return values.reduce((total, value) => total + value, 0) / values.length;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Classify a score series using a deterministic hysteresis delta. The trailing
|
|
212
|
-
* 2*window values are split into equal leading/trailing halves; an odd sample
|
|
213
|
-
* drops its middle value. Thresholds are inclusive at +riseDelta and -fallDelta.
|
|
214
|
-
*/
|
|
215
|
-
export function classify_trend(series: readonly number[], config: TrendConfig = {}): TrendResult {
|
|
216
|
-
const window = config.window ?? DEFAULT_TREND_WINDOW;
|
|
217
|
-
const riseDelta = config.riseDelta ?? DEFAULT_RISE_DELTA;
|
|
218
|
-
const fallDelta = config.fallDelta ?? DEFAULT_FALL_DELTA;
|
|
219
|
-
if (series.length < window + 1) {
|
|
220
|
-
return { trend: "flat", evidence: { series, window, delta: 0 } };
|
|
221
|
-
}
|
|
222
|
-
const sample = series.slice(-2 * window);
|
|
223
|
-
const usableLength = sample.length % 2 === 1 ? sample.length - 1 : sample.length;
|
|
224
|
-
const halfLength = usableLength / 2;
|
|
225
|
-
const leading = sample.slice(0, halfLength);
|
|
226
|
-
const trailing = sample.slice(sample.length - halfLength);
|
|
227
|
-
const delta = halfLength === 0 ? 0 : mean(trailing) - mean(leading);
|
|
228
|
-
const trend: Trend = delta >= riseDelta ? "rising" : delta <= fallDelta ? "regressing" : "flat";
|
|
229
|
-
return { trend, evidence: { series, window, delta } };
|
|
230
|
-
}
|