dahrk-node 0.1.23 → 0.1.25
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/main.js +232 -162
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import "./chunk-FYS2JH42.js";
|
|
3
3
|
|
|
4
4
|
// src/main.ts
|
|
5
|
-
import { execFileSync as
|
|
6
|
-
import { existsSync as
|
|
5
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
6
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, realpathSync as realpathSync5 } from "fs";
|
|
7
7
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
8
8
|
import { homedir as homedir7, platform as osPlatform4 } from "os";
|
|
9
|
-
import { basename as basename2, join as
|
|
9
|
+
import { basename as basename2, join as join20 } from "path";
|
|
10
10
|
import { pathToFileURL } from "url";
|
|
11
11
|
|
|
12
12
|
// ../../packages/edge/src/ws-client.ts
|
|
@@ -245,12 +245,12 @@ function documentsBlock(ctx) {
|
|
|
245
245
|
const truncated = body.length > cap;
|
|
246
246
|
const excerpt = truncated ? body.slice(0, cap) : body;
|
|
247
247
|
budget -= excerpt.length;
|
|
248
|
-
const
|
|
248
|
+
const tail2 = truncated ? `
|
|
249
249
|
...(truncated; full text at ${path})` : "";
|
|
250
250
|
const title = doc.title.replace(/[<>"]/g, "'");
|
|
251
251
|
parts.push(
|
|
252
252
|
`<document title="${title}" file="${path}">
|
|
253
|
-
${neutraliseDelimiters(excerpt)}${
|
|
253
|
+
${neutraliseDelimiters(excerpt)}${tail2}
|
|
254
254
|
</document>`
|
|
255
255
|
);
|
|
256
256
|
if (budget <= 0) break;
|
|
@@ -2564,6 +2564,59 @@ async function overlayComponents(opts) {
|
|
|
2564
2564
|
return result;
|
|
2565
2565
|
}
|
|
2566
2566
|
|
|
2567
|
+
// ../../packages/executor-worktree/src/repo-setup.ts
|
|
2568
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
2569
|
+
import { createHash as createHash3 } from "crypto";
|
|
2570
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
2571
|
+
import { dirname as dirname4, join as join10 } from "path";
|
|
2572
|
+
var noopLogger2 = { info: () => {
|
|
2573
|
+
}, warn: () => {
|
|
2574
|
+
} };
|
|
2575
|
+
var SCRATCH_DIR2 = join10(".dahrk", "scratch");
|
|
2576
|
+
var MARKER_NAME = ".setup-done";
|
|
2577
|
+
var DEFAULT_TIMEOUT_MS = 6e5;
|
|
2578
|
+
var OUTPUT_CAP = 16384;
|
|
2579
|
+
function digest(command) {
|
|
2580
|
+
return createHash3("sha256").update(command).digest("hex").slice(0, 16);
|
|
2581
|
+
}
|
|
2582
|
+
function tail(output) {
|
|
2583
|
+
return output.length > OUTPUT_CAP ? output.slice(output.length - OUTPUT_CAP) : output;
|
|
2584
|
+
}
|
|
2585
|
+
function runRepoSetup(opts) {
|
|
2586
|
+
const { worktreePath, command } = opts;
|
|
2587
|
+
const log = opts.log ?? noopLogger2;
|
|
2588
|
+
const markerPath = join10(worktreePath, SCRATCH_DIR2, MARKER_NAME);
|
|
2589
|
+
const want = digest(command);
|
|
2590
|
+
if (existsSync5(markerPath)) {
|
|
2591
|
+
try {
|
|
2592
|
+
if (readFileSync4(markerPath, "utf8").trim() === want) {
|
|
2593
|
+
log.info(`repo setup: cached (marker matches), skipping`);
|
|
2594
|
+
return { status: "cached" };
|
|
2595
|
+
}
|
|
2596
|
+
} catch {
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
log.info(`repo setup: running \`${command}\``);
|
|
2600
|
+
try {
|
|
2601
|
+
const stdout = execFileSync3("sh", ["-c", command], {
|
|
2602
|
+
cwd: worktreePath,
|
|
2603
|
+
env: opts.env ?? process.env,
|
|
2604
|
+
timeout: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
2605
|
+
encoding: "utf8",
|
|
2606
|
+
// Fold stderr into stdout so the captured trace shows what the installer said, in order.
|
|
2607
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2608
|
+
});
|
|
2609
|
+
mkdirSync5(dirname4(markerPath), { recursive: true });
|
|
2610
|
+
writeFileSync6(markerPath, want);
|
|
2611
|
+
return { status: "ran", output: tail(stdout ?? "") };
|
|
2612
|
+
} catch (e) {
|
|
2613
|
+
const err = e;
|
|
2614
|
+
const combined = `${err.stdout?.toString() ?? ""}${err.stderr?.toString() ?? ""}` || e.message;
|
|
2615
|
+
log.warn(`repo setup failed (exit ${err.status ?? "null"})`);
|
|
2616
|
+
return { status: "failed", exitCode: err.status ?? null, output: tail(combined) };
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2567
2620
|
// ../../packages/executor-worktree/src/index.ts
|
|
2568
2621
|
function makeRunner(runtime) {
|
|
2569
2622
|
if ((process.env.DAHRK_RUNNER ?? process.env.SKAKEL_RUNNER ?? "real") === "mock") return createMockRunner(runtime);
|
|
@@ -2630,8 +2683,8 @@ function collectHealth(inputs) {
|
|
|
2630
2683
|
}
|
|
2631
2684
|
|
|
2632
2685
|
// ../../packages/edge/src/job-ledger.ts
|
|
2633
|
-
import { chmodSync, existsSync as
|
|
2634
|
-
import { dirname as
|
|
2686
|
+
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync, unlinkSync, writeFileSync as writeFileSync7 } from "fs";
|
|
2687
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
2635
2688
|
var FILE_MODE = 384;
|
|
2636
2689
|
var DIR_MODE = 448;
|
|
2637
2690
|
function nullJobLedger() {
|
|
@@ -2647,9 +2700,9 @@ var isEntry = (v) => {
|
|
|
2647
2700
|
};
|
|
2648
2701
|
function fileJobLedger(file, warn = console.warn) {
|
|
2649
2702
|
const read = () => {
|
|
2650
|
-
if (!
|
|
2703
|
+
if (!existsSync6(file)) return [];
|
|
2651
2704
|
try {
|
|
2652
|
-
const parsed = JSON.parse(
|
|
2705
|
+
const parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
2653
2706
|
if (!Array.isArray(parsed)) return [];
|
|
2654
2707
|
return parsed.filter(isEntry);
|
|
2655
2708
|
} catch {
|
|
@@ -2659,15 +2712,15 @@ function fileJobLedger(file, warn = console.warn) {
|
|
|
2659
2712
|
const write = (entries) => {
|
|
2660
2713
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
2661
2714
|
try {
|
|
2662
|
-
|
|
2663
|
-
|
|
2715
|
+
mkdirSync6(dirname5(file), { recursive: true, mode: DIR_MODE });
|
|
2716
|
+
writeFileSync7(tmp, `${JSON.stringify(entries, null, 2)}
|
|
2664
2717
|
`, { mode: FILE_MODE });
|
|
2665
2718
|
chmodSync(tmp, FILE_MODE);
|
|
2666
2719
|
renameSync(tmp, file);
|
|
2667
2720
|
} catch (e) {
|
|
2668
2721
|
warn(`could not persist the job ledger to ${file}: ${e.message}`);
|
|
2669
2722
|
try {
|
|
2670
|
-
if (
|
|
2723
|
+
if (existsSync6(tmp)) unlinkSync(tmp);
|
|
2671
2724
|
} catch {
|
|
2672
2725
|
}
|
|
2673
2726
|
}
|
|
@@ -2695,7 +2748,7 @@ function announceableJobs(entries) {
|
|
|
2695
2748
|
return out2;
|
|
2696
2749
|
}
|
|
2697
2750
|
function jobLedgerFile(stateDir2) {
|
|
2698
|
-
return
|
|
2751
|
+
return join11(stateDir2, "jobs.json");
|
|
2699
2752
|
}
|
|
2700
2753
|
|
|
2701
2754
|
// ../../packages/edge/src/log-shipper.ts
|
|
@@ -2798,8 +2851,8 @@ function ceilingFromEnv(env) {
|
|
|
2798
2851
|
}
|
|
2799
2852
|
|
|
2800
2853
|
// ../../packages/edge/src/logger.ts
|
|
2801
|
-
import { closeSync, existsSync as
|
|
2802
|
-
import { join as
|
|
2854
|
+
import { closeSync, existsSync as existsSync7, mkdirSync as mkdirSync7, openSync, renameSync as renameSync2, rmSync as rmSync5, statSync as statSync2, writeSync } from "fs";
|
|
2855
|
+
import { join as join12 } from "path";
|
|
2803
2856
|
import pino from "pino";
|
|
2804
2857
|
|
|
2805
2858
|
// ../../packages/edge/src/redact.ts
|
|
@@ -2895,7 +2948,7 @@ var RotatingFile = class {
|
|
|
2895
2948
|
open() {
|
|
2896
2949
|
try {
|
|
2897
2950
|
this.fd = openSync(this.path, "a");
|
|
2898
|
-
this.size =
|
|
2951
|
+
this.size = existsSync7(this.path) ? statSync2(this.path).size : 0;
|
|
2899
2952
|
} catch (e) {
|
|
2900
2953
|
this.disable(e);
|
|
2901
2954
|
}
|
|
@@ -2923,12 +2976,12 @@ var RotatingFile = class {
|
|
|
2923
2976
|
closeSync(this.fd);
|
|
2924
2977
|
this.fd = void 0;
|
|
2925
2978
|
const oldest = `${this.path}.${this.maxFiles}`;
|
|
2926
|
-
if (
|
|
2979
|
+
if (existsSync7(oldest)) rmSync5(oldest, { force: true });
|
|
2927
2980
|
for (let i = this.maxFiles - 1; i >= 1; i--) {
|
|
2928
2981
|
const from = `${this.path}.${i}`;
|
|
2929
|
-
if (
|
|
2982
|
+
if (existsSync7(from)) renameSync2(from, `${this.path}.${i + 1}`);
|
|
2930
2983
|
}
|
|
2931
|
-
if (
|
|
2984
|
+
if (existsSync7(this.path)) renameSync2(this.path, `${this.path}.1`);
|
|
2932
2985
|
this.open();
|
|
2933
2986
|
} catch (e) {
|
|
2934
2987
|
this.disable(e);
|
|
@@ -2988,8 +3041,8 @@ function createNodeLogger(opts = {}) {
|
|
|
2988
3041
|
if (level !== "silent") streams.push({ level, stream: humanSink });
|
|
2989
3042
|
if (opts.dir && fileLevel !== "silent") {
|
|
2990
3043
|
try {
|
|
2991
|
-
|
|
2992
|
-
const file = new RotatingFile(
|
|
3044
|
+
mkdirSync7(opts.dir, { recursive: true, mode: 448 });
|
|
3045
|
+
const file = new RotatingFile(join12(opts.dir, "node.jsonl"), opts.maxBytes ?? 10 * 1024 * 1024, opts.maxFiles ?? 5);
|
|
2993
3046
|
streams.push({ level: fileLevel, stream: file });
|
|
2994
3047
|
} catch (e) {
|
|
2995
3048
|
process.stderr.write(`dahrk: file logging disabled (${e.message})
|
|
@@ -3045,21 +3098,21 @@ function denyToolRule(tool3) {
|
|
|
3045
3098
|
}
|
|
3046
3099
|
|
|
3047
3100
|
// ../../packages/edge/src/stage-runner.ts
|
|
3048
|
-
import { execFileSync as
|
|
3049
|
-
import { createHash as
|
|
3050
|
-
import { mkdirSync as
|
|
3101
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
3102
|
+
import { createHash as createHash4 } from "crypto";
|
|
3103
|
+
import { mkdirSync as mkdirSync8, readdirSync as readdirSync3, readFileSync as readFileSync6, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
3051
3104
|
import { tmpdir as tmpdir5 } from "os";
|
|
3052
|
-
import { isAbsolute as isAbsolute3, join as
|
|
3105
|
+
import { isAbsolute as isAbsolute3, join as join14, relative as relative3, resolve as resolve2, sep as sep3 } from "path";
|
|
3053
3106
|
import { attachedDocBasename as attachedDocBasename2 } from "@dahrk/contracts";
|
|
3054
3107
|
|
|
3055
3108
|
// ../../packages/edge/src/builtins.ts
|
|
3056
|
-
import { execFileSync as
|
|
3109
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
3057
3110
|
|
|
3058
3111
|
// ../../packages/edge/src/fs-roots.ts
|
|
3059
|
-
import { execFileSync as
|
|
3060
|
-
import { existsSync as
|
|
3112
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
3113
|
+
import { existsSync as existsSync8, realpathSync as realpathSync2 } from "fs";
|
|
3061
3114
|
import { homedir as homedir3, tmpdir as tmpdir4 } from "os";
|
|
3062
|
-
import { dirname as
|
|
3115
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, join as join13, relative as relative2, resolve, sep as sep2 } from "path";
|
|
3063
3116
|
function isUnder(root, target) {
|
|
3064
3117
|
const rel = relative2(resolve(root), resolve(target));
|
|
3065
3118
|
return rel === "" || !rel.startsWith(`..${sep2}`) && rel !== ".." && !isAbsolute2(rel);
|
|
@@ -3071,17 +3124,17 @@ function expandPath(raw, cwd) {
|
|
|
3071
3124
|
}
|
|
3072
3125
|
function realish(p) {
|
|
3073
3126
|
let head = p;
|
|
3074
|
-
const
|
|
3075
|
-
while (head !==
|
|
3076
|
-
if (
|
|
3127
|
+
const tail2 = [];
|
|
3128
|
+
while (head !== dirname6(head)) {
|
|
3129
|
+
if (existsSync8(head)) {
|
|
3077
3130
|
try {
|
|
3078
|
-
return
|
|
3131
|
+
return join13(realpathSync2.native(head), ...tail2.reverse());
|
|
3079
3132
|
} catch {
|
|
3080
3133
|
return p;
|
|
3081
3134
|
}
|
|
3082
3135
|
}
|
|
3083
|
-
|
|
3084
|
-
head =
|
|
3136
|
+
tail2.push(head.slice(dirname6(head).length + 1));
|
|
3137
|
+
head = dirname6(head);
|
|
3085
3138
|
}
|
|
3086
3139
|
return p;
|
|
3087
3140
|
}
|
|
@@ -3095,7 +3148,7 @@ function withinRoots(raw, roots, need) {
|
|
|
3095
3148
|
}
|
|
3096
3149
|
function gitCommonDir(worktreePath) {
|
|
3097
3150
|
try {
|
|
3098
|
-
const out2 =
|
|
3151
|
+
const out2 = execFileSync4("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
|
|
3099
3152
|
cwd: worktreePath,
|
|
3100
3153
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3101
3154
|
}).toString().trim();
|
|
@@ -3108,7 +3161,7 @@ var pnpmStoreCache;
|
|
|
3108
3161
|
function pnpmStore() {
|
|
3109
3162
|
if (pnpmStoreCache) return pnpmStoreCache.path;
|
|
3110
3163
|
try {
|
|
3111
|
-
const out2 =
|
|
3164
|
+
const out2 = execFileSync4("pnpm", ["store", "path"], { stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).toString().trim();
|
|
3112
3165
|
pnpmStoreCache = { path: out2 || void 0 };
|
|
3113
3166
|
} catch {
|
|
3114
3167
|
pnpmStoreCache = { path: void 0 };
|
|
@@ -3144,26 +3197,26 @@ function computeFsRoots(opts) {
|
|
|
3144
3197
|
"/System",
|
|
3145
3198
|
"/proc",
|
|
3146
3199
|
"/sys",
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3200
|
+
join13(home, ".gitconfig"),
|
|
3201
|
+
join13(home, ".config"),
|
|
3202
|
+
join13(home, ".npmrc"),
|
|
3203
|
+
join13(home, ".cache"),
|
|
3204
|
+
join13(home, "Library", "Caches"),
|
|
3205
|
+
join13(home, "Library", "pnpm"),
|
|
3206
|
+
join13(home, ".local", "share"),
|
|
3207
|
+
join13(home, ".nvm"),
|
|
3208
|
+
join13(home, ".volta"),
|
|
3209
|
+
join13(home, ".asdf"),
|
|
3210
|
+
join13(home, ".cargo"),
|
|
3211
|
+
join13(home, ".rustup"),
|
|
3159
3212
|
...splitRoots(process.env.DAHRK_FS_EXTRA_READ_ROOTS).map((p) => realish(resolve(p)))
|
|
3160
3213
|
].map(realish);
|
|
3161
3214
|
const deny = [
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3215
|
+
join13(home, ".ssh"),
|
|
3216
|
+
join13(home, ".aws"),
|
|
3217
|
+
join13(home, ".gnupg"),
|
|
3218
|
+
join13(home, ".config", "gcloud"),
|
|
3219
|
+
join13(home, "Library", "Keychains"),
|
|
3167
3220
|
"/Volumes",
|
|
3168
3221
|
"/etc/shadow",
|
|
3169
3222
|
"/etc/sudoers"
|
|
@@ -3515,7 +3568,7 @@ function isDangerousRm(cmd) {
|
|
|
3515
3568
|
}
|
|
3516
3569
|
function currentBranch(worktreePath) {
|
|
3517
3570
|
try {
|
|
3518
|
-
return
|
|
3571
|
+
return execFileSync5("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: worktreePath }).toString().trim();
|
|
3519
3572
|
} catch {
|
|
3520
3573
|
return "";
|
|
3521
3574
|
}
|
|
@@ -3817,34 +3870,34 @@ var attemptOf = (jobId) => {
|
|
|
3817
3870
|
const m = /-(\d+)$/.exec(jobId);
|
|
3818
3871
|
return m ? Number(m[1]) : 1;
|
|
3819
3872
|
};
|
|
3820
|
-
var
|
|
3873
|
+
var digest2 = (value) => `sha256:${createHash4("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 16)}`;
|
|
3821
3874
|
function writeScratchState(ref, job, attempt, status) {
|
|
3822
|
-
const statePath =
|
|
3875
|
+
const statePath = join14(ref.scratchPath, "state.json");
|
|
3823
3876
|
let state;
|
|
3824
3877
|
try {
|
|
3825
|
-
state = JSON.parse(
|
|
3878
|
+
state = JSON.parse(readFileSync6(statePath, "utf8"));
|
|
3826
3879
|
} catch {
|
|
3827
3880
|
state = { runId: job.runId, tenantId: job.tenantId, stages: {} };
|
|
3828
3881
|
}
|
|
3829
3882
|
state.stages[job.stageId] = { currentAttempt: attempt, status };
|
|
3830
|
-
|
|
3831
|
-
|
|
3883
|
+
mkdirSync8(ref.scratchPath, { recursive: true });
|
|
3884
|
+
writeFileSync8(statePath, JSON.stringify(state, null, 2));
|
|
3832
3885
|
}
|
|
3833
3886
|
function writeIssueContext(ref, issueContext) {
|
|
3834
3887
|
if (issueContext === void 0) return;
|
|
3835
3888
|
try {
|
|
3836
|
-
|
|
3837
|
-
|
|
3889
|
+
mkdirSync8(ref.scratchPath, { recursive: true });
|
|
3890
|
+
writeFileSync8(join14(ref.scratchPath, "issue.md"), issueContext);
|
|
3838
3891
|
} catch {
|
|
3839
3892
|
}
|
|
3840
3893
|
}
|
|
3841
3894
|
function writeAttachedDocuments(ref, docs) {
|
|
3842
3895
|
if (!docs || docs.length === 0) return;
|
|
3843
3896
|
try {
|
|
3844
|
-
const dir =
|
|
3845
|
-
|
|
3897
|
+
const dir = join14(ref.scratchPath, "docs");
|
|
3898
|
+
mkdirSync8(dir, { recursive: true });
|
|
3846
3899
|
for (const doc of docs) {
|
|
3847
|
-
|
|
3900
|
+
writeFileSync8(join14(dir, `${attachedDocBasename2(doc)}.md`), doc.content);
|
|
3848
3901
|
}
|
|
3849
3902
|
} catch {
|
|
3850
3903
|
}
|
|
@@ -3862,8 +3915,8 @@ ${lines.join("\n")}
|
|
|
3862
3915
|
function writeGuidance(ref, guidance) {
|
|
3863
3916
|
if (!guidance || guidance.length === 0) return;
|
|
3864
3917
|
try {
|
|
3865
|
-
|
|
3866
|
-
|
|
3918
|
+
mkdirSync8(ref.scratchPath, { recursive: true });
|
|
3919
|
+
writeFileSync8(join14(ref.scratchPath, "guidance.md"), renderGuidanceMarkdown(guidance));
|
|
3867
3920
|
} catch {
|
|
3868
3921
|
}
|
|
3869
3922
|
}
|
|
@@ -3889,7 +3942,7 @@ function readEmittedArtifact(ref, relPath) {
|
|
|
3889
3942
|
const path = resolveWorktreeRelativePath(ref, relPath);
|
|
3890
3943
|
if (!path) return void 0;
|
|
3891
3944
|
try {
|
|
3892
|
-
const raw =
|
|
3945
|
+
const raw = readFileSync6(path, "utf8");
|
|
3893
3946
|
return { path: relPath, content: capContent(raw) };
|
|
3894
3947
|
} catch {
|
|
3895
3948
|
return void 0;
|
|
@@ -3898,12 +3951,12 @@ function readEmittedArtifact(ref, relPath) {
|
|
|
3898
3951
|
function scanScratchOutput(ref, preferRel) {
|
|
3899
3952
|
const preferBase = preferRel?.split("/").pop();
|
|
3900
3953
|
try {
|
|
3901
|
-
const names = readdirSync3(
|
|
3954
|
+
const names = readdirSync3(join14(ref.worktreePath, SCRATCH_OUTPUT_DIR)).filter(
|
|
3902
3955
|
(n) => n.toLowerCase().endsWith(".md")
|
|
3903
3956
|
);
|
|
3904
3957
|
if (names.length === 0) return void 0;
|
|
3905
3958
|
const pick = preferBase && names.includes(preferBase) ? preferBase : names[0];
|
|
3906
|
-
const raw =
|
|
3959
|
+
const raw = readFileSync6(join14(ref.worktreePath, SCRATCH_OUTPUT_DIR, pick), "utf8");
|
|
3907
3960
|
if (raw.trim().length === 0) return void 0;
|
|
3908
3961
|
return { path: `${SCRATCH_OUTPUT_DIR}/${pick}`, content: capContent(raw) };
|
|
3909
3962
|
} catch {
|
|
@@ -3913,7 +3966,7 @@ function scanScratchOutput(ref, preferRel) {
|
|
|
3913
3966
|
function scanChangedMarkdown(ref) {
|
|
3914
3967
|
const git = (args) => {
|
|
3915
3968
|
try {
|
|
3916
|
-
return
|
|
3969
|
+
return execFileSync6("git", ["-C", ref.worktreePath, ...args], { encoding: "utf8" }).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
3917
3970
|
} catch {
|
|
3918
3971
|
return [];
|
|
3919
3972
|
}
|
|
@@ -3923,7 +3976,7 @@ function scanChangedMarkdown(ref) {
|
|
|
3923
3976
|
);
|
|
3924
3977
|
for (const rel of rels) {
|
|
3925
3978
|
try {
|
|
3926
|
-
const raw =
|
|
3979
|
+
const raw = readFileSync6(join14(ref.worktreePath, rel), "utf8");
|
|
3927
3980
|
if (raw.trim().length > 0) return { path: rel, content: capContent(raw) };
|
|
3928
3981
|
} catch {
|
|
3929
3982
|
}
|
|
@@ -4049,10 +4102,10 @@ function createStageRunner(deps) {
|
|
|
4049
4102
|
...job.workspaceRef.credentialToken ? { credentialToken: job.workspaceRef.credentialToken } : {}
|
|
4050
4103
|
});
|
|
4051
4104
|
} else {
|
|
4052
|
-
const base = deps.scratchRoot ??
|
|
4053
|
-
const worktreePath =
|
|
4054
|
-
const scratchPath =
|
|
4055
|
-
|
|
4105
|
+
const base = deps.scratchRoot ?? join14(tmpdir5(), "dahrk", "scratch");
|
|
4106
|
+
const worktreePath = join14(base, runId);
|
|
4107
|
+
const scratchPath = join14(worktreePath, ".dahrk", "scratch");
|
|
4108
|
+
mkdirSync8(scratchPath, { recursive: true });
|
|
4056
4109
|
ref = { repoId: "", gitUrl: "", repo: "", baseBranch: "", worktreePath, scratchPath };
|
|
4057
4110
|
scratchOnly.add(runId);
|
|
4058
4111
|
}
|
|
@@ -4067,7 +4120,7 @@ function createStageRunner(deps) {
|
|
|
4067
4120
|
const slash = job.agentConfig.emitArtifact.lastIndexOf("/");
|
|
4068
4121
|
if (artifactDir && slash > 0) {
|
|
4069
4122
|
try {
|
|
4070
|
-
|
|
4123
|
+
mkdirSync8(join14(ref.worktreePath, job.agentConfig.emitArtifact.slice(0, slash)), { recursive: true });
|
|
4071
4124
|
} catch {
|
|
4072
4125
|
}
|
|
4073
4126
|
}
|
|
@@ -4082,7 +4135,7 @@ function createStageRunner(deps) {
|
|
|
4082
4135
|
runtime: agentConfig.runtime,
|
|
4083
4136
|
model: agentConfig.model,
|
|
4084
4137
|
sessionId: job.sessionId,
|
|
4085
|
-
configDigest:
|
|
4138
|
+
configDigest: digest2(agentConfig),
|
|
4086
4139
|
startedAt: nowIso2()
|
|
4087
4140
|
};
|
|
4088
4141
|
const writer = createTraceWriter(ref.scratchPath, meta);
|
|
@@ -4095,8 +4148,8 @@ function createStageRunner(deps) {
|
|
|
4095
4148
|
if (!sink) return;
|
|
4096
4149
|
const base = { tenantId: job.tenantId, runId, stageId, attempt };
|
|
4097
4150
|
try {
|
|
4098
|
-
for (const name of readdirSync3(
|
|
4099
|
-
const bytes =
|
|
4151
|
+
for (const name of readdirSync3(join14(writer.dir, "blobs"))) {
|
|
4152
|
+
const bytes = readFileSync6(join14(writer.dir, "blobs", name));
|
|
4100
4153
|
const { url } = await sink.requestBlobUrl({
|
|
4101
4154
|
...base,
|
|
4102
4155
|
sha256: name,
|
|
@@ -4110,8 +4163,8 @@ function createStageRunner(deps) {
|
|
|
4110
4163
|
}
|
|
4111
4164
|
let archiveKey;
|
|
4112
4165
|
try {
|
|
4113
|
-
const bytes =
|
|
4114
|
-
const sha =
|
|
4166
|
+
const bytes = readFileSync6(join14(writer.dir, "trace.jsonl"));
|
|
4167
|
+
const sha = createHash4("sha256").update(bytes).digest("hex");
|
|
4115
4168
|
const { key, url } = await sink.requestBlobUrl({
|
|
4116
4169
|
...base,
|
|
4117
4170
|
sha256: sha,
|
|
@@ -4187,6 +4240,24 @@ function createStageRunner(deps) {
|
|
|
4187
4240
|
return finish("fail", `${stageId}: ${msg}`, job.sessionId);
|
|
4188
4241
|
}
|
|
4189
4242
|
}
|
|
4243
|
+
const setup = job.setup;
|
|
4244
|
+
if (setup?.command && ref) {
|
|
4245
|
+
const outcome = runRepoSetup({ worktreePath: ref.worktreePath, command: setup.command });
|
|
4246
|
+
if (outcome.status === "failed") {
|
|
4247
|
+
const msg = `repo setup failed (exit ${outcome.exitCode ?? "null"})`;
|
|
4248
|
+
const detail2 = outcome.output ? `${msg}: ${outcome.output}` : msg;
|
|
4249
|
+
writer.append({ seq: 0, ts: nowIso2(), type: "error", runtime: agentConfig.runtime, kind: "setup-failed", message: detail2 });
|
|
4250
|
+
deps.sendProgress({ jobId, kind: "error", ts: nowIso2(), text: detail2 });
|
|
4251
|
+
return finish("fail", `${stageId}: ${msg}`, job.sessionId, void 0, void 0, "harness");
|
|
4252
|
+
}
|
|
4253
|
+
const detail = outcome.status === "cached" ? "setup: cached (already installed)" : `setup: ran (exit 0, ${outcome.output.length} bytes)`;
|
|
4254
|
+
streamEvent(
|
|
4255
|
+
writer.append({ seq: 0, ts: nowIso2(), type: "state", runtime: agentConfig.runtime, event: "setup", detail })
|
|
4256
|
+
);
|
|
4257
|
+
if (outcome.status === "ran") {
|
|
4258
|
+
deps.sendProgress({ jobId, kind: "observation", ts: nowIso2(), text: outcome.output || detail });
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4190
4261
|
let counter = runToolCalls.get(runId);
|
|
4191
4262
|
if (!counter) {
|
|
4192
4263
|
counter = { count: 0 };
|
|
@@ -4291,9 +4362,8 @@ function createStageRunner(deps) {
|
|
|
4291
4362
|
// auth above belongs to, plus the model fallback. The adapter applies nothing for a provider
|
|
4292
4363
|
// the hint does not name, so without this passthrough `runtimeEnv` arrives and is ignored -
|
|
4293
4364
|
// a managed node then has no inference auth at all and falls through to whatever provider the
|
|
4294
|
-
// runtime defaults to.
|
|
4295
|
-
//
|
|
4296
|
-
// both drop the cast when contracts ships.
|
|
4365
|
+
// runtime defaults to. A plain typed read since `@dahrk/contracts` declares `runtimeAuth` on
|
|
4366
|
+
// both `JobRequest` and `RunnerContext`.
|
|
4297
4367
|
...job.runtimeAuth ? { runtimeAuth: job.runtimeAuth } : {},
|
|
4298
4368
|
// The adapter persists each runtime-native record under the attempt's raw/ sidecar
|
|
4299
4369
|
// and stamps the rawRef onto the emitted event.
|
|
@@ -4354,7 +4424,7 @@ function createStageRunner(deps) {
|
|
|
4354
4424
|
if (status === "ok" && job.hooks && job.hooks.length > 0) {
|
|
4355
4425
|
for (const cmd of job.hooks) {
|
|
4356
4426
|
try {
|
|
4357
|
-
|
|
4427
|
+
execFileSync6("sh", ["-c", cmd], { cwd: ref.worktreePath, stdio: ["pipe", "pipe", "pipe"] });
|
|
4358
4428
|
} catch (e) {
|
|
4359
4429
|
status = "fail";
|
|
4360
4430
|
writer.append({ seq: 0, ts: nowIso2(), type: "error", runtime, kind: "hook-failed", message: `hook "${cmd}" failed: ${e.message}` });
|
|
@@ -4976,7 +5046,7 @@ var PROBES = [
|
|
|
4976
5046
|
{ runtime: "claude-code", cmd: "claude" },
|
|
4977
5047
|
{ runtime: "pi", cmd: "pi" }
|
|
4978
5048
|
];
|
|
4979
|
-
var
|
|
5049
|
+
var DEFAULT_TIMEOUT_MS2 = 5e3;
|
|
4980
5050
|
var DEFAULT_ATTEMPTS = 2;
|
|
4981
5051
|
function probeOnce(cmd, timeoutMs) {
|
|
4982
5052
|
return new Promise((resolve3) => {
|
|
@@ -4998,14 +5068,14 @@ async function probe(cmd, timeoutMs, attempts) {
|
|
|
4998
5068
|
}
|
|
4999
5069
|
return void 0;
|
|
5000
5070
|
}
|
|
5001
|
-
async function probeRuntimeStatuses(timeoutMs =
|
|
5071
|
+
async function probeRuntimeStatuses(timeoutMs = DEFAULT_TIMEOUT_MS2, attempts = DEFAULT_ATTEMPTS) {
|
|
5002
5072
|
const versions = await Promise.all(PROBES.map((p) => probe(p.cmd, timeoutMs, attempts)));
|
|
5003
5073
|
return PROBES.map((p, i) => {
|
|
5004
5074
|
const version = versions[i];
|
|
5005
5075
|
return version === void 0 ? { runtime: p.runtime, cmd: p.cmd, installed: false } : { runtime: p.runtime, cmd: p.cmd, installed: true, version };
|
|
5006
5076
|
});
|
|
5007
5077
|
}
|
|
5008
|
-
async function detectRuntimes(timeoutMs =
|
|
5078
|
+
async function detectRuntimes(timeoutMs = DEFAULT_TIMEOUT_MS2, attempts = DEFAULT_ATTEMPTS) {
|
|
5009
5079
|
const statuses = await probeRuntimeStatuses(timeoutMs, attempts);
|
|
5010
5080
|
return statuses.filter((s) => s.installed).map((s) => s.runtime);
|
|
5011
5081
|
}
|
|
@@ -5611,8 +5681,8 @@ function usage(bin, command) {
|
|
|
5611
5681
|
}
|
|
5612
5682
|
|
|
5613
5683
|
// src/diagnose.ts
|
|
5614
|
-
import { existsSync as
|
|
5615
|
-
import { join as
|
|
5684
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
5685
|
+
import { join as join15 } from "path";
|
|
5616
5686
|
|
|
5617
5687
|
// src/ui.ts
|
|
5618
5688
|
import { styleText } from "util";
|
|
@@ -5727,7 +5797,7 @@ async function buildBundle(deps) {
|
|
|
5727
5797
|
if (deps.exists(deps.crashDir)) {
|
|
5728
5798
|
for (const name of deps.listDir(deps.crashDir).filter((f) => f.endsWith(".json")).sort()) {
|
|
5729
5799
|
try {
|
|
5730
|
-
crashes.push(JSON.parse(deps.readFile(
|
|
5800
|
+
crashes.push(JSON.parse(deps.readFile(join15(deps.crashDir, name))));
|
|
5731
5801
|
} catch (e) {
|
|
5732
5802
|
warnings.push(`could not read crash record ${name} (${e.message})`);
|
|
5733
5803
|
}
|
|
@@ -5784,18 +5854,18 @@ var defaultDiagnoseDeps = (paths, clientVersion, doctor) => ({
|
|
|
5784
5854
|
...paths,
|
|
5785
5855
|
clientVersion,
|
|
5786
5856
|
...doctor ? { doctor } : {},
|
|
5787
|
-
readFile: (p) =>
|
|
5857
|
+
readFile: (p) => readFileSync7(p, "utf8"),
|
|
5788
5858
|
listDir: (p) => readdirSync4(p),
|
|
5789
|
-
exists: (p) =>
|
|
5859
|
+
exists: (p) => existsSync9(p),
|
|
5790
5860
|
writeFile: (p, content) => {
|
|
5791
|
-
const dir =
|
|
5792
|
-
if (!
|
|
5793
|
-
|
|
5861
|
+
const dir = join15(p, "..");
|
|
5862
|
+
if (!existsSync9(dir)) mkdirSync9(dir, { recursive: true });
|
|
5863
|
+
writeFileSync9(p, content, { mode: 384 });
|
|
5794
5864
|
},
|
|
5795
5865
|
out
|
|
5796
5866
|
});
|
|
5797
5867
|
function defaultBundlePath(cwd, now) {
|
|
5798
|
-
return
|
|
5868
|
+
return join15(cwd, `dahrk-diagnose-${now.toISOString().replace(/[:.]/g, "-")}.json`);
|
|
5799
5869
|
}
|
|
5800
5870
|
|
|
5801
5871
|
// src/doctor.ts
|
|
@@ -5929,7 +5999,7 @@ async function runDoctor(inputs, deps = {}) {
|
|
|
5929
5999
|
}
|
|
5930
6000
|
|
|
5931
6001
|
// src/repo-add.ts
|
|
5932
|
-
import { createHash as
|
|
6002
|
+
import { createHash as createHash5 } from "crypto";
|
|
5933
6003
|
var stripRepoSuffix = (s) => s.replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
5934
6004
|
function splitOwnerRepo(path) {
|
|
5935
6005
|
const parts = stripRepoSuffix(path).split("/").filter(Boolean);
|
|
@@ -5967,7 +6037,7 @@ var deriveRepoName = (remote) => remote.repo;
|
|
|
5967
6037
|
function deriveRepoId(gitUrl) {
|
|
5968
6038
|
const parsed = parseGitRemote(gitUrl);
|
|
5969
6039
|
const canonical2 = parsed ? `${parsed.host}/${parsed.owner}/${parsed.repo}`.toLowerCase() : gitUrl.trim().toLowerCase();
|
|
5970
|
-
const hash =
|
|
6040
|
+
const hash = createHash5("sha256").update(canonical2).digest("hex").slice(0, 12);
|
|
5971
6041
|
const slug = (parsed ? parsed.repo : "repo").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
5972
6042
|
return `${slug}-${hash}`;
|
|
5973
6043
|
}
|
|
@@ -6015,8 +6085,8 @@ async function registerRepo(deps, args) {
|
|
|
6015
6085
|
}
|
|
6016
6086
|
|
|
6017
6087
|
// src/lock.ts
|
|
6018
|
-
import { existsSync as
|
|
6019
|
-
import { dirname as
|
|
6088
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync10, readFileSync as readFileSync8, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "fs";
|
|
6089
|
+
import { dirname as dirname7 } from "path";
|
|
6020
6090
|
function parseLock(content) {
|
|
6021
6091
|
if (!content) return void 0;
|
|
6022
6092
|
const pid = Number(content.trim());
|
|
@@ -6048,14 +6118,14 @@ var defaultLockDeps = (file) => ({
|
|
|
6048
6118
|
pid: process.pid,
|
|
6049
6119
|
readFile: (path) => {
|
|
6050
6120
|
try {
|
|
6051
|
-
return
|
|
6121
|
+
return readFileSync8(path, "utf8");
|
|
6052
6122
|
} catch {
|
|
6053
6123
|
return void 0;
|
|
6054
6124
|
}
|
|
6055
6125
|
},
|
|
6056
6126
|
writeFile: (path, content) => {
|
|
6057
|
-
if (!
|
|
6058
|
-
|
|
6127
|
+
if (!existsSync10(dirname7(path))) mkdirSync10(dirname7(path), { recursive: true, mode: 448 });
|
|
6128
|
+
writeFileSync10(path, content);
|
|
6059
6129
|
},
|
|
6060
6130
|
removeFile: (path) => rmSync7(path, { force: true }),
|
|
6061
6131
|
isAlive
|
|
@@ -6063,7 +6133,7 @@ var defaultLockDeps = (file) => ({
|
|
|
6063
6133
|
|
|
6064
6134
|
// src/logs.ts
|
|
6065
6135
|
import { spawn } from "child_process";
|
|
6066
|
-
import { copyFileSync, existsSync as
|
|
6136
|
+
import { copyFileSync, existsSync as existsSync11, readFileSync as readFileSync9, statSync as statSync4, truncateSync } from "fs";
|
|
6067
6137
|
var MAX_LOG_BYTES = 10 * 1024 * 1024;
|
|
6068
6138
|
function logsCommand(inputs) {
|
|
6069
6139
|
return [
|
|
@@ -6144,7 +6214,7 @@ async function runStructuredLogs(inputs, deps) {
|
|
|
6144
6214
|
}
|
|
6145
6215
|
function rotateIfLarge(file, maxBytes = MAX_LOG_BYTES) {
|
|
6146
6216
|
try {
|
|
6147
|
-
if (!
|
|
6217
|
+
if (!existsSync11(file) || statSync4(file).size <= maxBytes) return;
|
|
6148
6218
|
copyFileSync(file, `${file}.1`);
|
|
6149
6219
|
truncateSync(file, 0);
|
|
6150
6220
|
} catch {
|
|
@@ -6153,8 +6223,8 @@ function rotateIfLarge(file, maxBytes = MAX_LOG_BYTES) {
|
|
|
6153
6223
|
var defaultLogsDeps = (files, jsonlFile) => ({
|
|
6154
6224
|
files,
|
|
6155
6225
|
jsonlFile,
|
|
6156
|
-
fileExists: (path) =>
|
|
6157
|
-
readFile: (path) =>
|
|
6226
|
+
fileExists: (path) => existsSync11(path),
|
|
6227
|
+
readFile: (path) => readFileSync9(path, "utf8"),
|
|
6158
6228
|
run: (argv) => new Promise((resolve3) => {
|
|
6159
6229
|
const [cmd, ...args] = argv;
|
|
6160
6230
|
const child = spawn(cmd, args, { stdio: "inherit" });
|
|
@@ -6165,13 +6235,13 @@ var defaultLogsDeps = (files, jsonlFile) => ({
|
|
|
6165
6235
|
});
|
|
6166
6236
|
|
|
6167
6237
|
// src/process-safety.ts
|
|
6168
|
-
import { mkdirSync as
|
|
6169
|
-
import { join as
|
|
6238
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
|
|
6239
|
+
import { join as join16 } from "path";
|
|
6170
6240
|
function writeCrashRecord(dir, record) {
|
|
6171
6241
|
try {
|
|
6172
|
-
|
|
6173
|
-
const file =
|
|
6174
|
-
|
|
6242
|
+
mkdirSync11(dir, { recursive: true, mode: 448 });
|
|
6243
|
+
const file = join16(dir, `${record.at.replace(/[:.]/g, "-")}.json`);
|
|
6244
|
+
writeFileSync11(file, `${JSON.stringify(record, null, 2)}
|
|
6175
6245
|
`, { mode: 384 });
|
|
6176
6246
|
return file;
|
|
6177
6247
|
} catch {
|
|
@@ -6224,11 +6294,11 @@ function installProcessSafetyNet(opts) {
|
|
|
6224
6294
|
}
|
|
6225
6295
|
|
|
6226
6296
|
// src/preflight.ts
|
|
6227
|
-
import { execFileSync as
|
|
6297
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
6228
6298
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6229
|
-
import { accessSync, constants as fsConstants, existsSync as
|
|
6299
|
+
import { accessSync, constants as fsConstants, existsSync as existsSync12, readdirSync as readdirSync5, statfsSync as statfsSync2 } from "fs";
|
|
6230
6300
|
import { homedir as homedir4 } from "os";
|
|
6231
|
-
import { join as
|
|
6301
|
+
import { join as join17 } from "path";
|
|
6232
6302
|
var REPORT_BASE_URL = "https://app.dahrk.ai/r";
|
|
6233
6303
|
var LOW_DISK_BYTES = 512 * 1024 * 1024;
|
|
6234
6304
|
var PREFLIGHT_STAGES = [
|
|
@@ -6359,7 +6429,7 @@ var defaultDeps2 = () => ({
|
|
|
6359
6429
|
});
|
|
6360
6430
|
function commandPresent(cmd) {
|
|
6361
6431
|
try {
|
|
6362
|
-
|
|
6432
|
+
execFileSync7("sh", ["-c", `command -v ${cmd}`], { stdio: "ignore" });
|
|
6363
6433
|
return true;
|
|
6364
6434
|
} catch {
|
|
6365
6435
|
return false;
|
|
@@ -6367,12 +6437,12 @@ function commandPresent(cmd) {
|
|
|
6367
6437
|
}
|
|
6368
6438
|
function sshKeyPresent() {
|
|
6369
6439
|
try {
|
|
6370
|
-
const dir =
|
|
6371
|
-
if (
|
|
6440
|
+
const dir = join17(homedir4(), ".ssh");
|
|
6441
|
+
if (existsSync12(dir) && readdirSync5(dir).some((f) => f.endsWith(".pub"))) return true;
|
|
6372
6442
|
} catch {
|
|
6373
6443
|
}
|
|
6374
6444
|
try {
|
|
6375
|
-
|
|
6445
|
+
execFileSync7("ssh-add", ["-l"], { stdio: "ignore" });
|
|
6376
6446
|
return true;
|
|
6377
6447
|
} catch {
|
|
6378
6448
|
return false;
|
|
@@ -6387,12 +6457,12 @@ function writable(dir) {
|
|
|
6387
6457
|
}
|
|
6388
6458
|
}
|
|
6389
6459
|
function worktreeRoot(env) {
|
|
6390
|
-
return env.DAHRK_WORKTREES_DIR ??
|
|
6460
|
+
return env.DAHRK_WORKTREES_DIR ?? join17(env.DAHRK_STATE_DIR ?? join17(homedir4(), ".dahrk"), "worktrees");
|
|
6391
6461
|
}
|
|
6392
6462
|
function nearestExisting(dir) {
|
|
6393
6463
|
let cur = dir;
|
|
6394
|
-
while (!
|
|
6395
|
-
const parent =
|
|
6464
|
+
while (!existsSync12(cur)) {
|
|
6465
|
+
const parent = join17(cur, "..");
|
|
6396
6466
|
if (parent === cur) break;
|
|
6397
6467
|
cur = parent;
|
|
6398
6468
|
}
|
|
@@ -6407,7 +6477,7 @@ function freeDiskBytes(dir) {
|
|
|
6407
6477
|
}
|
|
6408
6478
|
}
|
|
6409
6479
|
function probeRepo(repoPath) {
|
|
6410
|
-
const git = (args) =>
|
|
6480
|
+
const git = (args) => execFileSync7("git", ["-C", repoPath, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
6411
6481
|
try {
|
|
6412
6482
|
if (git(["rev-parse", "--is-inside-work-tree"]) !== "true") {
|
|
6413
6483
|
return { path: repoPath, isGitRepo: false, headResolves: false, detail: "not inside a work tree" };
|
|
@@ -6453,15 +6523,15 @@ function gatherHostFacts(repoPath) {
|
|
|
6453
6523
|
}
|
|
6454
6524
|
|
|
6455
6525
|
// src/service.ts
|
|
6456
|
-
import { execFileSync as
|
|
6457
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
6526
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
6527
|
+
import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync13, readFileSync as readFileSync11, realpathSync as realpathSync3, rmSync as rmSync8, writeFileSync as writeFileSync13 } from "fs";
|
|
6458
6528
|
import { homedir as homedir6, platform as osPlatform3, userInfo } from "os";
|
|
6459
|
-
import { join as
|
|
6529
|
+
import { join as join19 } from "path";
|
|
6460
6530
|
|
|
6461
6531
|
// src/state.ts
|
|
6462
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
6532
|
+
import { chmodSync as chmodSync2, existsSync as existsSync13, mkdirSync as mkdirSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync12 } from "fs";
|
|
6463
6533
|
import { homedir as homedir5 } from "os";
|
|
6464
|
-
import { join as
|
|
6534
|
+
import { join as join18 } from "path";
|
|
6465
6535
|
var RUNTIMES = ["claude-code", "codex", "pi"];
|
|
6466
6536
|
var isRuntime = (v) => RUNTIMES.includes(v);
|
|
6467
6537
|
var STRING_FIELDS = ["nodeId", "enrolToken", "name", "tenantId", "updateCheckedAt", "updateLatest"];
|
|
@@ -6469,37 +6539,37 @@ var isDesired = (v) => v === "running" || v === "stopped";
|
|
|
6469
6539
|
var FILE_MODE2 = 384;
|
|
6470
6540
|
var DIR_MODE2 = 448;
|
|
6471
6541
|
function stateDir(env) {
|
|
6472
|
-
return env.DAHRK_STATE_DIR ??
|
|
6542
|
+
return env.DAHRK_STATE_DIR ?? join18(homedir5(), ".dahrk");
|
|
6473
6543
|
}
|
|
6474
6544
|
function legacyStateDir(env) {
|
|
6475
|
-
return env.DAHRK_STATE_DIR ? void 0 :
|
|
6545
|
+
return env.DAHRK_STATE_DIR ? void 0 : join18(homedir5(), ".skakel");
|
|
6476
6546
|
}
|
|
6477
6547
|
function stateFile(env) {
|
|
6478
|
-
return
|
|
6548
|
+
return join18(stateDir(env), "node.json");
|
|
6479
6549
|
}
|
|
6480
6550
|
function logDir(env) {
|
|
6481
|
-
return
|
|
6551
|
+
return join18(stateDir(env), "logs");
|
|
6482
6552
|
}
|
|
6483
6553
|
function logFiles(env) {
|
|
6484
6554
|
const dir = logDir(env);
|
|
6485
|
-
return { out:
|
|
6555
|
+
return { out: join18(dir, "node.out.log"), err: join18(dir, "node.err.log") };
|
|
6486
6556
|
}
|
|
6487
6557
|
function jsonlLogFile(env) {
|
|
6488
|
-
return
|
|
6558
|
+
return join18(logDir(env), "node.jsonl");
|
|
6489
6559
|
}
|
|
6490
6560
|
function crashDir(env) {
|
|
6491
|
-
return
|
|
6561
|
+
return join18(logDir(env), "crashes");
|
|
6492
6562
|
}
|
|
6493
6563
|
function lockFile(env) {
|
|
6494
|
-
return
|
|
6564
|
+
return join18(stateDir(env), "node.pid");
|
|
6495
6565
|
}
|
|
6496
6566
|
function setDesired(env, desired) {
|
|
6497
6567
|
writeState(env, { desired });
|
|
6498
6568
|
}
|
|
6499
6569
|
function readState(file) {
|
|
6500
|
-
if (!
|
|
6570
|
+
if (!existsSync13(file)) return {};
|
|
6501
6571
|
try {
|
|
6502
|
-
const parsed = JSON.parse(
|
|
6572
|
+
const parsed = JSON.parse(readFileSync10(file, "utf8"));
|
|
6503
6573
|
const state = {};
|
|
6504
6574
|
for (const key of STRING_FIELDS) {
|
|
6505
6575
|
const value = parsed[key];
|
|
@@ -6519,9 +6589,9 @@ function writeState(env, patch) {
|
|
|
6519
6589
|
const dir = stateDir(env);
|
|
6520
6590
|
const file = stateFile(env);
|
|
6521
6591
|
try {
|
|
6522
|
-
|
|
6592
|
+
mkdirSync12(dir, { recursive: true, mode: DIR_MODE2 });
|
|
6523
6593
|
const next = { ...readState(file), ...patch };
|
|
6524
|
-
|
|
6594
|
+
writeFileSync12(file, `${JSON.stringify(next, null, 2)}
|
|
6525
6595
|
`, { mode: FILE_MODE2 });
|
|
6526
6596
|
chmodSync2(file, FILE_MODE2);
|
|
6527
6597
|
} catch (e) {
|
|
@@ -6602,9 +6672,9 @@ ${envEntries}
|
|
|
6602
6672
|
<key>ThrottleInterval</key>
|
|
6603
6673
|
<integer>10</integer>
|
|
6604
6674
|
<key>StandardOutPath</key>
|
|
6605
|
-
<string>${xmlEscape(
|
|
6675
|
+
<string>${xmlEscape(join19(inputs.logDir, "node.out.log"))}</string>
|
|
6606
6676
|
<key>StandardErrorPath</key>
|
|
6607
|
-
<string>${xmlEscape(
|
|
6677
|
+
<string>${xmlEscape(join19(inputs.logDir, "node.err.log"))}</string>
|
|
6608
6678
|
</dict>
|
|
6609
6679
|
</plist>
|
|
6610
6680
|
`;
|
|
@@ -6627,8 +6697,8 @@ Type=simple
|
|
|
6627
6697
|
ExecStart=${exec}
|
|
6628
6698
|
${envLines}
|
|
6629
6699
|
WorkingDirectory=${inputs.homeDir}
|
|
6630
|
-
StandardOutput=append:${
|
|
6631
|
-
StandardError=append:${
|
|
6700
|
+
StandardOutput=append:${join19(inputs.logDir, "node.out.log")}
|
|
6701
|
+
StandardError=append:${join19(inputs.logDir, "node.err.log")}
|
|
6632
6702
|
Restart=on-failure
|
|
6633
6703
|
RestartSec=3
|
|
6634
6704
|
RestartPreventExitStatus=78
|
|
@@ -6639,7 +6709,7 @@ WantedBy=default.target
|
|
|
6639
6709
|
}
|
|
6640
6710
|
function buildPlan(inputs) {
|
|
6641
6711
|
if (inputs.manager === "launchd") {
|
|
6642
|
-
const filePath2 =
|
|
6712
|
+
const filePath2 = join19(inputs.homeDir, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
6643
6713
|
return {
|
|
6644
6714
|
manager: "launchd",
|
|
6645
6715
|
label: LAUNCHD_LABEL,
|
|
@@ -6656,7 +6726,7 @@ function buildPlan(inputs) {
|
|
|
6656
6726
|
logHint: "dahrk logs -f"
|
|
6657
6727
|
};
|
|
6658
6728
|
}
|
|
6659
|
-
const filePath =
|
|
6729
|
+
const filePath = join19(inputs.homeDir, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
6660
6730
|
const user = userInfo().username;
|
|
6661
6731
|
return {
|
|
6662
6732
|
manager: "systemd",
|
|
@@ -6686,7 +6756,7 @@ function unitIsCurrent(plan, onDisk) {
|
|
|
6686
6756
|
return onDisk === plan.content;
|
|
6687
6757
|
}
|
|
6688
6758
|
function unitPath(manager, homeDir) {
|
|
6689
|
-
return manager === "launchd" ?
|
|
6759
|
+
return manager === "launchd" ? join19(homeDir, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`) : join19(homeDir, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
6690
6760
|
}
|
|
6691
6761
|
function statusCommand(manager) {
|
|
6692
6762
|
return manager === "launchd" ? ["launchctl", "list", LAUNCHD_LABEL] : ["systemctl", "--user", "show", SYSTEMD_UNIT, "-p", "ActiveState", "-p", "MainPID"];
|
|
@@ -6983,29 +7053,29 @@ var defaultDeps3 = () => ({
|
|
|
6983
7053
|
// Snapshot the operator's PATH at install time so the daemon finds git + the runtime CLIs (Homebrew /
|
|
6984
7054
|
// npm-global bins) that a supervisor's minimal PATH would otherwise hide.
|
|
6985
7055
|
pathEnv: process.env.PATH,
|
|
6986
|
-
mkdirp: (dir) => void
|
|
7056
|
+
mkdirp: (dir) => void mkdirSync13(dir, { recursive: true }),
|
|
6987
7057
|
// The unit holds no secret any more, but it stays owner-only: it names paths on this host, and there is
|
|
6988
7058
|
// no reason for it to be world-readable. `writeFileSync`'s `mode` applies only when it CREATES the file,
|
|
6989
7059
|
// so chmod explicitly too - re-installing over a unit an older client left at 0644 must tighten it.
|
|
6990
7060
|
writeFile: (path, content) => {
|
|
6991
|
-
|
|
7061
|
+
writeFileSync13(path, content, { mode: UNIT_FILE_MODE });
|
|
6992
7062
|
chmodSync3(path, UNIT_FILE_MODE);
|
|
6993
7063
|
},
|
|
6994
7064
|
readFile: (path) => {
|
|
6995
7065
|
try {
|
|
6996
|
-
return
|
|
7066
|
+
return readFileSync11(path, "utf8");
|
|
6997
7067
|
} catch {
|
|
6998
7068
|
return void 0;
|
|
6999
7069
|
}
|
|
7000
7070
|
},
|
|
7001
7071
|
removeFile: (path) => rmSync8(path, { force: true }),
|
|
7002
|
-
fileExists: (path) =>
|
|
7072
|
+
fileExists: (path) => existsSync14(path),
|
|
7003
7073
|
// Captured, never inherited. A supervisor's stderr is ours to relay when it matters, not to leak
|
|
7004
7074
|
// unconditionally: `runCommands` decides who needs to read it.
|
|
7005
7075
|
run: (argv) => {
|
|
7006
7076
|
const [cmd, ...args] = argv;
|
|
7007
7077
|
try {
|
|
7008
|
-
const stdout =
|
|
7078
|
+
const stdout = execFileSync8(cmd, args, {
|
|
7009
7079
|
encoding: "utf8",
|
|
7010
7080
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7011
7081
|
});
|
|
@@ -7020,7 +7090,7 @@ var defaultDeps3 = () => ({
|
|
|
7020
7090
|
capture: (argv) => {
|
|
7021
7091
|
const [cmd, ...args] = argv;
|
|
7022
7092
|
try {
|
|
7023
|
-
const stdout =
|
|
7093
|
+
const stdout = execFileSync8(cmd, args, {
|
|
7024
7094
|
encoding: "utf8",
|
|
7025
7095
|
stdio: ["ignore", "pipe", "ignore"]
|
|
7026
7096
|
});
|
|
@@ -7034,7 +7104,7 @@ var defaultDeps3 = () => ({
|
|
|
7034
7104
|
});
|
|
7035
7105
|
|
|
7036
7106
|
// src/update.ts
|
|
7037
|
-
import { execFileSync as
|
|
7107
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
7038
7108
|
import { realpathSync as realpathSync4 } from "fs";
|
|
7039
7109
|
var LATEST_URL = "https://registry.npmjs.org/dahrk-node/latest";
|
|
7040
7110
|
var CHANNEL_COMMANDS = {
|
|
@@ -7166,7 +7236,7 @@ async function fetchLatestVersion(signal) {
|
|
|
7166
7236
|
function spawnUpgrade(argv) {
|
|
7167
7237
|
const [cmd, ...args] = argv;
|
|
7168
7238
|
try {
|
|
7169
|
-
const stdout =
|
|
7239
|
+
const stdout = execFileSync9(cmd, args, {
|
|
7170
7240
|
encoding: "utf8",
|
|
7171
7241
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7172
7242
|
});
|
|
@@ -7439,7 +7509,7 @@ async function runStatus(inputs, deps) {
|
|
|
7439
7509
|
}
|
|
7440
7510
|
|
|
7441
7511
|
// src/main.ts
|
|
7442
|
-
var CLIENT_VERSION = "0.1.
|
|
7512
|
+
var CLIENT_VERSION = "0.1.25";
|
|
7443
7513
|
var DEFAULT_HUB_URL = "wss://api.dahrk.ai";
|
|
7444
7514
|
var list = (v) => (v ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
7445
7515
|
var RUNTIMES2 = ["claude-code", "codex", "pi"];
|
|
@@ -7451,7 +7521,7 @@ function resolveNodeId(env, opts = {}) {
|
|
|
7451
7521
|
if (existing) return existing;
|
|
7452
7522
|
const legacy = legacyStateDir(env);
|
|
7453
7523
|
if (legacy) {
|
|
7454
|
-
const legacyId = readState(
|
|
7524
|
+
const legacyId = readState(join20(legacy, "node.json")).nodeId;
|
|
7455
7525
|
if (legacyId) return legacyId;
|
|
7456
7526
|
}
|
|
7457
7527
|
const nodeId = randomUUID3();
|
|
@@ -7719,11 +7789,11 @@ function statusDeps(env) {
|
|
|
7719
7789
|
}
|
|
7720
7790
|
return probeRuntimeStatuses();
|
|
7721
7791
|
},
|
|
7722
|
-
fileExists: (path) =>
|
|
7792
|
+
fileExists: (path) => existsSync15(path),
|
|
7723
7793
|
capture: (argv) => {
|
|
7724
7794
|
const [cmd, ...args] = argv;
|
|
7725
7795
|
try {
|
|
7726
|
-
const stdout =
|
|
7796
|
+
const stdout = execFileSync10(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
7727
7797
|
return { code: 0, stdout };
|
|
7728
7798
|
} catch (e) {
|
|
7729
7799
|
const status = e.status;
|
|
@@ -7748,7 +7818,7 @@ function statusDeps(env) {
|
|
|
7748
7818
|
}
|
|
7749
7819
|
function readFileOrUndefined(path) {
|
|
7750
7820
|
try {
|
|
7751
|
-
return
|
|
7821
|
+
return readFileSync12(path, "utf8");
|
|
7752
7822
|
} catch {
|
|
7753
7823
|
return void 0;
|
|
7754
7824
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dahrk-node",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"exports": "./dist/main.js",
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@anthropic-ai/claude-agent-sdk": "0.3.183",
|
|
37
|
-
"@dahrk/contracts": "^0.
|
|
37
|
+
"@dahrk/contracts": "^0.7.0",
|
|
38
38
|
"pino": "^10.3.1",
|
|
39
39
|
"ws": "^8.18.0",
|
|
40
40
|
"zod": "^3.23.8"
|