tines 0.0.170 → 0.0.171
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/dist/index.js +78 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4559,7 +4559,15 @@ function parseTargetSpec(spec) {
|
|
|
4559
4559
|
}
|
|
4560
4560
|
|
|
4561
4561
|
// src/config.ts
|
|
4562
|
-
import {
|
|
4562
|
+
import {
|
|
4563
|
+
existsSync,
|
|
4564
|
+
mkdirSync,
|
|
4565
|
+
readFileSync as readFileSync3,
|
|
4566
|
+
renameSync,
|
|
4567
|
+
rmSync,
|
|
4568
|
+
unlinkSync,
|
|
4569
|
+
writeFileSync
|
|
4570
|
+
} from "node:fs";
|
|
4563
4571
|
import { homedir } from "node:os";
|
|
4564
4572
|
import { dirname, join } from "node:path";
|
|
4565
4573
|
function defaultConfigDir() {
|
|
@@ -4575,8 +4583,15 @@ function readJsonFile(path2) {
|
|
|
4575
4583
|
}
|
|
4576
4584
|
function writeJsonFile(path2, value, { secret = false } = {}) {
|
|
4577
4585
|
mkdirSync(dirname(path2), { recursive: true });
|
|
4578
|
-
|
|
4586
|
+
const tmp = `${path2}.tmp-${process.pid}`;
|
|
4587
|
+
try {
|
|
4588
|
+
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}
|
|
4579
4589
|
`, secret ? { mode: 384 } : {});
|
|
4590
|
+
renameSync(tmp, path2);
|
|
4591
|
+
} catch (e) {
|
|
4592
|
+
rmSync(tmp, { force: true });
|
|
4593
|
+
throw e;
|
|
4594
|
+
}
|
|
4580
4595
|
}
|
|
4581
4596
|
function configPath(dir = defaultConfigDir()) {
|
|
4582
4597
|
return join(dir, "config.json");
|
|
@@ -6935,7 +6950,7 @@ import {
|
|
|
6935
6950
|
mkdirSync as mkdirSync4,
|
|
6936
6951
|
readFileSync as readFileSync9,
|
|
6937
6952
|
realpathSync,
|
|
6938
|
-
rmSync as
|
|
6953
|
+
rmSync as rmSync3,
|
|
6939
6954
|
statSync as statSync4,
|
|
6940
6955
|
unlinkSync as unlinkSync2,
|
|
6941
6956
|
writeFileSync as writeFileSync3
|
|
@@ -7436,7 +7451,7 @@ function buildHarnessInvocation(spec, input) {
|
|
|
7436
7451
|
file: "sh",
|
|
7437
7452
|
args: [
|
|
7438
7453
|
"-c",
|
|
7439
|
-
`claude -p --output-format stream-json --verbose${input.model ? ` --model ${shellQuote(input.model)}` : ""} < ${shellQuote(input.promptFile)}`
|
|
7454
|
+
`claude -p${input.resumeSessionId ? ` --resume ${shellQuote(input.resumeSessionId)}` : ""} --output-format stream-json --verbose${input.model ? ` --model ${shellQuote(input.model)}` : ""} < ${shellQuote(input.promptFile)}`
|
|
7440
7455
|
]
|
|
7441
7456
|
};
|
|
7442
7457
|
case "codex":
|
|
@@ -7474,7 +7489,10 @@ function formatLaunchBanner(invocation, input, meta) {
|
|
|
7474
7489
|
`model=${input.model ?? "(fixed)"}`,
|
|
7475
7490
|
`timeout=${meta.timeoutMinutes}m`,
|
|
7476
7491
|
`cli=${meta.cliVersion}`,
|
|
7477
|
-
`workspace=${input.workspace}
|
|
7492
|
+
`workspace=${input.workspace}`,
|
|
7493
|
+
// The one line that says a send-back reused a session rather than
|
|
7494
|
+
// re-exploring the repository from zero.
|
|
7495
|
+
...input.resumeSessionId ? [`resumed=${meta.resumedFromRunId ?? input.resumeSessionId}`] : []
|
|
7478
7496
|
];
|
|
7479
7497
|
return `$ ${formatLaunchCommand(invocation)}
|
|
7480
7498
|
# tines runner: ${fields.join(" ")}
|
|
@@ -7538,7 +7556,7 @@ var RunTable = class {
|
|
|
7538
7556
|
cleanup(run, outcome = "failed") {
|
|
7539
7557
|
this.runs.delete(run.runId);
|
|
7540
7558
|
this.effects.persist();
|
|
7541
|
-
this.effects.release(run, { keep: this.keep(outcome), outcome });
|
|
7559
|
+
this.effects.release(run, { keep: this.keep(outcome, run), outcome });
|
|
7542
7560
|
}
|
|
7543
7561
|
/**
|
|
7544
7562
|
* Ends a run: flush logs, finish-report, clean up. On a run someone
|
|
@@ -7559,11 +7577,15 @@ var RunTable = class {
|
|
|
7559
7577
|
run.settled = true;
|
|
7560
7578
|
run.endNote ??= error;
|
|
7561
7579
|
run.drain?.();
|
|
7562
|
-
if (this.keep(status)) this.effects.noteKept?.(run);
|
|
7580
|
+
if (this.keep(status, run)) this.effects.noteKept?.(run);
|
|
7563
7581
|
await run.flush?.();
|
|
7582
|
+
const keptBeforeFinish = this.keep(status, run);
|
|
7564
7583
|
try {
|
|
7565
7584
|
await this.effects.finish(run, status, error, judgment);
|
|
7566
7585
|
this.effects.log(`run ${run.runId} finished: ${status}${error ? ` (${error})` : ""}`);
|
|
7586
|
+
if (!keptBeforeFinish && this.keep(status, run)) {
|
|
7587
|
+
this.effects.log(`run ${run.runId} workspace kept for resume at ${run.workspace}`);
|
|
7588
|
+
}
|
|
7567
7589
|
} catch (err) {
|
|
7568
7590
|
this.effects.log(
|
|
7569
7591
|
`finish report for run ${run.runId} not accepted: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -7818,7 +7840,7 @@ function message(err) {
|
|
|
7818
7840
|
}
|
|
7819
7841
|
|
|
7820
7842
|
// src/daemon/store.ts
|
|
7821
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync8, rmSync, statSync as statSync3 } from "node:fs";
|
|
7843
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync8, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
7822
7844
|
import { join as join4 } from "node:path";
|
|
7823
7845
|
function credentialsKey(url, name2) {
|
|
7824
7846
|
return `${url.replace(/\/+$/, "")}#${name2}`;
|
|
@@ -7919,7 +7941,7 @@ function pruneKeptWorkspaces(configDir, opts) {
|
|
|
7919
7941
|
const removed = [];
|
|
7920
7942
|
for (const entry of doomed) {
|
|
7921
7943
|
try {
|
|
7922
|
-
|
|
7944
|
+
rmSync2(entry.path, { recursive: true, force: true });
|
|
7923
7945
|
removed.push(entry);
|
|
7924
7946
|
} catch {
|
|
7925
7947
|
}
|
|
@@ -8017,7 +8039,7 @@ async function runDaemon(opts) {
|
|
|
8017
8039
|
sweepKeptWorkspaces();
|
|
8018
8040
|
const settleWorkspace = (workspace, keep, marker) => {
|
|
8019
8041
|
if (!keep) {
|
|
8020
|
-
|
|
8042
|
+
rmSync3(workspace, { recursive: true, force: true });
|
|
8021
8043
|
return;
|
|
8022
8044
|
}
|
|
8023
8045
|
if (!existsSync5(workspace)) return;
|
|
@@ -8091,13 +8113,19 @@ async function runDaemon(opts) {
|
|
|
8091
8113
|
{
|
|
8092
8114
|
finish: async (run, status, error, judgment) => {
|
|
8093
8115
|
const summary = run.renderer?.summary();
|
|
8094
|
-
await client2.finishRun(run.runId, {
|
|
8116
|
+
const ended = await client2.finishRun(run.runId, {
|
|
8095
8117
|
status,
|
|
8096
8118
|
...error ? { error } : {},
|
|
8097
8119
|
...judgment,
|
|
8098
8120
|
usage: summary?.usage ?? { cost_source: "none" },
|
|
8099
|
-
...summary?.providerSessionId ? { provider_session_id: summary.providerSessionId } : {}
|
|
8121
|
+
...summary?.providerSessionId ? { provider_session_id: summary.providerSessionId } : {},
|
|
8122
|
+
...summary?.numTurns !== void 0 ? { turn_count: summary.numTurns } : {},
|
|
8123
|
+
// The whole conversation's turns, which for a resumed run is
|
|
8124
|
+
// more than this run's own: the size guard reads this one.
|
|
8125
|
+
...summary?.numTurns !== void 0 ? { conversation_turn_count: run.priorTurns + summary.numTurns } : {},
|
|
8126
|
+
workspace_path: run.workspace
|
|
8100
8127
|
});
|
|
8128
|
+
if (ended?.resume_expires_at) run.keepForResume = true;
|
|
8101
8129
|
},
|
|
8102
8130
|
release: (run, { keep, outcome }) => {
|
|
8103
8131
|
if (run.timeout) clearTimeout(run.timeout);
|
|
@@ -8126,7 +8154,11 @@ async function runDaemon(opts) {
|
|
|
8126
8154
|
},
|
|
8127
8155
|
log
|
|
8128
8156
|
},
|
|
8129
|
-
{
|
|
8157
|
+
{
|
|
8158
|
+
// A workspace the server retained for a resume is kept whatever the
|
|
8159
|
+
// --keep-workspaces mode says; pruning still bounds it by age/count.
|
|
8160
|
+
keep: (outcome, run) => run.keepForResume || keepWorkspace(opts.keepWorkspaces, outcome)
|
|
8161
|
+
}
|
|
8130
8162
|
);
|
|
8131
8163
|
for (const orphan of loadDaemonState(statePath)) {
|
|
8132
8164
|
if (pidAlive(orphan.pid)) {
|
|
@@ -8172,7 +8204,13 @@ async function runDaemon(opts) {
|
|
|
8172
8204
|
const launch = async (assignment) => {
|
|
8173
8205
|
const runId = assignment.run.id;
|
|
8174
8206
|
if (table2.has(runId)) return;
|
|
8175
|
-
const
|
|
8207
|
+
const resume = assignment.resume && existsSync5(assignment.resume.workspace_path) ? assignment.resume : null;
|
|
8208
|
+
if (assignment.resume && !resume) {
|
|
8209
|
+
log(
|
|
8210
|
+
`run ${runId}: resume workspace ${assignment.resume.workspace_path} is gone; launching fresh`
|
|
8211
|
+
);
|
|
8212
|
+
}
|
|
8213
|
+
const workspace = resume ? resume.workspace_path : join5(workspacesDir(opts.configDir), runId);
|
|
8176
8214
|
const issueLabel = assignment.run.issue_ref ? `${assignment.run.issue_ref.project_name}/${assignment.run.issue_ref.number}` : void 0;
|
|
8177
8215
|
const run = {
|
|
8178
8216
|
runId,
|
|
@@ -8182,6 +8220,8 @@ async function runDaemon(opts) {
|
|
|
8182
8220
|
timedOut: false,
|
|
8183
8221
|
settled: false,
|
|
8184
8222
|
keyFingerprint: assignment.run_key.slice(0, 14),
|
|
8223
|
+
priorTurns: resume?.prior_turn_count ?? 0,
|
|
8224
|
+
keepForResume: false,
|
|
8185
8225
|
batcher: new LogBatcher(
|
|
8186
8226
|
(chunk, seq) => client2.appendRunLog(runId, { chunk, seq }).then(() => {
|
|
8187
8227
|
}),
|
|
@@ -8191,26 +8231,32 @@ async function runDaemon(opts) {
|
|
|
8191
8231
|
run.flush = () => run.batcher.flush();
|
|
8192
8232
|
table2.track(run);
|
|
8193
8233
|
log(
|
|
8194
|
-
`run ${runId} assigned (issue ${issueLabel ?? assignment.run.issue_id}); materializing workspace`
|
|
8234
|
+
resume ? `run ${runId} assigned (issue ${issueLabel ?? assignment.run.issue_id}); resuming run ${resume.previous_run_id} in ${workspace}` : `run ${runId} assigned (issue ${issueLabel ?? assignment.run.issue_id}); materializing workspace`
|
|
8195
8235
|
);
|
|
8196
8236
|
try {
|
|
8197
|
-
|
|
8198
|
-
|
|
8237
|
+
if (!resume) {
|
|
8238
|
+
rmSync3(workspace, { recursive: true, force: true });
|
|
8239
|
+
mkdirSync4(workspace, { recursive: true });
|
|
8240
|
+
} else {
|
|
8241
|
+
rmSync3(join5(workspace, "kept.json"), { force: true });
|
|
8242
|
+
}
|
|
8199
8243
|
writeFileSync3(join5(workspace, "prompt.md"), `${assignment.prompt}
|
|
8200
8244
|
`);
|
|
8201
|
-
|
|
8202
|
-
for (const
|
|
8203
|
-
const
|
|
8204
|
-
|
|
8205
|
-
|
|
8245
|
+
if (!resume)
|
|
8246
|
+
for (const skill of assignment.bundle.skills) {
|
|
8247
|
+
for (const file of skill.files) {
|
|
8248
|
+
const target = join5(workspace, "skills", skill.name, file.path);
|
|
8249
|
+
mkdirSync4(dirname4(target), { recursive: true });
|
|
8250
|
+
writeFileSync3(target, file.content);
|
|
8251
|
+
}
|
|
8206
8252
|
}
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8253
|
+
if (!resume)
|
|
8254
|
+
writeFileSync3(
|
|
8255
|
+
join5(workspace, "repos.json"),
|
|
8256
|
+
`${JSON.stringify(assignment.bundle.repos, null, 2)}
|
|
8211
8257
|
`
|
|
8212
|
-
|
|
8213
|
-
for (const repo of assignment.bundle.repos) {
|
|
8258
|
+
);
|
|
8259
|
+
for (const repo of resume ? [] : assignment.bundle.repos) {
|
|
8214
8260
|
if (run.settled) return table2.cleanup(run);
|
|
8215
8261
|
const args = [
|
|
8216
8262
|
"clone",
|
|
@@ -8242,7 +8288,8 @@ async function runDaemon(opts) {
|
|
|
8242
8288
|
workspace,
|
|
8243
8289
|
promptFile: join5(workspace, "prompt.md"),
|
|
8244
8290
|
prompt: assignment.prompt,
|
|
8245
|
-
model: assignment.run.model
|
|
8291
|
+
model: assignment.run.model,
|
|
8292
|
+
...resume ? { resumeSessionId: resume.provider_session_id } : {}
|
|
8246
8293
|
};
|
|
8247
8294
|
const invocation = buildHarnessInvocation(
|
|
8248
8295
|
{ harness: opts.harness, command: opts.command },
|
|
@@ -8252,7 +8299,8 @@ async function runDaemon(opts) {
|
|
|
8252
8299
|
formatLaunchBanner(invocation, harnessInput, {
|
|
8253
8300
|
harness: opts.harness,
|
|
8254
8301
|
timeoutMinutes: assignment.timeout_minutes,
|
|
8255
|
-
cliVersion: DAEMON_VERSION
|
|
8302
|
+
cliVersion: DAEMON_VERSION,
|
|
8303
|
+
...resume ? { resumedFromRunId: resume.previous_run_id } : {}
|
|
8256
8304
|
})
|
|
8257
8305
|
);
|
|
8258
8306
|
const child = spawn2(invocation.file, invocation.args, {
|