@norman-else/dsh-claude 0.1.37 → 0.1.38
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/lib/client.js +53 -5
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +43 -18
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -3352,16 +3352,23 @@ function registerClaudeProjectionRoute(ctx, sidecar, ownsSession, commandsForSes
|
|
|
3352
3352
|
const info = (message) => {
|
|
3353
3353
|
ctx.logger?.info?.(message);
|
|
3354
3354
|
};
|
|
3355
|
-
|
|
3355
|
+
/** Everything the host already knows, without touching the repository. */
|
|
3356
|
+
const localMeta = (sessionId) => {
|
|
3356
3357
|
const owned = ownsSession(sessionId);
|
|
3357
|
-
const repository = owned ? await repositoryForSession(sessionId) : void 0;
|
|
3358
3358
|
return {
|
|
3359
3359
|
owned,
|
|
3360
3360
|
commands: commandsForSession(sessionId),
|
|
3361
|
-
...repository === void 0 ? {} : { repository },
|
|
3362
3361
|
reviewComments: owned ? reviewCommentsForSession(sessionId) : []
|
|
3363
3362
|
};
|
|
3364
3363
|
};
|
|
3364
|
+
const assembleMeta = async (sessionId) => {
|
|
3365
|
+
const meta = localMeta(sessionId);
|
|
3366
|
+
const repository = meta.owned ? await repositoryForSession(sessionId) : void 0;
|
|
3367
|
+
return {
|
|
3368
|
+
...meta,
|
|
3369
|
+
...repository === void 0 ? {} : { repository }
|
|
3370
|
+
};
|
|
3371
|
+
};
|
|
3365
3372
|
const streamMulti = async (res, io, sessionIds) => {
|
|
3366
3373
|
info(`dsh-claude: projection stream opened for ${sessionIds.length} session(s)`);
|
|
3367
3374
|
let textDeltas = 0;
|
|
@@ -3383,8 +3390,20 @@ function registerClaudeProjectionRoute(ctx, sidecar, ownsSession, commandsForSes
|
|
|
3383
3390
|
}
|
|
3384
3391
|
};
|
|
3385
3392
|
const metas = /* @__PURE__ */ new Map();
|
|
3393
|
+
const writeMeta = (sessionId, meta) => {
|
|
3394
|
+
metas.set(sessionId, meta);
|
|
3395
|
+
writeLine({
|
|
3396
|
+
type: "meta",
|
|
3397
|
+
session: sessionId,
|
|
3398
|
+
owned: meta.owned,
|
|
3399
|
+
commands: meta.commands,
|
|
3400
|
+
...meta.repository === void 0 ? {} : { repository: meta.repository },
|
|
3401
|
+
reviewComments: meta.reviewComments
|
|
3402
|
+
});
|
|
3403
|
+
};
|
|
3386
3404
|
const writeSnapshot = async (sessionId) => {
|
|
3387
|
-
const
|
|
3405
|
+
const projection = await sidecar.read(sessionId);
|
|
3406
|
+
const meta = metas.get(sessionId) ?? localMeta(sessionId);
|
|
3388
3407
|
metas.set(sessionId, meta);
|
|
3389
3408
|
writeLine({
|
|
3390
3409
|
type: "snapshot",
|
|
@@ -3392,6 +3411,9 @@ function registerClaudeProjectionRoute(ctx, sidecar, ownsSession, commandsForSes
|
|
|
3392
3411
|
seq: sidecar.sequence(sessionId),
|
|
3393
3412
|
...envelope(projection, meta)
|
|
3394
3413
|
});
|
|
3414
|
+
const probed = await assembleMeta(sessionId);
|
|
3415
|
+
if (closed || JSON.stringify(probed) === JSON.stringify(metas.get(sessionId))) return;
|
|
3416
|
+
writeMeta(sessionId, probed);
|
|
3395
3417
|
};
|
|
3396
3418
|
const unsubscribes = sessionIds.map((sessionId) => sidecar.subscribe(sessionId, (delta) => {
|
|
3397
3419
|
switch (delta.kind) {
|
|
@@ -3458,15 +3480,7 @@ function registerClaudeProjectionRoute(ctx, sidecar, ownsSession, commandsForSes
|
|
|
3458
3480
|
const next = await assembleMeta(sessionId);
|
|
3459
3481
|
if (closed) return;
|
|
3460
3482
|
if (JSON.stringify(next) === JSON.stringify(metas.get(sessionId))) continue;
|
|
3461
|
-
|
|
3462
|
-
writeLine({
|
|
3463
|
-
type: "meta",
|
|
3464
|
-
session: sessionId,
|
|
3465
|
-
owned: next.owned,
|
|
3466
|
-
commands: next.commands,
|
|
3467
|
-
...next.repository === void 0 ? {} : { repository: next.repository },
|
|
3468
|
-
reviewComments: next.reviewComments
|
|
3469
|
-
});
|
|
3483
|
+
writeMeta(sessionId, next);
|
|
3470
3484
|
}
|
|
3471
3485
|
writeLine({ type: "ping" });
|
|
3472
3486
|
})().catch(() => void 0);
|
|
@@ -4336,7 +4350,7 @@ var RepositorySetupService = class {
|
|
|
4336
4350
|
}
|
|
4337
4351
|
}
|
|
4338
4352
|
if (changed) await this.#writeLeases(retained);
|
|
4339
|
-
await this.#removeUnleasedDirectories(retained, active, now);
|
|
4353
|
+
await this.#removeUnleasedDirectories(retained, active, now, archiveSessions);
|
|
4340
4354
|
});
|
|
4341
4355
|
}
|
|
4342
4356
|
/** Remove directories under the plugin's own worktree root that no lease and
|
|
@@ -4344,7 +4358,7 @@ var RepositorySetupService = class {
|
|
|
4344
4358
|
* lease write failed, otherwise leaves a directory nothing will ever sweep.
|
|
4345
4359
|
* The grace period covers the gap between `worktree add` and the lease
|
|
4346
4360
|
* write, so a worktree being created right now is never taken. */
|
|
4347
|
-
async #removeUnleasedDirectories(retained, active, now) {
|
|
4361
|
+
async #removeUnleasedDirectories(retained, active, now, archiveSessions) {
|
|
4348
4362
|
const leased = new Set(retained.map((item) => comparablePath(item.path)));
|
|
4349
4363
|
let entries;
|
|
4350
4364
|
try {
|
|
@@ -4361,6 +4375,7 @@ var RepositorySetupService = class {
|
|
|
4361
4375
|
if (!info.isDirectory()) continue;
|
|
4362
4376
|
const created = info.birthtimeMs > 0 ? info.birthtimeMs : info.mtimeMs;
|
|
4363
4377
|
if (Math.max(0, now - created) < this.#cleanupGraceMs) continue;
|
|
4378
|
+
await archiveSessions?.(path).catch(() => void 0);
|
|
4364
4379
|
await rm(path, {
|
|
4365
4380
|
recursive: true,
|
|
4366
4381
|
force: true
|
|
@@ -5105,7 +5120,7 @@ async function streamSetup(res, service, input) {
|
|
|
5105
5120
|
* The prefix is registered as a stream because the setup POST holds its
|
|
5106
5121
|
* connection open for the whole worktree build; the short sibling paths ride
|
|
5107
5122
|
* the same registration and answer with `json` before releasing it. */
|
|
5108
|
-
function registerRepositorySetupRoute(ctx, service) {
|
|
5123
|
+
function registerRepositorySetupRoute(ctx, service, sweep) {
|
|
5109
5124
|
registerPluginRoute(ctx, {
|
|
5110
5125
|
mode: "stream",
|
|
5111
5126
|
kind: "prefix",
|
|
@@ -5139,6 +5154,11 @@ function registerRepositorySetupRoute(ctx, service) {
|
|
|
5139
5154
|
const input = await readJson$5(io);
|
|
5140
5155
|
return json(res, 200, await service.cleanupMerged(string$2(input, "path"), string$2(input, "baseBranch")));
|
|
5141
5156
|
}
|
|
5157
|
+
if (pathname === `/plugins/dsh-claude/repository/setup/sweep`) {
|
|
5158
|
+
if (io.method !== "POST") return json(res, 405, { error: "method not allowed" });
|
|
5159
|
+
sweep?.();
|
|
5160
|
+
return json(res, 200, { ok: true });
|
|
5161
|
+
}
|
|
5142
5162
|
if (pathname === `/plugins/dsh-claude/repository/setup/bind`) {
|
|
5143
5163
|
if (io.method !== "POST") return json(res, 405, { error: "method not allowed" });
|
|
5144
5164
|
const input = await readJson$5(io);
|
|
@@ -7853,6 +7873,7 @@ async function apply(ctx, config) {
|
|
|
7853
7873
|
reviewComments.disposeSession(agent.id);
|
|
7854
7874
|
await supervisor.disposeSession(agent.id);
|
|
7855
7875
|
});
|
|
7876
|
+
let sweepWorktrees;
|
|
7856
7877
|
const injectWorkspaceRegistry = ctx.inject;
|
|
7857
7878
|
injectWorkspaceRegistry(["workspaceRegistry"], (sweepCtx) => {
|
|
7858
7879
|
const archiveSessions = async (worktreePath) => {
|
|
@@ -7873,9 +7894,13 @@ async function apply(ctx, config) {
|
|
|
7873
7894
|
};
|
|
7874
7895
|
sweepCtx.effect(() => {
|
|
7875
7896
|
sweep();
|
|
7897
|
+
sweepWorktrees = sweep;
|
|
7876
7898
|
const timer = setInterval(sweep, 6e4);
|
|
7877
7899
|
timer.unref?.();
|
|
7878
|
-
return () =>
|
|
7900
|
+
return () => {
|
|
7901
|
+
sweepWorktrees = void 0;
|
|
7902
|
+
clearInterval(timer);
|
|
7903
|
+
};
|
|
7879
7904
|
}, "dsh-claude: worktree reconciliation");
|
|
7880
7905
|
});
|
|
7881
7906
|
ctx.effect(() => () => reviewComments.dispose(), "dsh-claude: review comments store");
|
|
@@ -7890,7 +7915,7 @@ async function apply(ctx, config) {
|
|
|
7890
7915
|
defaultLimits,
|
|
7891
7916
|
onUpdated: applySettingsOverrides
|
|
7892
7917
|
});
|
|
7893
|
-
registerRepositorySetupRoute(webCtx, repositorySetup);
|
|
7918
|
+
registerRepositorySetupRoute(webCtx, repositorySetup, () => sweepWorktrees?.());
|
|
7894
7919
|
registerRepositoryStatusRoute(webCtx, repositoryStatus);
|
|
7895
7920
|
registerRepositoryFileRoute(webCtx, repositoryStatus);
|
|
7896
7921
|
registerJiraRoute(webCtx, new JiraService());
|