cloving 1.0.1 → 1.2.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 +251 -20
- package/assets/watch-fonts/fira-code-OFL.md +93 -0
- package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-OFL.md +93 -0
- package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
- package/assets/watch-fonts/manifest.json +112 -0
- package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
- package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
- package/dist/src/authority/commands.d.ts +1 -0
- package/dist/src/authority/commands.js +33 -4
- package/dist/src/authority/dispatch-decision.d.ts +1 -0
- package/dist/src/authority/dispatch-decision.js +7 -4
- package/dist/src/authority/events.js +2 -2
- package/dist/src/authority/handoff-chain.d.ts +24 -0
- package/dist/src/authority/handoff-chain.js +46 -0
- package/dist/src/authority/reconciliation.d.ts +3 -0
- package/dist/src/authority/reconciliation.js +21 -5
- package/dist/src/authority/transitions.d.ts +1 -1
- package/dist/src/authority/transitions.js +5 -0
- package/dist/src/broker/actor/authority-queries.d.ts +4 -0
- package/dist/src/broker/actor/authority-queries.js +51 -2
- package/dist/src/broker/actor/authority-session.d.ts +2 -0
- package/dist/src/broker/actor/authority-session.js +3 -4
- package/dist/src/broker/actor/delivery-intents.d.ts +1 -0
- package/dist/src/broker/actor/effect-delivery.js +9 -0
- package/dist/src/broker/authority-admission.js +13 -5
- package/dist/src/chats/analysis-batches.d.ts +42 -0
- package/dist/src/chats/analysis-batches.js +97 -0
- package/dist/src/chats/analysis-checkpoint.d.ts +29 -0
- package/dist/src/chats/analysis-checkpoint.js +31 -0
- package/dist/src/chats/analysis-contract.d.ts +80 -0
- package/dist/src/chats/analysis-contract.js +16 -0
- package/dist/src/chats/analysis-data.d.ts +3 -0
- package/dist/src/chats/analysis-data.js +85 -0
- package/dist/src/chats/analysis-input.d.ts +18 -0
- package/dist/src/chats/analysis-input.js +97 -0
- package/dist/src/chats/analysis-links.d.ts +2 -0
- package/dist/src/chats/analysis-links.js +25 -0
- package/dist/src/chats/analysis-merge.d.ts +16 -0
- package/dist/src/chats/analysis-merge.js +134 -0
- package/dist/src/chats/analysis-prompt.d.ts +18 -0
- package/dist/src/chats/analysis-prompt.js +42 -0
- package/dist/src/chats/analysis-proposal.d.ts +4 -0
- package/dist/src/chats/analysis-proposal.js +41 -0
- package/dist/src/chats/analysis-provenance.d.ts +4 -0
- package/dist/src/chats/analysis-provenance.js +99 -0
- package/dist/src/chats/analysis-shape.d.ts +4 -0
- package/dist/src/chats/analysis-shape.js +235 -0
- package/dist/src/chats/analysis.d.ts +3 -0
- package/dist/src/chats/analysis.js +42 -0
- package/dist/src/chats/corpus-input.d.ts +5 -0
- package/dist/src/chats/corpus-input.js +288 -0
- package/dist/src/chats/destination.js +3 -1
- package/dist/src/chats/import.d.ts +8 -6
- package/dist/src/chats/import.js +195 -23
- package/dist/src/chats/input-file.d.ts +3 -0
- package/dist/src/chats/input-file.js +32 -0
- package/dist/src/chats/normalize.d.ts +11 -2
- package/dist/src/chats/normalize.js +18 -2
- package/dist/src/chats/previous-import.d.ts +5 -0
- package/dist/src/chats/previous-import.js +34 -0
- package/dist/src/chats/reader.d.ts +7 -1
- package/dist/src/chats/reader.js +46 -15
- package/dist/src/chats/redact-import.d.ts +14 -0
- package/dist/src/chats/redact-import.js +141 -0
- package/dist/src/chats/redaction.d.ts +41 -0
- package/dist/src/chats/redaction.js +161 -0
- package/dist/src/chats/reference-mapping.d.ts +16 -0
- package/dist/src/chats/reference-mapping.js +153 -0
- package/dist/src/chats/revision-input.d.ts +3 -0
- package/dist/src/chats/revision-input.js +180 -0
- package/dist/src/chats/revision.d.ts +48 -0
- package/dist/src/chats/revision.js +94 -0
- package/dist/src/chats/selection.d.ts +25 -0
- package/dist/src/chats/selection.js +109 -0
- package/dist/src/chats/source.d.ts +23 -0
- package/dist/src/chats/source.js +135 -0
- package/dist/src/chats/structure.d.ts +57 -0
- package/dist/src/chats/structure.js +216 -0
- package/dist/src/chats/workflow-generation-projection.d.ts +8 -0
- package/dist/src/chats/workflow-generation-projection.js +75 -0
- package/dist/src/chats/workflow-generation-source.d.ts +25 -0
- package/dist/src/chats/workflow-generation-source.js +124 -0
- package/dist/src/chats/workflow-generation-text.d.ts +23 -0
- package/dist/src/chats/workflow-generation-text.js +74 -0
- package/dist/src/chats/workflow-generation.d.ts +69 -0
- package/dist/src/chats/workflow-generation.js +142 -0
- package/dist/src/cli/arguments.d.ts +8 -0
- package/dist/src/cli/arguments.js +94 -13
- package/dist/src/cli/client.d.ts +1 -0
- package/dist/src/cli/client.js +38 -1
- package/dist/src/cli/commands.d.ts +3 -0
- package/dist/src/cli/commands.js +29 -11
- package/dist/src/cli/main.d.ts +2 -1
- package/dist/src/cli/main.js +61 -14
- package/dist/src/cli/render.d.ts +3 -0
- package/dist/src/cli/render.js +122 -7
- package/dist/src/cli/usage-render.d.ts +3 -0
- package/dist/src/cli/usage-render.js +28 -0
- package/dist/src/cli/usage.d.ts +3 -2
- package/dist/src/cli/usage.js +42 -7
- package/dist/src/cli/watch-actions.d.ts +10 -0
- package/dist/src/cli/watch-actions.js +58 -0
- package/dist/src/cli/watch-board-view.d.ts +44 -1
- package/dist/src/cli/watch-board-view.js +137 -18
- package/dist/src/cli/watch-board.d.ts +7 -1
- package/dist/src/cli/watch-board.js +48 -11
- package/dist/src/cli/watch-card-client.d.ts +1 -0
- package/dist/src/cli/watch-card-client.js +44 -0
- package/dist/src/cli/watch-card-forms.d.ts +2 -0
- package/dist/src/cli/watch-card-forms.js +33 -0
- package/dist/src/cli/watch-card-reply.d.ts +5 -0
- package/dist/src/cli/watch-card-reply.js +34 -0
- package/dist/src/cli/watch-card-view.d.ts +40 -0
- package/dist/src/cli/watch-card-view.js +86 -0
- package/dist/src/cli/watch-client.d.ts +1 -0
- package/dist/src/cli/watch-client.js +122 -0
- package/dist/src/cli/watch-model.d.ts +10 -4
- package/dist/src/cli/watch-model.js +61 -67
- package/dist/src/cli/watch-page.d.ts +1 -1
- package/dist/src/cli/watch-page.js +89 -86
- package/dist/src/cli/watch-phases.js +3 -3
- package/dist/src/cli/watch-pr-board.d.ts +3 -0
- package/dist/src/cli/watch-pr-board.js +26 -0
- package/dist/src/cli/watch-pr-command.d.ts +18 -0
- package/dist/src/cli/watch-pr-command.js +74 -0
- package/dist/src/cli/watch-pr-identity.d.ts +32 -0
- package/dist/src/cli/watch-pr-identity.js +87 -0
- package/dist/src/cli/watch-pr-observer.d.ts +20 -0
- package/dist/src/cli/watch-pr-observer.js +150 -0
- package/dist/src/cli/watch-pr-settings.d.ts +8 -0
- package/dist/src/cli/watch-pr-settings.js +47 -0
- package/dist/src/cli/watch-pull-request.d.ts +10 -0
- package/dist/src/cli/watch-pull-request.js +130 -0
- package/dist/src/cli/watch-reads.d.ts +7 -1
- package/dist/src/cli/watch-reads.js +44 -18
- package/dist/src/cli/watch-render.d.ts +29 -2
- package/dist/src/cli/watch-render.js +11 -3
- package/dist/src/cli/watch-run-input.d.ts +14 -0
- package/dist/src/cli/watch-run-input.js +49 -0
- package/dist/src/cli/watch-server.d.ts +3 -0
- package/dist/src/cli/watch-server.js +77 -8
- package/dist/src/cli/watch-start-view.d.ts +18 -0
- package/dist/src/cli/watch-start-view.js +77 -0
- package/dist/src/cli/watch-turn.d.ts +1 -0
- package/dist/src/cli/watch-turn.js +8 -3
- package/dist/src/cli/watch-usage.d.ts +6 -0
- package/dist/src/cli/watch-usage.js +65 -0
- package/dist/src/cli/watch-view.d.ts +22 -0
- package/dist/src/cli/watch-view.js +111 -19
- package/dist/src/cli.js +48 -6
- package/dist/src/daemon/analysis-launch.d.ts +5 -0
- package/dist/src/daemon/analysis-launch.js +81 -0
- package/dist/src/daemon/analysis-token.d.ts +6 -0
- package/dist/src/daemon/analysis-token.js +88 -0
- package/dist/src/daemon/analysis-worker.d.ts +20 -0
- package/dist/src/daemon/analysis-worker.js +271 -0
- package/dist/src/daemon/chats-batch-binding.d.ts +23 -0
- package/dist/src/daemon/chats-batch-binding.js +99 -0
- package/dist/src/daemon/chats-capture.d.ts +18 -0
- package/dist/src/daemon/chats-capture.js +194 -0
- package/dist/src/daemon/chats-checkpoints.d.ts +41 -0
- package/dist/src/daemon/chats-checkpoints.js +186 -0
- package/dist/src/daemon/chats-files.d.ts +42 -0
- package/dist/src/daemon/chats-files.js +252 -0
- package/dist/src/daemon/chats-follow-up.d.ts +38 -0
- package/dist/src/daemon/chats-follow-up.js +180 -0
- package/dist/src/daemon/chats-question.d.ts +15 -0
- package/dist/src/daemon/chats-question.js +93 -0
- package/dist/src/daemon/chats-worker.d.ts +13 -0
- package/dist/src/daemon/chats-worker.js +201 -0
- package/dist/src/daemon/claude-turn.d.ts +11 -0
- package/dist/src/daemon/claude-turn.js +96 -15
- package/dist/src/daemon/claude-worker.d.ts +2 -1
- package/dist/src/daemon/claude-worker.js +92 -45
- package/dist/src/daemon/codex-stream.js +16 -0
- package/dist/src/daemon/daemon.d.ts +8 -1
- package/dist/src/daemon/daemon.js +51 -14
- package/dist/src/daemon/delivery-router.js +6 -0
- package/dist/src/daemon/github-calls.d.ts +4 -0
- package/dist/src/daemon/github-calls.js +16 -7
- package/dist/src/daemon/github-ci.d.ts +6 -0
- package/dist/src/daemon/github-ci.js +170 -0
- package/dist/src/daemon/github-merge-call.d.ts +14 -0
- package/dist/src/daemon/github-merge-call.js +73 -0
- package/dist/src/daemon/github-merge.d.ts +3 -5
- package/dist/src/daemon/github-merge.js +52 -95
- package/dist/src/daemon/github-methods.d.ts +28 -0
- package/dist/src/daemon/github-methods.js +84 -16
- package/dist/src/daemon/github-operation.d.ts +2 -0
- package/dist/src/daemon/github-retry.d.ts +6 -0
- package/dist/src/daemon/github-retry.js +49 -0
- package/dist/src/daemon/github-ticket-status.d.ts +3 -0
- package/dist/src/daemon/github-ticket-status.js +294 -0
- package/dist/src/daemon/github-worker.js +2 -1
- package/dist/src/daemon/handoff-worker.d.ts +10 -0
- package/dist/src/daemon/handoff-worker.js +232 -0
- package/dist/src/daemon/issue-queue.d.ts +2 -0
- package/dist/src/daemon/issue-queue.js +186 -43
- package/dist/src/daemon/notify-journal.d.ts +18 -0
- package/dist/src/daemon/notify-journal.js +108 -0
- package/dist/src/daemon/notify-message.js +2 -1
- package/dist/src/daemon/notify.js +176 -37
- package/dist/src/daemon/operation-journal.d.ts +1 -0
- package/dist/src/daemon/operation-journal.js +4 -2
- package/dist/src/daemon/retrying-turn.d.ts +12 -0
- package/dist/src/daemon/retrying-turn.js +231 -0
- package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
- package/dist/src/daemon/ticket-dependency-waits.js +60 -0
- package/dist/src/daemon/ticket-registration.d.ts +8 -4
- package/dist/src/daemon/ticket-registration.js +76 -22
- package/dist/src/daemon/ticket-source.d.ts +4 -1
- package/dist/src/daemon/ticket-source.js +8 -2
- package/dist/src/decision-visibility.d.ts +2 -0
- package/dist/src/decision-visibility.js +10 -0
- package/dist/src/execution-pin.d.ts +4 -0
- package/dist/src/execution-pin.js +23 -2
- package/dist/src/host/start-delivery.d.ts +2 -1
- package/dist/src/host/start-delivery.js +1 -1
- package/dist/src/host/step-bridge-host.d.ts +1 -0
- package/dist/src/host/step-bridge-host.js +16 -0
- package/dist/src/host/world-reconciliation.d.ts +3 -0
- package/dist/src/host/world-reconciliation.js +9 -0
- package/dist/src/host/world-runs.js +14 -1
- package/dist/src/issue-identity.d.ts +6 -0
- package/dist/src/issue-identity.js +23 -0
- package/dist/src/service/queue-runs.d.ts +3 -0
- package/dist/src/service/queue-runs.js +39 -0
- package/dist/src/service/registry.d.ts +8 -2
- package/dist/src/service/registry.js +20 -8
- package/dist/src/service/replies.d.ts +2 -0
- package/dist/src/service/run-handlers.js +54 -30
- package/dist/src/service/service.d.ts +3 -0
- package/dist/src/service/service.js +3 -1
- package/dist/src/service/submission-handler.d.ts +1 -0
- package/dist/src/service/submission-handler.js +92 -13
- package/dist/src/service/worker-totals.d.ts +3 -0
- package/dist/src/service/worker-totals.js +52 -0
- package/dist/src/step-bridge.d.ts +9 -0
- package/dist/src/steps/handoff.d.ts +2 -0
- package/dist/src/steps/handoff.js +13 -0
- package/dist/src/ticket-dependencies.d.ts +1 -0
- package/dist/src/ticket-dependencies.js +15 -0
- package/dist/src/ticket-status.d.ts +8 -0
- package/dist/src/ticket-status.js +48 -0
- package/dist/src/token-prices.d.ts +21 -0
- package/dist/src/token-prices.js +108 -0
- package/dist/src/worker-usage.d.ts +31 -0
- package/dist/src/worker-usage.js +44 -0
- package/dist/src/workflow-admission.d.ts +1 -0
- package/dist/src/workflow-candidate.d.ts +29 -0
- package/dist/src/workflow-candidate.js +60 -0
- package/dist/src/workflow-contracts.d.ts +4 -0
- package/dist/src/workflow-contracts.js +32 -5
- package/dist/src/workflow-declaration.d.ts +12 -1
- package/dist/src/workflow-declaration.js +71 -13
- package/dist/src/workflow-discovery.d.ts +18 -0
- package/dist/src/workflow-discovery.js +33 -0
- package/dist/src/workflow-refusals.d.ts +6 -0
- package/dist/src/workflow-refusals.js +39 -0
- package/dist/src/workflows.d.ts +3 -1
- package/dist/src/workflows.js +2 -0
- package/dist/tools/admit-workflow.d.ts +13 -0
- package/dist/tools/admit-workflow.js +94 -0
- package/dist/tools/self-host-processes.js +7 -2
- package/dist/tools/self-host-project.d.ts +17 -0
- package/dist/tools/self-host-project.js +177 -0
- package/dist/tools/self-host-workflows.d.ts +1 -1
- package/dist/tools/self-host-workflows.js +2 -2
- package/dist/tools/self-host.js +30 -84
- package/dist/tools/self-update-host.d.ts +7 -0
- package/dist/tools/self-update-host.js +48 -1
- package/dist/tools/self-update.d.ts +1 -0
- package/dist/tools/self-update.js +85 -13
- package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
- package/dist/tools/workflow-bundle-dependencies.js +93 -0
- package/dist/tools/workflow-bundles.d.ts +20 -0
- package/dist/tools/workflow-bundles.js +173 -0
- package/dist/tools/workflow-candidate-counts.d.ts +8 -0
- package/dist/tools/workflow-candidate-counts.js +251 -0
- package/dist/tools/workflow-candidate-program.d.ts +11 -0
- package/dist/tools/workflow-candidate-program.js +78 -0
- package/dist/tools/workflow-candidate-source.d.ts +6 -0
- package/dist/tools/workflow-candidate-source.js +107 -0
- package/dist/tools/workflow-candidate-syntax.d.ts +15 -0
- package/dist/tools/workflow-candidate-syntax.js +219 -0
- package/dist/tools/workflow-folder-capture.d.ts +17 -0
- package/dist/tools/workflow-folder-capture.js +216 -0
- package/dist/tools/workflow-folders.d.ts +33 -0
- package/dist/tools/workflow-folders.js +150 -0
- package/dist/tools/workflow-source-effects.d.ts +10 -0
- package/dist/tools/workflow-source-effects.js +213 -0
- package/dist/workflows/analyze-chats.d.ts +15 -0
- package/dist/workflows/analyze-chats.declaration.json +22 -0
- package/dist/workflows/analyze-chats.js +250 -0
- package/dist/workflows/develop-prd.js +71 -3
- package/dist/workflows/develop-ticket.d.ts +1 -7
- package/dist/workflows/develop-ticket.js +47 -141
- package/dist/workflows/issue-labels.d.ts +3 -1
- package/dist/workflows/issue-labels.js +34 -0
- package/dist/workflows/ticket-prompts.d.ts +35 -0
- package/dist/workflows/ticket-prompts.js +143 -0
- package/package.json +25 -5
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, realpath, rm, symlink, writeFile, } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { findPackageJSON } from "node:module";
|
|
6
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { checkWorkflowCandidate, } from "../src/workflow-candidate.js";
|
|
9
|
+
import { candidatePackageRoot, } from "./workflow-candidate-program.js";
|
|
10
|
+
import { analyzeWorkflowCandidate } from "./workflow-candidate-source.js";
|
|
11
|
+
import { isWorkflowManifest } from "./workflow-manifest.js";
|
|
12
|
+
export async function admitWorkflowCandidate(input, installed = {}) {
|
|
13
|
+
const { source, declaration } = input;
|
|
14
|
+
if (Buffer.from(source, "utf8").toString("utf8") !== source)
|
|
15
|
+
return { kind: "refused", codes: ["unsupported-source"] };
|
|
16
|
+
try {
|
|
17
|
+
const packageRoot = resolve(installed.packageRoot ?? candidatePackageRoot);
|
|
18
|
+
const facts = analyzeWorkflowCandidate(source, { packageRoot });
|
|
19
|
+
const codes = checkWorkflowCandidate({ declaration, ...facts });
|
|
20
|
+
if (codes.length > 0)
|
|
21
|
+
return { kind: "refused", codes };
|
|
22
|
+
return await compiledCandidate(source, packageRoot);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { kind: "refused", codes: ["compile-failed"] };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function compiledCandidate(source, packageRoot) {
|
|
29
|
+
const directory = await realpath(await mkdtemp(join(tmpdir(), "cloving-candidate-")));
|
|
30
|
+
try {
|
|
31
|
+
await prepareCandidateProject(directory, { source, packageRoot });
|
|
32
|
+
if (!(await compile(directory)))
|
|
33
|
+
return { kind: "refused", codes: ["compile-failed"] };
|
|
34
|
+
const artifactDirectory = join(directory, "artifacts");
|
|
35
|
+
const manifest = JSON.parse(await readFile(join(artifactDirectory, "manifest.json"), "utf8"));
|
|
36
|
+
if (!isWorkflowManifest(manifest) ||
|
|
37
|
+
Object.values(manifest.workflows ?? {}).flatMap((entries) => Object.values(entries)).length !== 1)
|
|
38
|
+
return { kind: "refused", codes: ["compile-failed"] };
|
|
39
|
+
const digest = createHash("sha256");
|
|
40
|
+
for (const name of [
|
|
41
|
+
"manifest.json",
|
|
42
|
+
"flow.mjs",
|
|
43
|
+
"steps.mjs",
|
|
44
|
+
"client.mjs",
|
|
45
|
+
]) {
|
|
46
|
+
const bytes = await readFile(join(artifactDirectory, name));
|
|
47
|
+
digest.update(JSON.stringify([name, bytes.length]));
|
|
48
|
+
digest.update(bytes);
|
|
49
|
+
}
|
|
50
|
+
return { kind: "admitted", artifactDigest: digest.digest("hex") };
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await rm(directory, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function prepareCandidateProject(directory, input) {
|
|
57
|
+
const { source, packageRoot } = input;
|
|
58
|
+
await mkdir(join(directory, "workflows"));
|
|
59
|
+
await mkdir(join(directory, "node_modules"));
|
|
60
|
+
await symlink(packageRoot, join(directory, "node_modules/cloving"));
|
|
61
|
+
const runtime = findPackageJSON("workflow", import.meta.url);
|
|
62
|
+
if (!runtime)
|
|
63
|
+
throw new Error("candidate-runtime-unavailable");
|
|
64
|
+
await symlink(dirname(runtime), join(directory, "node_modules/workflow"));
|
|
65
|
+
await writeFile(join(directory, "package.json"), '{"name":"candidate-project","private":true,"type":"module"}');
|
|
66
|
+
await writeFile(join(directory, "tsconfig.json"), JSON.stringify({
|
|
67
|
+
compilerOptions: {
|
|
68
|
+
target: "ES2024",
|
|
69
|
+
module: "ESNext",
|
|
70
|
+
moduleResolution: "Bundler",
|
|
71
|
+
types: [],
|
|
72
|
+
},
|
|
73
|
+
include: ["workflows/candidate.ts"],
|
|
74
|
+
}));
|
|
75
|
+
await writeFile(join(directory, "workflows/candidate.ts"), source, "utf8");
|
|
76
|
+
}
|
|
77
|
+
function compile(directory) {
|
|
78
|
+
const extension = extname(fileURLToPath(import.meta.url));
|
|
79
|
+
const executable = fileURLToPath(new URL(`./compile-workflows${extension}`, import.meta.url));
|
|
80
|
+
return new Promise((settle) => {
|
|
81
|
+
const child = spawn(process.execPath, [executable, "workflows", "artifacts"], {
|
|
82
|
+
cwd: directory,
|
|
83
|
+
env: { PATH: dirname(process.execPath), TMPDIR: tmpdir() },
|
|
84
|
+
stdio: "ignore",
|
|
85
|
+
timeout: 30000,
|
|
86
|
+
});
|
|
87
|
+
child.once("error", () => {
|
|
88
|
+
settle(false);
|
|
89
|
+
});
|
|
90
|
+
child.once("close", (code) => {
|
|
91
|
+
settle(code === 0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -4,7 +4,7 @@ import { extname, join } from "node:path";
|
|
|
4
4
|
import { setTimeout as delay } from "node:timers/promises";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { selfUpdater } from "./self-update.js";
|
|
7
|
-
import {
|
|
7
|
+
import { selfUpdateActive } from "./self-update-host.js";
|
|
8
8
|
function launched(argumentsList, settings) {
|
|
9
9
|
const child = spawn(process.execPath, argumentsList, {
|
|
10
10
|
cwd: settings.directory,
|
|
@@ -58,7 +58,11 @@ async function polled(settings, lifecycle) {
|
|
|
58
58
|
directory: settings.directory,
|
|
59
59
|
git: updatingGit(settings, lifecycle.stopping),
|
|
60
60
|
active: async () => lifecycle.stopping.aborted ||
|
|
61
|
-
(await
|
|
61
|
+
(await selfUpdateActive({
|
|
62
|
+
directory: settings.directory,
|
|
63
|
+
runtimeDirectory: settings.runtime,
|
|
64
|
+
signal: lifecycle.stopping,
|
|
65
|
+
})),
|
|
62
66
|
stop: async () => {
|
|
63
67
|
if (lifecycle.stopping.aborted)
|
|
64
68
|
throw new Error("self-update-stopped");
|
|
@@ -102,6 +106,7 @@ function hostedChildren(settings) {
|
|
|
102
106
|
environment: {
|
|
103
107
|
...process.env,
|
|
104
108
|
CLOVING_RUNTIME_DIR: settings.runtime,
|
|
109
|
+
CLOVING_WATCH_REPOSITORY: settings.repository,
|
|
105
110
|
},
|
|
106
111
|
}),
|
|
107
112
|
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type DeclaredWorkflow } from "../src/workflow-declaration.ts";
|
|
2
|
+
import type { WorkflowRefusal } from "../src/workflow-refusals.ts";
|
|
3
|
+
interface ProjectSettings {
|
|
4
|
+
readonly product: string;
|
|
5
|
+
readonly project: string;
|
|
6
|
+
readonly repository: string;
|
|
7
|
+
readonly home: string;
|
|
8
|
+
readonly xdgConfigHome?: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export interface RegisteredWorkflows {
|
|
11
|
+
readonly repository: string;
|
|
12
|
+
readonly manifests: Readonly<Record<string, string>>;
|
|
13
|
+
readonly declarations: readonly DeclaredWorkflow[];
|
|
14
|
+
readonly workflowRefusals: readonly WorkflowRefusal[];
|
|
15
|
+
}
|
|
16
|
+
export declare function preparedProject(settings: ProjectSettings): Promise<RegisteredWorkflows>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { copyFile, mkdir, readFile, rm, symlink, writeFile, } from "node:fs/promises";
|
|
4
|
+
import { findPackageJSON } from "node:module";
|
|
5
|
+
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
6
|
+
import packageMetadata from "#package" with { type: "json" };
|
|
7
|
+
import { record } from "../src/protocol.js";
|
|
8
|
+
import { isWorkflowDeclaration, } from "../src/workflow-declaration.js";
|
|
9
|
+
import { bundledWorkflowIds, } from "../src/workflow-discovery.js";
|
|
10
|
+
import { workflowDeclarations, workflowFiles, workflowManifests, } from "./self-host-workflows.js";
|
|
11
|
+
import { loadWorkflowFolders, } from "./workflow-folders.js";
|
|
12
|
+
import { isWorkflowManifest } from "./workflow-manifest.js";
|
|
13
|
+
import { retainWorkflowBundle } from "./workflow-bundles.js";
|
|
14
|
+
import { workflowBundleDependencies, workflowPackageRoot, } from "./workflow-bundle-dependencies.js";
|
|
15
|
+
async function initializeProject(settings) {
|
|
16
|
+
const { project, product } = settings;
|
|
17
|
+
await rm(project, { recursive: true, force: true });
|
|
18
|
+
await mkdir(join(project, "workflows"), { recursive: true, mode: 0o700 });
|
|
19
|
+
await writeFile(join(project, "package.json"), '{"name":"cloving-self-host","private":true,"type":"module"}');
|
|
20
|
+
const files = await workflowFiles(join(product, "workflows"));
|
|
21
|
+
for (const file of files)
|
|
22
|
+
await copyWorkflow(settings, file);
|
|
23
|
+
const modules = join(project, "node_modules");
|
|
24
|
+
await mkdir(join(modules, "cloving"), { recursive: true });
|
|
25
|
+
for (const name of Object.keys(packageMetadata.dependencies)) {
|
|
26
|
+
const location = findPackageJSON(name, join(product, "package.json"));
|
|
27
|
+
if (location === undefined)
|
|
28
|
+
throw new Error(`missing-runtime-dependency: ${name}`);
|
|
29
|
+
await mkdir(dirname(join(modules, name)), { recursive: true });
|
|
30
|
+
await symlink(dirname(location), join(modules, name));
|
|
31
|
+
}
|
|
32
|
+
await symlink(join(product, "src"), join(modules, "cloving", "src"));
|
|
33
|
+
await writeFile(join(modules, "cloving", "package.json"), JSON.stringify({
|
|
34
|
+
name: packageMetadata.name,
|
|
35
|
+
version: packageMetadata.version,
|
|
36
|
+
type: "module",
|
|
37
|
+
exports: Object.fromEntries(Object.keys(packageMetadata.exports)
|
|
38
|
+
.filter((subpath) => subpath.startsWith("./workflows"))
|
|
39
|
+
.map((subpath) => [
|
|
40
|
+
subpath,
|
|
41
|
+
`./src/${subpath.slice("./workflows/".length) || "workflows"}${extname(import.meta.filename)}`,
|
|
42
|
+
])),
|
|
43
|
+
}));
|
|
44
|
+
return files;
|
|
45
|
+
}
|
|
46
|
+
async function compile(settings) {
|
|
47
|
+
const { product, project } = settings;
|
|
48
|
+
await rm(join(project, "artifacts"), { recursive: true, force: true });
|
|
49
|
+
await new Promise((settle, reject) => {
|
|
50
|
+
const child = spawn(process.execPath, [
|
|
51
|
+
join(product, `tools/compile-workflows${extname(import.meta.filename)}`),
|
|
52
|
+
"workflows",
|
|
53
|
+
"artifacts",
|
|
54
|
+
], { cwd: project, env: process.env, stdio: "ignore", timeout: 30000 });
|
|
55
|
+
child.once("error", reject);
|
|
56
|
+
child.once("close", (code) => {
|
|
57
|
+
if (code === 0)
|
|
58
|
+
settle();
|
|
59
|
+
else
|
|
60
|
+
reject(new Error("The workflows did not compile."));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
const compiled = JSON.parse(await readFile(join(project, "artifacts/manifest.json"), "utf8"));
|
|
64
|
+
if (!isWorkflowManifest(compiled))
|
|
65
|
+
throw new Error("The compiled workflow manifest is invalid.");
|
|
66
|
+
return compiled;
|
|
67
|
+
}
|
|
68
|
+
function reservations(input) {
|
|
69
|
+
const { files, manifests, declarations } = input;
|
|
70
|
+
return [
|
|
71
|
+
...files.map((file) => ({
|
|
72
|
+
baseName: basename(file, extname(file)),
|
|
73
|
+
})),
|
|
74
|
+
...Object.entries(manifests).map(([functionName, manifest]) => ({
|
|
75
|
+
baseName: manifest.name,
|
|
76
|
+
workflowId: manifest.workflowId,
|
|
77
|
+
functionName,
|
|
78
|
+
})),
|
|
79
|
+
...[
|
|
80
|
+
...Object.values(bundledWorkflowIds),
|
|
81
|
+
...declarations.map((item) => item.workflowId),
|
|
82
|
+
].map((workflowId) => ({ workflowId })),
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
async function stageCandidates(project, candidates) {
|
|
86
|
+
if (candidates.length === 0)
|
|
87
|
+
return [];
|
|
88
|
+
const directory = join(project, "workflows", "operators");
|
|
89
|
+
await mkdir(directory, { mode: 0o700 });
|
|
90
|
+
const staged = [];
|
|
91
|
+
for (const candidate of candidates) {
|
|
92
|
+
const name = createHash("sha256")
|
|
93
|
+
.update(JSON.stringify([
|
|
94
|
+
candidate.scope,
|
|
95
|
+
candidate.baseName,
|
|
96
|
+
candidate.source,
|
|
97
|
+
candidate.declaration,
|
|
98
|
+
]))
|
|
99
|
+
.digest("hex");
|
|
100
|
+
const file = join(directory, `${name}.ts`);
|
|
101
|
+
await writeFile(file, candidate.source);
|
|
102
|
+
await writeFile(join(directory, `${name}.declaration.json`), candidate.declaration);
|
|
103
|
+
staged.push({ candidate, file });
|
|
104
|
+
}
|
|
105
|
+
return staged;
|
|
106
|
+
}
|
|
107
|
+
function operatorDeclaration(staged, compiled) {
|
|
108
|
+
const { candidate, project } = staged;
|
|
109
|
+
const declaration = record(JSON.parse(candidate.declaration))?.["workflow"];
|
|
110
|
+
const entries = Object.entries(compiled.workflows ?? {}).filter(([file]) => resolve(project, file) === staged.file);
|
|
111
|
+
const functions = entries.flatMap(([, functions]) => Object.values(functions));
|
|
112
|
+
const [workflow] = functions;
|
|
113
|
+
if (!isWorkflowDeclaration(declaration) ||
|
|
114
|
+
functions.length !== 1 ||
|
|
115
|
+
workflow === undefined)
|
|
116
|
+
throw new Error("The admitted workflow is missing from the compiled bundle.");
|
|
117
|
+
return {
|
|
118
|
+
...declaration,
|
|
119
|
+
capabilities: [...new Set(declaration.capabilities)],
|
|
120
|
+
functionName: workflow.workflowId.slice(workflow.workflowId.lastIndexOf("//") + 2),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async function copyWorkflow(settings, file) {
|
|
124
|
+
const { product, project } = settings;
|
|
125
|
+
await copyFile(join(product, "workflows", file), join(project, "workflows", file));
|
|
126
|
+
const sidecar = `${basename(file, extname(file))}.declaration.json`;
|
|
127
|
+
const declaration = await readFile(join(product, "workflows", sidecar)).catch((error) => {
|
|
128
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
129
|
+
return undefined;
|
|
130
|
+
throw error;
|
|
131
|
+
});
|
|
132
|
+
if (declaration !== undefined)
|
|
133
|
+
await writeFile(join(project, "workflows", sidecar), declaration);
|
|
134
|
+
}
|
|
135
|
+
export async function preparedProject(settings) {
|
|
136
|
+
const { product, project } = settings;
|
|
137
|
+
const files = await initializeProject(settings);
|
|
138
|
+
let compiled = await compile(settings);
|
|
139
|
+
const bundled = workflowManifests(compiled);
|
|
140
|
+
const declarations = await workflowDeclarations(join(project, "workflows"), bundled);
|
|
141
|
+
const folders = await loadWorkflowFolders({
|
|
142
|
+
...settings,
|
|
143
|
+
bundled: reservations({ files, manifests: bundled, declarations }),
|
|
144
|
+
}, { packageRoot: await workflowPackageRoot(product) });
|
|
145
|
+
const staged = await stageCandidates(project, folders.candidates);
|
|
146
|
+
if (staged.length > 0)
|
|
147
|
+
compiled = await compile(settings);
|
|
148
|
+
const combined = [
|
|
149
|
+
...declarations,
|
|
150
|
+
...staged.map((candidate) => operatorDeclaration({ ...candidate, project }, compiled)),
|
|
151
|
+
];
|
|
152
|
+
const manifests = {};
|
|
153
|
+
for (const [functionName, manifest] of Object.entries(workflowManifests(compiled, combined))) {
|
|
154
|
+
const path = join(project, `${manifest.name}.workflow.json`);
|
|
155
|
+
await writeFile(path, JSON.stringify(manifest));
|
|
156
|
+
Object.defineProperty(manifests, functionName, {
|
|
157
|
+
value: path,
|
|
158
|
+
enumerable: true,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
await writeFile(join(project, "declarations.json"), JSON.stringify(combined));
|
|
162
|
+
await writeFile(join(project, "dependencies.json"), await workflowBundleDependencies({
|
|
163
|
+
product,
|
|
164
|
+
packages: Object.keys(packageMetadata.dependencies),
|
|
165
|
+
}));
|
|
166
|
+
await retainWorkflowBundle({
|
|
167
|
+
project,
|
|
168
|
+
repository: folders.repository,
|
|
169
|
+
directory: join(dirname(project), "workflow-bundles"),
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
repository: folders.repository,
|
|
173
|
+
manifests,
|
|
174
|
+
declarations: combined,
|
|
175
|
+
workflowRefusals: folders.refusals,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -11,5 +11,5 @@ interface HostManifest {
|
|
|
11
11
|
}
|
|
12
12
|
export declare function workflowFiles(directory: string): Promise<string[]>;
|
|
13
13
|
export declare function workflowDeclarations(directory: string, manifests: Readonly<Record<string, HostManifest>>): Promise<readonly DeclaredWorkflow[]>;
|
|
14
|
-
export declare function workflowManifests(compiled: WorkflowManifest): Readonly<Record<string, HostManifest>>;
|
|
14
|
+
export declare function workflowManifests(compiled: WorkflowManifest, declarations?: readonly DeclaredWorkflow[]): Readonly<Record<string, HostManifest>>;
|
|
15
15
|
export {};
|
|
@@ -45,7 +45,7 @@ export async function workflowDeclarations(directory, manifests) {
|
|
|
45
45
|
}
|
|
46
46
|
return declarations;
|
|
47
47
|
}
|
|
48
|
-
export function workflowManifests(compiled) {
|
|
48
|
+
export function workflowManifests(compiled, declarations = []) {
|
|
49
49
|
const names = new Set();
|
|
50
50
|
const steps = Object.values(compiled.steps ?? {})
|
|
51
51
|
.flatMap((entries) => Object.values(entries))
|
|
@@ -68,7 +68,7 @@ export function workflowManifests(compiled) {
|
|
|
68
68
|
name: basename(file, extname(file)),
|
|
69
69
|
workflowId,
|
|
70
70
|
steps,
|
|
71
|
-
capabilities: ["claude", "github"],
|
|
71
|
+
capabilities: declarations.find((declaration) => declaration.functionName === functionName)?.capabilities ?? ["claude", "github"],
|
|
72
72
|
resources: [],
|
|
73
73
|
artifacts: "artifacts",
|
|
74
74
|
},
|
package/dist/tools/self-host.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { isProfilesFile } from "../src/turn-profile.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { parseFallbackModels, parseTokenPrices, } from "../src/token-prices.js";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { readFile, realpath, writeFile } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
4
6
|
import { dirname, extname, join, resolve } from "node:path";
|
|
5
|
-
import packageMetadata from "#package" with { type: "json" };
|
|
6
|
-
import { findPackageJSON } from "node:module";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
|
-
import {
|
|
9
|
-
import { isWorkflowManifest } from "./workflow-manifest.js";
|
|
8
|
+
import { preparedProject, } from "./self-host-project.js";
|
|
10
9
|
import { selfUpdateMilliseconds } from "./self-update-host.js";
|
|
11
10
|
import { hostedPrograms } from "./self-host-processes.js";
|
|
12
11
|
const product = resolve(import.meta.dirname, "..");
|
|
@@ -31,7 +30,7 @@ if (runtimeArgument === undefined)
|
|
|
31
30
|
throw new Error("The start program needs --runtime. Use: cloving start");
|
|
32
31
|
const runtime = resolve(runtimeArgument);
|
|
33
32
|
const directory = dirname(runtime);
|
|
34
|
-
const repository = topLevel(resolve(flag("--repository") ?? process.cwd()));
|
|
33
|
+
const repository = await realpath(topLevel(resolve(flag("--repository") ?? process.cwd())));
|
|
35
34
|
const updateMilliseconds = await selfUpdateMilliseconds({
|
|
36
35
|
seconds: process.env["CLOVING_SELF_UPDATE_SECONDS"],
|
|
37
36
|
repository,
|
|
@@ -83,6 +82,16 @@ async function profilesFile() {
|
|
|
83
82
|
}
|
|
84
83
|
throw new Error("The daemon did not start: invalid-profiles");
|
|
85
84
|
}
|
|
85
|
+
function queueLanes() {
|
|
86
|
+
const value = process.env["CLOVING_QUEUE_LANES"];
|
|
87
|
+
if (value === undefined)
|
|
88
|
+
return 1;
|
|
89
|
+
if (!/^[1-4]$/.test(value))
|
|
90
|
+
throw new Error("The daemon did not start: invalid-queue-lanes");
|
|
91
|
+
if (process.env["CLOVING_QUEUE_SECONDS"] === undefined)
|
|
92
|
+
throw new Error("The daemon did not start: queue-lanes-needs-queue");
|
|
93
|
+
return Number(value);
|
|
94
|
+
}
|
|
86
95
|
function queueInterval(commands) {
|
|
87
96
|
const value = process.env["CLOVING_QUEUE_SECONDS"];
|
|
88
97
|
if (value === undefined)
|
|
@@ -108,65 +117,6 @@ function listed(name) {
|
|
|
108
117
|
throw new Error(`${name} is not a JSON list of texts.`);
|
|
109
118
|
return list.map(String);
|
|
110
119
|
}
|
|
111
|
-
function record(value) {
|
|
112
|
-
return typeof value === "object" && value !== null ? { ...value } : {};
|
|
113
|
-
}
|
|
114
|
-
function ended(argumentsList, environment) {
|
|
115
|
-
return new Promise((settle, reject) => {
|
|
116
|
-
const child = spawn(process.execPath, argumentsList, {
|
|
117
|
-
cwd: project,
|
|
118
|
-
env: environment,
|
|
119
|
-
stdio: "inherit",
|
|
120
|
-
});
|
|
121
|
-
for (const signal of ["SIGINT", "SIGTERM"])
|
|
122
|
-
process.on(signal, () => child.kill(signal));
|
|
123
|
-
child.once("error", reject);
|
|
124
|
-
child.once("close", (status) => {
|
|
125
|
-
settle(status ?? 1);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
async function linkedPackages() {
|
|
130
|
-
const modules = join(project, "node_modules");
|
|
131
|
-
await mkdir(join(modules, "cloving"), { recursive: true });
|
|
132
|
-
for (const name of Object.keys(packageMetadata.dependencies)) {
|
|
133
|
-
const location = findPackageJSON(name, join(product, "package.json"));
|
|
134
|
-
if (location === undefined)
|
|
135
|
-
throw new Error(`missing-runtime-dependency: ${name}`);
|
|
136
|
-
await mkdir(dirname(join(modules, name)), { recursive: true });
|
|
137
|
-
await symlink(dirname(location), join(modules, name));
|
|
138
|
-
}
|
|
139
|
-
const manifest = record(packageMetadata);
|
|
140
|
-
const exported = Object.keys(record(manifest["exports"])).filter((subpath) => subpath.startsWith("./workflows"));
|
|
141
|
-
await symlink(join(product, "src"), join(modules, "cloving", "src"));
|
|
142
|
-
await writeFile(join(modules, "cloving", "package.json"), JSON.stringify({
|
|
143
|
-
name: manifest["name"],
|
|
144
|
-
version: manifest["version"],
|
|
145
|
-
type: "module",
|
|
146
|
-
exports: Object.fromEntries(exported.map((subpath) => [
|
|
147
|
-
subpath,
|
|
148
|
-
`./src/${subpath.slice("./workflows/".length) || "workflows"}${extname(import.meta.filename)}`,
|
|
149
|
-
])),
|
|
150
|
-
}));
|
|
151
|
-
}
|
|
152
|
-
async function registered() {
|
|
153
|
-
const compiled = JSON.parse(await readFile(join(project, "artifacts/manifest.json"), "utf8"));
|
|
154
|
-
if (!isWorkflowManifest(compiled))
|
|
155
|
-
throw new Error("The compiled workflow manifest is invalid.");
|
|
156
|
-
const manifests = workflowManifests(compiled);
|
|
157
|
-
const declarations = await workflowDeclarations(join(product, "workflows"), manifests);
|
|
158
|
-
const paths = new Map();
|
|
159
|
-
for (const [functionName, manifest] of Object.entries(manifests)) {
|
|
160
|
-
const path = join(project, `${manifest.name}.workflow.json`);
|
|
161
|
-
const declared = declarations.find((entry) => entry.functionName === functionName);
|
|
162
|
-
await writeFile(path, JSON.stringify({
|
|
163
|
-
...manifest,
|
|
164
|
-
capabilities: declared?.capabilities ?? manifest.capabilities,
|
|
165
|
-
}));
|
|
166
|
-
paths.set(functionName, path);
|
|
167
|
-
}
|
|
168
|
-
return { manifests: Object.fromEntries(paths), declarations };
|
|
169
|
-
}
|
|
170
120
|
function source(file) {
|
|
171
121
|
return JSON.stringify(pathToFileURL(join(product, file.replace(/\.ts$/, extname(import.meta.filename)))).href);
|
|
172
122
|
}
|
|
@@ -174,7 +124,6 @@ async function launchers(commands, workflows) {
|
|
|
174
124
|
const settings = {
|
|
175
125
|
...commands,
|
|
176
126
|
directory,
|
|
177
|
-
repository,
|
|
178
127
|
concurrency,
|
|
179
128
|
runtimeDirectory: runtime,
|
|
180
129
|
...workflows,
|
|
@@ -213,22 +162,8 @@ function guide() {
|
|
|
213
162
|
"",
|
|
214
163
|
].join("\n");
|
|
215
164
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
await mkdir(join(project, "workflows"), { recursive: true });
|
|
219
|
-
await writeFile(join(project, "package.json"), '{"name":"cloving-self-host","private":true,"type":"module"}');
|
|
220
|
-
for (const file of await workflowFiles(join(product, "workflows")))
|
|
221
|
-
await copyFile(join(product, "workflows", file), join(project, "workflows", file));
|
|
222
|
-
await linkedPackages();
|
|
223
|
-
const compiled = await ended([
|
|
224
|
-
join(product, `tools/compile-workflows${extname(import.meta.filename)}`),
|
|
225
|
-
"workflows",
|
|
226
|
-
"artifacts",
|
|
227
|
-
], process.env);
|
|
228
|
-
if (compiled !== 0)
|
|
229
|
-
throw new Error("The workflows did not compile.");
|
|
230
|
-
return registered();
|
|
231
|
-
}
|
|
165
|
+
const tokenPrices = parseTokenPrices(process.env["CLOVING_TOKEN_PRICES"]);
|
|
166
|
+
const fallbackModels = parseFallbackModels(process.env["CLOVING_FALLBACK_MODELS"]);
|
|
232
167
|
const profiles = await profilesFile();
|
|
233
168
|
const worker = selectedWorker();
|
|
234
169
|
const command = worker === "codex"
|
|
@@ -236,15 +171,26 @@ const command = worker === "codex"
|
|
|
236
171
|
: (listed("CLOVING_CLAUDE_COMMAND") ?? defaultCommand);
|
|
237
172
|
const nextCommand = listed("CLOVING_NEXT_COMMAND");
|
|
238
173
|
const ticketCommand = listed("CLOVING_TICKET_COMMAND");
|
|
174
|
+
const lanes = queueLanes();
|
|
239
175
|
const queueMilliseconds = queueInterval({ nextCommand, ticketCommand });
|
|
240
|
-
const manifests = await
|
|
176
|
+
const manifests = await preparedProject({
|
|
177
|
+
product,
|
|
178
|
+
project,
|
|
179
|
+
repository,
|
|
180
|
+
home: homedir(),
|
|
181
|
+
xdgConfigHome: process.env["XDG_CONFIG_HOME"],
|
|
182
|
+
});
|
|
241
183
|
await launchers({
|
|
184
|
+
tokenPrices,
|
|
185
|
+
fallbackModels,
|
|
242
186
|
worker,
|
|
243
187
|
profiles,
|
|
244
188
|
command,
|
|
245
189
|
ticketCommand,
|
|
246
190
|
nextCommand,
|
|
247
191
|
queueMilliseconds,
|
|
192
|
+
queueLanes: lanes,
|
|
193
|
+
resetQueue: flags.includes("--reset-queue"),
|
|
248
194
|
notifyCommand: listed("CLOVING_NOTIFY_COMMAND"),
|
|
249
195
|
githubCommand: listed("CLOVING_GH_COMMAND"),
|
|
250
196
|
checkCommand: listed("CLOVING_CHECK_COMMAND"),
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
interface ActivitySettings {
|
|
2
|
+
readonly directory: string;
|
|
3
|
+
readonly runtimeDirectory: string;
|
|
4
|
+
readonly signal?: AbortSignal;
|
|
5
|
+
}
|
|
6
|
+
export declare function selfUpdateActive(settings: ActivitySettings): Promise<boolean>;
|
|
1
7
|
export declare function selfUpdateMilliseconds(settings: {
|
|
2
8
|
readonly seconds: string | undefined;
|
|
3
9
|
readonly repository: string;
|
|
4
10
|
readonly product: string;
|
|
5
11
|
}): Promise<number | undefined>;
|
|
6
12
|
export declare function workerTurnActive(directory: string): Promise<boolean>;
|
|
13
|
+
export {};
|
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
import { access, readdir, realpath } from "node:fs/promises";
|
|
2
|
-
import {
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { extname, join } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { record } from "../src/protocol.js";
|
|
6
|
+
async function runPage(settings, after) {
|
|
7
|
+
const output = await promisify(execFile)(process.execPath, [
|
|
8
|
+
join(import.meta.dirname, `../src/cli${extname(import.meta.filename)}`),
|
|
9
|
+
"status",
|
|
10
|
+
"--json",
|
|
11
|
+
"--limit",
|
|
12
|
+
"500",
|
|
13
|
+
...(after === "" ? [] : ["--after", after]),
|
|
14
|
+
], {
|
|
15
|
+
env: { ...process.env, CLOVING_RUNTIME_DIR: settings.runtimeDirectory },
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
timeout: 30000,
|
|
18
|
+
signal: settings.signal,
|
|
19
|
+
});
|
|
20
|
+
const page = record(JSON.parse(output.stdout));
|
|
21
|
+
if (!page)
|
|
22
|
+
throw new Error("invalid-run-list");
|
|
23
|
+
return page;
|
|
24
|
+
}
|
|
25
|
+
export async function selfUpdateActive(settings) {
|
|
26
|
+
if (await present(join(settings.directory, "queue-submission")))
|
|
27
|
+
return true;
|
|
28
|
+
if (await workerTurnActive(settings.directory))
|
|
29
|
+
return true;
|
|
30
|
+
let after = "";
|
|
31
|
+
do {
|
|
32
|
+
const page = await runPage(settings, after);
|
|
33
|
+
const runs = page["runs"];
|
|
34
|
+
if (!Array.isArray(runs))
|
|
35
|
+
throw new Error("invalid-run-list");
|
|
36
|
+
if (runs.some((value) => {
|
|
37
|
+
const run = record(value);
|
|
38
|
+
if (!run)
|
|
39
|
+
throw new Error("invalid-run-status");
|
|
40
|
+
return !["completed", "failed", "cancelled"].includes(String(run["state"]));
|
|
41
|
+
}))
|
|
42
|
+
return true;
|
|
43
|
+
const next = page["next"];
|
|
44
|
+
if (next !== null && (typeof next !== "string" || next <= after))
|
|
45
|
+
throw new Error("invalid-run-page");
|
|
46
|
+
after = next;
|
|
47
|
+
} while (after !== null);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
3
50
|
export async function selfUpdateMilliseconds(settings) {
|
|
4
51
|
const { seconds } = settings;
|
|
5
52
|
if (seconds === undefined)
|
|
@@ -5,6 +5,7 @@ export interface SelfUpdateSettings {
|
|
|
5
5
|
readonly stop: () => Promise<void>;
|
|
6
6
|
readonly error: (line: string) => void;
|
|
7
7
|
}
|
|
8
|
+
export declare function lockRequiresInstall(before: string, after: string): boolean;
|
|
8
9
|
export declare function selfUpdater(settings: SelfUpdateSettings): {
|
|
9
10
|
readonly check: () => Promise<number | undefined>;
|
|
10
11
|
};
|