@norman-else/dsh-claude 0.1.20 → 0.1.21
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/INSTALL.md +55 -55
- package/LICENSE +21 -21
- package/README.md +82 -191
- package/cordis.patch.yml +12 -12
- package/legacy-preset/agent.cordis.yml +11 -11
- package/legacy-preset/preset.yml +4 -4
- package/lib/bin.mjs +0 -0
- package/lib/bin.mjs.map +1 -1
- package/lib/client.js +439 -183
- package/lib/client.js.map +1 -1
- package/lib/command-bridge-C10-lz6A.mjs.map +1 -1
- package/lib/events-BdDs9ebF.mjs.map +1 -1
- package/lib/index.d.mts +33 -0
- package/lib/index.mjs +292 -31
- package/lib/index.mjs.map +1 -1
- package/lib/preset-installer-DMANIjwu.mjs.map +1 -1
- package/lib/preset-route.mjs.map +1 -1
- package/package.json +181 -181
- package/preset/claude/agent.cordis.yml +11 -11
- package/preset/claude/preset.yml +4 -4
package/lib/client.js
CHANGED
|
@@ -2606,6 +2606,426 @@ window.__ModuleLoader__.load({
|
|
|
2606
2606
|
});
|
|
2607
2607
|
}
|
|
2608
2608
|
//#endregion
|
|
2609
|
+
//#region src/client/projection.ts
|
|
2610
|
+
const EMPTY_CLAUDE_PROJECTION = {
|
|
2611
|
+
schemaVersion: 1,
|
|
2612
|
+
revision: 0,
|
|
2613
|
+
owned: false,
|
|
2614
|
+
commands: [],
|
|
2615
|
+
activities: []
|
|
2616
|
+
};
|
|
2617
|
+
const RETRY_DELAY_MS = 2e3;
|
|
2618
|
+
/** Coalesce stream deltas into at most one React notification per frame. */
|
|
2619
|
+
const FRAME_MS = 16;
|
|
2620
|
+
/** Typewriter smoothing: drain newly arrived prose over roughly this window,
|
|
2621
|
+
* so the CLI's paragraph-sized deltas read as a continuous character flow. */
|
|
2622
|
+
const REVEAL_WINDOW_MS = 1200;
|
|
2623
|
+
/** A burst larger than this (redaction rewrite, reconnect catch-up) shows
|
|
2624
|
+
* instantly instead of animating for a long stretch. */
|
|
2625
|
+
const MAX_INSTANT_REVEAL = 4e3;
|
|
2626
|
+
const MAX_ACTIVITIES = 1e4;
|
|
2627
|
+
const MAX_COMMANDS = 2e3;
|
|
2628
|
+
const MAX_REPOSITORY_TEXT_CHARS = 1024;
|
|
2629
|
+
const MAX_DIFF_CHARS = 262144;
|
|
2630
|
+
const MAX_REVIEW_COMMENTS = 50;
|
|
2631
|
+
const MAX_REVIEW_COMMENT_CHARS = 2e3;
|
|
2632
|
+
const MAX_TRANSCRIPT_CHARS = 64e3;
|
|
2633
|
+
function record$4(value) {
|
|
2634
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2635
|
+
}
|
|
2636
|
+
function nonNegativeInteger(value) {
|
|
2637
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
2638
|
+
}
|
|
2639
|
+
function optionalBoundedString(value) {
|
|
2640
|
+
return value === void 0 || typeof value === "string" && value.length <= MAX_REPOSITORY_TEXT_CHARS;
|
|
2641
|
+
}
|
|
2642
|
+
function validateRepository(value) {
|
|
2643
|
+
const repository = record$4(value);
|
|
2644
|
+
if (repository === void 0 || ![
|
|
2645
|
+
"ready",
|
|
2646
|
+
"not-repository",
|
|
2647
|
+
"unavailable"
|
|
2648
|
+
].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean" || repository.upstream !== void 0 && typeof repository.upstream !== "boolean" || repository.ahead !== void 0 && !nonNegativeInteger(repository.ahead) || repository.behind !== void 0 && !nonNegativeInteger(repository.behind)) return false;
|
|
2649
|
+
if (repository.diff !== void 0) {
|
|
2650
|
+
const diff = record$4(repository.diff);
|
|
2651
|
+
if (diff === void 0 || !nonNegativeInteger(diff.additions) || !nonNegativeInteger(diff.deletions) || !nonNegativeInteger(diff.files) || typeof diff.truncated !== "boolean" || diff.patch !== void 0 && (typeof diff.patch !== "string" || diff.patch.length > MAX_DIFF_CHARS)) return false;
|
|
2652
|
+
}
|
|
2653
|
+
if (repository.pullRequest === void 0) return true;
|
|
2654
|
+
const pullRequest = record$4(repository.pullRequest);
|
|
2655
|
+
if (pullRequest === void 0 || !Number.isSafeInteger(pullRequest.number) || Number(pullRequest.number) <= 0 || typeof pullRequest.title !== "string" || pullRequest.title.length > MAX_REPOSITORY_TEXT_CHARS || typeof pullRequest.url !== "string" || pullRequest.url.length > MAX_REPOSITORY_TEXT_CHARS || ![
|
|
2656
|
+
"open",
|
|
2657
|
+
"closed",
|
|
2658
|
+
"merged"
|
|
2659
|
+
].includes(String(pullRequest.state)) || typeof pullRequest.draft !== "boolean" || ![
|
|
2660
|
+
"approved",
|
|
2661
|
+
"changes-requested",
|
|
2662
|
+
"review-required",
|
|
2663
|
+
"none"
|
|
2664
|
+
].includes(String(pullRequest.review)) || ![
|
|
2665
|
+
"passing",
|
|
2666
|
+
"pending",
|
|
2667
|
+
"failing",
|
|
2668
|
+
"none"
|
|
2669
|
+
].includes(String(pullRequest.checks)) || !optionalBoundedString(pullRequest.mergeState) || !optionalBoundedString(pullRequest.author) || !optionalBoundedString(pullRequest.baseBranch) || pullRequest.createdAt !== void 0 && (typeof pullRequest.createdAt !== "string" || !Number.isFinite(Date.parse(pullRequest.createdAt))) || pullRequest.mergedAt !== void 0 && (typeof pullRequest.mergedAt !== "string" || !Number.isFinite(Date.parse(pullRequest.mergedAt)))) return false;
|
|
2670
|
+
try {
|
|
2671
|
+
const url = new URL(pullRequest.url);
|
|
2672
|
+
return url.protocol === "https:" && url.hostname === "github.com";
|
|
2673
|
+
} catch {
|
|
2674
|
+
return false;
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
/** Validate the public route envelope before publishing it to UI components. */
|
|
2678
|
+
function parseClaudeClientProjection(value) {
|
|
2679
|
+
const input = record$4(value);
|
|
2680
|
+
if (input === void 0 || input.schemaVersion !== 1 || !nonNegativeInteger(input.revision) || typeof input.owned !== "boolean" || !Array.isArray(input.commands) || input.commands.length > MAX_COMMANDS || !Array.isArray(input.activities) || input.activities.length > MAX_ACTIVITIES) throw new Error("invalid Claude sidecar projection");
|
|
2681
|
+
for (const item of input.commands) {
|
|
2682
|
+
const command = record$4(item);
|
|
2683
|
+
if (command === void 0 || typeof command.publicName !== "string" || typeof command.claudeName !== "string" || typeof command.description !== "string" || command.hint !== void 0 && typeof command.hint !== "string" || typeof command.prefixed !== "boolean") throw new Error("invalid Claude command projection");
|
|
2684
|
+
}
|
|
2685
|
+
for (const item of input.activities) {
|
|
2686
|
+
const activity = record$4(item);
|
|
2687
|
+
if (activity === void 0 || !nonNegativeInteger(activity.turn) || !nonNegativeInteger(activity.step) || !nonNegativeInteger(activity.ordinal) || typeof activity.kind !== "string") throw new Error("invalid Claude sidecar activity");
|
|
2688
|
+
}
|
|
2689
|
+
if (input.contextUsage !== void 0 && record$4(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
|
|
2690
|
+
const tasks = input.tasks === void 0 ? void 0 : record$4(input.tasks);
|
|
2691
|
+
if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
|
|
2692
|
+
if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
|
|
2693
|
+
if (input.reviewComments !== void 0) {
|
|
2694
|
+
if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
|
|
2695
|
+
for (const item of input.reviewComments) {
|
|
2696
|
+
const comment = record$4(item);
|
|
2697
|
+
if (comment === void 0 || typeof comment.id !== "string" || comment.id.length === 0 || comment.id.length > 128 || typeof comment.path !== "string" || comment.path.length === 0 || comment.path.length > MAX_REPOSITORY_TEXT_CHARS || !nonNegativeInteger(comment.line) || comment.side !== "old" && comment.side !== "new" || typeof comment.text !== "string" || comment.text.length > MAX_REVIEW_COMMENT_CHARS) throw new Error("invalid Claude review comment projection");
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
return input;
|
|
2701
|
+
}
|
|
2702
|
+
/** Validate one incremental delta payload with the same rules as a snapshot. */
|
|
2703
|
+
function validateEnvelopeFragment(fragment) {
|
|
2704
|
+
parseClaudeClientProjection({
|
|
2705
|
+
schemaVersion: 1,
|
|
2706
|
+
revision: 0,
|
|
2707
|
+
owned: false,
|
|
2708
|
+
commands: [],
|
|
2709
|
+
activities: [],
|
|
2710
|
+
...fragment
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
function stepKeyOf(turn, step) {
|
|
2714
|
+
return `${turn}:${step}`;
|
|
2715
|
+
}
|
|
2716
|
+
const EMPTY_ACTIVITIES = [];
|
|
2717
|
+
/** Identity-stable per-step slice; untouched steps never re-render while
|
|
2718
|
+
* another step streams. Falls back to filtering for snapshot-only hooks. */
|
|
2719
|
+
function selectStepActivities(value, turn, step) {
|
|
2720
|
+
const sliced = value.byStep?.get(stepKeyOf(turn, step));
|
|
2721
|
+
if (sliced !== void 0) return sliced;
|
|
2722
|
+
const filtered = value.activities.filter((activity) => activity.turn === turn && activity.step === step);
|
|
2723
|
+
return filtered.length === 0 ? EMPTY_ACTIVITIES : filtered;
|
|
2724
|
+
}
|
|
2725
|
+
function isAbort(error) {
|
|
2726
|
+
return error?.name === "AbortError";
|
|
2727
|
+
}
|
|
2728
|
+
function delay(ms) {
|
|
2729
|
+
return new Promise((resolve) => {
|
|
2730
|
+
setTimeout(resolve, ms).unref?.();
|
|
2731
|
+
});
|
|
2732
|
+
}
|
|
2733
|
+
/** Create one lazy source: active subscribers open the Host NDJSON stream, and
|
|
2734
|
+
* a dropped stream reconnects with a fresh snapshot after a bounded delay. */
|
|
2735
|
+
function createClaudeProjectionSource(sessionId, fetchProjection = fetch, retryDelayMs = RETRY_DELAY_MS) {
|
|
2736
|
+
let snapshot = EMPTY_CLAUDE_PROJECTION;
|
|
2737
|
+
let revision = 0;
|
|
2738
|
+
let owned = false;
|
|
2739
|
+
let commands = [];
|
|
2740
|
+
let contextUsage;
|
|
2741
|
+
let tasks;
|
|
2742
|
+
let repository;
|
|
2743
|
+
let reviewComments;
|
|
2744
|
+
const byStep = /* @__PURE__ */ new Map();
|
|
2745
|
+
const stepOrder = [];
|
|
2746
|
+
/** Streaming prose still being revealed: full arrived text plus shown chars. */
|
|
2747
|
+
const reveal = /* @__PURE__ */ new Map();
|
|
2748
|
+
let disposed = false;
|
|
2749
|
+
let running = false;
|
|
2750
|
+
let controller;
|
|
2751
|
+
let frame;
|
|
2752
|
+
let usedAnimationFrame = false;
|
|
2753
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2754
|
+
const ensureStep = (turn, step) => {
|
|
2755
|
+
const key = stepKeyOf(turn, step);
|
|
2756
|
+
const existing = byStep.get(key);
|
|
2757
|
+
if (existing !== void 0) return existing;
|
|
2758
|
+
const created = [];
|
|
2759
|
+
byStep.set(key, created);
|
|
2760
|
+
const at = stepOrder.findIndex((entry) => entry.turn > turn || entry.turn === turn && entry.step > step);
|
|
2761
|
+
stepOrder.splice(at === -1 ? stepOrder.length : at, 0, {
|
|
2762
|
+
turn,
|
|
2763
|
+
step,
|
|
2764
|
+
key
|
|
2765
|
+
});
|
|
2766
|
+
return created;
|
|
2767
|
+
};
|
|
2768
|
+
const upsertActivity = (activity) => {
|
|
2769
|
+
const key = stepKeyOf(activity.turn, activity.step);
|
|
2770
|
+
const next = ensureStep(activity.turn, activity.step).slice();
|
|
2771
|
+
const index = next.findIndex((item) => item.ordinal === activity.ordinal);
|
|
2772
|
+
if (index === -1) {
|
|
2773
|
+
const at = next.findIndex((item) => item.ordinal > activity.ordinal);
|
|
2774
|
+
next.splice(at === -1 ? next.length : at, 0, activity);
|
|
2775
|
+
} else next[index] = activity;
|
|
2776
|
+
byStep.set(key, next);
|
|
2777
|
+
};
|
|
2778
|
+
const reset = (activities) => {
|
|
2779
|
+
byStep.clear();
|
|
2780
|
+
stepOrder.length = 0;
|
|
2781
|
+
reveal.clear();
|
|
2782
|
+
for (const activity of activities) ensureStep(activity.turn, activity.step).push(activity);
|
|
2783
|
+
};
|
|
2784
|
+
/** Advance every pending typewriter reveal by one frame's worth of characters.
|
|
2785
|
+
* The per-frame step scales with the backlog so any burst drains in roughly
|
|
2786
|
+
* REVEAL_WINDOW_MS. Returns whether another frame is still needed. */
|
|
2787
|
+
const advanceReveals = () => {
|
|
2788
|
+
let remaining = false;
|
|
2789
|
+
for (const [key, entry] of reveal) {
|
|
2790
|
+
const total = entry.full.text?.length ?? 0;
|
|
2791
|
+
if (entry.shown >= total) {
|
|
2792
|
+
reveal.delete(key);
|
|
2793
|
+
continue;
|
|
2794
|
+
}
|
|
2795
|
+
const step = Math.max(1, Math.ceil((total - entry.shown) * FRAME_MS / REVEAL_WINDOW_MS));
|
|
2796
|
+
entry.shown = Math.min(total, entry.shown + step);
|
|
2797
|
+
upsertActivity({
|
|
2798
|
+
...entry.full,
|
|
2799
|
+
text: (entry.full.text ?? "").slice(0, entry.shown)
|
|
2800
|
+
});
|
|
2801
|
+
if (entry.shown >= total) reveal.delete(key);
|
|
2802
|
+
else remaining = true;
|
|
2803
|
+
}
|
|
2804
|
+
return remaining;
|
|
2805
|
+
};
|
|
2806
|
+
const publish = () => {
|
|
2807
|
+
frame = void 0;
|
|
2808
|
+
if (disposed) return;
|
|
2809
|
+
const revealing = advanceReveals();
|
|
2810
|
+
const activities = [];
|
|
2811
|
+
for (const entry of stepOrder) {
|
|
2812
|
+
const slice = byStep.get(entry.key);
|
|
2813
|
+
if (slice !== void 0) for (const item of slice) activities.push(item);
|
|
2814
|
+
}
|
|
2815
|
+
snapshot = {
|
|
2816
|
+
schemaVersion: 1,
|
|
2817
|
+
revision,
|
|
2818
|
+
owned,
|
|
2819
|
+
commands,
|
|
2820
|
+
activities,
|
|
2821
|
+
...contextUsage === void 0 ? {} : { contextUsage },
|
|
2822
|
+
...tasks === void 0 ? {} : { tasks },
|
|
2823
|
+
...repository === void 0 ? {} : { repository },
|
|
2824
|
+
...reviewComments === void 0 ? {} : { reviewComments },
|
|
2825
|
+
byStep: new Map(byStep)
|
|
2826
|
+
};
|
|
2827
|
+
for (const listener of [...listeners]) listener();
|
|
2828
|
+
if (revealing) schedulePublish();
|
|
2829
|
+
};
|
|
2830
|
+
const cancelFrame = () => {
|
|
2831
|
+
if (frame === void 0) return;
|
|
2832
|
+
if (usedAnimationFrame) globalThis.cancelAnimationFrame?.(frame);
|
|
2833
|
+
else clearTimeout(frame);
|
|
2834
|
+
frame = void 0;
|
|
2835
|
+
};
|
|
2836
|
+
const schedulePublish = () => {
|
|
2837
|
+
if (disposed || frame !== void 0 || listeners.size === 0) return;
|
|
2838
|
+
const raf = globalThis.requestAnimationFrame;
|
|
2839
|
+
if (typeof raf === "function") {
|
|
2840
|
+
usedAnimationFrame = true;
|
|
2841
|
+
frame = raf(publish);
|
|
2842
|
+
} else {
|
|
2843
|
+
usedAnimationFrame = false;
|
|
2844
|
+
frame = setTimeout(publish, FRAME_MS);
|
|
2845
|
+
}
|
|
2846
|
+
};
|
|
2847
|
+
const applyText = (event) => {
|
|
2848
|
+
const { turn, step, ordinal, append, text } = event;
|
|
2849
|
+
if (!nonNegativeInteger(turn) || !nonNegativeInteger(step) || !nonNegativeInteger(ordinal)) return false;
|
|
2850
|
+
if (append !== void 0 && (typeof append !== "string" || append.length > MAX_TRANSCRIPT_CHARS)) return false;
|
|
2851
|
+
if (text !== void 0 && (typeof text !== "string" || text.length > MAX_TRANSCRIPT_CHARS)) return false;
|
|
2852
|
+
if (append === void 0 && text === void 0) return false;
|
|
2853
|
+
const revealKey = `${turn}:${step}:${ordinal}`;
|
|
2854
|
+
const existing = byStep.get(stepKeyOf(turn, step))?.find((item) => item.ordinal === ordinal);
|
|
2855
|
+
const pending = reveal.get(revealKey);
|
|
2856
|
+
if (existing === void 0 && pending === void 0 && typeof text !== "string") return false;
|
|
2857
|
+
const baseText = pending?.full.text ?? existing?.text ?? "";
|
|
2858
|
+
const fullText = (typeof text === "string" ? text : `${baseText}${append}`).slice(0, MAX_TRANSCRIPT_CHARS);
|
|
2859
|
+
const full = {
|
|
2860
|
+
...pending?.full ?? existing ?? {
|
|
2861
|
+
turn,
|
|
2862
|
+
step,
|
|
2863
|
+
ordinal,
|
|
2864
|
+
kind: "text",
|
|
2865
|
+
phase: "updated"
|
|
2866
|
+
},
|
|
2867
|
+
text: fullText
|
|
2868
|
+
};
|
|
2869
|
+
const shown = Math.min(pending?.shown ?? existing?.text?.length ?? 0, fullText.length);
|
|
2870
|
+
if (fullText.length - shown > MAX_INSTANT_REVEAL) {
|
|
2871
|
+
reveal.delete(revealKey);
|
|
2872
|
+
upsertActivity(full);
|
|
2873
|
+
return true;
|
|
2874
|
+
}
|
|
2875
|
+
reveal.set(revealKey, {
|
|
2876
|
+
full,
|
|
2877
|
+
shown
|
|
2878
|
+
});
|
|
2879
|
+
upsertActivity({
|
|
2880
|
+
...full,
|
|
2881
|
+
text: fullText.slice(0, shown)
|
|
2882
|
+
});
|
|
2883
|
+
return true;
|
|
2884
|
+
};
|
|
2885
|
+
const applyLine = (line) => {
|
|
2886
|
+
const trimmed = line.trim();
|
|
2887
|
+
if (trimmed.length === 0) return;
|
|
2888
|
+
let value;
|
|
2889
|
+
try {
|
|
2890
|
+
value = JSON.parse(trimmed);
|
|
2891
|
+
} catch {
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
const event = record$4(value);
|
|
2895
|
+
if (event === void 0 || typeof event.type !== "string") return;
|
|
2896
|
+
try {
|
|
2897
|
+
switch (event.type) {
|
|
2898
|
+
case "snapshot": {
|
|
2899
|
+
const next = parseClaudeClientProjection(event);
|
|
2900
|
+
revision = next.revision;
|
|
2901
|
+
owned = next.owned;
|
|
2902
|
+
commands = next.commands;
|
|
2903
|
+
contextUsage = next.contextUsage;
|
|
2904
|
+
tasks = next.tasks;
|
|
2905
|
+
repository = next.repository;
|
|
2906
|
+
reviewComments = next.reviewComments;
|
|
2907
|
+
reset(next.activities);
|
|
2908
|
+
break;
|
|
2909
|
+
}
|
|
2910
|
+
case "text":
|
|
2911
|
+
if (!applyText(event)) return;
|
|
2912
|
+
revision += 1;
|
|
2913
|
+
break;
|
|
2914
|
+
case "activity":
|
|
2915
|
+
validateEnvelopeFragment({ activities: [event.activity] });
|
|
2916
|
+
upsertActivity(event.activity);
|
|
2917
|
+
revision += 1;
|
|
2918
|
+
break;
|
|
2919
|
+
case "contextUsage":
|
|
2920
|
+
validateEnvelopeFragment({ contextUsage: event.value });
|
|
2921
|
+
contextUsage = event.value;
|
|
2922
|
+
revision += 1;
|
|
2923
|
+
break;
|
|
2924
|
+
case "tasks":
|
|
2925
|
+
validateEnvelopeFragment({ tasks: event.value });
|
|
2926
|
+
tasks = event.value;
|
|
2927
|
+
revision += 1;
|
|
2928
|
+
break;
|
|
2929
|
+
case "meta":
|
|
2930
|
+
validateEnvelopeFragment({
|
|
2931
|
+
owned: event.owned,
|
|
2932
|
+
commands: event.commands,
|
|
2933
|
+
...event.repository === void 0 ? {} : { repository: event.repository },
|
|
2934
|
+
...event.reviewComments === void 0 ? {} : { reviewComments: event.reviewComments }
|
|
2935
|
+
});
|
|
2936
|
+
owned = event.owned;
|
|
2937
|
+
commands = event.commands;
|
|
2938
|
+
repository = event.repository;
|
|
2939
|
+
reviewComments = event.reviewComments;
|
|
2940
|
+
revision += 1;
|
|
2941
|
+
break;
|
|
2942
|
+
default: return;
|
|
2943
|
+
}
|
|
2944
|
+
} catch {
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
schedulePublish();
|
|
2948
|
+
};
|
|
2949
|
+
const run = async () => {
|
|
2950
|
+
if (running) return;
|
|
2951
|
+
running = true;
|
|
2952
|
+
try {
|
|
2953
|
+
while (!disposed && listeners.size > 0) {
|
|
2954
|
+
controller = new AbortController();
|
|
2955
|
+
try {
|
|
2956
|
+
const response = await fetchProjection(`${CLAUDE_PROJECTION_PATH}/${encodeURIComponent(sessionId)}/stream`, {
|
|
2957
|
+
headers: { accept: "application/x-ndjson" },
|
|
2958
|
+
signal: controller.signal
|
|
2959
|
+
});
|
|
2960
|
+
if (!response.ok) throw new Error(`Claude projection stream failed (${response.status})`);
|
|
2961
|
+
if (response.body === null) throw new Error("Claude projection stream is unavailable");
|
|
2962
|
+
const reader = response.body.getReader();
|
|
2963
|
+
const decoder = new TextDecoder();
|
|
2964
|
+
let buffer = "";
|
|
2965
|
+
while (true) {
|
|
2966
|
+
if (disposed || listeners.size === 0) {
|
|
2967
|
+
await reader.cancel().catch(() => void 0);
|
|
2968
|
+
break;
|
|
2969
|
+
}
|
|
2970
|
+
const chunk = await reader.read();
|
|
2971
|
+
buffer += decoder.decode(chunk.value, { stream: !chunk.done });
|
|
2972
|
+
const lines = buffer.split("\n");
|
|
2973
|
+
buffer = lines.pop() ?? "";
|
|
2974
|
+
for (const line of lines) applyLine(line);
|
|
2975
|
+
if (chunk.done) break;
|
|
2976
|
+
}
|
|
2977
|
+
} catch (error) {
|
|
2978
|
+
if (isAbort(error)) return;
|
|
2979
|
+
} finally {
|
|
2980
|
+
controller = void 0;
|
|
2981
|
+
}
|
|
2982
|
+
if (disposed || listeners.size === 0) return;
|
|
2983
|
+
await delay(retryDelayMs);
|
|
2984
|
+
}
|
|
2985
|
+
} finally {
|
|
2986
|
+
running = false;
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
return {
|
|
2990
|
+
getSnapshot: () => snapshot,
|
|
2991
|
+
subscribe(listener) {
|
|
2992
|
+
if (disposed) return () => {};
|
|
2993
|
+
const wasIdle = listeners.size === 0;
|
|
2994
|
+
listeners.add(listener);
|
|
2995
|
+
if (wasIdle) run();
|
|
2996
|
+
return () => {
|
|
2997
|
+
listeners.delete(listener);
|
|
2998
|
+
if (listeners.size !== 0) return;
|
|
2999
|
+
controller?.abort();
|
|
3000
|
+
controller = void 0;
|
|
3001
|
+
cancelFrame();
|
|
3002
|
+
};
|
|
3003
|
+
},
|
|
3004
|
+
dispose() {
|
|
3005
|
+
disposed = true;
|
|
3006
|
+
listeners.clear();
|
|
3007
|
+
controller?.abort();
|
|
3008
|
+
controller = void 0;
|
|
3009
|
+
cancelFrame();
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
}
|
|
3013
|
+
var ClaudeProjectionStore = class {
|
|
3014
|
+
#sources = /* @__PURE__ */ new Map();
|
|
3015
|
+
source(sessionId) {
|
|
3016
|
+
let source = this.#sources.get(sessionId);
|
|
3017
|
+
if (source === void 0) {
|
|
3018
|
+
source = createClaudeProjectionSource(sessionId);
|
|
3019
|
+
this.#sources.set(sessionId, source);
|
|
3020
|
+
}
|
|
3021
|
+
return source;
|
|
3022
|
+
}
|
|
3023
|
+
dispose() {
|
|
3024
|
+
for (const source of this.#sources.values()) source.dispose();
|
|
3025
|
+
this.#sources.clear();
|
|
3026
|
+
}
|
|
3027
|
+
};
|
|
3028
|
+
//#endregion
|
|
2609
3029
|
//#region src/client/ClaudeActivityNode.tsx
|
|
2610
3030
|
const EMPTY_TASKS = [];
|
|
2611
3031
|
const ACTIVITY_CSS = [
|
|
@@ -2730,7 +3150,7 @@ window.__ModuleLoader__.load({
|
|
|
2730
3150
|
return value;
|
|
2731
3151
|
}
|
|
2732
3152
|
}
|
|
2733
|
-
function record$
|
|
3153
|
+
function record$3(value) {
|
|
2734
3154
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2735
3155
|
}
|
|
2736
3156
|
function text(value) {
|
|
@@ -2744,7 +3164,7 @@ window.__ModuleLoader__.load({
|
|
|
2744
3164
|
if (typeof value === "string") return value;
|
|
2745
3165
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2746
3166
|
if (Array.isArray(value)) return value.map(displayValue).join(", ");
|
|
2747
|
-
return record$
|
|
3167
|
+
return record$3(value) === void 0 ? String(value) : Object.entries(value).map(([key, item]) => `${key}: ${displayValue(item)}`).join("\n");
|
|
2748
3168
|
}
|
|
2749
3169
|
function Section({ title, children }) {
|
|
2750
3170
|
return /* @__PURE__ */ jsxs("section", {
|
|
@@ -2814,15 +3234,15 @@ window.__ModuleLoader__.load({
|
|
|
2814
3234
|
function ToolPresentation({ tool, t }) {
|
|
2815
3235
|
const inputValue = parsedValue(tool.input);
|
|
2816
3236
|
const outputValue = parsedValue(tool.output);
|
|
2817
|
-
const input = record$
|
|
2818
|
-
const output = record$
|
|
3237
|
+
const input = record$3(inputValue);
|
|
3238
|
+
const output = record$3(outputValue);
|
|
2819
3239
|
const outputTitle = tool.isError === true ? t("toolError") : t("toolOutput");
|
|
2820
3240
|
if (tool.diffs !== void 0) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(DiffBlock, { diffs: [...tool.diffs] }), /* @__PURE__ */ jsx(TextDetail, {
|
|
2821
3241
|
title: outputTitle,
|
|
2822
3242
|
value: typeof outputValue === "string" ? outputValue : void 0
|
|
2823
3243
|
})] });
|
|
2824
3244
|
if (tool.toolName === "Read") {
|
|
2825
|
-
const file = record$
|
|
3245
|
+
const file = record$3(output?.file);
|
|
2826
3246
|
const path = text(file?.filePath) ?? text(input?.file_path);
|
|
2827
3247
|
const content = text(file?.content) ?? (typeof outputValue === "string" ? outputValue : void 0);
|
|
2828
3248
|
const offset = numberValue(input?.offset) ?? 1;
|
|
@@ -2984,7 +3404,7 @@ window.__ModuleLoader__.load({
|
|
|
2984
3404
|
function ClaudeActivityNode({ node, useClaudeProjection, t }) {
|
|
2985
3405
|
ensureCss();
|
|
2986
3406
|
const marker = node.data;
|
|
2987
|
-
const activities = useClaudeProjection((value) => value.
|
|
3407
|
+
const activities = useClaudeProjection((value) => selectStepActivities(value, marker.turn, marker.step));
|
|
2988
3408
|
const tasks = useClaudeProjection((value) => value.tasks?.tasks ?? EMPTY_TASKS);
|
|
2989
3409
|
const items = useMemo(() => transcriptItemsForStep(activities, marker.turn, marker.step, tasks), [
|
|
2990
3410
|
activities,
|
|
@@ -3851,7 +4271,7 @@ window.__ModuleLoader__.load({
|
|
|
3851
4271
|
}
|
|
3852
4272
|
//#endregion
|
|
3853
4273
|
//#region src/client/review-comment-api.ts
|
|
3854
|
-
function record$
|
|
4274
|
+
function record$2(value) {
|
|
3855
4275
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3856
4276
|
}
|
|
3857
4277
|
async function post(path, sessionId, body) {
|
|
@@ -3866,13 +4286,13 @@ window.__ModuleLoader__.load({
|
|
|
3866
4286
|
});
|
|
3867
4287
|
const value = await response.json();
|
|
3868
4288
|
if (!response.ok) {
|
|
3869
|
-
const error = record$
|
|
4289
|
+
const error = record$2(value);
|
|
3870
4290
|
throw new Error(typeof error?.message === "string" ? error.message : "Review comment request failed.");
|
|
3871
4291
|
}
|
|
3872
4292
|
return value;
|
|
3873
4293
|
}
|
|
3874
4294
|
async function addReviewComment(sessionId, comment) {
|
|
3875
|
-
const created = record$
|
|
4295
|
+
const created = record$2(record$2(await post("", sessionId, comment))?.comment);
|
|
3876
4296
|
if (created === void 0 || typeof created.id !== "string") throw new Error("Invalid review comment response.");
|
|
3877
4297
|
return created;
|
|
3878
4298
|
}
|
|
@@ -4037,33 +4457,33 @@ window.__ModuleLoader__.load({
|
|
|
4037
4457
|
if (commit !== void 0) this.commit = commit;
|
|
4038
4458
|
}
|
|
4039
4459
|
};
|
|
4040
|
-
function record$
|
|
4460
|
+
function record$1(value) {
|
|
4041
4461
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
4042
4462
|
}
|
|
4043
4463
|
async function response$1(pending) {
|
|
4044
4464
|
const result = await pending;
|
|
4045
4465
|
const body = await result.json();
|
|
4046
4466
|
if (!result.ok) {
|
|
4047
|
-
const error = record$
|
|
4467
|
+
const error = record$1(body);
|
|
4048
4468
|
throw new RepositoryActionClientError(typeof error?.message === "string" ? error.message : "Repository action failed.", typeof error?.error === "string" ? error.error : void 0, typeof error?.commit === "string" ? error.commit : void 0);
|
|
4049
4469
|
}
|
|
4050
4470
|
return body;
|
|
4051
4471
|
}
|
|
4052
4472
|
function preview(value) {
|
|
4053
|
-
const input = record$
|
|
4473
|
+
const input = record$1(value);
|
|
4054
4474
|
if (input === void 0 || typeof input.root !== "string" || typeof input.branch !== "string" || typeof input.head !== "string" || typeof input.fingerprint !== "string" || !Array.isArray(input.files) || typeof input.patch !== "string" || typeof input.truncated !== "boolean" || typeof input.hasStaged !== "boolean" || typeof input.hasUnstaged !== "boolean" || typeof input.hasUntracked !== "boolean" || input.upstream !== void 0 && typeof input.upstream !== "string" || !Array.isArray(input.unpushedCommits) || typeof input.unpushedTruncated !== "boolean") throw new Error("Invalid repository action preview.");
|
|
4055
4475
|
for (const file of input.files) {
|
|
4056
|
-
const item = record$
|
|
4476
|
+
const item = record$1(file);
|
|
4057
4477
|
if (item === void 0 || typeof item.path !== "string" || typeof item.staged !== "boolean" || typeof item.unstaged !== "boolean" || typeof item.untracked !== "boolean") throw new Error("Invalid repository action file.");
|
|
4058
4478
|
}
|
|
4059
4479
|
for (const commit of input.unpushedCommits) {
|
|
4060
|
-
const item = record$
|
|
4480
|
+
const item = record$1(commit);
|
|
4061
4481
|
if (item === void 0 || typeof item.hash !== "string" || typeof item.subject !== "string") throw new Error("Invalid repository action commit.");
|
|
4062
4482
|
}
|
|
4063
4483
|
return input;
|
|
4064
4484
|
}
|
|
4065
4485
|
function result(value) {
|
|
4066
|
-
const input = record$
|
|
4486
|
+
const input = record$1(value);
|
|
4067
4487
|
if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string") throw new Error("Invalid repository action result.");
|
|
4068
4488
|
return input;
|
|
4069
4489
|
}
|
|
@@ -4079,7 +4499,7 @@ window.__ModuleLoader__.load({
|
|
|
4079
4499
|
})));
|
|
4080
4500
|
}
|
|
4081
4501
|
async function generateCommitMessage(sessionId, fingerprint, signal) {
|
|
4082
|
-
const value = record$
|
|
4502
|
+
const value = record$1(await response$1(fetch(endpoint("/message", sessionId), {
|
|
4083
4503
|
method: "POST",
|
|
4084
4504
|
credentials: "same-origin",
|
|
4085
4505
|
headers: {
|
|
@@ -5019,16 +5439,16 @@ window.__ModuleLoader__.load({
|
|
|
5019
5439
|
"saving-worktree",
|
|
5020
5440
|
"switching-branch"
|
|
5021
5441
|
]);
|
|
5022
|
-
function record
|
|
5442
|
+
function record(value) {
|
|
5023
5443
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
5024
5444
|
}
|
|
5025
5445
|
function setupResult(value) {
|
|
5026
|
-
const item = record
|
|
5446
|
+
const item = record(value);
|
|
5027
5447
|
if (item === void 0 || item.mode !== "checkout" && item.mode !== "worktree" || typeof item.root !== "string" || typeof item.path !== "string" || typeof item.branch !== "string" || item.leaseId !== void 0 && typeof item.leaseId !== "string") return void 0;
|
|
5028
5448
|
return item;
|
|
5029
5449
|
}
|
|
5030
5450
|
function parseRepositorySetupEvent(line, onProgress) {
|
|
5031
|
-
const event = record
|
|
5451
|
+
const event = record(JSON.parse(line));
|
|
5032
5452
|
if (event?.type === "progress" && typeof event.stage === "string" && HOST_STAGES.has(event.stage)) {
|
|
5033
5453
|
onProgress(event.stage);
|
|
5034
5454
|
return;
|
|
@@ -5572,170 +5992,6 @@ window.__ModuleLoader__.load({
|
|
|
5572
5992
|
}), portal);
|
|
5573
5993
|
}
|
|
5574
5994
|
//#endregion
|
|
5575
|
-
//#region src/client/projection.ts
|
|
5576
|
-
const EMPTY_CLAUDE_PROJECTION = {
|
|
5577
|
-
schemaVersion: 1,
|
|
5578
|
-
revision: 0,
|
|
5579
|
-
owned: false,
|
|
5580
|
-
commands: [],
|
|
5581
|
-
activities: []
|
|
5582
|
-
};
|
|
5583
|
-
const POLL_INTERVAL_MS = 2e3;
|
|
5584
|
-
const MAX_ACTIVITIES = 1e4;
|
|
5585
|
-
const MAX_COMMANDS = 2e3;
|
|
5586
|
-
const MAX_REPOSITORY_TEXT_CHARS = 1024;
|
|
5587
|
-
const MAX_DIFF_CHARS = 262144;
|
|
5588
|
-
const MAX_REVIEW_COMMENTS = 50;
|
|
5589
|
-
const MAX_REVIEW_COMMENT_CHARS = 2e3;
|
|
5590
|
-
function record(value) {
|
|
5591
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
5592
|
-
}
|
|
5593
|
-
function nonNegativeInteger(value) {
|
|
5594
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
5595
|
-
}
|
|
5596
|
-
function optionalBoundedString(value) {
|
|
5597
|
-
return value === void 0 || typeof value === "string" && value.length <= MAX_REPOSITORY_TEXT_CHARS;
|
|
5598
|
-
}
|
|
5599
|
-
function validateRepository(value) {
|
|
5600
|
-
const repository = record(value);
|
|
5601
|
-
if (repository === void 0 || ![
|
|
5602
|
-
"ready",
|
|
5603
|
-
"not-repository",
|
|
5604
|
-
"unavailable"
|
|
5605
|
-
].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean" || repository.upstream !== void 0 && typeof repository.upstream !== "boolean" || repository.ahead !== void 0 && !nonNegativeInteger(repository.ahead) || repository.behind !== void 0 && !nonNegativeInteger(repository.behind)) return false;
|
|
5606
|
-
if (repository.diff !== void 0) {
|
|
5607
|
-
const diff = record(repository.diff);
|
|
5608
|
-
if (diff === void 0 || !nonNegativeInteger(diff.additions) || !nonNegativeInteger(diff.deletions) || !nonNegativeInteger(diff.files) || typeof diff.truncated !== "boolean" || diff.patch !== void 0 && (typeof diff.patch !== "string" || diff.patch.length > MAX_DIFF_CHARS)) return false;
|
|
5609
|
-
}
|
|
5610
|
-
if (repository.pullRequest === void 0) return true;
|
|
5611
|
-
const pullRequest = record(repository.pullRequest);
|
|
5612
|
-
if (pullRequest === void 0 || !Number.isSafeInteger(pullRequest.number) || Number(pullRequest.number) <= 0 || typeof pullRequest.title !== "string" || pullRequest.title.length > MAX_REPOSITORY_TEXT_CHARS || typeof pullRequest.url !== "string" || pullRequest.url.length > MAX_REPOSITORY_TEXT_CHARS || ![
|
|
5613
|
-
"open",
|
|
5614
|
-
"closed",
|
|
5615
|
-
"merged"
|
|
5616
|
-
].includes(String(pullRequest.state)) || typeof pullRequest.draft !== "boolean" || ![
|
|
5617
|
-
"approved",
|
|
5618
|
-
"changes-requested",
|
|
5619
|
-
"review-required",
|
|
5620
|
-
"none"
|
|
5621
|
-
].includes(String(pullRequest.review)) || ![
|
|
5622
|
-
"passing",
|
|
5623
|
-
"pending",
|
|
5624
|
-
"failing",
|
|
5625
|
-
"none"
|
|
5626
|
-
].includes(String(pullRequest.checks)) || !optionalBoundedString(pullRequest.mergeState) || !optionalBoundedString(pullRequest.author) || !optionalBoundedString(pullRequest.baseBranch) || pullRequest.createdAt !== void 0 && (typeof pullRequest.createdAt !== "string" || !Number.isFinite(Date.parse(pullRequest.createdAt))) || pullRequest.mergedAt !== void 0 && (typeof pullRequest.mergedAt !== "string" || !Number.isFinite(Date.parse(pullRequest.mergedAt)))) return false;
|
|
5627
|
-
try {
|
|
5628
|
-
const url = new URL(pullRequest.url);
|
|
5629
|
-
return url.protocol === "https:" && url.hostname === "github.com";
|
|
5630
|
-
} catch {
|
|
5631
|
-
return false;
|
|
5632
|
-
}
|
|
5633
|
-
}
|
|
5634
|
-
/** Validate the public route envelope before publishing it to UI components. */
|
|
5635
|
-
function parseClaudeClientProjection(value) {
|
|
5636
|
-
const input = record(value);
|
|
5637
|
-
if (input === void 0 || input.schemaVersion !== 1 || !nonNegativeInteger(input.revision) || typeof input.owned !== "boolean" || !Array.isArray(input.commands) || input.commands.length > MAX_COMMANDS || !Array.isArray(input.activities) || input.activities.length > MAX_ACTIVITIES) throw new Error("invalid Claude sidecar projection");
|
|
5638
|
-
for (const item of input.commands) {
|
|
5639
|
-
const command = record(item);
|
|
5640
|
-
if (command === void 0 || typeof command.publicName !== "string" || typeof command.claudeName !== "string" || typeof command.description !== "string" || command.hint !== void 0 && typeof command.hint !== "string" || typeof command.prefixed !== "boolean") throw new Error("invalid Claude command projection");
|
|
5641
|
-
}
|
|
5642
|
-
for (const item of input.activities) {
|
|
5643
|
-
const activity = record(item);
|
|
5644
|
-
if (activity === void 0 || !nonNegativeInteger(activity.turn) || !nonNegativeInteger(activity.step) || !nonNegativeInteger(activity.ordinal) || typeof activity.kind !== "string") throw new Error("invalid Claude sidecar activity");
|
|
5645
|
-
}
|
|
5646
|
-
if (input.contextUsage !== void 0 && record(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
|
|
5647
|
-
const tasks = input.tasks === void 0 ? void 0 : record(input.tasks);
|
|
5648
|
-
if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
|
|
5649
|
-
if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
|
|
5650
|
-
if (input.reviewComments !== void 0) {
|
|
5651
|
-
if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
|
|
5652
|
-
for (const item of input.reviewComments) {
|
|
5653
|
-
const comment = record(item);
|
|
5654
|
-
if (comment === void 0 || typeof comment.id !== "string" || comment.id.length === 0 || comment.id.length > 128 || typeof comment.path !== "string" || comment.path.length === 0 || comment.path.length > MAX_REPOSITORY_TEXT_CHARS || !nonNegativeInteger(comment.line) || comment.side !== "old" && comment.side !== "new" || typeof comment.text !== "string" || comment.text.length > MAX_REVIEW_COMMENT_CHARS) throw new Error("invalid Claude review comment projection");
|
|
5655
|
-
}
|
|
5656
|
-
}
|
|
5657
|
-
return input;
|
|
5658
|
-
}
|
|
5659
|
-
/** Create one lazy source: active subscribers trigger an immediate load and bounded polling. */
|
|
5660
|
-
function createClaudeProjectionSource(sessionId, fetchProjection = fetch, pollIntervalMs = POLL_INTERVAL_MS) {
|
|
5661
|
-
let snapshot = EMPTY_CLAUDE_PROJECTION;
|
|
5662
|
-
let timer;
|
|
5663
|
-
let controller;
|
|
5664
|
-
let disposed = false;
|
|
5665
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
5666
|
-
const schedule = () => {
|
|
5667
|
-
if (disposed || listeners.size === 0) return;
|
|
5668
|
-
timer = setTimeout(() => {
|
|
5669
|
-
refresh();
|
|
5670
|
-
}, pollIntervalMs);
|
|
5671
|
-
};
|
|
5672
|
-
const refresh = async () => {
|
|
5673
|
-
if (disposed || listeners.size === 0) return;
|
|
5674
|
-
controller?.abort();
|
|
5675
|
-
controller = new AbortController();
|
|
5676
|
-
try {
|
|
5677
|
-
const response = await fetchProjection(`${CLAUDE_PROJECTION_PATH}/${encodeURIComponent(sessionId)}`, {
|
|
5678
|
-
headers: { accept: "application/json" },
|
|
5679
|
-
signal: controller.signal
|
|
5680
|
-
});
|
|
5681
|
-
if (!response.ok) throw new Error(`Claude projection request failed (${response.status})`);
|
|
5682
|
-
const next = parseClaudeClientProjection(await response.json());
|
|
5683
|
-
const commandCatalogChanged = JSON.stringify(next.commands) !== JSON.stringify(snapshot.commands);
|
|
5684
|
-
const repositoryChanged = JSON.stringify(next.repository) !== JSON.stringify(snapshot.repository);
|
|
5685
|
-
const reviewCommentsChanged = JSON.stringify(next.reviewComments) !== JSON.stringify(snapshot.reviewComments);
|
|
5686
|
-
if (next.revision !== snapshot.revision || next.owned !== snapshot.owned || commandCatalogChanged || repositoryChanged || reviewCommentsChanged) {
|
|
5687
|
-
snapshot = next;
|
|
5688
|
-
for (const listener of [...listeners]) listener();
|
|
5689
|
-
}
|
|
5690
|
-
} catch (error) {
|
|
5691
|
-
if (error instanceof DOMException && error.name === "AbortError") return;
|
|
5692
|
-
} finally {
|
|
5693
|
-
controller = void 0;
|
|
5694
|
-
schedule();
|
|
5695
|
-
}
|
|
5696
|
-
};
|
|
5697
|
-
return {
|
|
5698
|
-
getSnapshot: () => snapshot,
|
|
5699
|
-
subscribe(listener) {
|
|
5700
|
-
if (disposed) return () => {};
|
|
5701
|
-
const wasIdle = listeners.size === 0;
|
|
5702
|
-
listeners.add(listener);
|
|
5703
|
-
if (wasIdle) refresh();
|
|
5704
|
-
return () => {
|
|
5705
|
-
listeners.delete(listener);
|
|
5706
|
-
if (listeners.size !== 0) return;
|
|
5707
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
5708
|
-
timer = void 0;
|
|
5709
|
-
controller?.abort();
|
|
5710
|
-
controller = void 0;
|
|
5711
|
-
};
|
|
5712
|
-
},
|
|
5713
|
-
dispose() {
|
|
5714
|
-
disposed = true;
|
|
5715
|
-
listeners.clear();
|
|
5716
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
5717
|
-
timer = void 0;
|
|
5718
|
-
controller?.abort();
|
|
5719
|
-
controller = void 0;
|
|
5720
|
-
}
|
|
5721
|
-
};
|
|
5722
|
-
}
|
|
5723
|
-
var ClaudeProjectionStore = class {
|
|
5724
|
-
#sources = /* @__PURE__ */ new Map();
|
|
5725
|
-
source(sessionId) {
|
|
5726
|
-
let source = this.#sources.get(sessionId);
|
|
5727
|
-
if (source === void 0) {
|
|
5728
|
-
source = createClaudeProjectionSource(sessionId);
|
|
5729
|
-
this.#sources.set(sessionId, source);
|
|
5730
|
-
}
|
|
5731
|
-
return source;
|
|
5732
|
-
}
|
|
5733
|
-
dispose() {
|
|
5734
|
-
for (const source of this.#sources.values()) source.dispose();
|
|
5735
|
-
this.#sources.clear();
|
|
5736
|
-
}
|
|
5737
|
-
};
|
|
5738
|
-
//#endregion
|
|
5739
5995
|
//#region src/client/claude-command-source.ts
|
|
5740
5996
|
const SOURCE_NAME = "Claude Code";
|
|
5741
5997
|
function commandsFor(store, session) {
|