@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/client.js
CHANGED
|
@@ -6674,6 +6674,12 @@ window.__ModuleLoader__.load({
|
|
|
6674
6674
|
if (body.mode !== "worktree" && body.mode !== "checkout" || typeof body.root !== "string" || typeof body.branch !== "string") throw new Error("Invalid repository cleanup response.");
|
|
6675
6675
|
return body;
|
|
6676
6676
|
}
|
|
6677
|
+
/** Ask the Host to reconcile worktrees against the workspace registry now.
|
|
6678
|
+
* Deleting a workspace only touches the registry, so this kick is what makes
|
|
6679
|
+
* the worktree and its sessions go without waiting out the sweep interval. */
|
|
6680
|
+
async function sweepWorktrees() {
|
|
6681
|
+
await pluginWrite(`${CLAUDE_REPOSITORY_SETUP_PATH}/sweep`, "fast");
|
|
6682
|
+
}
|
|
6677
6683
|
/** Lines [from, to] of a working-tree file plus its total line count, for expanding unmodified diff context. */
|
|
6678
6684
|
async function loadRepositoryFileLines(cwd, path, from, to, signal) {
|
|
6679
6685
|
const body = await pluginRead(CLAUDE_REPOSITORY_FILE_PATH, "git", signal, { query: {
|
|
@@ -7398,6 +7404,14 @@ window.__ModuleLoader__.load({
|
|
|
7398
7404
|
}) : null]
|
|
7399
7405
|
});
|
|
7400
7406
|
}
|
|
7407
|
+
/** The trigger only shows on a clean branch that is behind its base -- but a
|
|
7408
|
+
* conflicted rebase leaves the tree dirty on a detached HEAD, so an open
|
|
7409
|
+
* dialog (and its resolve button) has to outlive that. */
|
|
7410
|
+
function updateBranchMounted(repository, dialogOpen) {
|
|
7411
|
+
const pullRequest = repository.pullRequest;
|
|
7412
|
+
if (pullRequest?.baseBranch === void 0) return false;
|
|
7413
|
+
return dialogOpen || pullRequest.state === "open" && repository.detached !== true && repository.dirty !== true && (repository.baseBehind ?? 0) > 0;
|
|
7414
|
+
}
|
|
7401
7415
|
function UpdateBranchControl({ sessionId, repository, t, report, submitPrompt }) {
|
|
7402
7416
|
const [dialog, setDialog] = useState();
|
|
7403
7417
|
const [method, setMethod] = useState("rebase");
|
|
@@ -7406,7 +7420,8 @@ window.__ModuleLoader__.load({
|
|
|
7406
7420
|
const base = pullRequest?.baseBranch;
|
|
7407
7421
|
const behind = repository.baseBehind ?? 0;
|
|
7408
7422
|
useEffect(() => () => controller.current?.abort(), []);
|
|
7409
|
-
if (pullRequest === void 0 ||
|
|
7423
|
+
if (pullRequest === void 0 || base === void 0) return null;
|
|
7424
|
+
if (!updateBranchMounted(repository, dialog !== void 0)) return null;
|
|
7410
7425
|
const openDialog = () => {
|
|
7411
7426
|
controller.current?.abort();
|
|
7412
7427
|
setDialog({
|
|
@@ -15338,13 +15353,37 @@ window.__ModuleLoader__.load({
|
|
|
15338
15353
|
function directChildContaining(parent, descendant) {
|
|
15339
15354
|
return Array.from(parent.children).find((child) => child === descendant || child.contains(descendant));
|
|
15340
15355
|
}
|
|
15341
|
-
/**
|
|
15342
|
-
|
|
15356
|
+
/** The hero's preset buttons: menu buttons without an `aria-label`, which is
|
|
15357
|
+
* what separates the preset seat from the labelled workspace picker. The
|
|
15358
|
+
* portal's own branch trigger answers that description too, so it is excluded
|
|
15359
|
+
* -- counting it made the row look like it held two staged presets from the
|
|
15360
|
+
* moment these controls mounted. */
|
|
15361
|
+
function heroPresetButtons(root) {
|
|
15343
15362
|
const heroes = Array.from(root.querySelectorAll(HERO_SELECTOR));
|
|
15344
15363
|
if (heroes.length !== 1) return void 0;
|
|
15345
15364
|
const hero = heroes[0];
|
|
15346
15365
|
if (hero === void 0) return void 0;
|
|
15347
|
-
|
|
15366
|
+
return {
|
|
15367
|
+
hero,
|
|
15368
|
+
presets: Array.from(hero.querySelectorAll("button[aria-haspopup=\"menu\"]")).filter((button) => button.getAttribute("aria-label") === null && button.closest(`[${PORTAL_ATTRIBUTE}]`) === null)
|
|
15369
|
+
};
|
|
15370
|
+
}
|
|
15371
|
+
/** True once the hero has settled on a preset that is not Claude.
|
|
15372
|
+
* `locateClaudePresetSeat` reports that the same way it reports a hero
|
|
15373
|
+
* mid-render -- by missing -- so without this the retention rule below reads a
|
|
15374
|
+
* deliberate switch away from Claude as a re-render and leaves the controls up. */
|
|
15375
|
+
function showsOtherPresetSeat(root = document) {
|
|
15376
|
+
const found = heroPresetButtons(root);
|
|
15377
|
+
if (found === void 0 || found.presets.length !== 1) return false;
|
|
15378
|
+
const preset = found.presets[0];
|
|
15379
|
+
return preset !== void 0 && !isClaudePresetText(normalizedText(preset));
|
|
15380
|
+
}
|
|
15381
|
+
/** Locate rc.8's hero preset seat without relying on hashed CSS module names. */
|
|
15382
|
+
function locateClaudePresetSeat(root = document) {
|
|
15383
|
+
const found = heroPresetButtons(root);
|
|
15384
|
+
if (found === void 0) return void 0;
|
|
15385
|
+
const { hero } = found;
|
|
15386
|
+
const presetButtons = found.presets.filter((button) => isClaudePresetText(normalizedText(button)));
|
|
15348
15387
|
if (presetButtons.length !== 1) return void 0;
|
|
15349
15388
|
const preset = presetButtons[0];
|
|
15350
15389
|
if (preset === void 0) return void 0;
|
|
@@ -15803,7 +15842,7 @@ window.__ModuleLoader__.load({
|
|
|
15803
15842
|
scheduled = false;
|
|
15804
15843
|
const target = locateClaudePresetSeat();
|
|
15805
15844
|
if (target === void 0) {
|
|
15806
|
-
if (retainsClaudeHeroPortal(current)) return;
|
|
15845
|
+
if (retainsClaudeHeroPortal(current) && !showsOtherPresetSeat()) return;
|
|
15807
15846
|
current = void 0;
|
|
15808
15847
|
removeClaudeHeroPortals();
|
|
15809
15848
|
setPortal(void 0);
|
|
@@ -17800,6 +17839,15 @@ window.__ModuleLoader__.load({
|
|
|
17800
17839
|
const workspaces = ctx.get("workspaces");
|
|
17801
17840
|
const uiWorkspace = ctx.get("uiWorkspace");
|
|
17802
17841
|
const connectWorkspace = uiWorkspace?.connectWorkspace?.bind(uiWorkspace) ?? (typeof workspaces?.connectWorkspace === "function" ? workspaces.connectWorkspace.bind(workspaces) : void 0);
|
|
17842
|
+
if (workspaces !== void 0) ctx.effect(() => {
|
|
17843
|
+
let known = new Set(workspaces.list.getSnapshot().items.map((item) => item.workspaceId));
|
|
17844
|
+
return workspaces.list.subscribe(() => {
|
|
17845
|
+
const next = new Set(workspaces.list.getSnapshot().items.map((item) => item.workspaceId));
|
|
17846
|
+
const removed = [...known].some((id) => !next.has(id));
|
|
17847
|
+
known = next;
|
|
17848
|
+
if (removed) sweepWorktrees().catch(() => void 0);
|
|
17849
|
+
});
|
|
17850
|
+
}, "dsh-claude: worktree sweep on workspace deletion");
|
|
17803
17851
|
const conversation = ctx.get("conversation");
|
|
17804
17852
|
const connection = ctx.get("connection");
|
|
17805
17853
|
const remote = ctx.get("remote");
|