cloving 1.0.1 → 1.1.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 +145 -14
- package/dist/src/authority/commands.js +10 -2
- package/dist/src/authority/reconciliation.d.ts +2 -0
- package/dist/src/authority/reconciliation.js +10 -1
- package/dist/src/authority/transitions.d.ts +1 -1
- package/dist/src/authority/transitions.js +2 -0
- package/dist/src/broker/actor/authority-session.d.ts +2 -0
- package/dist/src/broker/actor/authority-session.js +3 -4
- package/dist/src/chats/analysis-batches.d.ts +24 -0
- package/dist/src/chats/analysis-batches.js +83 -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 +12 -0
- package/dist/src/chats/analysis-input.js +83 -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-prompt.d.ts +10 -0
- package/dist/src/chats/analysis-prompt.js +16 -0
- package/dist/src/chats/analysis-proposal.d.ts +2 -0
- package/dist/src/chats/analysis-proposal.js +32 -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 +3 -0
- package/dist/src/chats/analysis-shape.js +228 -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/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/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 +2 -0
- package/dist/src/cli/render.js +70 -2
- 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 +38 -6
- 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 +32 -0
- package/dist/src/cli/watch-board-view.js +88 -15
- package/dist/src/cli/watch-board.js +6 -1
- 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 +118 -0
- package/dist/src/cli/watch-model.js +31 -14
- package/dist/src/cli/watch-page.d.ts +1 -1
- package/dist/src/cli/watch-page.js +71 -85
- 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 +15 -0
- package/dist/src/cli/watch-pr-command.js +37 -0
- package/dist/src/cli/watch-pr-identity.d.ts +20 -0
- package/dist/src/cli/watch-pr-identity.js +62 -0
- package/dist/src/cli/watch-pr-observer.d.ts +19 -0
- package/dist/src/cli/watch-pr-observer.js +108 -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-reads.js +4 -0
- package/dist/src/cli/watch-render.d.ts +16 -2
- package/dist/src/cli/watch-render.js +10 -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 +44 -6
- 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 +7 -2
- 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 +15 -0
- package/dist/src/cli/watch-view.js +61 -17
- 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 +22 -0
- package/dist/src/daemon/analysis-worker.js +219 -0
- package/dist/src/daemon/chats-files.d.ts +15 -0
- package/dist/src/daemon/chats-files.js +113 -0
- package/dist/src/daemon/chats-worker.d.ts +12 -0
- package/dist/src/daemon/chats-worker.js +200 -0
- package/dist/src/daemon/claude-turn.d.ts +10 -0
- package/dist/src/daemon/claude-turn.js +96 -15
- package/dist/src/daemon/claude-worker.d.ts +4 -1
- package/dist/src/daemon/claude-worker.js +99 -47
- package/dist/src/daemon/codex-stream.js +16 -0
- package/dist/src/daemon/daemon.d.ts +3 -0
- package/dist/src/daemon/daemon.js +16 -7
- package/dist/src/daemon/github-methods.js +4 -0
- package/dist/src/daemon/github-ticket-status.d.ts +3 -0
- package/dist/src/daemon/github-ticket-status.js +268 -0
- package/dist/src/daemon/issue-queue.d.ts +1 -0
- package/dist/src/daemon/issue-queue.js +115 -24
- 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 +9 -0
- package/dist/src/daemon/retrying-turn.js +185 -0
- package/dist/src/host/world-reconciliation.d.ts +2 -0
- package/dist/src/host/world-reconciliation.js +6 -0
- package/dist/src/host/world-runs.js +9 -1
- package/dist/src/service/run-handlers.js +15 -23
- package/dist/src/service/worker-totals.d.ts +3 -0
- package/dist/src/service/worker-totals.js +28 -0
- package/dist/src/ticket-status.d.ts +8 -0
- package/dist/src/ticket-status.js +45 -0
- package/dist/src/token-prices.d.ts +19 -0
- package/dist/src/token-prices.js +76 -0
- package/dist/src/worker-usage.d.ts +22 -0
- package/dist/src/worker-usage.js +44 -0
- package/dist/src/workflow-candidate.d.ts +29 -0
- package/dist/src/workflow-candidate.js +59 -0
- package/dist/src/workflow-contracts.d.ts +2 -0
- package/dist/src/workflow-contracts.js +27 -5
- package/dist/src/workflow-declaration.d.ts +1 -1
- package/dist/src/workflow-declaration.js +3 -1
- package/dist/src/workflows.d.ts +1 -0
- package/dist/src/workflows.js +1 -0
- package/dist/tools/self-host-processes.js +7 -2
- 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 +6 -6
- 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/workflows/analyze-chats.d.ts +10 -0
- package/dist/workflows/analyze-chats.declaration.json +9 -0
- package/dist/workflows/analyze-chats.js +73 -0
- package/dist/workflows/develop-ticket.d.ts +1 -7
- package/dist/workflows/develop-ticket.js +42 -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 +133 -0
- package/package.json +5 -3
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
+
import { ticketStatus } from "../ticket-status.js";
|
|
3
|
+
import { analysisWorker } from "./analysis-worker.js";
|
|
4
|
+
import { analysisMethod } from "./analysis-launch.js";
|
|
5
|
+
import { estimatedCostUsd, priceForModel, } from "../token-prices.js";
|
|
2
6
|
import { profileCommand, } from "../turn-profile.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
7
|
+
import {} from "./claude-turn.js";
|
|
8
|
+
import { startRetriedTurn } from "./retrying-turn.js";
|
|
9
|
+
import { interrupted, located, operationKey, readRecord as read, replied, reportOf, writeRecord as written, } from "./operation-journal.js";
|
|
5
10
|
import { changes, treeFailure, workTree } from "./work-tree.js";
|
|
6
11
|
export const claudeLimits = {
|
|
7
12
|
summaryCharacters: 16_000,
|
|
@@ -9,9 +14,6 @@ export const claudeLimits = {
|
|
|
9
14
|
stopMilliseconds: 2_000,
|
|
10
15
|
};
|
|
11
16
|
const worker = "claude";
|
|
12
|
-
function located(settings, operationId) {
|
|
13
|
-
return locatedIn(settings.journal, operationId);
|
|
14
|
-
}
|
|
15
17
|
function alive(processId) {
|
|
16
18
|
if (typeof processId !== "number")
|
|
17
19
|
return false;
|
|
@@ -23,14 +25,11 @@ function alive(processId) {
|
|
|
23
25
|
return Reflect.get(Object(error), "code") === "EPERM";
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
|
-
function replied(key, recorded) {
|
|
27
|
-
return repliedWith({ receipt: key, worker }, recorded);
|
|
28
|
-
}
|
|
29
28
|
async function reconciled(parts, intent) {
|
|
30
|
-
const { key, folder } = located(parts.settings, intent.operationId);
|
|
29
|
+
const { key, folder } = located(parts.settings.journal, intent.operationId);
|
|
31
30
|
const result = await read(folder, "result.json");
|
|
32
31
|
if (result !== undefined)
|
|
33
|
-
return replied(key, result);
|
|
32
|
+
return replied({ receipt: key, worker }, result);
|
|
34
33
|
if (parts.active.has(key))
|
|
35
34
|
return { kind: "accepted", receipt: key, worker };
|
|
36
35
|
const started = await read(folder, "started.json");
|
|
@@ -40,64 +39,78 @@ async function reconciled(parts, intent) {
|
|
|
40
39
|
return { kind: "unknown", evidence: `claude-turn:${key}` };
|
|
41
40
|
const ending = interrupted("claude-turn-interrupted");
|
|
42
41
|
await written(folder, { name: "result.json", value: ending });
|
|
43
|
-
return replied(key, ending);
|
|
42
|
+
return replied({ receipt: key, worker }, ending);
|
|
44
43
|
}
|
|
45
|
-
async function resultText(tree,
|
|
44
|
+
async function resultText(tree, turn) {
|
|
45
|
+
const { result, settings } = turn;
|
|
46
46
|
const fields = {
|
|
47
|
+
ticketStatus: ticketStatus(result.text),
|
|
47
48
|
summary: result.text.slice(0, claudeLimits.summaryCharacters),
|
|
48
49
|
...(await changes(tree)),
|
|
49
50
|
worktree: tree.path,
|
|
50
51
|
costUsd: result.costUsd,
|
|
52
|
+
usage: result.usage,
|
|
53
|
+
model: result.model,
|
|
54
|
+
estimatedCostUsd: estimatedCostUsd(result.usage, {
|
|
55
|
+
worker: settings.worker ?? "claude",
|
|
56
|
+
price: priceForModel(settings.tokenPrices ?? {}, result.model),
|
|
57
|
+
}),
|
|
51
58
|
sessionId: result.sessionId,
|
|
52
59
|
turns: result.turns,
|
|
53
60
|
};
|
|
54
61
|
const text = JSON.stringify(fields);
|
|
55
62
|
const excess = Buffer.byteLength(text) - claudeLimits.resultBytes;
|
|
56
63
|
if (excess <= 0)
|
|
57
|
-
return text;
|
|
64
|
+
return { text };
|
|
58
65
|
const kept = Math.max(0, fields.summary.length - excess);
|
|
59
|
-
|
|
66
|
+
const shortened = JSON.stringify({
|
|
67
|
+
...fields,
|
|
68
|
+
summary: fields.summary.slice(0, kept),
|
|
69
|
+
});
|
|
70
|
+
if (Buffer.byteLength(shortened) <= claudeLimits.resultBytes)
|
|
71
|
+
return { text: shortened };
|
|
72
|
+
const metadata = JSON.stringify({
|
|
73
|
+
...fields,
|
|
74
|
+
ticketStatus: undefined,
|
|
75
|
+
summary: "",
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
reason: "claude-result-too-large",
|
|
79
|
+
...(Buffer.byteLength(metadata) <= claudeLimits.resultBytes
|
|
80
|
+
? { text: metadata }
|
|
81
|
+
: {}),
|
|
82
|
+
};
|
|
60
83
|
}
|
|
61
84
|
async function outcome(running, end) {
|
|
62
85
|
const endedAt = new Date().toISOString();
|
|
63
86
|
const { result } = end;
|
|
64
|
-
const
|
|
65
|
-
|
|
87
|
+
const report = result === undefined
|
|
88
|
+
? {}
|
|
89
|
+
: await resultText(running.tree, { result, settings: running.settings });
|
|
90
|
+
const { text, reason } = report;
|
|
91
|
+
if (reason === undefined &&
|
|
92
|
+
text !== undefined &&
|
|
93
|
+
end.exitCode === 0 &&
|
|
94
|
+
result?.failed === false)
|
|
66
95
|
return { outcome: "completed", result: text, endedAt };
|
|
67
96
|
if (running.stopping.requested)
|
|
68
97
|
return { outcome: "stopped", endedAt };
|
|
69
98
|
return {
|
|
70
99
|
outcome: "failed",
|
|
71
|
-
reason: "claude-turn-failed",
|
|
100
|
+
reason: reason ?? "claude-turn-failed",
|
|
72
101
|
...(text === undefined ? {} : { result: text }),
|
|
73
102
|
endedAt,
|
|
74
103
|
};
|
|
75
104
|
}
|
|
76
|
-
function reported(started, recorded) {
|
|
77
|
-
const { intent, key } = started;
|
|
78
|
-
return reportOf({ intent, commandId: `claude-turn:${key}`, worker }, recorded);
|
|
79
|
-
}
|
|
80
105
|
async function concluded(parts, running) {
|
|
81
|
-
const
|
|
106
|
+
const { intent, key } = running;
|
|
107
|
+
const recorded = await outcome({ ...running, settings: parts.settings }, await running.turn.ended);
|
|
82
108
|
await written(running.folder, { name: "result.json", value: recorded });
|
|
83
|
-
await parts.settings.report(
|
|
109
|
+
await parts.settings.report(reportOf({ intent, commandId: `claude-turn:${key}`, worker }, recorded));
|
|
84
110
|
}
|
|
85
111
|
async function begun(parts, start) {
|
|
86
112
|
const { intent, key, folder, tree, prompt } = start;
|
|
87
|
-
const
|
|
88
|
-
name: "started.json",
|
|
89
|
-
value: {
|
|
90
|
-
operationId: intent.operationId,
|
|
91
|
-
target: intent.target,
|
|
92
|
-
branch: tree.branch,
|
|
93
|
-
worktree: tree.path,
|
|
94
|
-
startCommit: tree.startCommit,
|
|
95
|
-
processId,
|
|
96
|
-
startedAt: new Date().toISOString(),
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
await record(null);
|
|
100
|
-
const turn = startTurn({
|
|
113
|
+
const turn = startRetriedTurn({
|
|
101
114
|
worker: parts.settings.worker ?? "claude",
|
|
102
115
|
command: profileCommand(parts.settings.command, start.profile),
|
|
103
116
|
environment: start.profile.env ?? {},
|
|
@@ -105,16 +118,26 @@ async function begun(parts, start) {
|
|
|
105
118
|
directory: tree.path,
|
|
106
119
|
folder,
|
|
107
120
|
prompt,
|
|
121
|
+
}, {
|
|
122
|
+
...parts.settings,
|
|
123
|
+
metadata: {
|
|
124
|
+
operationId: intent.operationId,
|
|
125
|
+
target: intent.target,
|
|
126
|
+
branch: tree.branch,
|
|
127
|
+
worktree: tree.path,
|
|
128
|
+
startCommit: tree.startCommit,
|
|
129
|
+
},
|
|
108
130
|
});
|
|
109
131
|
const stopping = { requested: false };
|
|
110
132
|
parts.active.set(key, {
|
|
111
133
|
turn,
|
|
112
134
|
stopping,
|
|
113
|
-
concluded:
|
|
135
|
+
concluded: turn
|
|
136
|
+
.then((running) => concluded(parts, { ...start, turn: running, stopping }))
|
|
114
137
|
.catch(() => undefined)
|
|
115
138
|
.finally(() => parts.active.delete(key)),
|
|
116
139
|
});
|
|
117
|
-
await
|
|
140
|
+
await turn;
|
|
118
141
|
}
|
|
119
142
|
async function firstTurn(settings, opening) {
|
|
120
143
|
const { tree, intent } = opening;
|
|
@@ -171,8 +194,11 @@ async function selectedProfile(settings, intent) {
|
|
|
171
194
|
async function delivered(parts, call) {
|
|
172
195
|
const { intent, signal } = call;
|
|
173
196
|
const { settings } = parts;
|
|
197
|
+
const aborted = () => signal.aborted;
|
|
174
198
|
if (!turnIntent(intent))
|
|
175
199
|
return failure("unsupported-effect");
|
|
200
|
+
if (aborted())
|
|
201
|
+
return failure("claude-start-aborted");
|
|
176
202
|
const known = await reconciled(parts, intent);
|
|
177
203
|
if (known.kind !== "absent")
|
|
178
204
|
return known;
|
|
@@ -188,22 +214,25 @@ async function delivered(parts, call) {
|
|
|
188
214
|
target: intent.target,
|
|
189
215
|
signal,
|
|
190
216
|
}).catch(treeFailure);
|
|
191
|
-
if (
|
|
217
|
+
if (aborted())
|
|
192
218
|
return failure("claude-start-aborted");
|
|
193
219
|
if (typeof tree === "string")
|
|
194
220
|
return failure(tree);
|
|
195
|
-
const place = located(settings, intent.operationId);
|
|
221
|
+
const place = located(settings.journal, intent.operationId);
|
|
196
222
|
const first = await firstTurn(settings, { tree, intent });
|
|
223
|
+
if (aborted())
|
|
224
|
+
return failure("claude-start-aborted");
|
|
197
225
|
await begun(parts, { ...place, intent, tree: first, prompt, profile });
|
|
198
226
|
return { receipt: place.key, worker };
|
|
199
227
|
}
|
|
200
228
|
async function halted(parts, active) {
|
|
201
229
|
active.stopping.requested = true;
|
|
202
|
-
active.turn.
|
|
230
|
+
const turn = await active.turn.catch(() => undefined);
|
|
231
|
+
turn?.stop(parts.settings.stopMilliseconds ?? claudeLimits.stopMilliseconds);
|
|
203
232
|
await active.concluded;
|
|
204
233
|
}
|
|
205
234
|
async function stopped(parts, intent) {
|
|
206
|
-
const { key } = located(parts.settings, intent.operationId);
|
|
235
|
+
const { key } = located(parts.settings.journal, intent.operationId);
|
|
207
236
|
const active = parts.active.get(key);
|
|
208
237
|
if (active !== undefined)
|
|
209
238
|
await halted(parts, active);
|
|
@@ -212,12 +241,35 @@ async function stopped(parts, intent) {
|
|
|
212
241
|
export function claudeWorker(settings) {
|
|
213
242
|
if (settings.command.length === 0)
|
|
214
243
|
throw new Error("invalid-claude-command");
|
|
215
|
-
const parts = {
|
|
244
|
+
const parts = {
|
|
245
|
+
settings,
|
|
246
|
+
active: new Map(),
|
|
247
|
+
stopping: new AbortController(),
|
|
248
|
+
};
|
|
249
|
+
const analysis = analysisWorker(settings);
|
|
250
|
+
const guarded = async (intent, run) => {
|
|
251
|
+
if (!turnIntent(intent) ||
|
|
252
|
+
Object.hasOwn(settings.profiles ?? {}, "analyze-chats") ||
|
|
253
|
+
(await runWorkflow(settings, intent.runId)) !== "analyze-chats")
|
|
254
|
+
return failure("analysis-worker-unavailable");
|
|
255
|
+
return run();
|
|
256
|
+
};
|
|
216
257
|
return {
|
|
217
|
-
deliver: (intent, signal) =>
|
|
218
|
-
|
|
219
|
-
|
|
258
|
+
deliver: (intent, signal) => intent.method === analysisMethod
|
|
259
|
+
? guarded(intent, () => analysis.deliver(intent, signal))
|
|
260
|
+
: delivered(parts, {
|
|
261
|
+
intent,
|
|
262
|
+
signal: AbortSignal.any([signal, parts.stopping.signal]),
|
|
263
|
+
}),
|
|
264
|
+
reconcile: (intent, signal) => intent.method === analysisMethod
|
|
265
|
+
? guarded(intent, () => analysis.reconcile(intent, signal))
|
|
266
|
+
: reconciled(parts, intent),
|
|
267
|
+
stop: (intent, signal) => intent.method === analysisMethod
|
|
268
|
+
? guarded(intent, () => analysis.stop(intent, signal))
|
|
269
|
+
: stopped(parts, intent),
|
|
220
270
|
close: async () => {
|
|
271
|
+
parts.stopping.abort();
|
|
272
|
+
await analysis.close();
|
|
221
273
|
await Promise.all([...parts.active.values()].map((active) => halted(parts, active)));
|
|
222
274
|
},
|
|
223
275
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sumUsage, usageOf } from "../worker-usage.js";
|
|
1
2
|
function record(value) {
|
|
2
3
|
return typeof value === "object" && value !== null ? { ...value } : {};
|
|
3
4
|
}
|
|
@@ -43,9 +44,20 @@ function completed(item) {
|
|
|
43
44
|
}
|
|
44
45
|
function updated(event, state) {
|
|
45
46
|
const type = event["type"];
|
|
47
|
+
if (typeof type === "string" &&
|
|
48
|
+
["thread.started", "turn.started", "turn.completed"].includes(type))
|
|
49
|
+
state.model = text(event["model"]) || state.model;
|
|
46
50
|
if (type === "thread.started")
|
|
47
51
|
state.sessionId = text(event["thread_id"]) || null;
|
|
48
52
|
if (type === "turn.completed") {
|
|
53
|
+
const usage = record(event["usage"]);
|
|
54
|
+
const current = usageOf({
|
|
55
|
+
input_tokens: usage["input_tokens"],
|
|
56
|
+
cache_read_input_tokens: usage["cached_input_tokens"],
|
|
57
|
+
output_tokens: usage["output_tokens"],
|
|
58
|
+
});
|
|
59
|
+
state.usage =
|
|
60
|
+
state.turns === 0 ? current : sumUsage([state.usage, current]);
|
|
49
61
|
state.turns += 1;
|
|
50
62
|
state.error = null;
|
|
51
63
|
}
|
|
@@ -82,8 +94,10 @@ function translated(event, state) {
|
|
|
82
94
|
}
|
|
83
95
|
export function codexStream() {
|
|
84
96
|
const state = {
|
|
97
|
+
model: null,
|
|
85
98
|
sessionId: null,
|
|
86
99
|
turns: 0,
|
|
100
|
+
usage: usageOf(null),
|
|
87
101
|
failure: null,
|
|
88
102
|
error: null,
|
|
89
103
|
message: "",
|
|
@@ -105,6 +119,8 @@ export function codexStream() {
|
|
|
105
119
|
state.error ||
|
|
106
120
|
`codex ended with the code ${String(exitCode)}`,
|
|
107
121
|
total_cost_usd: null,
|
|
122
|
+
...(state.model === null ? {} : { model: state.model }),
|
|
123
|
+
usage: state.usage,
|
|
108
124
|
session_id: state.sessionId,
|
|
109
125
|
num_turns: state.turns,
|
|
110
126
|
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type WorkflowFunction } from "../host/start-delivery.ts";
|
|
2
2
|
import { type WorkflowHandler } from "../host/world-host.ts";
|
|
3
3
|
import type { TurnProfiles } from "../turn-profile.ts";
|
|
4
|
+
import type { TokenPrices } from "../token-prices.ts";
|
|
4
5
|
import type { DeclaredWorkflow } from "../workflow-declaration.ts";
|
|
5
6
|
import type { Worker } from "./claude-turn.ts";
|
|
6
7
|
export interface DaemonSettings {
|
|
8
|
+
readonly tokenPrices?: TokenPrices;
|
|
7
9
|
readonly worker?: Worker;
|
|
8
10
|
readonly profiles?: TurnProfiles;
|
|
9
11
|
readonly directory: string;
|
|
@@ -19,6 +21,7 @@ export interface DaemonSettings {
|
|
|
19
21
|
readonly notifyCommand?: readonly string[];
|
|
20
22
|
readonly notifyMilliseconds?: number;
|
|
21
23
|
readonly queueMilliseconds?: number;
|
|
24
|
+
readonly resetQueue?: boolean;
|
|
22
25
|
readonly githubCommand?: readonly string[];
|
|
23
26
|
readonly checkCommand?: readonly string[];
|
|
24
27
|
readonly privateTexts?: readonly string[];
|
|
@@ -9,6 +9,7 @@ import { startService, } from "../service/service.js";
|
|
|
9
9
|
import { claudeWorker } from "./claude-worker.js";
|
|
10
10
|
import { deliveryRouter } from "./delivery-router.js";
|
|
11
11
|
import { githubWorker } from "./github-worker.js";
|
|
12
|
+
import { chatsWorker } from "./chats-worker.js";
|
|
12
13
|
import { worldDirectory } from "./host-environment.js";
|
|
13
14
|
import { issueQueue } from "./issue-queue.js";
|
|
14
15
|
import { notifyRuns } from "./notify.js";
|
|
@@ -76,6 +77,7 @@ function adapters(settings, options) {
|
|
|
76
77
|
const document = async (digest) => (await given).document(digest);
|
|
77
78
|
const report = async (effect) => (await given).reportEffect(effect);
|
|
78
79
|
const worker = claudeWorker({
|
|
80
|
+
tokenPrices: settings.tokenPrices ?? {},
|
|
79
81
|
worker: settings.worker ?? "claude",
|
|
80
82
|
profiles: settings.profiles ?? {},
|
|
81
83
|
workflowId: async (runId) => (await given).workflowId(runId),
|
|
@@ -87,6 +89,11 @@ function adapters(settings, options) {
|
|
|
87
89
|
journal: join(directory, "journal"),
|
|
88
90
|
});
|
|
89
91
|
const github = githubOf(settings, given);
|
|
92
|
+
const chats = chatsWorker({
|
|
93
|
+
runtimeDirectory: settings.runtimeDirectory,
|
|
94
|
+
document,
|
|
95
|
+
workflowId: async (runId) => (await given).workflowId(runId),
|
|
96
|
+
});
|
|
90
97
|
const runs = startDelivery({
|
|
91
98
|
document,
|
|
92
99
|
runs: taggedRuns,
|
|
@@ -94,7 +101,7 @@ function adapters(settings, options) {
|
|
|
94
101
|
input: async (runId) => (await given).input(runId),
|
|
95
102
|
workflow: async (runId) => workflows[String(await (await given).workflowId(runId))],
|
|
96
103
|
});
|
|
97
|
-
return { worker, github, runs };
|
|
104
|
+
return { worker, github, runs, chats };
|
|
98
105
|
}
|
|
99
106
|
export async function startDaemon(settings) {
|
|
100
107
|
const { directory } = settings;
|
|
@@ -111,7 +118,7 @@ export async function startDaemon(settings) {
|
|
|
111
118
|
detail: admitted.detail,
|
|
112
119
|
};
|
|
113
120
|
const given = Promise.withResolvers();
|
|
114
|
-
const { worker, github, runs } = adapters(settings, {
|
|
121
|
+
const { worker, github, runs, chats } = adapters(settings, {
|
|
115
122
|
given: given.promise,
|
|
116
123
|
table,
|
|
117
124
|
});
|
|
@@ -129,7 +136,7 @@ export async function startDaemon(settings) {
|
|
|
129
136
|
})),
|
|
130
137
|
delivery: deliveryRouter({
|
|
131
138
|
runs,
|
|
132
|
-
effects: { claude: worker, github },
|
|
139
|
+
effects: { claude: worker, github, chats },
|
|
133
140
|
}),
|
|
134
141
|
effects: { leaseMilliseconds: turnLeaseMilliseconds },
|
|
135
142
|
host: (ports) => {
|
|
@@ -138,7 +145,7 @@ export async function startDaemon(settings) {
|
|
|
138
145
|
},
|
|
139
146
|
});
|
|
140
147
|
if (opening.kind === "refused") {
|
|
141
|
-
await Promise.all([worker.close(), github.close()]);
|
|
148
|
+
await Promise.all([worker.close(), github.close(), chats.close()]);
|
|
142
149
|
return opening;
|
|
143
150
|
}
|
|
144
151
|
return {
|
|
@@ -147,11 +154,12 @@ export async function startDaemon(settings) {
|
|
|
147
154
|
service: opening.service,
|
|
148
155
|
worker,
|
|
149
156
|
github,
|
|
157
|
+
chats,
|
|
150
158
|
}),
|
|
151
159
|
};
|
|
152
160
|
}
|
|
153
161
|
async function runningDaemon(settings, resources) {
|
|
154
|
-
const { service, worker, github } = resources;
|
|
162
|
+
const { service, worker, github, chats } = resources;
|
|
155
163
|
await github.scan();
|
|
156
164
|
const notifier = settings.notifyCommand === undefined
|
|
157
165
|
? undefined
|
|
@@ -163,7 +171,7 @@ async function runningDaemon(settings, resources) {
|
|
|
163
171
|
? {}
|
|
164
172
|
: { intervalMilliseconds: settings.notifyMilliseconds }),
|
|
165
173
|
}).catch(async (error) => {
|
|
166
|
-
await Promise.all([worker.close(), github.close()]);
|
|
174
|
+
await Promise.all([worker.close(), github.close(), chats.close()]);
|
|
167
175
|
await service.close();
|
|
168
176
|
throw error;
|
|
169
177
|
});
|
|
@@ -173,13 +181,14 @@ async function runningDaemon(settings, resources) {
|
|
|
173
181
|
directory: settings.directory,
|
|
174
182
|
runtimeDirectory: settings.runtimeDirectory,
|
|
175
183
|
intervalMilliseconds: settings.queueMilliseconds,
|
|
184
|
+
resetQueue: settings.resetQueue ?? false,
|
|
176
185
|
});
|
|
177
186
|
return {
|
|
178
187
|
socket: service.socket,
|
|
179
188
|
close: async () => {
|
|
180
189
|
await notifier?.stop();
|
|
181
190
|
await queue?.stop();
|
|
182
|
-
await Promise.all([worker.close(), github.close()]);
|
|
191
|
+
await Promise.all([worker.close(), github.close(), chats.close()]);
|
|
183
192
|
await service.close();
|
|
184
193
|
},
|
|
185
194
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2
2
|
import { findingsOf, scoreOf } from "./github-calls.js";
|
|
3
|
+
import { closeIssue, partialIssue } from "./github-ticket-status.js";
|
|
3
4
|
import { merge } from "./github-merge.js";
|
|
4
5
|
import { createIssue, discard } from "./github-issue-methods.js";
|
|
5
6
|
import { existingTree, defaultBranch, changeChecked, field, githubTiming, repositoryPath, text, } from "./github-operation.js";
|
|
@@ -11,6 +12,7 @@ export const methodReasons = new Set([
|
|
|
11
12
|
"post-uncertain",
|
|
12
13
|
"private-texts-not-set",
|
|
13
14
|
"github-call-failed",
|
|
15
|
+
"github-issue-conflict",
|
|
14
16
|
"git-call-failed",
|
|
15
17
|
"check-failed",
|
|
16
18
|
"merge-conflict",
|
|
@@ -183,6 +185,8 @@ async function waitReview(operation) {
|
|
|
183
185
|
}
|
|
184
186
|
export const methods = new Map([
|
|
185
187
|
["prepare", prepare],
|
|
188
|
+
["close-issue", closeIssue],
|
|
189
|
+
["partial-issue", partialIssue],
|
|
186
190
|
["label", label],
|
|
187
191
|
["create-issue", createIssue],
|
|
188
192
|
["discard", discard],
|