@wrongstack/core 0.8.5 → 0.9.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/dist/{agent-bridge-DPxcUVkn.d.ts → agent-bridge-Bad3ZGQ7.d.ts} +1 -1
- package/dist/{agent-subagent-runner-Cav3yEJM.d.ts → agent-subagent-runner-Cc8sRJOF.d.ts} +3 -3
- package/dist/coordination/index.d.ts +8 -8
- package/dist/defaults/index.d.ts +11 -11
- package/dist/defaults/index.js +17 -4
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-DyhxkstG.d.ts → events-yCpJD4wa.d.ts} +49 -0
- package/dist/execution/index.d.ts +7 -7
- package/dist/extension/index.d.ts +2 -2
- package/dist/index-Dl3PaD7f.d.ts +209 -0
- package/dist/{index-oYZeWsuJ.d.ts → index-SxpnwRlJ.d.ts} +1 -1
- package/dist/index.d.ts +51 -18
- package/dist/index.js +448 -51
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +2 -2
- package/dist/kernel/index.d.ts +16 -88
- package/dist/kernel/index.js +3 -1
- package/dist/kernel/index.js.map +1 -1
- package/dist/{multi-agent-CRMznZmf.d.ts → multi-agent-C8uY45AY.d.ts} +9 -1
- package/dist/{multi-agent-coordinator-IQKrMfXz.d.ts → multi-agent-coordinator-C7YbZUY8.d.ts} +2 -2
- package/dist/{null-fleet-bus-sKnVwEd8.d.ts → null-fleet-bus-Bb2jVLKr.d.ts} +5 -5
- package/dist/observability/index.d.ts +1 -1
- package/dist/{path-resolver-1CIYbH2Q.d.ts → path-resolver-DnC1nOjb.d.ts} +1 -1
- package/dist/{plan-templates-D8zQgZzc.d.ts → plan-templates-Cc-04Z8o.d.ts} +10 -5
- package/dist/{provider-runner-BrA0XR-l.d.ts → provider-runner-C4ouU7--.d.ts} +1 -1
- package/dist/sdd/index.d.ts +4 -4
- package/dist/storage/index.d.ts +7 -4
- package/dist/storage/index.js +32 -10
- package/dist/storage/index.js.map +1 -1
- package/dist/{tool-executor-QwfWnQZ8.d.ts → tool-executor-Ch25BDwa.d.ts} +1 -1
- package/dist/types/index.d.ts +7 -7
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/{wstack-paths-Bxik3CsK.d.ts → wstack-paths-CJYrjQU8.d.ts} +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { randomBytes, createCipheriv, createDecipheriv, randomUUID, createHash }
|
|
|
3
3
|
import * as fsp2 from 'fs/promises';
|
|
4
4
|
import { readFile, readdir, stat, mkdir } from 'fs/promises';
|
|
5
5
|
import * as path6 from 'path';
|
|
6
|
-
import { join, extname, relative } from 'path';
|
|
6
|
+
import { join, extname, relative, resolve, sep } from 'path';
|
|
7
7
|
import * as fs2 from 'fs';
|
|
8
8
|
import * as os5 from 'os';
|
|
9
9
|
import { execFile, spawn } from 'child_process';
|
|
@@ -93,7 +93,7 @@ async function renameWithRetry(from, to) {
|
|
|
93
93
|
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
94
94
|
throw err;
|
|
95
95
|
}
|
|
96
|
-
await new Promise((
|
|
96
|
+
await new Promise((resolve9) => setTimeout(resolve9, delays[i]));
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
throw lastErr;
|
|
@@ -830,7 +830,9 @@ var TOKENS = {
|
|
|
830
830
|
ModelsRegistry: t("ModelsRegistry"),
|
|
831
831
|
ModeStore: t("ModeStore"),
|
|
832
832
|
/** Replaces the entire provider call layer — retry, streaming, tracing. */
|
|
833
|
-
ProviderRunner: t("ProviderRunner")
|
|
833
|
+
ProviderRunner: t("ProviderRunner"),
|
|
834
|
+
/** Optional git-worktree lifecycle manager (per-phase isolation in AutoPhase). */
|
|
835
|
+
WorktreeManager: t("WorktreeManager")
|
|
834
836
|
};
|
|
835
837
|
|
|
836
838
|
// src/kernel/run-controller.ts
|
|
@@ -2692,7 +2694,7 @@ var InMemoryAgentBridge = class {
|
|
|
2692
2694
|
);
|
|
2693
2695
|
}
|
|
2694
2696
|
this.inflightGuards.add(correlationId);
|
|
2695
|
-
return new Promise((
|
|
2697
|
+
return new Promise((resolve9, reject) => {
|
|
2696
2698
|
const timer = setTimeout(() => {
|
|
2697
2699
|
this.inflightGuards.delete(correlationId);
|
|
2698
2700
|
this.pendingRequests.delete(correlationId);
|
|
@@ -2704,7 +2706,7 @@ var InMemoryAgentBridge = class {
|
|
|
2704
2706
|
return;
|
|
2705
2707
|
}
|
|
2706
2708
|
this.pendingRequests.set(correlationId, {
|
|
2707
|
-
resolve:
|
|
2709
|
+
resolve: resolve9,
|
|
2708
2710
|
reject,
|
|
2709
2711
|
timer
|
|
2710
2712
|
});
|
|
@@ -3920,6 +3922,7 @@ function resolveWstackPaths(opts) {
|
|
|
3920
3922
|
projectLocalConfig: path6.join(projectDir, "config.local.json"),
|
|
3921
3923
|
inProjectAgentsFile: path6.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
3922
3924
|
inProjectSkills: path6.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
3925
|
+
inProjectWorktrees: path6.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
3923
3926
|
projectHash: hash,
|
|
3924
3927
|
projectGoal: path6.join(projectDir, "goal.json"),
|
|
3925
3928
|
projectSpecs: path6.join(projectDir, "specs"),
|
|
@@ -3987,7 +3990,9 @@ function looksSecret(name) {
|
|
|
3987
3990
|
}
|
|
3988
3991
|
function buildChildEnv(optsOrSessionId) {
|
|
3989
3992
|
const opts = typeof optsOrSessionId === "string" ? { sessionId: optsOrSessionId } : optsOrSessionId ?? {};
|
|
3990
|
-
const
|
|
3993
|
+
const hasOwn = Object.prototype.hasOwnProperty.call(process.env, "WRONGSTACK_CHILD_ENV_PASSTHROUGH");
|
|
3994
|
+
const legacyHasOwn = Object.prototype.hasOwnProperty.call(process.env, "WRONGSTACK_BASH_ENV_PASSTHROUGH");
|
|
3995
|
+
const passthrough = hasOwn && process.env["WRONGSTACK_CHILD_ENV_PASSTHROUGH"] === "1" || legacyHasOwn && process.env["WRONGSTACK_BASH_ENV_PASSTHROUGH"] === "1";
|
|
3991
3996
|
if (passthrough && !process.env["CI"]) {
|
|
3992
3997
|
console.warn(
|
|
3993
3998
|
"[WrongStack] WARNING: WRONGSTACK_*_ENV_PASSTHROUGH=1 is active \u2014\n all parent env vars (including API keys) forwarded to child processes.\n Do not use on shared or multi-tenant systems."
|
|
@@ -5366,9 +5371,14 @@ var RecoveryLock = class {
|
|
|
5366
5371
|
};
|
|
5367
5372
|
}
|
|
5368
5373
|
/**
|
|
5369
|
-
* Claim the lock for the given session.
|
|
5370
|
-
*
|
|
5371
|
-
* `checkAbandoned`
|
|
5374
|
+
* Claim the lock for the given session. Uses exclusive-create (`O_EXCL`)
|
|
5375
|
+
* to detect whether another process acquired the lock between our
|
|
5376
|
+
* `checkAbandoned()` call and now. If the file already exists, it means
|
|
5377
|
+
* another process won the race and we throw instead of silently
|
|
5378
|
+
* overwriting their recovery record.
|
|
5379
|
+
*
|
|
5380
|
+
* The caller MUST have already called `checkAbandoned()` and handled its
|
|
5381
|
+
* null return before calling this.
|
|
5372
5382
|
*/
|
|
5373
5383
|
async write(sessionId) {
|
|
5374
5384
|
await ensureDir(path6.dirname(this.file));
|
|
@@ -5379,7 +5389,15 @@ var RecoveryLock = class {
|
|
|
5379
5389
|
hostname: this.hostname,
|
|
5380
5390
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5381
5391
|
};
|
|
5382
|
-
|
|
5392
|
+
try {
|
|
5393
|
+
await fsp2.writeFile(this.file, JSON.stringify(lock), { flag: "wx", mode: 384 });
|
|
5394
|
+
} catch (err) {
|
|
5395
|
+
const code = err.code;
|
|
5396
|
+
if (code === "EEXIST") {
|
|
5397
|
+
throw new Error(`Recovery lock already held by another process`);
|
|
5398
|
+
}
|
|
5399
|
+
throw err;
|
|
5400
|
+
}
|
|
5383
5401
|
}
|
|
5384
5402
|
/**
|
|
5385
5403
|
* Release the lock. Idempotent — silently succeeds if the file is
|
|
@@ -6621,8 +6639,8 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
|
|
|
6621
6639
|
try {
|
|
6622
6640
|
await Promise.race([
|
|
6623
6641
|
Promise.resolve(iter.return?.()),
|
|
6624
|
-
new Promise((
|
|
6625
|
-
drainTimer = setTimeout(
|
|
6642
|
+
new Promise((resolve9) => {
|
|
6643
|
+
drainTimer = setTimeout(resolve9, 500);
|
|
6626
6644
|
})
|
|
6627
6645
|
]);
|
|
6628
6646
|
} finally {
|
|
@@ -6683,7 +6701,7 @@ async function runProviderWithRetry(opts) {
|
|
|
6683
6701
|
description
|
|
6684
6702
|
});
|
|
6685
6703
|
}
|
|
6686
|
-
await new Promise((
|
|
6704
|
+
await new Promise((resolve9, reject) => {
|
|
6687
6705
|
let settled = false;
|
|
6688
6706
|
const onAbort = () => {
|
|
6689
6707
|
if (settled) return;
|
|
@@ -6696,7 +6714,7 @@ async function runProviderWithRetry(opts) {
|
|
|
6696
6714
|
settled = true;
|
|
6697
6715
|
clearTimeout(t2);
|
|
6698
6716
|
signal.removeEventListener("abort", onAbort);
|
|
6699
|
-
|
|
6717
|
+
resolve9();
|
|
6700
6718
|
}, delay);
|
|
6701
6719
|
if (signal.aborted) {
|
|
6702
6720
|
onAbort();
|
|
@@ -8340,7 +8358,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
8340
8358
|
}
|
|
8341
8359
|
};
|
|
8342
8360
|
function sleep(ms) {
|
|
8343
|
-
return new Promise((
|
|
8361
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
8344
8362
|
}
|
|
8345
8363
|
|
|
8346
8364
|
// src/coordination/subagent-budget.ts
|
|
@@ -8490,12 +8508,12 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
8490
8508
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
8491
8509
|
return Promise.resolve("stop");
|
|
8492
8510
|
}
|
|
8493
|
-
return new Promise((
|
|
8511
|
+
return new Promise((resolve9) => {
|
|
8494
8512
|
let resolved = false;
|
|
8495
8513
|
const respond = (d) => {
|
|
8496
8514
|
if (resolved) return;
|
|
8497
8515
|
resolved = true;
|
|
8498
|
-
|
|
8516
|
+
resolve9(d);
|
|
8499
8517
|
};
|
|
8500
8518
|
const fallback = setTimeout(
|
|
8501
8519
|
() => respond("stop"),
|
|
@@ -11536,7 +11554,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
11536
11554
|
taskIds.map((id) => {
|
|
11537
11555
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
11538
11556
|
if (cached) return cached;
|
|
11539
|
-
return new Promise((
|
|
11557
|
+
return new Promise((resolve9, reject) => {
|
|
11540
11558
|
const timeout = setTimeout(() => {
|
|
11541
11559
|
this.off("task.completed", handler);
|
|
11542
11560
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -11545,7 +11563,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
11545
11563
|
if (result.taskId === id) {
|
|
11546
11564
|
clearTimeout(timeout);
|
|
11547
11565
|
this.off("task.completed", handler);
|
|
11548
|
-
|
|
11566
|
+
resolve9(result);
|
|
11549
11567
|
}
|
|
11550
11568
|
};
|
|
11551
11569
|
this.on("task.completed", handler);
|
|
@@ -11975,7 +11993,7 @@ function providerErrorToSubagentError(err, message, cause) {
|
|
|
11975
11993
|
|
|
11976
11994
|
// src/execution/parallel-eternal-engine.ts
|
|
11977
11995
|
function sleep2(ms) {
|
|
11978
|
-
return new Promise((
|
|
11996
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
11979
11997
|
}
|
|
11980
11998
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
11981
11999
|
var ParallelEternalEngine = class {
|
|
@@ -13617,11 +13635,11 @@ var Director = class {
|
|
|
13617
13635
|
if (cached) return cached;
|
|
13618
13636
|
const existing = this.taskWaiters.get(id);
|
|
13619
13637
|
if (existing) return existing.promise;
|
|
13620
|
-
let
|
|
13638
|
+
let resolve9;
|
|
13621
13639
|
const promise = new Promise((res) => {
|
|
13622
|
-
|
|
13640
|
+
resolve9 = res;
|
|
13623
13641
|
});
|
|
13624
|
-
this.taskWaiters.set(id, { promise, resolve:
|
|
13642
|
+
this.taskWaiters.set(id, { promise, resolve: resolve9 });
|
|
13625
13643
|
return promise;
|
|
13626
13644
|
})
|
|
13627
13645
|
);
|
|
@@ -13937,7 +13955,7 @@ function createDelegateTool(opts) {
|
|
|
13937
13955
|
subagentId
|
|
13938
13956
|
});
|
|
13939
13957
|
const dir = director;
|
|
13940
|
-
const result = await new Promise((
|
|
13958
|
+
const result = await new Promise((resolve9) => {
|
|
13941
13959
|
let settled = false;
|
|
13942
13960
|
let timer;
|
|
13943
13961
|
const finish = (value) => {
|
|
@@ -13946,7 +13964,7 @@ function createDelegateTool(opts) {
|
|
|
13946
13964
|
if (timer) clearTimeout(timer);
|
|
13947
13965
|
offTool();
|
|
13948
13966
|
offIter();
|
|
13949
|
-
|
|
13967
|
+
resolve9(value);
|
|
13950
13968
|
};
|
|
13951
13969
|
const arm = () => {
|
|
13952
13970
|
if (timer) clearTimeout(timer);
|
|
@@ -17089,9 +17107,9 @@ var DefaultHealthRegistry = class {
|
|
|
17089
17107
|
}
|
|
17090
17108
|
async runOne(check) {
|
|
17091
17109
|
let timer = null;
|
|
17092
|
-
const timeout = new Promise((
|
|
17110
|
+
const timeout = new Promise((resolve9) => {
|
|
17093
17111
|
timer = setTimeout(
|
|
17094
|
-
() =>
|
|
17112
|
+
() => resolve9({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
|
|
17095
17113
|
this.timeoutMs
|
|
17096
17114
|
);
|
|
17097
17115
|
});
|
|
@@ -17330,14 +17348,14 @@ async function startMetricsServer(opts) {
|
|
|
17330
17348
|
const { createServer } = await import('http');
|
|
17331
17349
|
server = createServer(listener);
|
|
17332
17350
|
}
|
|
17333
|
-
await new Promise((
|
|
17351
|
+
await new Promise((resolve9, reject) => {
|
|
17334
17352
|
const onError = (err) => {
|
|
17335
17353
|
server.off("listening", onListening);
|
|
17336
17354
|
reject(err);
|
|
17337
17355
|
};
|
|
17338
17356
|
const onListening = () => {
|
|
17339
17357
|
server.off("error", onError);
|
|
17340
|
-
|
|
17358
|
+
resolve9();
|
|
17341
17359
|
};
|
|
17342
17360
|
server.once("error", onError);
|
|
17343
17361
|
server.once("listening", onListening);
|
|
@@ -17349,8 +17367,8 @@ async function startMetricsServer(opts) {
|
|
|
17349
17367
|
return {
|
|
17350
17368
|
port: boundPort,
|
|
17351
17369
|
url: `${protocol}://${host}:${boundPort}${path28}`,
|
|
17352
|
-
close: () => new Promise((
|
|
17353
|
-
server.close((err) => err ? reject(err) :
|
|
17370
|
+
close: () => new Promise((resolve9, reject) => {
|
|
17371
|
+
server.close((err) => err ? reject(err) : resolve9());
|
|
17354
17372
|
})
|
|
17355
17373
|
};
|
|
17356
17374
|
}
|
|
@@ -18446,10 +18464,12 @@ async function collectFiles(dir, baseDir) {
|
|
|
18446
18464
|
// src/storage/session-rewinder.ts
|
|
18447
18465
|
init_atomic_write();
|
|
18448
18466
|
var DefaultSessionRewinder = class {
|
|
18449
|
-
constructor(sessionsDir) {
|
|
18467
|
+
constructor(sessionsDir, projectRoot) {
|
|
18450
18468
|
this.sessionsDir = sessionsDir;
|
|
18469
|
+
this.projectRoot = projectRoot;
|
|
18451
18470
|
}
|
|
18452
18471
|
sessionsDir;
|
|
18472
|
+
projectRoot;
|
|
18453
18473
|
async listCheckpoints(sessionId) {
|
|
18454
18474
|
const file = path6.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
18455
18475
|
const raw = await fsp2.readFile(file, "utf8");
|
|
@@ -18506,7 +18526,7 @@ var DefaultSessionRewinder = class {
|
|
|
18506
18526
|
}
|
|
18507
18527
|
}
|
|
18508
18528
|
}
|
|
18509
|
-
const result = await revertSnapshots(snapshotsToRevert);
|
|
18529
|
+
const result = await revertSnapshots(snapshotsToRevert, this.projectRoot);
|
|
18510
18530
|
const removedEvents = events.length - targetIdx - 1;
|
|
18511
18531
|
return { ...result, toPromptIndex: checkpointIndex, removedEvents };
|
|
18512
18532
|
}
|
|
@@ -18536,7 +18556,7 @@ var DefaultSessionRewinder = class {
|
|
|
18536
18556
|
snapshotsToRevert.push({ promptIndex: event.promptIndex, files: event.files });
|
|
18537
18557
|
}
|
|
18538
18558
|
}
|
|
18539
|
-
const result = await revertSnapshots(snapshotsToRevert.reverse());
|
|
18559
|
+
const result = await revertSnapshots(snapshotsToRevert.reverse(), this.projectRoot);
|
|
18540
18560
|
return { ...result, toPromptIndex: targetIndex, removedEvents: snapshotsToRevert.length };
|
|
18541
18561
|
}
|
|
18542
18562
|
async rewindToStart(sessionId) {
|
|
@@ -18552,7 +18572,7 @@ var DefaultSessionRewinder = class {
|
|
|
18552
18572
|
if (allSnapshots.length === 0) {
|
|
18553
18573
|
return { revertedFiles: [], errors: [], toPromptIndex: 0, removedEvents: 0 };
|
|
18554
18574
|
}
|
|
18555
|
-
const result = await revertSnapshots(allSnapshots.reverse());
|
|
18575
|
+
const result = await revertSnapshots(allSnapshots.reverse(), this.projectRoot);
|
|
18556
18576
|
return { ...result, toPromptIndex: 0, removedEvents: allSnapshots.length };
|
|
18557
18577
|
}
|
|
18558
18578
|
};
|
|
@@ -18570,12 +18590,19 @@ function parseEvents(raw) {
|
|
|
18570
18590
|
}
|
|
18571
18591
|
return events;
|
|
18572
18592
|
}
|
|
18573
|
-
async function revertSnapshots(snapshots) {
|
|
18593
|
+
async function revertSnapshots(snapshots, projectRoot) {
|
|
18574
18594
|
const revertedFiles = [];
|
|
18575
18595
|
const errors = [];
|
|
18576
18596
|
for (const snapshot of snapshots) {
|
|
18577
18597
|
for (const file of snapshot.files) {
|
|
18578
18598
|
try {
|
|
18599
|
+
const absPath = path6.resolve(file.path);
|
|
18600
|
+
const root = path6.resolve(projectRoot);
|
|
18601
|
+
const rel = path6.relative(root, absPath);
|
|
18602
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) {
|
|
18603
|
+
errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
|
|
18604
|
+
continue;
|
|
18605
|
+
}
|
|
18579
18606
|
if (file.action === "deleted") {
|
|
18580
18607
|
if (file.before !== null) {
|
|
18581
18608
|
await atomicWrite(file.path, file.before, { mode: 420 });
|
|
@@ -19474,8 +19501,8 @@ var ReportGenerator = class {
|
|
|
19474
19501
|
try {
|
|
19475
19502
|
await stat(this.options.outputDir);
|
|
19476
19503
|
} catch {
|
|
19477
|
-
const { mkdir:
|
|
19478
|
-
await
|
|
19504
|
+
const { mkdir: mkdir14 } = await import('fs/promises');
|
|
19505
|
+
await mkdir14(this.options.outputDir, { recursive: true });
|
|
19479
19506
|
}
|
|
19480
19507
|
}
|
|
19481
19508
|
generateMarkdown(result) {
|
|
@@ -19751,7 +19778,7 @@ var SecurityScannerOrchestrator = class {
|
|
|
19751
19778
|
const delay = Math.round(policy.delayMs(attempt));
|
|
19752
19779
|
const status = isProviderErr ? err.status : 0;
|
|
19753
19780
|
console.warn(`[SecurityScanner] retry ${attempt + 1} after ${delay}ms (status=${status}) \u2014 ${errAsErr.message}`);
|
|
19754
|
-
await new Promise((
|
|
19781
|
+
await new Promise((resolve9) => setTimeout(resolve9, delay));
|
|
19755
19782
|
return this.completeWithRetry(provider, request, abortController, attempt + 1);
|
|
19756
19783
|
}
|
|
19757
19784
|
}
|
|
@@ -21248,12 +21275,12 @@ function makeContinueToNextIterationTool() {
|
|
|
21248
21275
|
// src/core/iteration-limit.ts
|
|
21249
21276
|
function requestLimitExtension(opts) {
|
|
21250
21277
|
const { events, currentIterations, currentLimit, autoExtend, timeoutMs = 3e4 } = opts;
|
|
21251
|
-
return new Promise((
|
|
21278
|
+
return new Promise((resolve9) => {
|
|
21252
21279
|
let resolved = false;
|
|
21253
21280
|
const timerFired = () => {
|
|
21254
21281
|
if (!resolved) {
|
|
21255
21282
|
resolved = true;
|
|
21256
|
-
|
|
21283
|
+
resolve9(0);
|
|
21257
21284
|
}
|
|
21258
21285
|
};
|
|
21259
21286
|
const timer = setTimeout(timerFired, timeoutMs);
|
|
@@ -21262,14 +21289,14 @@ function requestLimitExtension(opts) {
|
|
|
21262
21289
|
if (!resolved) {
|
|
21263
21290
|
resolved = true;
|
|
21264
21291
|
clearTimeout(timer);
|
|
21265
|
-
|
|
21292
|
+
resolve9(0);
|
|
21266
21293
|
}
|
|
21267
21294
|
};
|
|
21268
21295
|
const grant = (extra) => {
|
|
21269
21296
|
if (!resolved) {
|
|
21270
21297
|
resolved = true;
|
|
21271
21298
|
clearTimeout(timer);
|
|
21272
|
-
|
|
21299
|
+
resolve9(Math.max(0, extra));
|
|
21273
21300
|
}
|
|
21274
21301
|
};
|
|
21275
21302
|
events.emit("iteration.limit_reached", {
|
|
@@ -21283,7 +21310,7 @@ function requestLimitExtension(opts) {
|
|
|
21283
21310
|
if (!resolved) {
|
|
21284
21311
|
resolved = true;
|
|
21285
21312
|
clearTimeout(timer);
|
|
21286
|
-
|
|
21313
|
+
resolve9(100);
|
|
21287
21314
|
}
|
|
21288
21315
|
});
|
|
21289
21316
|
}
|
|
@@ -21852,13 +21879,13 @@ var Agent = class {
|
|
|
21852
21879
|
}
|
|
21853
21880
|
}
|
|
21854
21881
|
waitForConfirm(info) {
|
|
21855
|
-
return new Promise((
|
|
21882
|
+
return new Promise((resolve9) => {
|
|
21856
21883
|
this.events.emit("tool.confirm_needed", {
|
|
21857
21884
|
tool: info.tool,
|
|
21858
21885
|
input: info.input,
|
|
21859
21886
|
toolUseId: info.toolUseId,
|
|
21860
21887
|
suggestedPattern: info.suggestedPattern,
|
|
21861
|
-
resolve:
|
|
21888
|
+
resolve: resolve9
|
|
21862
21889
|
});
|
|
21863
21890
|
});
|
|
21864
21891
|
}
|
|
@@ -22575,12 +22602,12 @@ ${mem}`);
|
|
|
22575
22602
|
}
|
|
22576
22603
|
}
|
|
22577
22604
|
async gitStatus(root) {
|
|
22578
|
-
return new Promise((
|
|
22605
|
+
return new Promise((resolve9) => {
|
|
22579
22606
|
let settled = false;
|
|
22580
22607
|
const finish = (s) => {
|
|
22581
22608
|
if (settled) return;
|
|
22582
22609
|
settled = true;
|
|
22583
|
-
|
|
22610
|
+
resolve9(s);
|
|
22584
22611
|
};
|
|
22585
22612
|
let proc;
|
|
22586
22613
|
const timer = setTimeout(() => {
|
|
@@ -23455,10 +23482,19 @@ var PhaseOrchestrator = class {
|
|
|
23455
23482
|
tickInterval = null;
|
|
23456
23483
|
trackerCache = /* @__PURE__ */ new Map();
|
|
23457
23484
|
taskRetryCounts = /* @__PURE__ */ new Map();
|
|
23485
|
+
// ── Git-worktree isolation (optional) ──────────────────────────────────────
|
|
23486
|
+
worktrees;
|
|
23487
|
+
/** Per-phase worktree handles, keyed by phase id. */
|
|
23488
|
+
phaseWorktrees = /* @__PURE__ */ new Map();
|
|
23489
|
+
/** Serializes all merges back to the base branch (one at a time). */
|
|
23490
|
+
mergeQueue = Promise.resolve();
|
|
23491
|
+
/** Per-phase merge promise, so a phase merges only after its deps do. */
|
|
23492
|
+
phaseMergePromise = /* @__PURE__ */ new Map();
|
|
23458
23493
|
constructor(opts) {
|
|
23459
23494
|
this.graph = opts.graph;
|
|
23460
23495
|
this.ctx = opts.ctx;
|
|
23461
23496
|
this.events = opts.events ?? this.createNoopEventBus();
|
|
23497
|
+
this.worktrees = opts.worktrees;
|
|
23462
23498
|
this.opts = {
|
|
23463
23499
|
maxConcurrentPhases: opts.maxConcurrentPhases ?? 1,
|
|
23464
23500
|
maxConcurrentTasks: opts.maxConcurrentTasks ?? 2,
|
|
@@ -23490,10 +23526,17 @@ var PhaseOrchestrator = class {
|
|
|
23490
23526
|
(p) => !this.runningPhases.has(p.id) && p.status !== "completed" && p.status !== "failed"
|
|
23491
23527
|
);
|
|
23492
23528
|
}
|
|
23529
|
+
await this.drainMerges();
|
|
23493
23530
|
if (this.opts.autonomous) {
|
|
23494
23531
|
this.tickInterval = setInterval(() => this.tick(), 1e3);
|
|
23495
23532
|
}
|
|
23496
23533
|
}
|
|
23534
|
+
/** Bekleyen tüm faz merge'lerini (dep-sıralı + global seri) bekle. */
|
|
23535
|
+
async drainMerges() {
|
|
23536
|
+
await Promise.allSettled([...this.phaseMergePromise.values()]);
|
|
23537
|
+
await this.mergeQueue.catch(() => {
|
|
23538
|
+
});
|
|
23539
|
+
}
|
|
23497
23540
|
/** Duraklat — aktif fazlar çalışmaya devam eder ama yeni faz başlamaz */
|
|
23498
23541
|
pause() {
|
|
23499
23542
|
this.paused = true;
|
|
@@ -23518,6 +23561,12 @@ var PhaseOrchestrator = class {
|
|
|
23518
23561
|
this.updatePhaseStatus(phase, "paused");
|
|
23519
23562
|
}
|
|
23520
23563
|
}
|
|
23564
|
+
if (this.worktrees) {
|
|
23565
|
+
for (const handle of this.worktrees.list()) {
|
|
23566
|
+
void this.worktrees.release(handle, { keep: true }).catch(() => {
|
|
23567
|
+
});
|
|
23568
|
+
}
|
|
23569
|
+
}
|
|
23521
23570
|
}
|
|
23522
23571
|
// ─── Tick Loop (Autonomous) ───────────────────────────────────────────────
|
|
23523
23572
|
async tick() {
|
|
@@ -23556,6 +23605,16 @@ var PhaseOrchestrator = class {
|
|
|
23556
23605
|
phase.startedAt = Date.now();
|
|
23557
23606
|
this.runningPhases.add(phase.id);
|
|
23558
23607
|
this.graph.activePhaseIds.push(phase.id);
|
|
23608
|
+
if (this.worktrees && !this.phaseWorktrees.has(phase.id)) {
|
|
23609
|
+
try {
|
|
23610
|
+
const handle = await this.worktrees.allocate(phase.id, {
|
|
23611
|
+
slugHint: phase.name,
|
|
23612
|
+
ownerLabel: phase.name
|
|
23613
|
+
});
|
|
23614
|
+
if (handle.status === "active") this.phaseWorktrees.set(phase.id, handle);
|
|
23615
|
+
} catch {
|
|
23616
|
+
}
|
|
23617
|
+
}
|
|
23559
23618
|
this.emit("phase.started", { phaseId: phase.id, name: phase.name });
|
|
23560
23619
|
try {
|
|
23561
23620
|
await this.executePhaseTasks(phase);
|
|
@@ -23578,6 +23637,7 @@ var PhaseOrchestrator = class {
|
|
|
23578
23637
|
error: `${failedTasks} task(s) failed`
|
|
23579
23638
|
});
|
|
23580
23639
|
this.ctx.onPhaseFail?.(phase, new Error(`${failedTasks} task(s) failed`));
|
|
23640
|
+
await this.keepWorktreeForReview(phase);
|
|
23581
23641
|
} else {
|
|
23582
23642
|
this.updatePhaseStatus(phase, "completed");
|
|
23583
23643
|
phase.completedAt = Date.now();
|
|
@@ -23591,6 +23651,7 @@ var PhaseOrchestrator = class {
|
|
|
23591
23651
|
durationMs: phase.actualDurationMs
|
|
23592
23652
|
});
|
|
23593
23653
|
this.ctx.onPhaseComplete?.(phase);
|
|
23654
|
+
await this.commitAndEnqueueMerge(phase);
|
|
23594
23655
|
}
|
|
23595
23656
|
} catch (error) {
|
|
23596
23657
|
this.updatePhaseStatus(phase, "failed");
|
|
@@ -23605,8 +23666,56 @@ var PhaseOrchestrator = class {
|
|
|
23605
23666
|
error: error instanceof Error ? error.message : String(error)
|
|
23606
23667
|
});
|
|
23607
23668
|
this.ctx.onPhaseFail?.(phase, error instanceof Error ? error : new Error(String(error)));
|
|
23669
|
+
await this.keepWorktreeForReview(phase);
|
|
23608
23670
|
}
|
|
23609
23671
|
}
|
|
23672
|
+
// ─── Worktree integration ───────────────────────────────────────────────────
|
|
23673
|
+
/**
|
|
23674
|
+
* Commit the phase's worktree changes, then enqueue the merge back into the
|
|
23675
|
+
* base branch. Merges run dependency-ordered (a phase merges only after its
|
|
23676
|
+
* `dependsOn` phases) and globally serialized (one at a time) to avoid
|
|
23677
|
+
* concurrent writes to the base tree.
|
|
23678
|
+
*/
|
|
23679
|
+
async commitAndEnqueueMerge(phase) {
|
|
23680
|
+
const handle = this.phaseWorktrees.get(phase.id);
|
|
23681
|
+
if (!this.worktrees || !handle) return;
|
|
23682
|
+
try {
|
|
23683
|
+
await this.worktrees.commitAll(handle, `autophase(${phase.name}): ${phase.id}`);
|
|
23684
|
+
} catch {
|
|
23685
|
+
}
|
|
23686
|
+
const depPromises = phase.dependsOn.map((d) => this.phaseMergePromise.get(d)).filter((p) => Boolean(p));
|
|
23687
|
+
const merged = (async () => {
|
|
23688
|
+
await Promise.allSettled(depPromises);
|
|
23689
|
+
this.mergeQueue = this.mergeQueue.then(() => this.mergeOne(phase, handle));
|
|
23690
|
+
await this.mergeQueue;
|
|
23691
|
+
})();
|
|
23692
|
+
this.phaseMergePromise.set(phase.id, merged);
|
|
23693
|
+
}
|
|
23694
|
+
/** Squash-merge one phase. Conflicts mark the worktree needs-review (run continues). */
|
|
23695
|
+
async mergeOne(phase, handle) {
|
|
23696
|
+
if (!this.worktrees) return;
|
|
23697
|
+
try {
|
|
23698
|
+
const result = await this.worktrees.merge(handle, { squash: true });
|
|
23699
|
+
await this.worktrees.release(handle, { keep: !result.ok });
|
|
23700
|
+
} catch (err) {
|
|
23701
|
+
this.emit("phase.failed", {
|
|
23702
|
+
phaseId: phase.id,
|
|
23703
|
+
name: phase.name,
|
|
23704
|
+
error: `worktree merge failed: ${err instanceof Error ? err.message : String(err)}`
|
|
23705
|
+
});
|
|
23706
|
+
}
|
|
23707
|
+
}
|
|
23708
|
+
/** A failed phase keeps its worktree on disk for inspection (no merge). */
|
|
23709
|
+
async keepWorktreeForReview(phase) {
|
|
23710
|
+
const handle = this.phaseWorktrees.get(phase.id);
|
|
23711
|
+
if (!this.worktrees || !handle) return;
|
|
23712
|
+
try {
|
|
23713
|
+
await this.worktrees.commitAll(handle, `autophase(${phase.name}) [failed]: ${phase.id}`);
|
|
23714
|
+
} catch {
|
|
23715
|
+
}
|
|
23716
|
+
await this.worktrees.release(handle, { keep: true }).catch(() => {
|
|
23717
|
+
});
|
|
23718
|
+
}
|
|
23610
23719
|
async executePhaseTasks(phase) {
|
|
23611
23720
|
const pendingTasks = this.getExecutableTasks(phase);
|
|
23612
23721
|
while (pendingTasks.length > 0 && !this.stopped) {
|
|
@@ -23632,7 +23741,8 @@ var PhaseOrchestrator = class {
|
|
|
23632
23741
|
async executeSingleTask(task, phase) {
|
|
23633
23742
|
const tracker = this.getTrackerForPhase(phase);
|
|
23634
23743
|
tracker.updateNodeStatus(task.id, "in_progress");
|
|
23635
|
-
|
|
23744
|
+
const handle = this.phaseWorktrees.get(phase.id);
|
|
23745
|
+
return this.ctx.executeTask(task, phase.id, { cwd: handle?.dir, branch: handle?.branch });
|
|
23636
23746
|
}
|
|
23637
23747
|
markTaskCompleted(phase, task) {
|
|
23638
23748
|
const tracker = this.getTrackerForPhase(phase);
|
|
@@ -23855,7 +23965,7 @@ var PhaseOrchestrator = class {
|
|
|
23855
23965
|
};
|
|
23856
23966
|
}
|
|
23857
23967
|
delay(ms) {
|
|
23858
|
-
return new Promise((
|
|
23968
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
23859
23969
|
}
|
|
23860
23970
|
};
|
|
23861
23971
|
|
|
@@ -24499,7 +24609,294 @@ var CheckpointManager = class {
|
|
|
24499
24609
|
}
|
|
24500
24610
|
}
|
|
24501
24611
|
};
|
|
24612
|
+
var MAX_SLUG = 40;
|
|
24613
|
+
var WorktreeManager = class {
|
|
24614
|
+
projectRoot;
|
|
24615
|
+
events;
|
|
24616
|
+
gitBin;
|
|
24617
|
+
runGit;
|
|
24618
|
+
/** Keyed by ownerId. */
|
|
24619
|
+
handles = /* @__PURE__ */ new Map();
|
|
24620
|
+
usedSlugs = /* @__PURE__ */ new Set();
|
|
24621
|
+
constructor(opts) {
|
|
24622
|
+
this.projectRoot = resolve(opts.projectRoot);
|
|
24623
|
+
this.events = opts.events;
|
|
24624
|
+
this.gitBin = opts.gitBin ?? "git";
|
|
24625
|
+
this.runGit = opts.run ?? ((args, cwd) => this.defaultRun(args, cwd));
|
|
24626
|
+
}
|
|
24627
|
+
/** Create a fresh worktree + branch forked from the current base branch. */
|
|
24628
|
+
async allocate(ownerId, opts = {}) {
|
|
24629
|
+
const existing = this.handles.get(ownerId);
|
|
24630
|
+
if (existing && (existing.status === "allocating" || existing.status === "active")) {
|
|
24631
|
+
return existing;
|
|
24632
|
+
}
|
|
24633
|
+
const slug = this.makeSlug(opts.slugHint ?? ownerId);
|
|
24634
|
+
const branch = `wstack/ap/${slug}`;
|
|
24635
|
+
const dir = join(this.worktreesRoot(), slug);
|
|
24636
|
+
const absDir = resolve(dir);
|
|
24637
|
+
const absRoot = resolve(this.projectRoot);
|
|
24638
|
+
if (!absDir.startsWith(absRoot + sep)) {
|
|
24639
|
+
throw new Error(`Worktree dir "${absDir}" resolves outside project root`);
|
|
24640
|
+
}
|
|
24641
|
+
const baseBranch = opts.baseBranch ?? await this.detectBaseBranch();
|
|
24642
|
+
const handle = {
|
|
24643
|
+
id: slug,
|
|
24644
|
+
ownerId,
|
|
24645
|
+
ownerLabel: opts.ownerLabel ?? opts.slugHint ?? ownerId,
|
|
24646
|
+
slug,
|
|
24647
|
+
dir,
|
|
24648
|
+
branch,
|
|
24649
|
+
baseBranch,
|
|
24650
|
+
status: "allocating",
|
|
24651
|
+
createdAt: Date.now(),
|
|
24652
|
+
updatedAt: Date.now(),
|
|
24653
|
+
insertions: 0,
|
|
24654
|
+
deletions: 0,
|
|
24655
|
+
files: 0
|
|
24656
|
+
};
|
|
24657
|
+
this.handles.set(ownerId, handle);
|
|
24658
|
+
try {
|
|
24659
|
+
await mkdir(this.worktreesRoot(), { recursive: true });
|
|
24660
|
+
const res = await this.runGit(
|
|
24661
|
+
["worktree", "add", "-b", branch, dir, baseBranch],
|
|
24662
|
+
this.projectRoot
|
|
24663
|
+
);
|
|
24664
|
+
if (res.code !== 0) {
|
|
24665
|
+
return this.fail(handle, res.stderr || "git worktree add failed");
|
|
24666
|
+
}
|
|
24667
|
+
} catch (err) {
|
|
24668
|
+
return this.fail(handle, err instanceof Error ? err.message : String(err));
|
|
24669
|
+
}
|
|
24670
|
+
this.setStatus(handle, "active");
|
|
24671
|
+
this.emit("worktree.allocated", {
|
|
24672
|
+
handleId: handle.id,
|
|
24673
|
+
ownerId: handle.ownerId,
|
|
24674
|
+
ownerLabel: handle.ownerLabel,
|
|
24675
|
+
slug: handle.slug,
|
|
24676
|
+
dir: handle.dir,
|
|
24677
|
+
branch: handle.branch,
|
|
24678
|
+
baseBranch: handle.baseBranch
|
|
24679
|
+
});
|
|
24680
|
+
return handle;
|
|
24681
|
+
}
|
|
24682
|
+
/** Stage everything and commit inside the worktree. */
|
|
24683
|
+
async commitAll(handle, message) {
|
|
24684
|
+
this.setStatus(handle, "committing");
|
|
24685
|
+
await this.runGit(["add", "-A"], handle.dir);
|
|
24686
|
+
const staged = await this.runGit(["diff", "--cached", "--quiet"], handle.dir);
|
|
24687
|
+
if (staged.code === 0) {
|
|
24688
|
+
this.emitCommitted(handle, false);
|
|
24689
|
+
return { committed: false };
|
|
24690
|
+
}
|
|
24691
|
+
const idArgs = await this.identityArgs(handle.dir);
|
|
24692
|
+
const committed = await this.runGit([...idArgs, "commit", "-m", message], handle.dir);
|
|
24693
|
+
if (committed.code !== 0) {
|
|
24694
|
+
this.fail(handle, committed.stderr || "git commit failed");
|
|
24695
|
+
return { committed: false };
|
|
24696
|
+
}
|
|
24697
|
+
const stats = await this.collectStats(handle.dir);
|
|
24698
|
+
handle.insertions = stats.insertions;
|
|
24699
|
+
handle.deletions = stats.deletions;
|
|
24700
|
+
handle.files = stats.files;
|
|
24701
|
+
handle.sha = stats.sha;
|
|
24702
|
+
handle.updatedAt = Date.now();
|
|
24703
|
+
this.emitCommitted(handle, true);
|
|
24704
|
+
return { committed: true };
|
|
24705
|
+
}
|
|
24706
|
+
/** Merge the worktree branch back into the base branch (squash by default). */
|
|
24707
|
+
async merge(handle, opts = {}) {
|
|
24708
|
+
const squash = opts.squash ?? true;
|
|
24709
|
+
this.setStatus(handle, "merging");
|
|
24710
|
+
const checkout = await this.runGit(["checkout", handle.baseBranch], this.projectRoot);
|
|
24711
|
+
if (checkout.code !== 0) {
|
|
24712
|
+
this.fail(handle, checkout.stderr || `checkout ${handle.baseBranch} failed`);
|
|
24713
|
+
return { ok: false, stderr: checkout.stderr };
|
|
24714
|
+
}
|
|
24715
|
+
const mergeArgs = squash ? ["merge", "--squash", handle.branch] : ["merge", "--no-ff", handle.branch];
|
|
24716
|
+
const merged = await this.runGit(mergeArgs, this.projectRoot);
|
|
24717
|
+
if (merged.code !== 0) {
|
|
24718
|
+
const fromOutput = parseConflictPaths(`${merged.stdout}
|
|
24719
|
+
${merged.stderr}`);
|
|
24720
|
+
const fromIndex = await this.unmergedFiles();
|
|
24721
|
+
const conflictFiles = [.../* @__PURE__ */ new Set([...fromOutput, ...fromIndex])];
|
|
24722
|
+
await this.runGit(["reset", "--hard", "HEAD"], this.projectRoot);
|
|
24723
|
+
handle.conflictFiles = conflictFiles;
|
|
24724
|
+
this.setStatus(handle, "needs-review", { lastError: merged.stderr });
|
|
24725
|
+
this.emit("worktree.conflict", {
|
|
24726
|
+
handleId: handle.id,
|
|
24727
|
+
ownerId: handle.ownerId,
|
|
24728
|
+
branch: handle.branch,
|
|
24729
|
+
conflictFiles
|
|
24730
|
+
});
|
|
24731
|
+
return { ok: false, conflict: true, conflictFiles, stderr: merged.stderr };
|
|
24732
|
+
}
|
|
24733
|
+
if (squash) {
|
|
24734
|
+
const msg = opts.message ?? `merge ${handle.branch} (squash)`;
|
|
24735
|
+
const idArgs = await this.identityArgs(this.projectRoot);
|
|
24736
|
+
const commit = await this.runGit([...idArgs, "commit", "-m", msg], this.projectRoot);
|
|
24737
|
+
if (commit.code !== 0 && !/nothing to commit/i.test(commit.stdout + commit.stderr)) {
|
|
24738
|
+
this.fail(handle, commit.stderr || "squash commit failed");
|
|
24739
|
+
return { ok: false, stderr: commit.stderr };
|
|
24740
|
+
}
|
|
24741
|
+
}
|
|
24742
|
+
this.setStatus(handle, "merged");
|
|
24743
|
+
this.emit("worktree.merged", {
|
|
24744
|
+
handleId: handle.id,
|
|
24745
|
+
ownerId: handle.ownerId,
|
|
24746
|
+
branch: handle.branch,
|
|
24747
|
+
baseBranch: handle.baseBranch,
|
|
24748
|
+
squash
|
|
24749
|
+
});
|
|
24750
|
+
return { ok: true };
|
|
24751
|
+
}
|
|
24752
|
+
/**
|
|
24753
|
+
* Remove the worktree + branch. Conflicted/failed handles (or `keep:true`)
|
|
24754
|
+
* are left on disk for inspection.
|
|
24755
|
+
*/
|
|
24756
|
+
async release(handle, opts = {}) {
|
|
24757
|
+
const keep = opts.keep || handle.status === "needs-review" || handle.status === "failed";
|
|
24758
|
+
if (!keep) {
|
|
24759
|
+
await this.runGit(["worktree", "remove", "--force", handle.dir], this.projectRoot);
|
|
24760
|
+
await this.runGit(["branch", "-D", handle.branch], this.projectRoot);
|
|
24761
|
+
await this.runGit(["worktree", "prune"], this.projectRoot);
|
|
24762
|
+
this.handles.delete(handle.ownerId);
|
|
24763
|
+
}
|
|
24764
|
+
this.emit("worktree.released", {
|
|
24765
|
+
handleId: handle.id,
|
|
24766
|
+
ownerId: handle.ownerId,
|
|
24767
|
+
branch: handle.branch,
|
|
24768
|
+
kept: keep
|
|
24769
|
+
});
|
|
24770
|
+
}
|
|
24771
|
+
get(ownerId) {
|
|
24772
|
+
return this.handles.get(ownerId);
|
|
24773
|
+
}
|
|
24774
|
+
list() {
|
|
24775
|
+
return [...this.handles.values()];
|
|
24776
|
+
}
|
|
24777
|
+
// ── internals ────────────────────────────────────────────────────────────
|
|
24778
|
+
worktreesRoot() {
|
|
24779
|
+
return join(this.projectRoot, ".wrongstack", "worktrees");
|
|
24780
|
+
}
|
|
24781
|
+
async detectBaseBranch() {
|
|
24782
|
+
const head = await this.runGit(["rev-parse", "--abbrev-ref", "HEAD"], this.projectRoot);
|
|
24783
|
+
const name = head.stdout.trim();
|
|
24784
|
+
if (name && name !== "HEAD") return name;
|
|
24785
|
+
const sha = await this.runGit(["rev-parse", "HEAD"], this.projectRoot);
|
|
24786
|
+
return sha.stdout.trim() || "HEAD";
|
|
24787
|
+
}
|
|
24788
|
+
makeSlug(hint) {
|
|
24789
|
+
let base = hint.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^[-.]+/, "").replace(/[-.]+$/, "").slice(0, MAX_SLUG).replace(/[-.]+$/, "");
|
|
24790
|
+
if (!base) base = "wt";
|
|
24791
|
+
let slug = `${base}-${crypto.randomUUID().slice(0, 6)}`;
|
|
24792
|
+
while (this.usedSlugs.has(slug)) slug = `${base}-${crypto.randomUUID().slice(0, 6)}`;
|
|
24793
|
+
this.usedSlugs.add(slug);
|
|
24794
|
+
return slug;
|
|
24795
|
+
}
|
|
24796
|
+
async collectStats(dir) {
|
|
24797
|
+
const sha = (await this.runGit(["rev-parse", "HEAD"], dir)).stdout.trim();
|
|
24798
|
+
const numstat = await this.runGit(["show", "--numstat", "--format=", "HEAD"], dir);
|
|
24799
|
+
let insertions = 0;
|
|
24800
|
+
let deletions = 0;
|
|
24801
|
+
let files = 0;
|
|
24802
|
+
for (const line of numstat.stdout.split("\n")) {
|
|
24803
|
+
const m = line.trim().match(/^(\d+|-)\t(\d+|-)\t(.+)$/);
|
|
24804
|
+
if (!m) continue;
|
|
24805
|
+
files++;
|
|
24806
|
+
if (m[1] !== "-") insertions += Number(m[1]);
|
|
24807
|
+
if (m[2] !== "-") deletions += Number(m[2]);
|
|
24808
|
+
}
|
|
24809
|
+
return { insertions, deletions, files, sha };
|
|
24810
|
+
}
|
|
24811
|
+
/**
|
|
24812
|
+
* `git -c user.*` fallback so commits succeed on machines and CI runners
|
|
24813
|
+
* that have no global git identity configured. Returns `[]` when both
|
|
24814
|
+
* `user.name` and `user.email` are already set (the common case), so a real
|
|
24815
|
+
* user's identity is never overridden. The worktree branch commits are
|
|
24816
|
+
* squashed away on merge, so the fallback identity never reaches the base
|
|
24817
|
+
* branch history.
|
|
24818
|
+
*/
|
|
24819
|
+
async identityArgs(cwd) {
|
|
24820
|
+
const name = (await this.runGit(["config", "user.name"], cwd)).stdout.trim();
|
|
24821
|
+
const email = (await this.runGit(["config", "user.email"], cwd)).stdout.trim();
|
|
24822
|
+
if (name && email) return [];
|
|
24823
|
+
return [
|
|
24824
|
+
"-c",
|
|
24825
|
+
`user.name=${name || "WrongStack AutoPhase"}`,
|
|
24826
|
+
"-c",
|
|
24827
|
+
`user.email=${email || "autophase@wrongstack.local"}`
|
|
24828
|
+
];
|
|
24829
|
+
}
|
|
24830
|
+
async unmergedFiles() {
|
|
24831
|
+
const res = await this.runGit(["diff", "--name-only", "--diff-filter=U"], this.projectRoot);
|
|
24832
|
+
return res.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
24833
|
+
}
|
|
24834
|
+
emitCommitted(handle, committed) {
|
|
24835
|
+
this.emit("worktree.committed", {
|
|
24836
|
+
handleId: handle.id,
|
|
24837
|
+
ownerId: handle.ownerId,
|
|
24838
|
+
branch: handle.branch,
|
|
24839
|
+
committed,
|
|
24840
|
+
insertions: handle.insertions,
|
|
24841
|
+
deletions: handle.deletions,
|
|
24842
|
+
files: handle.files,
|
|
24843
|
+
sha: handle.sha
|
|
24844
|
+
});
|
|
24845
|
+
}
|
|
24846
|
+
fail(handle, error) {
|
|
24847
|
+
this.setStatus(handle, "failed", { lastError: error });
|
|
24848
|
+
this.emit("worktree.failed", {
|
|
24849
|
+
handleId: handle.id,
|
|
24850
|
+
ownerId: handle.ownerId,
|
|
24851
|
+
branch: handle.branch,
|
|
24852
|
+
error
|
|
24853
|
+
});
|
|
24854
|
+
return handle;
|
|
24855
|
+
}
|
|
24856
|
+
setStatus(handle, status, patch) {
|
|
24857
|
+
handle.status = status;
|
|
24858
|
+
handle.updatedAt = Date.now();
|
|
24859
|
+
if (patch) Object.assign(handle, patch);
|
|
24860
|
+
}
|
|
24861
|
+
emit(event, payload) {
|
|
24862
|
+
this.events?.emit(event, payload);
|
|
24863
|
+
}
|
|
24864
|
+
defaultRun(args, cwd) {
|
|
24865
|
+
return new Promise((res) => {
|
|
24866
|
+
let stdout = "";
|
|
24867
|
+
let stderr = "";
|
|
24868
|
+
const child = spawn(this.gitBin, args, {
|
|
24869
|
+
cwd,
|
|
24870
|
+
env: buildChildEnv(),
|
|
24871
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
24872
|
+
});
|
|
24873
|
+
child.stdout?.on("data", (c) => {
|
|
24874
|
+
stdout += c.toString();
|
|
24875
|
+
});
|
|
24876
|
+
child.stderr?.on("data", (c) => {
|
|
24877
|
+
stderr += c.toString();
|
|
24878
|
+
});
|
|
24879
|
+
child.on("error", (err) => res({ code: 1, stdout, stderr: err.message }));
|
|
24880
|
+
child.on("close", (code) => res({ code: code ?? 1, stdout, stderr }));
|
|
24881
|
+
});
|
|
24882
|
+
}
|
|
24883
|
+
};
|
|
24884
|
+
function parseConflictPaths(output) {
|
|
24885
|
+
const paths = /* @__PURE__ */ new Set();
|
|
24886
|
+
for (const line of output.split("\n")) {
|
|
24887
|
+
const m = line.match(/^CONFLICT \([^)]*\): Merge conflict in (.+?)\s*$/);
|
|
24888
|
+
if (m?.[1]) paths.add(m[1]);
|
|
24889
|
+
}
|
|
24890
|
+
return [...paths];
|
|
24891
|
+
}
|
|
24892
|
+
function assertSafePath(dir, projectRoot) {
|
|
24893
|
+
const root = resolve(projectRoot);
|
|
24894
|
+
const abs = resolve(dir);
|
|
24895
|
+
if (abs !== root && !abs.startsWith(root + sep)) {
|
|
24896
|
+
throw new Error(`worktree path escapes project root: ${dir}`);
|
|
24897
|
+
}
|
|
24898
|
+
}
|
|
24502
24899
|
|
|
24503
|
-
export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, CheckpointManager, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeLLMClassifier, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, pendingBtwCount, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
24900
|
+
export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, CheckpointManager, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WorktreeManager, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, assertSafePath, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeLLMClassifier, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, pendingBtwCount, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
24504
24901
|
//# sourceMappingURL=index.js.map
|
|
24505
24902
|
//# sourceMappingURL=index.js.map
|