glimmervoid 0.42.2 → 0.43.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.
Files changed (28) hide show
  1. package/dist/bin/glimmervoid.js +13 -13
  2. package/dist/chunks/{adapters-DeqV4wUv.js → adapters-EqOJN5vD.js} +1 -1
  3. package/dist/chunks/{adapters-Bga1N6Ie.js → adapters-jRUJYLhH.js} +5 -5
  4. package/dist/chunks/{agent-api-cli-YvQ8WxHA.js → agent-api-cli-B0fpc41n.js} +3 -3
  5. package/dist/chunks/{agent-api-cli-DWVeqlLu.js → agent-api-cli-DYwXyAmN.js} +1 -1
  6. package/dist/chunks/{agent-api-core-DFYLP1bF.js → agent-api-core-BeSecYrA.js} +3 -3
  7. package/dist/chunks/{agent-setup-cli-C9qDV2g5.js → agent-setup-cli-NfJQxNdp.js} +1 -1
  8. package/dist/chunks/{config-store-DOGtTJ1d.js → config-store-CBjnq-OI.js} +2 -2
  9. package/dist/chunks/config-store-DCrosJLg.js +1 -0
  10. package/dist/chunks/{contracts-Ds_eevZs.js → contracts-BJGgl8et.js} +2 -2
  11. package/dist/chunks/{control-messages-Dgap3JRR.js → control-messages-CD99vE0V.js} +9 -3
  12. package/dist/chunks/{git-version-DqagvnAZ.js → git-version-ByOV7a_h.js} +1 -1
  13. package/dist/chunks/{grok-DwrAcNHC.js → grok-DPmX1ozS.js} +1 -1
  14. package/dist/chunks/{main-Ywst1s6Z.js → main-_78bVmTr.js} +1917 -1428
  15. package/dist/chunks/{pair-cli-PCXITdEd.js → pair-cli-DAJNPgsi.js} +2 -2
  16. package/dist/chunks/{remote-config-DeWURqqr.js → remote-config-BdCTswa1.js} +1 -1
  17. package/dist/chunks/{session-3eSP3t1i.js → session-BUcx9uJa.js} +2 -0
  18. package/dist/chunks/{session-routes-B2oSzmQn.js → session-routes-DdeSkLqC.js} +1 -1
  19. package/dist/chunks/{settings-cli-xpR7vk9L.js → settings-cli-CMLEvC05.js} +5 -5
  20. package/dist/chunks/{settings-readout-core-C2mOk9Yz.js → settings-readout-core-CBqSjZiW.js} +2 -2
  21. package/dist/chunks/{ssh-sign-cli-rKiqiNem.js → ssh-sign-cli-CvqtQNQe.js} +6 -6
  22. package/dist/client/assets/{index-NhAGtpDY.css → index-CW2LelmE.css} +1 -1
  23. package/dist/client/assets/index-Cl0UmezJ.js +177 -0
  24. package/dist/client/index.html +2 -2
  25. package/dist/server/index.js +1 -1
  26. package/package.json +2 -2
  27. package/dist/chunks/config-store-CGrS8s6x.js +0 -1
  28. package/dist/client/assets/index-D9A5nTKg.js +0 -177
@@ -2,13 +2,13 @@ import { i as sanitizeOneLine, n as requireExecutableSpawnHelper, r as firstLine
2
2
  import { a as isMissingFileError, i as errorText$1, r as errorMessage, t as errorCode } from "./text-DoirglWV.js";
3
3
  import { a as sanitizeWorktreeName, i as safePathSegment, n as equalsIgnoringCaseOnWindows, r as isPathInside, t as caseFoldedPathKey } from "./paths-Bu4eH1Yd.js";
4
4
  import { a as packageRoot, n as cliPath, o as relayPath, r as clientDir, s as resolvePackageBin, t as bundled } from "./runtime-paths-BkeftE60.js";
5
- import { $t as STATES, A as SIGN_URL_ENV, At as TeamReviewStatus, B as LinkedPr, Bt as shortSha, Ct as ReviewThreadId, Dt as TeamReviewCompareFiles, E as SESSION_DOC_BODY_CAP_BYTES, Ft as decisionAsIfApprovalRequired, G as MyPrKeepMergeableRequest, H as MyPrAutoRebase, Ht as NODE_ID_RE, I as SshSignRequest, J as MyPrMergeMethod, L as TASK_TITLE_CONTROL_CHARACTERS, Lt as hasStandingViewerApproval, Mt as TeamReviewThreadResult, Nt as TeamReviewThreadsRepository, O as SESSION_NAME_PATTERN, Ot as TeamReviewResolveResponse, Pt as canApproveAfterComment, Q as MyPrMergeWhenReadyRequest, Qt as RESTARTABLE_STATES, R as TaskTitle, S as ConversationQuestion, St as ReviewResult, Tt as TeamReviewActionRequest, U as MyPrCheckContext, Ut as REPO_SLUG_RE, V as MyPr, Vt as GH_SEGMENT, W as MyPrCheckContextsResponse, Wt as repoParts, Xt as KILLABLE_STATES, Y as MyPrMergeRequest, Yt as BADGE_LABELS, Z as MyPrMergeStateResponse, Zt as MERGEABLE_LIVE_STATES, _ as CONVERSATION_TOOL_RESULT_HOOK_EVENT, _t as QueuedReview, bt as ReviewDraft, dt as EarlierReview, ft as FindingSeverity, g as CONVERSATION_PERMISSION_HOOK_EVENT, gt as PrDetail, h as CONVERSATION_APPROVAL_SUMMARY_MAX_CHARS, ht as PostingPlan, it as MyPrsState, j as SSH_SIGN_BODY_CAP_BYTES, jt as TeamReviewThreadCommentsResponse, k as SESSION_NAME_RULE_TEXT, kt as TeamReviewStateEntry, lt as CommitSha, m as COHERENCE_HOOKS_INACTIVE, mt as GithubReviewState, n as AGENT_URL_ENV, nt as MyPrThreadsResponse, q as MyPrLaneEntry, r as ASK_USER_QUESTION_TOOL_NAME, rt as MyPrsSnapshot, tt as MyPrThreadNode, ut as DECIDING_REVIEW_STATES, w as RefinedTaskTitle, wt as ReviewVerdict, xt as ReviewFinding, yt as ReviewComment, zt as HEX_SHA_RE } from "./session-3eSP3t1i.js";
5
+ import { $t as STATES, A as SIGN_URL_ENV, At as TeamReviewStatus, B as LinkedPr, Bt as shortSha, Ct as ReviewThreadId, Dt as TeamReviewCompareFiles, E as SESSION_DOC_BODY_CAP_BYTES, Ft as decisionAsIfApprovalRequired, G as MyPrKeepMergeableRequest, H as MyPrAutoRebase, Ht as NODE_ID_RE, I as SshSignRequest, J as MyPrMergeMethod, L as TASK_TITLE_CONTROL_CHARACTERS, Lt as hasStandingViewerApproval, Mt as TeamReviewThreadResult, Nt as TeamReviewThreadsRepository, O as SESSION_NAME_PATTERN, Ot as TeamReviewResolveResponse, Pt as canApproveAfterComment, Q as MyPrMergeWhenReadyRequest, Qt as RESTARTABLE_STATES, R as TaskTitle, S as ConversationQuestion, St as ReviewResult, Tt as TeamReviewActionRequest, U as MyPrCheckContext, Ut as REPO_SLUG_RE, V as MyPr, Vt as GH_SEGMENT, W as MyPrCheckContextsResponse, Wt as repoParts, Xt as KILLABLE_STATES, Y as MyPrMergeRequest, Yt as BADGE_LABELS, Z as MyPrMergeStateResponse, Zt as MERGEABLE_LIVE_STATES, _ as CONVERSATION_TOOL_RESULT_HOOK_EVENT, _t as QueuedReview, bt as ReviewDraft, dt as EarlierReview, ft as FindingSeverity, g as CONVERSATION_PERMISSION_HOOK_EVENT, gt as PrDetail, h as CONVERSATION_APPROVAL_SUMMARY_MAX_CHARS, ht as PostingPlan, it as MyPrsState, j as SSH_SIGN_BODY_CAP_BYTES, jt as TeamReviewThreadCommentsResponse, k as SESSION_NAME_RULE_TEXT, kt as TeamReviewStateEntry, lt as CommitSha, m as COHERENCE_HOOKS_INACTIVE, mt as GithubReviewState, n as AGENT_URL_ENV, nt as MyPrThreadsResponse, q as MyPrLaneEntry, r as ASK_USER_QUESTION_TOOL_NAME, rt as MyPrsSnapshot, tt as MyPrThreadNode, ut as DECIDING_REVIEW_STATES, w as RefinedTaskTitle, wt as ReviewVerdict, xt as ReviewFinding, yt as ReviewComment, zt as HEX_SHA_RE } from "./session-BUcx9uJa.js";
6
6
  import { n as execFileAsync, o as spawn, r as execFileSync, t as execFile } from "./child-process-safe-D4hyVIXj.js";
7
- import { At as GithubIssueResponse, C as comparablePrKey, Ct as PLAN_RESULT_HOOK_EVENT, Dt as parseExitPlanModeHookPayload, E as WorkflowsSettings, Et as PlanRevision, F as KEEP_MERGEABLE_TIMEOUT_MINUTES_RANGE, Ft as IssuesStatus, It as issuePullRequestStateFromGithub, Mt as IssueUpdate, Nt as IssuesSearchResponse, O as WorkflowsState, Ot as planTitle, Pt as IssuesState, S as GithubPrsFrame, St as PLAN_HOOK_OUTPUT_MAX_CHARS, T as WorkflowLabelName, Tt as PlanDecision, _ as MinedPrReviewData, _t as CoherenceJournalOutput, b as GithubPrKey, bt as PLAN_BODY_CAP_BYTES, c as BenchmarkActionRequest, d as BenchmarkJudgement, f as BenchmarkRun, ft as UpdateJournal, g as MergedPrListing, gt as TraceRecord, h as CommitComparison, ht as TraceCheckpoint, jt as IssueKey, kt as GithubIssuePullRequestsRepository, l as BenchmarkCase, m as BenchmarkSuite, mt as MAX_RAW_LINE_CHARS, n as ClientMessage, p as BenchmarkStatus, pt as SessionSetup, s as pullRequestKeyFromReference, t as CONTROL_FRAME_MAX_BYTES, tt as USAGE_INTEGER_RANGES, u as BenchmarkId, v as PrCheckoutCaseInput, vt as ChangeMap, w as WorkflowCommentBody, wt as PLAN_TOOL_NAME, x as GithubPrLightSearchNode, xt as PLAN_HOOK_EVENT, y as GithubPrDetailNode, yt as changeMapFactId } from "./control-messages-Dgap3JRR.js";
8
- import { a as permitsHelpCommand, r as describeSessionLimits } from "./session-routes-B2oSzmQn.js";
9
- import { a as decideSpawnAllowance, c as describeKeptChildAttention, d as describeUnpushedCloseRefusal, h as projectReviews, i as decideAgentRequest, l as describePushLanding, m as projectMyPrs, n as REFUSAL_REASON, o as deriveChildSessionName, p as parseAgentVerb, s as describeChildEndNote, u as describeRoleRefusal } from "./agent-api-core-DFYLP1bF.js";
7
+ import { At as GithubIssueResponse, C as comparablePrKey, Ct as PLAN_RESULT_HOOK_EVENT, Dt as parseExitPlanModeHookPayload, E as WorkflowsSettings, Et as PlanRevision, F as KEEP_MERGEABLE_TIMEOUT_MINUTES_RANGE, Ft as IssuesStatus, It as issuePullRequestStateFromGithub, Mt as IssueUpdate, Nt as IssuesSearchResponse, O as WorkflowsState, Ot as planTitle, Pt as IssuesState, S as GithubPrsFrame, St as PLAN_HOOK_OUTPUT_MAX_CHARS, T as WorkflowLabelName, Tt as PlanDecision, _ as MinedPrReviewData, _t as CoherenceJournalOutput, b as GithubPrKey, bt as PLAN_BODY_CAP_BYTES, c as BenchmarkActionRequest, d as BenchmarkJudgement, f as BenchmarkRun, ft as UpdateJournal, g as MergedPrListing, gt as TraceRecord, h as CommitComparison, ht as TraceCheckpoint, jt as IssueKey, kt as GithubIssuePullRequestsRepository, l as BenchmarkCase, m as BenchmarkSuite, mt as MAX_RAW_LINE_CHARS, n as ClientMessage, p as BenchmarkStatus, pt as SessionSetup, s as pullRequestKeyFromReference, t as CONTROL_FRAME_MAX_BYTES, tt as USAGE_INTEGER_RANGES, u as BenchmarkId, v as PrCheckoutCaseInput, vt as ChangeMap, w as WorkflowCommentBody, wt as PLAN_TOOL_NAME, x as GithubPrLightSearchNode, xt as PLAN_HOOK_EVENT, y as GithubPrDetailNode, yt as changeMapFactId } from "./control-messages-CD99vE0V.js";
8
+ import { a as permitsHelpCommand, r as describeSessionLimits } from "./session-routes-DdeSkLqC.js";
9
+ import { a as decideSpawnAllowance, c as describeKeptChildAttention, d as describeUnpushedCloseRefusal, h as projectReviews, i as decideAgentRequest, l as describePushLanding, m as projectMyPrs, n as REFUSAL_REASON, o as deriveChildSessionName, p as parseAgentVerb, s as describeChildEndNote, u as describeRoleRefusal } from "./agent-api-core-BeSecYrA.js";
10
10
  import { n as glimmervoidHomeDir, t as decideConfigPath } from "./config-path-core-DFt-TemS.js";
11
- import { i as parseCommandLine, n as warnWhenGitIsTooOld } from "./git-version-DqagvnAZ.js";
11
+ import { i as parseCommandLine, n as warnWhenGitIsTooOld } from "./git-version-ByOV7a_h.js";
12
12
  import { n as checkGuardrailsDependencies, t as allowGuardedSpawn } from "./guardrails-deps-BjPzk1rE.js";
13
13
  import { t as HOOK_URL_ENV } from "./hook-relay-core-DA_bz2KA.js";
14
14
  import { t as HOOK_VIA_GUARDRAILS_PROXY_ENV } from "./guardrails-proxy-core-BI3rdY-m.js";
@@ -21,13 +21,13 @@ import { n as DEFAULT_MAX_MS, r as nextBackoffMs, t as DEFAULT_BASE_MS } from ".
21
21
  import { n as unrefTimer, t as DEFAULT_TIMER_FNS } from "./timer-deps-u2DAQLok.js";
22
22
  import { n as shellQuote } from "./hook-command-core-qTNK-xMF.js";
23
23
  import { C as parseCgroupBytes, S as memoryReserveBytes, T as parseMemAvailableBytes, _ as createSpawnGate, a as jsonStateLoadError, b as cgroupLimitBytes, c as loadedJsonValue, d as writeJsonAtomicSync, f as writeTextAtomic, g as createSerialQueue, h as createMemoryAdmission, i as createJsonStateWriter, m as createKeyedSerialQueue, n as appendJsonLines, o as loadJsonStateFile, p as writeTextAtomicSync, r as createJsonStateStore, s as loadJsonStateFileSync, t as appendJsonLine, u as writeJsonAtomic, v as isQueueAdmissionTimeout, w as parseCgroupV2Path, x as headroomFromReadings, y as cgroupAncestorPaths } from "./json-file-DFCTvPjj.js";
24
- import { $ as DEFAULT_BRANCH_GC_PREFIXES, B as buildExceptionProperties, F as TELEMETRY_BATCH_URL, G as exceptionFingerprint, H as decideIsDevInstall, I as TELEMETRY_FLAGS_URL, J as resolveProjectToken, K as nodeMajorVersion, L as adapterBucket, P as FIRST_RUN_NOTICE, R as buildAiGenerationEvents, U as decideRemoteTelemetryState, V as classifySessionExit, W as decideTelemetryConsent, Z as stableConfigKey, a as generateProjectId, at as worktreeIntegrationTips, b as validateSettingsBlock, ct as isSameDirectoryPath, d as assetForPlatform, et as matchedPrefix, f as decideRtkInstall, g as verifyDigest, h as isRtkBinaryName, i as ensureProjectIds, it as usablePrefixes, m as installTargetPath, n as DEFAULT_CONFIG, nt as planWorktreeGc, o as glimmervoidHomeDir$1, ot as canonicalizePath, p as findEscapingArchiveMember, q as parsePosthogReleaseId, r as createConfigStore, rt as sessionIdFromBranch, st as comparableDirectoryPath, t as ABORT_CONFIG_SAVE, tt as planBranchGc, v as mergeSettingsBlock, y as settingsBlockSpecFor, z as buildBrowserExceptionProperties } from "./config-store-DOGtTJ1d.js";
25
- import { T as USAGE_VENDOR_KEYS, _ as PersistedTaskTitle, a as parseDataClientMessage, b as configIssueMessage, c as PendingCrashReport, d as TelemetryState, g as ConfigUpdate, i as parseDataAttachHistory, l as TELEMETRY_EVENT_SCHEMAS, m as BrowserConfig, n as HookEnvelope, o as DashboardTelemetryReport, r as DEEP_HISTORY_SCROLLBACK_LINES, t as HTTP_URL_RE, v as RUNTIME_CONFIG_SCALAR_KEYS, w as USAGE_COST_MODES, y as TASK_TITLE_SOURCE_PRIORITY } from "./contracts-Ds_eevZs.js";
26
- import { A as dedupeCodexFiles, B as shouldPersistWarehouse, C as shortSha$1, D as codexSessionIdFromPath, E as codexRootCandidates, F as passOutcome, H as claudeCode, I as projectDirCandidates, L as resolveProjectsDirs, M as grokHomes, N as grokRootCandidates, O as continuationDelayMs, P as isUsageFile, R as scopedClaudeRoots, S as parseResolvedSha, T as codexHomes, V as splitLines$1, _ as isCheckFresh, a as describeAgentResolvability, b as parseRegistryDeprecation, c as isKnownAgentId, d as resolveAdapter, f as setCustomAgents, g as decideUpdateStatus, h as decideInstallFlavor, i as customAgentFingerprint, j as expandTilde, k as decideFileRead, l as listAgentIds, m as readHostCodexVersion, n as cachedAgentResolvability, o as getAdapter, p as codex, r as commandFor, s as hookProfileOf, t as DEFAULT_AGENT_ID, u as resetCommandCache, v as normalizeSha, w as codexFallbackRoots, x as parseRegistryLatest, y as normalizeUpdateChannel, z as shouldEvaluateDespiteIoFailures } from "./adapters-Bga1N6Ie.js";
24
+ import { $ as DEFAULT_BRANCH_GC_PREFIXES, B as buildExceptionProperties, F as TELEMETRY_BATCH_URL, G as exceptionFingerprint, H as decideIsDevInstall, I as TELEMETRY_FLAGS_URL, J as resolveProjectToken, K as nodeMajorVersion, L as adapterBucket, P as FIRST_RUN_NOTICE, R as buildAiGenerationEvents, U as decideRemoteTelemetryState, V as classifySessionExit, W as decideTelemetryConsent, Z as stableConfigKey, a as generateProjectId, at as worktreeIntegrationTips, b as validateSettingsBlock, ct as isSameDirectoryPath, d as assetForPlatform, et as matchedPrefix, f as decideRtkInstall, g as verifyDigest, h as isRtkBinaryName, i as ensureProjectIds, it as usablePrefixes, m as installTargetPath, n as DEFAULT_CONFIG, nt as planWorktreeGc, o as glimmervoidHomeDir$1, ot as canonicalizePath, p as findEscapingArchiveMember, q as parsePosthogReleaseId, r as createConfigStore, rt as sessionIdFromBranch, st as comparableDirectoryPath, t as ABORT_CONFIG_SAVE, tt as planBranchGc, v as mergeSettingsBlock, y as settingsBlockSpecFor, z as buildBrowserExceptionProperties } from "./config-store-CBjnq-OI.js";
25
+ import { T as USAGE_VENDOR_KEYS, _ as PersistedTaskTitle, a as parseDataClientMessage, b as configIssueMessage, c as PendingCrashReport, d as TelemetryState, g as ConfigUpdate, i as parseDataAttachHistory, l as TELEMETRY_EVENT_SCHEMAS, m as BrowserConfig, n as HookEnvelope, o as DashboardTelemetryReport, r as DEEP_HISTORY_SCROLLBACK_LINES, t as HTTP_URL_RE, v as RUNTIME_CONFIG_SCALAR_KEYS, w as USAGE_COST_MODES, y as TASK_TITLE_SOURCE_PRIORITY } from "./contracts-BJGgl8et.js";
26
+ import { A as dedupeCodexFiles, B as shouldPersistWarehouse, C as shortSha$1, D as codexSessionIdFromPath, E as codexRootCandidates, F as passOutcome, H as claudeCode, I as projectDirCandidates, L as resolveProjectsDirs, M as grokHomes, N as grokRootCandidates, O as continuationDelayMs, P as isUsageFile, R as scopedClaudeRoots, S as parseResolvedSha, T as codexHomes, V as splitLines$1, _ as isCheckFresh, a as describeAgentResolvability, b as parseRegistryDeprecation, c as isKnownAgentId, d as resolveAdapter, f as setCustomAgents, g as decideUpdateStatus, h as decideInstallFlavor, i as customAgentFingerprint, j as expandTilde, k as decideFileRead, l as listAgentIds, m as readHostCodexVersion, n as cachedAgentResolvability, o as getAdapter, p as codex, r as commandFor, s as hookProfileOf, t as DEFAULT_AGENT_ID, u as resetCommandCache, v as normalizeSha, w as codexFallbackRoots, x as parseRegistryLatest, y as normalizeUpdateChannel, z as shouldEvaluateDespiteIoFailures } from "./adapters-jRUJYLhH.js";
27
27
  import { t as HOOK_TOOLS } from "./hook-tools-Dl7-r2Eb.js";
28
28
  import { a as formatSshPublicKey, c as orderAgentSockets, i as commitSigningShimText, l as parseSshPublicKey, n as NO_AGENT_HOLDS_KEY, o as isForwardedAgentDirName, r as agentListsKey, s as isSignableGitObject, t as COMMIT_SIGNING_SHIM_NAME } from "./ssh-signing-core-CRhVVWNW.js";
29
- import { a as configSiblingPath, c as defaultPairingsPath, d as decideDeviceAuth, f as deviceNameFromUserAgent, l as defaultSeenPath, n as normalizeRemoteConfig, o as createPairingsStore, p as hashSecret, r as validateRemoteConfig, s as createSeenStore, t as decideBindHost, u as DEFAULT_DEVICE_MAX_AGE_MS } from "./remote-config-DeWURqqr.js";
30
- import { n as configFileViewOf, u as readSettingsForAgent } from "./settings-readout-core-C2mOk9Yz.js";
29
+ import { a as configSiblingPath, c as defaultPairingsPath, d as decideDeviceAuth, f as deviceNameFromUserAgent, l as defaultSeenPath, n as normalizeRemoteConfig, o as createPairingsStore, p as hashSecret, r as validateRemoteConfig, s as createSeenStore, t as decideBindHost, u as DEFAULT_DEVICE_MAX_AGE_MS } from "./remote-config-BdCTswa1.js";
30
+ import { n as configFileViewOf, u as readSettingsForAgent } from "./settings-readout-core-CBqSjZiW.js";
31
31
  import { _ as escapeMarkup, g as createLaneLog, n as createVisionsSetup } from "./visions-setup-DB2P8JUL.js";
32
32
  import { t as getRtkPath } from "./rtk-resolver-BDHi6RMv.js";
33
33
  import { createRequire } from "node:module";
@@ -39,7 +39,7 @@ import crypto, { createHash, randomBytes, randomInt, randomUUID } from "node:cry
39
39
  import WebSocket$1, { WebSocket, WebSocketServer } from "ws";
40
40
  import http from "node:http";
41
41
  import net, { isIPv6 } from "node:net";
42
- import fsp, { access, chmod, copyFile, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
42
+ import fs$1, { access, chmod, copyFile, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
43
43
  import { pipeline } from "node:stream";
44
44
  import express from "express";
45
45
  import { EventEmitter } from "node:events";
@@ -49,6 +49,168 @@ import { AsyncLocalStorage } from "node:async_hooks";
49
49
  import https from "node:https";
50
50
  import { StringDecoder } from "node:string_decoder";
51
51
  import { monitorEventLoopDelay } from "node:perf_hooks";
52
+ //#region shared/contracts/owned-paths.ts
53
+ var OwnedPathOwner = z.string().regex(/^(session|lane):[A-Za-z0-9._:#-]+$/);
54
+ var OwnedPathEntry = z.object({
55
+ path: z.string().min(1),
56
+ owner: OwnedPathOwner,
57
+ kind: z.enum(["git-worktree", "folder"]),
58
+ projectPath: z.string().min(1).nullable(),
59
+ branch: z.string().min(1).nullable()
60
+ }).strict();
61
+ var OwnedPathsLedger = z.object({
62
+ version: z.literal(1),
63
+ entries: z.array(OwnedPathEntry)
64
+ }).strict();
65
+ //#endregion
66
+ //#region server/core/owned-paths-core.ts
67
+ var SESSION_OWNER_PREFIX = "session:";
68
+ var RESTART_SURVIVING_LANE_OWNERS = /* @__PURE__ */ new Set(["lane:update-apply", "lane:team-review"]);
69
+ function isOwnerGone(owner, configuredSessionIds) {
70
+ if (!owner.startsWith(SESSION_OWNER_PREFIX)) return !RESTART_SURVIVING_LANE_OWNERS.has(owner);
71
+ return !configuredSessionIds.has(owner.slice(8));
72
+ }
73
+ function orphanedOwnedPaths(entries, configuredSessionIds) {
74
+ const orphans = entries.filter((entry) => isOwnerGone(entry.owner, configuredSessionIds));
75
+ return [...orphans.filter((entry) => entry.kind === "git-worktree"), ...orphans.filter((entry) => entry.kind === "folder")];
76
+ }
77
+ function holdsKeptPath(folderPath, keptPaths) {
78
+ return keptPaths.some((keptPath) => {
79
+ const relativePath = path.relative(folderPath, keptPath);
80
+ return relativePath === "" || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
81
+ });
82
+ }
83
+ //#endregion
84
+ //#region server/owned-paths-ledger.ts
85
+ function ownedPathsLedgerPath(glimmervoidHome = glimmervoidHomeDir$1()) {
86
+ return path.join(glimmervoidHome, "owned-paths.json");
87
+ }
88
+ function ledgerKey(ownedPath) {
89
+ return caseFoldedPathKey(path.resolve(ownedPath));
90
+ }
91
+ async function canonicalOwnedPath(ownedPath) {
92
+ const resolvedPath = path.resolve(ownedPath);
93
+ const missingSegments = [];
94
+ let existingAncestor = resolvedPath;
95
+ while (true) {
96
+ const realAncestor = await fs$1.realpath(existingAncestor).catch(() => null);
97
+ if (realAncestor !== null) return path.join(realAncestor, ...missingSegments);
98
+ const parent = path.dirname(existingAncestor);
99
+ if (parent === existingAncestor) return resolvedPath;
100
+ missingSegments.unshift(path.basename(existingAncestor));
101
+ existingAncestor = parent;
102
+ }
103
+ }
104
+ function createOwnedPathsLedger({ filePath, log = console }) {
105
+ const entriesByPath = /* @__PURE__ */ new Map();
106
+ const keysRecordedThisRun = /* @__PURE__ */ new Set();
107
+ let isLoaded = false;
108
+ const store = createJsonStateStore({
109
+ name: "owned paths ledger",
110
+ filePath,
111
+ parse: (raw) => OwnedPathsLedger.safeParse(raw).data ?? null,
112
+ adopt: (ledger) => {
113
+ entriesByPath.clear();
114
+ for (const entry of ledger?.entries ?? []) entriesByPath.set(ledgerKey(entry.path), entry);
115
+ isLoaded = true;
116
+ },
117
+ warn: (message, fields) => log.warn(`[owned-paths] ${message} ${JSON.stringify(fields)}`)
118
+ });
119
+ async function persist() {
120
+ const ledger = {
121
+ version: 1,
122
+ entries: [...entriesByPath.values()]
123
+ };
124
+ await store.write(ledger, () => `${JSON.stringify(ledger, null, 2)}\n`);
125
+ }
126
+ async function record(entry) {
127
+ await store.load();
128
+ if (!isLoaded) return;
129
+ const canonicalEntry = {
130
+ ...entry,
131
+ path: await canonicalOwnedPath(entry.path)
132
+ };
133
+ const canonicalKey = ledgerKey(canonicalEntry.path);
134
+ keysRecordedThisRun.add(canonicalKey);
135
+ entriesByPath.set(canonicalKey, canonicalEntry);
136
+ await persist();
137
+ }
138
+ async function forget(ownedPath) {
139
+ await store.load();
140
+ if (!isLoaded || !entriesByPath.delete(ledgerKey(await canonicalOwnedPath(ownedPath)))) return;
141
+ await persist();
142
+ }
143
+ async function loadEarlierRunEntries() {
144
+ await store.load();
145
+ if (!isLoaded) return { ok: false };
146
+ return {
147
+ ok: true,
148
+ entries: [...entriesByPath.entries()].filter(([key]) => !keysRecordedThisRun.has(key)).map(([, entry]) => entry)
149
+ };
150
+ }
151
+ return {
152
+ loadEarlierRunEntries,
153
+ record,
154
+ forget,
155
+ idle: () => store.idle()
156
+ };
157
+ }
158
+ async function pathExists$1(ownedPath) {
159
+ return fs$1.lstat(ownedPath).then(() => true, () => false);
160
+ }
161
+ async function holdsCheckout(folderPath) {
162
+ const children = await fs$1.readdir(folderPath).catch(() => []);
163
+ return (await Promise.all(children.map((child) => pathExists$1(path.join(folderPath, child, ".git"))))).includes(true);
164
+ }
165
+ async function removeOrphanedWorktree(entry, git, shareList) {
166
+ if (!entry.projectPath || !entry.branch) return "it names no repository and branch to check its work against";
167
+ const work = await git.describeWorkspaceMemberWork({
168
+ projectPath: entry.projectPath,
169
+ cwd: entry.path,
170
+ branch: entry.branch
171
+ });
172
+ if (work) return work;
173
+ const removed = await git.removeWorkspaceMember({
174
+ projectPath: entry.projectPath,
175
+ cwd: entry.path,
176
+ shareList
177
+ });
178
+ if (!removed.ok || await pathExists$1(entry.path)) return `git could not remove it: ${removed.err || "the folder is still there"}`;
179
+ return null;
180
+ }
181
+ async function removeOrphanedFolder(entry, ledger, keptPaths) {
182
+ if (holdsKeptPath(entry.path, keptPaths)) return "it holds a checkout that was kept";
183
+ if (await holdsCheckout(entry.path)) return "it still holds a checkout";
184
+ const removal = await fs$1.rm(entry.path, {
185
+ recursive: true,
186
+ force: true
187
+ }).then(() => null, (error) => `it could not be deleted: ${errorMessage(error)}`);
188
+ if (removal) return removal;
189
+ await ledger.forget(entry.path);
190
+ return null;
191
+ }
192
+ async function reconcileOwnedPaths({ ledger, configuredSessionIds, git, shareList, log = console }) {
193
+ const loaded = await ledger.loadEarlierRunEntries();
194
+ if (!loaded.ok) {
195
+ log.warn("[owned-paths] deleted nothing at startup because the owned paths ledger could not be read");
196
+ return;
197
+ }
198
+ const keptPaths = [];
199
+ for (const entry of orphanedOwnedPaths(loaded.entries, configuredSessionIds)) {
200
+ if (!await pathExists$1(entry.path)) {
201
+ await ledger.forget(entry.path);
202
+ continue;
203
+ }
204
+ const keepReason = entry.kind === "folder" ? await removeOrphanedFolder(entry, ledger, keptPaths) : await removeOrphanedWorktree(entry, git, shareList);
205
+ if (!keepReason) {
206
+ log.log(`[owned-paths] deleted ${entry.path}, left by ${entry.owner}`);
207
+ continue;
208
+ }
209
+ keptPaths.push(entry.path);
210
+ log.warn(`[owned-paths] kept ${entry.path}, left by ${entry.owner}, because ${keepReason}`);
211
+ }
212
+ }
213
+ //#endregion
52
214
  //#region server/core/restart-strategy.ts
53
215
  function decideRestartStrategy(env) {
54
216
  const invocationId = env ? env.INVOCATION_ID : void 0;
@@ -1363,7 +1525,7 @@ function decideByteRange(rangeHeader, sizeBytes) {
1363
1525
  var CUSTOM_SOUNDS_ROUTE = "/custom-sounds";
1364
1526
  async function listCustomSounds(soundsDir) {
1365
1527
  try {
1366
- return selectCustomSoundNames((await fsp.readdir(soundsDir, { withFileTypes: true })).map((entry) => ({
1528
+ return selectCustomSoundNames((await fs$1.readdir(soundsDir, { withFileTypes: true })).map((entry) => ({
1367
1529
  name: entry.name,
1368
1530
  isFile: entry.isFile()
1369
1531
  })));
@@ -1373,10 +1535,10 @@ async function listCustomSounds(soundsDir) {
1373
1535
  }
1374
1536
  async function resolveServableSound(soundsDir, name) {
1375
1537
  try {
1376
- const realDirectory = await fsp.realpath(soundsDir);
1377
- const realFile = await fsp.realpath(path.join(soundsDir, name));
1538
+ const realDirectory = await fs$1.realpath(soundsDir);
1539
+ const realFile = await fs$1.realpath(path.join(soundsDir, name));
1378
1540
  if (!isDirectChildOf$1(realDirectory, realFile)) return null;
1379
- const linkStats = await fsp.lstat(path.join(soundsDir, name));
1541
+ const linkStats = await fs$1.lstat(path.join(soundsDir, name));
1380
1542
  if (!linkStats.isFile()) return null;
1381
1543
  return {
1382
1544
  realFile,
@@ -1584,12 +1746,12 @@ function isStatuslineEvent(event) {
1584
1746
  async function sweepSessionUploads(dir, justWritten) {
1585
1747
  let entries = null;
1586
1748
  try {
1587
- entries = await fsp.readdir(dir);
1749
+ entries = await fs$1.readdir(dir);
1588
1750
  } catch {
1589
1751
  return;
1590
1752
  }
1591
1753
  for (const name of planUploadRetention(entries, { justWritten })) try {
1592
- await fsp.unlink(path.join(dir, name));
1754
+ await fs$1.unlink(path.join(dir, name));
1593
1755
  } catch {}
1594
1756
  }
1595
1757
  function receiveUpload({ req, res, sess, dir, filename, savedPath }) {
@@ -1604,7 +1766,7 @@ function receiveUpload({ req, res, sess, dir, filename, savedPath }) {
1604
1766
  let discardWanted = false;
1605
1767
  let streamClosed = false;
1606
1768
  const unlinkPartial = () => {
1607
- fsp.unlink(savedPath).catch(() => {});
1769
+ fs$1.unlink(savedPath).catch(() => {});
1608
1770
  };
1609
1771
  const discardPartial = () => {
1610
1772
  discardWanted = true;
@@ -1929,7 +2091,7 @@ function createBackendHttpApp(dependencies) {
1929
2091
  abortedBeforeReceive = true;
1930
2092
  };
1931
2093
  req.on("error", markAbortedBeforeReceive);
1932
- fsp.mkdir(dir, {
2094
+ fs$1.mkdir(dir, {
1933
2095
  recursive: true,
1934
2096
  mode: 448
1935
2097
  }).then(() => {
@@ -1955,7 +2117,7 @@ function createBackendHttpApp(dependencies) {
1955
2117
  return;
1956
2118
  }
1957
2119
  const savedPath = path.join(uploadsRoot, sessionId, filename);
1958
- fsp.lstat(savedPath).then((savedStat) => {
2120
+ fs$1.lstat(savedPath).then((savedStat) => {
1959
2121
  if (!savedStat.isFile()) {
1960
2122
  res.status(404).end();
1961
2123
  return;
@@ -5819,6 +5981,1006 @@ function decideMarkerBase({ marker, fallbackBase, configuredIntegrationBranch, d
5819
5981
  };
5820
5982
  }
5821
5983
  //#endregion
5984
+ //#region shared/contracts/guardrails-launch.ts
5985
+ var GuardrailsLaunchLogin = z.object({
5986
+ linkPath: z.string().min(1),
5987
+ targetPath: z.string().min(1)
5988
+ }).strict();
5989
+ var GuardrailsLaunchOwner = z.object({
5990
+ ownerPid: z.number().int().positive(),
5991
+ ownerHost: z.string(),
5992
+ ownerPidNamespace: z.string().nullable(),
5993
+ ownsTempDir: z.boolean(),
5994
+ keptTempFolderName: z.string().min(1).optional(),
5995
+ logins: z.array(GuardrailsLaunchLogin),
5996
+ placeholderPaths: z.array(z.string().min(1))
5997
+ }).strict();
5998
+ //#endregion
5999
+ //#region server/core/claude-trust-core.ts
6000
+ var CLAUDE_GLOBAL_CONFIG_FILE_NAME = ".claude.json";
6001
+ var CLAUDE_LEGACY_CONFIG_FILE_NAME = ".config.json";
6002
+ var CLAUDE_CONFIG_LOCK_SUFFIX = ".lock";
6003
+ var CLAUDE_CONFIG_LOCK_STALE_MS = 1e4;
6004
+ var CLAUDE_CONFIG_LOCK_RETRY_DELAYS_MS = Object.freeze([
6005
+ 200,
6006
+ 400,
6007
+ 800,
6008
+ 1600
6009
+ ]);
6010
+ var GRANTED_KEYS = Object.freeze([
6011
+ "hasTrustDialogAccepted",
6012
+ "hasClaudeMdExternalIncludesApproved",
6013
+ "hasClaudeMdExternalIncludesWarningShown"
6014
+ ]);
6015
+ var TRUST_ONLY_KEYS = Object.freeze(["hasTrustDialogAccepted"]);
6016
+ function isPlainRecord(value) {
6017
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6018
+ }
6019
+ function newProjectEntry() {
6020
+ return {
6021
+ allowedTools: [],
6022
+ mcpContextUris: [],
6023
+ mcpServers: {},
6024
+ enabledMcpjsonServers: [],
6025
+ disabledMcpjsonServers: []
6026
+ };
6027
+ }
6028
+ function listClaudeGlobalConfigPathCandidates(env, homeDir) {
6029
+ const configuredDir = env.CLAUDE_CONFIG_DIR?.trim();
6030
+ const legacyConfigHome = (configuredDir || path.join(homeDir, ".claude")).normalize("NFC");
6031
+ return [path.join(legacyConfigHome, CLAUDE_LEGACY_CONFIG_FILE_NAME), path.join(configuredDir || homeDir, CLAUDE_GLOBAL_CONFIG_FILE_NAME)];
6032
+ }
6033
+ function claudeProjectKeyOf(folderPath, platform) {
6034
+ if (platform !== "win32") return path.posix.normalize(folderPath);
6035
+ return path.win32.normalize(folderPath).replaceAll("\\", "/");
6036
+ }
6037
+ function repositoryRootOfCommonGitDir(commonGitDir) {
6038
+ if (!path.isAbsolute(commonGitDir) || path.basename(commonGitDir) !== ".git") return null;
6039
+ return path.dirname(commonGitDir);
6040
+ }
6041
+ function isConfigLockStale(lockModifiedMs, nowMs) {
6042
+ return nowMs - lockModifiedMs > CLAUDE_CONFIG_LOCK_STALE_MS;
6043
+ }
6044
+ function hasRecordedExternalImportsDecline(existingEntry) {
6045
+ return existingEntry?.hasClaudeMdExternalIncludesWarningShown === true && existingEntry.hasClaudeMdExternalIncludesApproved !== true;
6046
+ }
6047
+ function decideFolderTrust(configText, repositoryRoot, platform) {
6048
+ const projectKey = claudeProjectKeyOf(repositoryRoot, platform);
6049
+ let config;
6050
+ try {
6051
+ config = JSON.parse(configText);
6052
+ } catch {
6053
+ return {
6054
+ kind: "unreadable",
6055
+ reason: "it is not valid JSON"
6056
+ };
6057
+ }
6058
+ if (!isPlainRecord(config)) return {
6059
+ kind: "unreadable",
6060
+ reason: "it is not a JSON object"
6061
+ };
6062
+ const projects = config.projects ?? {};
6063
+ if (!isPlainRecord(projects)) return {
6064
+ kind: "unreadable",
6065
+ reason: "its projects key is not an object"
6066
+ };
6067
+ const existingEntry = projects[projectKey];
6068
+ if (existingEntry !== void 0 && !isPlainRecord(existingEntry)) return {
6069
+ kind: "unreadable",
6070
+ reason: "its entry for this folder is not an object"
6071
+ };
6072
+ const keysToGrant = hasRecordedExternalImportsDecline(existingEntry) ? TRUST_ONLY_KEYS : GRANTED_KEYS;
6073
+ if (keysToGrant.every((key) => existingEntry?.[key] === true)) return { kind: "trusted" };
6074
+ const trustedEntry = {
6075
+ ...existingEntry ?? newProjectEntry(),
6076
+ ...Object.fromEntries(keysToGrant.map((key) => [key, true]))
6077
+ };
6078
+ const nextConfigText = JSON.stringify({
6079
+ ...config,
6080
+ projects: {
6081
+ ...projects,
6082
+ [projectKey]: trustedEntry
6083
+ }
6084
+ }, null, 2);
6085
+ return {
6086
+ kind: "grant",
6087
+ nextConfigText: configText.endsWith("\n") ? `${nextConfigText}\n` : nextConfigText
6088
+ };
6089
+ }
6090
+ //#endregion
6091
+ //#region server/guardrails/core/guardrails-bridge-socket-core.ts
6092
+ var LONGEST_BRIDGE_SOCKET_NAME = "claude-socks-0123456789abcdef.sock";
6093
+ var UNIX_SOCKET_PATH_BYTE_LIMIT = 107;
6094
+ var SHORT_BRIDGE_SOCKET_FOLDER = "/tmp";
6095
+ function bridgeSocketPathBytes(tempDirectory) {
6096
+ return Buffer.byteLength(path.join(tempDirectory, LONGEST_BRIDGE_SOCKET_NAME));
6097
+ }
6098
+ function hasRoomForBridgeSocket(tempDirectory, platform) {
6099
+ return platform !== "linux" || bridgeSocketPathBytes(tempDirectory) <= UNIX_SOCKET_PATH_BYTE_LIMIT;
6100
+ }
6101
+ function bridgeSocketLauncherEnv(inheritedTempDirectory, platform) {
6102
+ if (hasRoomForBridgeSocket(inheritedTempDirectory, platform)) return { TMPDIR: inheritedTempDirectory };
6103
+ return { TMPDIR: SHORT_BRIDGE_SOCKET_FOLDER };
6104
+ }
6105
+ //#endregion
6106
+ //#region server/guardrails/core/guardrails-policy-core.ts
6107
+ var VENDOR_PROFILES = Object.freeze({
6108
+ claude: {
6109
+ homeEntries: [".claude", ".claude.json"],
6110
+ launchWritableFolders: ({ cwd, agentSessionId }) => [path.join("projects", encodeProjectDir(cwd)), ...agentSessionId === null ? [] : [path.join("session-env", agentSessionId)]],
6111
+ launchPrivateFolders: ["shell-snapshots"],
6112
+ launchHomeEnvName: null,
6113
+ loginFiles: [".credentials.json"],
6114
+ configEntries: [
6115
+ "settings.json",
6116
+ "settings.local.json",
6117
+ "hooks",
6118
+ "skills",
6119
+ "plugins",
6120
+ "commands",
6121
+ "agents",
6122
+ "CLAUDE.md",
6123
+ "AGENTS.md"
6124
+ ],
6125
+ apiDomains: ["api.anthropic.com", "platform.claude.com"],
6126
+ launchEnv: { DISABLE_AUTOUPDATER: "1" }
6127
+ },
6128
+ codex: {
6129
+ homeEntries: [".codex"],
6130
+ launchWritableFolders: () => [],
6131
+ launchPrivateFolders: [],
6132
+ launchHomeEnvName: "CODEX_HOME",
6133
+ loginFiles: ["auth.json"],
6134
+ configEntries: [
6135
+ "config.toml",
6136
+ "AGENTS.md",
6137
+ "skills",
6138
+ "rules",
6139
+ "prompts",
6140
+ "hooks.json"
6141
+ ],
6142
+ apiDomains: [
6143
+ "chatgpt.com",
6144
+ "*.chatgpt.com",
6145
+ "auth.openai.com",
6146
+ "api.openai.com",
6147
+ "*.openai.com"
6148
+ ],
6149
+ launchEnv: {}
6150
+ }
6151
+ });
6152
+ var GUARDRAILS_VENDORS = Object.freeze(["claude", "codex"]);
6153
+ var UNWRAPPED_VENDOR_HOME_ENTRIES = Object.freeze([".grok"]);
6154
+ var CREDENTIAL_HOME_ENTRIES = Object.freeze([
6155
+ ".ssh",
6156
+ ".config/gh",
6157
+ ".config/coderv2",
6158
+ "Library/Application Support/coderv2",
6159
+ "Library/Keychains",
6160
+ ".git-credentials"
6161
+ ]);
6162
+ var CLOUD_CREDENTIAL_HOME_ENTRIES = Object.freeze([
6163
+ ".aws",
6164
+ ".azure",
6165
+ ".config/gcloud",
6166
+ ".kube",
6167
+ ".docker",
6168
+ ".gnupg",
6169
+ ".netrc",
6170
+ ".npmrc"
6171
+ ]);
6172
+ var STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES = Object.freeze(["Library/Keychains"]);
6173
+ var XDG_CONFIG_DEFAULT_HOME_PREFIX = ".config/";
6174
+ var SHARED_TEMP_DIRS = Object.freeze(["/tmp/claude", "/private/tmp/claude"]);
6175
+ var SHARED_HOME_WRITE_ENTRIES = Object.freeze([".npm/_logs"]);
6176
+ var GUARDRAILS_PLACEHOLDER_NAMES = Object.freeze([
6177
+ ".bash_profile",
6178
+ ".bashrc",
6179
+ ".claude",
6180
+ ".gitconfig",
6181
+ ".gitmodules",
6182
+ ".idea",
6183
+ ".mcp.json",
6184
+ ".profile",
6185
+ ".ripgreprc",
6186
+ ".vscode",
6187
+ ".zprofile",
6188
+ ".zshrc"
6189
+ ]);
6190
+ var WHOLE_FILESYSTEM = "/";
6191
+ var GUARDRAILS_TEMP_FOLDER = "guardrails-temp";
6192
+ var AGENT_LOGINS_SIBLING_ENTRY = "agent-logins";
6193
+ var GLIMMERVOID_CONFIG_SIBLING_ENTRIES = Object.freeze([
6194
+ AGENT_LOGINS_SIBLING_ENTRY,
6195
+ "bin",
6196
+ "pairings.json",
6197
+ "pairings-seen.json",
6198
+ "plans",
6199
+ "telegram-outbox.json",
6200
+ "traces",
6201
+ "uploads",
6202
+ "usage-budget-state.json",
6203
+ "usage-lanes.json",
6204
+ "usage-warehouse.json",
6205
+ "visions-intent.json"
6206
+ ]);
6207
+ var GLIMMERVOID_HOME_STATE_ENTRIES = Object.freeze([
6208
+ "benchmark-runs",
6209
+ "benchmarks",
6210
+ "config.json",
6211
+ "issues-cache.json",
6212
+ "litellm-pricing.json",
6213
+ "my-prs-state.json",
6214
+ "my-prs-work",
6215
+ "posthog-reports",
6216
+ "posthog-state.json",
6217
+ "posthog-work",
6218
+ "recordings",
6219
+ "guardrails-homes",
6220
+ "guardrails-policies",
6221
+ "sane-yolo",
6222
+ "scratch",
6223
+ "sounds",
6224
+ "team-review-repos",
6225
+ "team-review-state.json",
6226
+ "team-review-work",
6227
+ "team-review-worktrees",
6228
+ "telemetry-pending-crash.json",
6229
+ "telemetry.json",
6230
+ "tmp",
6231
+ "update-check.json",
6232
+ "update-journal.json",
6233
+ "workflows-state.json",
6234
+ "workflows-work"
6235
+ ]);
6236
+ var RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS = Object.freeze(["commands", "agents"]);
6237
+ var GUARDED_PROXY_BYPASS = "localhost,::1,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16";
6238
+ var HOOK_LOOPBACK_HOST = "127.0.0.1";
6239
+ var AGENT_SESSION_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
6240
+ var STANDARD_OPEN_NETWORK = Object.freeze({
6241
+ allowAllUnixSockets: true,
6242
+ allowMachLookup: ["*"]
6243
+ });
6244
+ var STRICT_OPEN_NETWORK = Object.freeze({ allowAllUnixSockets: false });
6245
+ function unique(entries) {
6246
+ return [...new Set(entries)];
6247
+ }
6248
+ function literalEntries(entryPaths) {
6249
+ return unique(entryPaths).map((entryPath) => ({
6250
+ path: entryPath,
6251
+ literal: true
6252
+ }));
6253
+ }
6254
+ function homePaths(host, homeEntries) {
6255
+ return homeEntries.map((entry) => path.join(host.homeDir, entry));
6256
+ }
6257
+ function isInsideAny(parents, child) {
6258
+ return parents.some((parent) => isPathInside(parent, child));
6259
+ }
6260
+ function vendorStatePaths(host, vendor, stateFolderEntries) {
6261
+ return stateFolderEntries.map((entry) => path.join(host.vendorLocations[vendor].stateFolder, entry));
6262
+ }
6263
+ function vendorHeldPaths(host, vendor) {
6264
+ const { stateFolder, configFiles, otherHomes } = host.vendorLocations[vendor];
6265
+ return [
6266
+ stateFolder,
6267
+ ...configFiles,
6268
+ ...otherHomes
6269
+ ];
6270
+ }
6271
+ function launchHomeOf(host, vendor) {
6272
+ return path.join(host.launchHomeDir, vendor);
6273
+ }
6274
+ function vendorsWithLaunchHome(role) {
6275
+ if (role.vendorHome.scope === "state") return [];
6276
+ return role.vendors.filter((vendor) => VENDOR_PROFILES[vendor].launchHomeEnvName !== null);
6277
+ }
6278
+ function vendorWritableFolders(role, host) {
6279
+ const { vendorHome } = role;
6280
+ if (vendorHome.scope === "state") return role.vendors.map((vendor) => host.vendorLocations[vendor].stateFolder);
6281
+ return role.vendors.flatMap((vendor) => {
6282
+ const profile = VENDOR_PROFILES[vendor];
6283
+ if (profile.launchHomeEnvName !== null) return [launchHomeOf(host, vendor)];
6284
+ return vendorStatePaths(host, vendor, profile.launchWritableFolders(vendorHome));
6285
+ });
6286
+ }
6287
+ function launchPrivateFolders(role, host) {
6288
+ if (role.vendorHome.scope === "state") return [];
6289
+ return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].launchPrivateFolders));
6290
+ }
6291
+ function launchHomeLinkCandidates(role, host) {
6292
+ return vendorsWithLaunchHome(role).flatMap((vendor) => {
6293
+ const { configEntries, loginFiles } = VENDOR_PROFILES[vendor];
6294
+ const linkFor = (entry, isLogin) => ({
6295
+ linkPath: path.join(launchHomeOf(host, vendor), entry),
6296
+ targetPath: path.join(host.vendorLocations[vendor].stateFolder, entry),
6297
+ isLogin
6298
+ });
6299
+ return [...configEntries.map((entry) => linkFor(entry, false)), ...loginFiles.map((entry) => linkFor(entry, true))];
6300
+ });
6301
+ }
6302
+ function launchHomeEnv(role, host) {
6303
+ return Object.fromEntries(vendorsWithLaunchHome(role).flatMap((vendor) => {
6304
+ const envName = VENDOR_PROFILES[vendor].launchHomeEnvName;
6305
+ return envName === null ? [] : [[envName, launchHomeOf(host, vendor)]];
6306
+ }));
6307
+ }
6308
+ function vendorLoginFiles(role, host) {
6309
+ return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].loginFiles));
6310
+ }
6311
+ function roleWritableRoots(role) {
6312
+ return [
6313
+ ...role.writableRoots,
6314
+ ...role.lockedCheckouts,
6315
+ ...role.commitCheckouts.flatMap(({ checkout, gitDir }) => [checkout, gitDir])
6316
+ ];
6317
+ }
6318
+ function alwaysWritablePaths(role, host) {
6319
+ return [
6320
+ host.tempDir,
6321
+ ...roleWritableRoots(role),
6322
+ ...vendorWritableFolders(role, host)
6323
+ ];
6324
+ }
6325
+ function commitCheckoutWriteDenies({ checkout, gitDir }) {
6326
+ const gitPointer = path.join(checkout, ".git");
6327
+ const gitDirDenies = [path.join(gitDir, "hooks"), path.join(gitDir, "config")];
6328
+ if (path.resolve(gitPointer) === path.resolve(gitDir)) return gitDirDenies;
6329
+ return [gitPointer, ...gitDirDenies];
6330
+ }
6331
+ function writeDeniesWhenPresent(role, host) {
6332
+ const writablePaths = alwaysWritablePaths(role, host);
6333
+ const sharedHomeWrites = homePaths(host, SHARED_HOME_WRITE_ENTRIES).filter((sharedPath) => !isInsideAny(roleWritableRoots(role), sharedPath));
6334
+ const vendorConfig = role.vendors.flatMap((vendor) => [...vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].configEntries), ...host.vendorLocations[vendor].configFiles]).filter((configPath) => isInsideAny(writablePaths, configPath));
6335
+ return [
6336
+ ...SHARED_TEMP_DIRS,
6337
+ ...sharedHomeWrites,
6338
+ ...vendorConfig,
6339
+ ...role.commitCheckouts.flatMap(commitCheckoutWriteDenies)
6340
+ ];
6341
+ }
6342
+ function lockedCheckoutWriteDenies(role) {
6343
+ return role.lockedCheckouts.flatMap((checkout) => [path.join(checkout, ".git"), path.join(checkout, ".claude")]);
6344
+ }
6345
+ function lockedClaudeMountPoints(role) {
6346
+ return role.lockedCheckouts.flatMap((checkout) => RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS.map((folder) => path.join(checkout, ".claude", folder)));
6347
+ }
6348
+ function guardrailsPlaceholderPaths(role) {
6349
+ return unique([...(role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : []).flatMap((workingFolder) => GUARDRAILS_PLACEHOLDER_NAMES.map((placeholderName) => path.join(workingFolder, placeholderName))), ...lockedCheckoutWriteDenies(role)]);
6350
+ }
6351
+ function homeEntriesNamedLike(host, homeEntries) {
6352
+ return host.homeEntryNames.filter((entryName) => homeEntries.some((homeEntry) => entryName.startsWith(homeEntry)));
6353
+ }
6354
+ function relocatedXdgConfigPaths(host, homeEntries) {
6355
+ const xdgConfigHome = host.relocatedXdgConfigHome;
6356
+ if (xdgConfigHome === null) return [];
6357
+ return homeEntries.filter((entry) => entry.startsWith(XDG_CONFIG_DEFAULT_HOME_PREFIX)).map((entry) => path.join(xdgConfigHome, entry.slice(8)));
6358
+ }
6359
+ function isStandardLevel(role) {
6360
+ return role.guardrailLevel === "standard";
6361
+ }
6362
+ function blockedCredentialHomeEntries(role) {
6363
+ const credentialHomeEntries = [...CREDENTIAL_HOME_ENTRIES, ...CLOUD_CREDENTIAL_HOME_ENTRIES];
6364
+ if (!isStandardLevel(role)) return credentialHomeEntries;
6365
+ return credentialHomeEntries.filter((entry) => !STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES.includes(entry));
6366
+ }
6367
+ function credentialWriteBlocks(role, host) {
6368
+ const credentialHomeEntries = blockedCredentialHomeEntries(role);
6369
+ return [...homePaths(host, credentialHomeEntries), ...relocatedXdgConfigPaths(host, credentialHomeEntries)];
6370
+ }
6371
+ function glimmervoidStateWriteBlocks(role, host) {
6372
+ const keptWritable = alwaysWritablePaths(role, host);
6373
+ const configFolder = path.dirname(host.glimmervoidConfigFile);
6374
+ const homeEntries = [
6375
+ ...GLIMMERVOID_HOME_STATE_ENTRIES,
6376
+ ...GLIMMERVOID_CONFIG_SIBLING_ENTRIES,
6377
+ ...host.glimmervoidHomeEntryNames
6378
+ ].map((entryName) => path.join(host.glimmervoidHome, entryName));
6379
+ const configSiblings = GLIMMERVOID_CONFIG_SIBLING_ENTRIES.map((entryName) => path.join(configFolder, entryName));
6380
+ return unique([
6381
+ host.glimmervoidConfigFile,
6382
+ ...homeEntries,
6383
+ ...configSiblings
6384
+ ]).filter((entryPath) => !keptWritable.some((writable) => isPathInside(entryPath, writable)));
6385
+ }
6386
+ function standardWriteBlockCandidates(role, host) {
6387
+ if (!isStandardLevel(role)) return [];
6388
+ return unique([
6389
+ ...credentialWriteBlocks(role, host),
6390
+ ...glimmervoidStateWriteBlocks(role, host),
6391
+ ...role.blockedPaths ?? []
6392
+ ]);
6393
+ }
6394
+ function readDeniedPaths(role, host) {
6395
+ const otherVendors = GUARDRAILS_VENDORS.filter((vendor) => !role.vendors.includes(vendor));
6396
+ const otherVendorHomeEntries = [...otherVendors.flatMap((vendor) => VENDOR_PROFILES[vendor].homeEntries), ...UNWRAPPED_VENDOR_HOME_ENTRIES];
6397
+ const credentialHomeEntries = blockedCredentialHomeEntries(role);
6398
+ return [
6399
+ ...homePaths(host, [
6400
+ ...credentialHomeEntries,
6401
+ ...otherVendorHomeEntries,
6402
+ ...homeEntriesNamedLike(host, otherVendorHomeEntries)
6403
+ ]),
6404
+ ...relocatedXdgConfigPaths(host, credentialHomeEntries),
6405
+ ...otherVendors.flatMap((vendor) => vendorHeldPaths(host, vendor)),
6406
+ ...host.unwrappedVendorHomes,
6407
+ host.glimmervoidHome,
6408
+ path.join(path.dirname(host.glimmervoidConfigFile), AGENT_LOGINS_SIBLING_ENTRY),
6409
+ ...launchPrivateFolders(role, host),
6410
+ ...role.readDenied
6411
+ ];
6412
+ }
6413
+ function guardrailsPolicyProbePaths(role, host) {
6414
+ return unique([
6415
+ ...writeDeniesWhenPresent(role, host),
6416
+ ...vendorLoginFiles(role, host),
6417
+ ...launchHomeLinkCandidates(role, host).map((link) => link.targetPath)
6418
+ ]);
6419
+ }
6420
+ function isValidPort(port) {
6421
+ return Number.isInteger(port) && port >= 1 && port <= 65535;
6422
+ }
6423
+ function hostNamedPaths(host) {
6424
+ const relocatedXdgConfigHomes = host.relocatedXdgConfigHome === null ? [] : [host.relocatedXdgConfigHome];
6425
+ return [
6426
+ host.homeDir,
6427
+ host.glimmervoidHome,
6428
+ host.glimmervoidConfigFile,
6429
+ host.tempDir,
6430
+ host.launchHomeDir,
6431
+ ...relocatedXdgConfigHomes,
6432
+ ...host.unwrappedVendorHomes,
6433
+ ...GUARDRAILS_VENDORS.flatMap((vendor) => vendorHeldPaths(host, vendor))
6434
+ ];
6435
+ }
6436
+ function guardrailsRoleRefusal(role, host) {
6437
+ const launchCwds = role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : [];
6438
+ const relativePath = [
6439
+ ...hostNamedPaths(host),
6440
+ ...roleWritableRoots(role),
6441
+ ...role.readDenied,
6442
+ ...role.readableWithinDenied,
6443
+ ...launchCwds
6444
+ ].find((namedPath) => !path.isAbsolute(namedPath));
6445
+ if (relativePath !== void 0) return `guardrails policy path is not absolute: ${relativePath}`;
6446
+ const rootOverProtectedHome = [...roleWritableRoots(role), ...vendorWritableFolders(role, host)].find((root) => isPathInside(root, host.homeDir) || isPathInside(root, host.glimmervoidHome));
6447
+ if (rootOverProtectedHome !== void 0) return `writable root ${rootOverProtectedHome} contains the home folder or the Glimmervoid home`;
6448
+ const writablePaths = alwaysWritablePaths(role, host);
6449
+ const reallowedAncestor = role.readableWithinDenied.find((readable) => writablePaths.some((writable) => isPathInside(readable, writable, { allowEqual: false })));
6450
+ if (reallowedAncestor !== void 0) return `readable path ${reallowedAncestor} is an ancestor of a writable root`;
6451
+ if (role.network.access === "allowlist" && role.network.hookPort !== null && !isValidPort(role.network.hookPort)) return "hook listener port is invalid";
6452
+ const agentSessionId = role.vendorHome.scope === "launch" ? role.vendorHome.agentSessionId : null;
6453
+ if (agentSessionId !== null && !AGENT_SESSION_ID_SHAPE.test(agentSessionId)) return "agent session id is invalid";
6454
+ return null;
6455
+ }
6456
+ function networkPolicy(role) {
6457
+ if (role.network.access === "open") return isStandardLevel(role) ? { ...STANDARD_OPEN_NETWORK } : { ...STRICT_OPEN_NETWORK };
6458
+ if (role.network.access === "none") return {
6459
+ allowedDomains: [],
6460
+ deniedDomains: [],
6461
+ allowLocalBinding: false,
6462
+ allowAllUnixSockets: false
6463
+ };
6464
+ const hookEndpoint = role.network.hookPort === null ? [] : [`${HOOK_LOOPBACK_HOST}:${role.network.hookPort}`];
6465
+ const vendorDomains = role.vendors.flatMap((vendor) => VENDOR_PROFILES[vendor].apiDomains);
6466
+ return {
6467
+ allowedDomains: unique([
6468
+ ...hookEndpoint,
6469
+ ...vendorDomains,
6470
+ ...role.network.domains
6471
+ ]),
6472
+ deniedDomains: [],
6473
+ strictAllowlist: true,
6474
+ allowLocalBinding: false,
6475
+ allowAllUnixSockets: false
6476
+ };
6477
+ }
6478
+ function guardedEnvFor(role, host) {
6479
+ if (role.network.access === "allowlist") return {
6480
+ NO_PROXY: GUARDED_PROXY_BYPASS,
6481
+ no_proxy: GUARDED_PROXY_BYPASS,
6482
+ [HOOK_VIA_GUARDRAILS_PROXY_ENV]: "1"
6483
+ };
6484
+ if (role.network.access === "open") return { TMPDIR: host.tempDir };
6485
+ return {};
6486
+ }
6487
+ function filesystemWrites(role, host, writablePaths) {
6488
+ if (isStandardLevel(role)) return {
6489
+ allowWrite: literalEntries([WHOLE_FILESYSTEM, ...writablePaths]),
6490
+ denyWrite: literalEntries(host.writeBlockedPaths)
6491
+ };
6492
+ const isPresent = (candidate) => host.existingPaths.has(candidate);
6493
+ return {
6494
+ allowWrite: literalEntries(writablePaths),
6495
+ denyWrite: literalEntries([...writeDeniesWhenPresent(role, host).filter(isPresent), ...lockedCheckoutWriteDenies(role)])
6496
+ };
6497
+ }
6498
+ function buildGuardrailsLaunchPlan(role, host) {
6499
+ const refusal = guardrailsRoleRefusal(role, host);
6500
+ if (refusal !== null) return {
6501
+ ok: false,
6502
+ reason: refusal
6503
+ };
6504
+ const isPresent = (candidate) => host.existingPaths.has(candidate);
6505
+ const writablePaths = [...alwaysWritablePaths(role, host), ...vendorLoginFiles(role, host).filter(isPresent)];
6506
+ const readDenied = readDeniedPaths(role, host);
6507
+ const writableWithinDenied = writablePaths.filter((writable) => isInsideAny(readDenied, writable));
6508
+ return {
6509
+ ok: true,
6510
+ plan: {
6511
+ launcher: role.network.access === "open" ? "open-network" : "runtime-cli",
6512
+ policy: {
6513
+ network: networkPolicy(role),
6514
+ filesystem: {
6515
+ denyRead: literalEntries(readDenied),
6516
+ allowRead: literalEntries([...writableWithinDenied, ...role.readableWithinDenied]),
6517
+ ...filesystemWrites(role, host, writablePaths)
6518
+ },
6519
+ terminalScope: isStandardLevel(role) ? "any" : "own",
6520
+ allowAppleEvents: isStandardLevel(role)
6521
+ },
6522
+ launchEnv: Object.assign({ CLAUDE_CODE_TMPDIR: host.tempDir }, ...role.vendors.map((vendor) => VENDOR_PROFILES[vendor].launchEnv), launchHomeEnv(role, host)),
6523
+ guardedEnv: guardedEnvFor(role, host),
6524
+ requiredDirectories: unique([
6525
+ host.tempDir,
6526
+ ...vendorWritableFolders(role, host),
6527
+ ...launchPrivateFolders(role, host)
6528
+ ]),
6529
+ launchHomeLinks: launchHomeLinkCandidates(role, host).filter((link) => isPresent(link.targetPath))
6530
+ }
6531
+ };
6532
+ }
6533
+ //#endregion
6534
+ //#region server/prune-files.ts
6535
+ var MS_PER_DAY = 864e5;
6536
+ function idForEntry(entry, suffixes) {
6537
+ for (const suffix of suffixes) {
6538
+ if (suffix.length === 0) return entry;
6539
+ if (entry.endsWith(suffix)) return entry.slice(0, -suffix.length);
6540
+ }
6541
+ return null;
6542
+ }
6543
+ async function pruneAgedFiles({ directory, suffixes, retainDays, now = Date.now(), isRetainedId = () => false, entryMode = "file", fsPromises = fs.promises }) {
6544
+ let entries;
6545
+ try {
6546
+ entries = await fsPromises.readdir(directory);
6547
+ } catch {
6548
+ return [];
6549
+ }
6550
+ const cutoff = now - retainDays * MS_PER_DAY;
6551
+ const removedIds = [];
6552
+ for (const entry of entries) {
6553
+ const id = idForEntry(entry, suffixes);
6554
+ if (!id || isRetainedId(id)) continue;
6555
+ const filePath = path.join(directory, entry);
6556
+ try {
6557
+ if ((await fsPromises.stat(filePath)).mtimeMs >= cutoff) continue;
6558
+ if (entryMode === "directory") await fsPromises.rm(filePath, {
6559
+ recursive: true,
6560
+ force: true
6561
+ });
6562
+ if (entryMode === "file") await fsPromises.unlink(filePath);
6563
+ removedIds.push(id);
6564
+ } catch {}
6565
+ }
6566
+ return removedIds;
6567
+ }
6568
+ //#endregion
6569
+ //#region server/guardrails/guardrails-launch.ts
6570
+ var LAUNCH_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
6571
+ var GUARDED_ENV_COMMAND = "/usr/bin/env";
6572
+ var POLICY_FOLDER = "guardrails-policies";
6573
+ var LAUNCH_HOME_FOLDER = "guardrails-homes";
6574
+ var START_FOLDER = "start";
6575
+ var OWNER_FILE_SUFFIX = ".owner.json";
6576
+ var ENTER_FOLDER_SCRIPT = "cd \"$1\" && shift && exec \"$@\"";
6577
+ var LOGIN_FILE_MODE = 384;
6578
+ var ABSENT_PATH_DENY_PLATFORM = "darwin";
6579
+ var OWN_PID_NAMESPACE_LINK = "/proc/self/ns/pid";
6580
+ var SESSION_TEMP_RETAIN_DAYS = 7;
6581
+ async function isPresent(candidate) {
6582
+ try {
6583
+ await access(candidate);
6584
+ return true;
6585
+ } catch (error) {
6586
+ if (!isMissingFileError(error)) throw error;
6587
+ return false;
6588
+ }
6589
+ }
6590
+ async function presentPaths$1(candidates) {
6591
+ const presence = await Promise.all(candidates.map(isPresent));
6592
+ return new Set(candidates.filter((_candidate, index) => presence[index]));
6593
+ }
6594
+ async function realPathWhenPresent(candidate) {
6595
+ if (!path.isAbsolute(candidate)) return candidate;
6596
+ try {
6597
+ return await realpath(candidate);
6598
+ } catch (error) {
6599
+ if (!isMissingFileError(error)) throw error;
6600
+ return candidate;
6601
+ }
6602
+ }
6603
+ function realPathsWhenPresent(candidates) {
6604
+ return Promise.all(candidates.map(realPathWhenPresent));
6605
+ }
6606
+ async function symlinkTargetsInside(folder) {
6607
+ const symlinkEntries = (await readdir(folder, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isSymbolicLink());
6608
+ return (await Promise.all(symlinkEntries.map((entry) => realpath(path.join(folder, entry.name)).catch(() => null)))).filter((target) => target !== null);
6609
+ }
6610
+ async function blockedPathsWithRealTargets(candidates, operatorBlockedPaths) {
6611
+ const resolved = await Promise.all(candidates.map(async (candidate) => {
6612
+ const isPresentEntry = await lstat(candidate).then(() => true, (error) => !isMissingFileError(error));
6613
+ const isKeptWhenAbsent = process.platform === ABSENT_PATH_DENY_PLATFORM || operatorBlockedPaths.includes(candidate);
6614
+ if (!isPresentEntry) return isKeptWhenAbsent ? [candidate] : [];
6615
+ const realCandidate = await realpath(candidate).catch(() => candidate);
6616
+ return [
6617
+ candidate,
6618
+ realCandidate,
6619
+ ...await symlinkTargetsInside(realCandidate)
6620
+ ];
6621
+ }));
6622
+ return [...new Set(resolved.flat())];
6623
+ }
6624
+ async function configuredConfigFile(glimmervoidHome) {
6625
+ const { envPath, homePath } = decideConfigPath({
6626
+ env: process.env,
6627
+ homeDir: glimmervoidHome
6628
+ }, () => false);
6629
+ const configFile = envPath ?? homePath;
6630
+ return path.join(await realPathWhenPresent(path.dirname(configFile)), path.basename(configFile));
6631
+ }
6632
+ function scannedClaudeHomes(env, homeDir) {
6633
+ return [env, {
6634
+ ...env,
6635
+ CLAUDE_CONFIG_DIR: void 0
6636
+ }].flatMap((scannedEnv) => projectDirCandidates(scannedEnv, [], homeDir)).map((projectsDir) => path.dirname(projectsDir));
6637
+ }
6638
+ async function resolveVendorLocations(env, homeDir) {
6639
+ const [legacyClaudeConfigPath, claudeConfigPath] = listClaudeGlobalConfigPathCandidates(env, homeDir);
6640
+ const [codexStateFolder, ...otherCodexHomes] = codexHomes(env, homeDir);
6641
+ if (codexStateFolder === void 0) return null;
6642
+ return {
6643
+ claude: {
6644
+ stateFolder: await realPathWhenPresent(path.dirname(legacyClaudeConfigPath)),
6645
+ configFiles: [await realPathWhenPresent(claudeConfigPath)],
6646
+ otherHomes: await realPathsWhenPresent(scannedClaudeHomes(env, homeDir))
6647
+ },
6648
+ codex: {
6649
+ stateFolder: await realPathWhenPresent(codexStateFolder),
6650
+ configFiles: [],
6651
+ otherHomes: await realPathsWhenPresent(otherCodexHomes)
6652
+ }
6653
+ };
6654
+ }
6655
+ async function withRealRoots(role) {
6656
+ const [writableRoots, lockedCheckouts, commitCheckouts] = await Promise.all([
6657
+ Promise.all(role.writableRoots.map((root) => realpath(root))),
6658
+ Promise.all(role.lockedCheckouts.map((checkout) => realpath(checkout))),
6659
+ Promise.all(role.commitCheckouts.map(async ({ checkout, gitDir }) => ({
6660
+ checkout: await realpath(checkout),
6661
+ gitDir: await realpath(gitDir)
6662
+ })))
6663
+ ]);
6664
+ const vendorHome = role.vendorHome.scope === "launch" ? {
6665
+ ...role.vendorHome,
6666
+ cwd: await realPathWhenPresent(role.vendorHome.cwd)
6667
+ } : role.vendorHome;
6668
+ return {
6669
+ ...role,
6670
+ vendorHome,
6671
+ writableRoots,
6672
+ lockedCheckouts,
6673
+ commitCheckouts,
6674
+ readableWithinDenied: await realPathsWhenPresent(role.readableWithinDenied)
6675
+ };
6676
+ }
6677
+ async function lstatWhenPresent(candidate) {
6678
+ try {
6679
+ return await lstat(candidate);
6680
+ } catch (error) {
6681
+ if (!isMissingFileError(error)) throw error;
6682
+ return null;
6683
+ }
6684
+ }
6685
+ async function isRegularFile(candidate) {
6686
+ return (await lstatWhenPresent(candidate))?.isFile() ?? false;
6687
+ }
6688
+ async function isRealDirectory$1(candidate) {
6689
+ return (await lstatWhenPresent(candidate))?.isDirectory() ?? false;
6690
+ }
6691
+ async function absentPaths(candidates) {
6692
+ const presentCandidates = await presentPaths$1(candidates);
6693
+ return candidates.filter((candidate) => !presentCandidates.has(candidate));
6694
+ }
6695
+ async function removeLeftoverPlaceholders(placeholderPaths) {
6696
+ for (const placeholderPath of placeholderPaths) {
6697
+ const placeholderStats = await lstat(placeholderPath).catch(() => null);
6698
+ if (placeholderStats?.isFile() && placeholderStats.size === 0) await rm(placeholderPath, { force: true });
6699
+ }
6700
+ }
6701
+ async function createMissingMountPoints(mountPoints) {
6702
+ for (const mountPoint of mountPoints) {
6703
+ if (!await isRealDirectory$1(path.dirname(mountPoint))) continue;
6704
+ await mkdir(mountPoint).catch((error) => {
6705
+ if (errorCode(error) !== "EEXIST") throw error;
6706
+ });
6707
+ }
6708
+ }
6709
+ async function isNewerThanTarget(linkPath, targetPath) {
6710
+ const targetStats = await stat(targetPath).catch(() => null);
6711
+ if (targetStats === null) return true;
6712
+ return (await lstat(linkPath)).mtimeMs > targetStats.mtimeMs;
6713
+ }
6714
+ async function keepRefreshedLogins(logins, launchId, { onlyWhenNewer }) {
6715
+ for (const { linkPath, targetPath } of logins) {
6716
+ if (!await isRegularFile(linkPath)) continue;
6717
+ if (onlyWhenNewer && !await isNewerThanTarget(linkPath, targetPath)) continue;
6718
+ const stagedPath = `${targetPath}.${launchId}`;
6719
+ await copyFile(linkPath, stagedPath);
6720
+ await chmod(stagedPath, LOGIN_FILE_MODE);
6721
+ await rename(stagedPath, targetPath);
6722
+ }
6723
+ }
6724
+ async function removeLaunch(folders, owner, launchId, { onlyNewerLogins }) {
6725
+ await rm(folders.policyPath, { force: true });
6726
+ await removeLeftoverPlaceholders(owner.placeholderPaths);
6727
+ await keepRefreshedLogins(owner.logins.filter((login) => isPathInside(folders.launchHomeDir, login.linkPath, { allowEqual: false })), launchId, { onlyWhenNewer: onlyNewerLogins });
6728
+ await rm(folders.launchHomeDir, {
6729
+ recursive: true,
6730
+ force: true
6731
+ });
6732
+ if (folders.ownedTempDir !== null) await rm(folders.ownedTempDir, {
6733
+ recursive: true,
6734
+ force: true
6735
+ });
6736
+ await rm(folders.ownerPath, { force: true });
6737
+ }
6738
+ function isProcessAlive$1(pid) {
6739
+ try {
6740
+ process.kill(pid, 0);
6741
+ return true;
6742
+ } catch (error) {
6743
+ return errorCode(error) === "EPERM";
6744
+ }
6745
+ }
6746
+ function readOwnPidNamespace() {
6747
+ return readlink(OWN_PID_NAMESPACE_LINK).catch(() => null);
6748
+ }
6749
+ async function readOwnerFile(ownerPath) {
6750
+ const outcome = await loadJsonStateFile({
6751
+ filePath: ownerPath,
6752
+ quarantine: false,
6753
+ parse: (raw) => GuardrailsLaunchOwner.safeParse(raw).data ?? null
6754
+ });
6755
+ return outcome.status === "loaded" ? outcome.value : null;
6756
+ }
6757
+ async function sweepOrphanedGuardrailsLaunches(log = console) {
6758
+ try {
6759
+ const policyDir = path.join(glimmervoidHomeDir$1(), POLICY_FOLDER);
6760
+ const entryNames = await readdir(policyDir).catch((error) => {
6761
+ if (isMissingFileError(error)) return [];
6762
+ throw error;
6763
+ });
6764
+ const glimmervoidHome = await realpath(glimmervoidHomeDir$1());
6765
+ const sweeperPidNamespace = await readOwnPidNamespace();
6766
+ let removedLaunchCount = 0;
6767
+ for (const entryName of entryNames) {
6768
+ if (!entryName.endsWith(OWNER_FILE_SUFFIX)) continue;
6769
+ const launchId = entryName.slice(0, -11);
6770
+ if (!LAUNCH_ID_SHAPE.test(launchId)) continue;
6771
+ const ownerPath = path.join(policyDir, entryName);
6772
+ const owner = await readOwnerFile(ownerPath);
6773
+ if (owner === null || owner.ownerHost !== os.hostname() || owner.ownerPidNamespace !== sweeperPidNamespace || isProcessAlive$1(owner.ownerPid)) continue;
6774
+ try {
6775
+ await removeLaunch({
6776
+ policyPath: path.join(policyDir, `${launchId}.json`),
6777
+ ownerPath,
6778
+ launchHomeDir: path.join(glimmervoidHome, LAUNCH_HOME_FOLDER, launchId),
6779
+ ownedTempDir: owner.ownsTempDir ? path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER, launchId) : null
6780
+ }, owner, launchId, { onlyNewerLogins: true });
6781
+ removedLaunchCount += 1;
6782
+ } catch (error) {
6783
+ log.warn(`[guardrails] could not remove the leftover launch ${launchId}: ${errorMessage(error)}`);
6784
+ }
6785
+ }
6786
+ if (removedLaunchCount > 0) log.log(`[guardrails] removed ${removedLaunchCount} launch folders left by sessions that ended without a clean shutdown`);
6787
+ } catch (error) {
6788
+ log.warn(`[guardrails] could not sweep leftover launch folders: ${errorMessage(error)}`);
6789
+ }
6790
+ }
6791
+ async function pruneLeftoverSessionTempFolders(glimmervoidHome, liveSessionIds, log = console) {
6792
+ const policyEntryNames = await readdir(path.join(glimmervoidHome, POLICY_FOLDER)).catch((error) => {
6793
+ if (isMissingFileError(error)) return [];
6794
+ log.warn(`[guardrails] kept every session temp folder because the launch list could not be read: ${errorMessage(error)}`);
6795
+ return null;
6796
+ });
6797
+ if (policyEntryNames === null) return;
6798
+ const ownerEntryNames = policyEntryNames.filter((entryName) => entryName.endsWith(OWNER_FILE_SUFFIX));
6799
+ const owners = await Promise.all(ownerEntryNames.map((entryName) => readOwnerFile(path.join(glimmervoidHome, POLICY_FOLDER, entryName))));
6800
+ const tempFolderNamesWithOwners = /* @__PURE__ */ new Set([...ownerEntryNames.map((entryName) => entryName.slice(0, -11)), ...owners.flatMap((owner) => owner?.keptTempFolderName === void 0 ? [] : [owner.keptTempFolderName])]);
6801
+ await pruneAgedFiles({
6802
+ directory: path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER),
6803
+ suffixes: [""],
6804
+ retainDays: SESSION_TEMP_RETAIN_DAYS,
6805
+ entryMode: "directory",
6806
+ isRetainedId: (id) => liveSessionIds.has(id) || tempFolderNamesWithOwners.has(id)
6807
+ });
6808
+ }
6809
+ function launcherCommand(plan, policyPath) {
6810
+ if (plan.launcher === "open-network") return {
6811
+ file: process.execPath,
6812
+ args: [relayPath("guardrails-open-launcher"), policyPath]
6813
+ };
6814
+ const runtimeCliPath = resolvePackageBin("@anthropic-ai/sandbox-runtime", "srt");
6815
+ if (!runtimeCliPath) return null;
6816
+ return {
6817
+ file: process.execPath,
6818
+ args: [
6819
+ runtimeCliPath,
6820
+ "--settings",
6821
+ policyPath,
6822
+ "--"
6823
+ ]
6824
+ };
6825
+ }
6826
+ function guardedEnvPrefix(plan) {
6827
+ const assignments = Object.entries(plan.guardedEnv).map(([name, value]) => `${name}=${value}`);
6828
+ return assignments.length === 0 ? [] : [GUARDED_ENV_COMMAND, ...assignments];
6829
+ }
6830
+ function enteringFolder(enterDir, file, args) {
6831
+ if (enterDir === void 0) return [file, ...args];
6832
+ return [
6833
+ "/bin/sh",
6834
+ "-c",
6835
+ ENTER_FOLDER_SCRIPT,
6836
+ "sh",
6837
+ enterDir,
6838
+ file,
6839
+ ...args
6840
+ ];
6841
+ }
6842
+ function sessionTempFolderFor(sessionId) {
6843
+ if (!LAUNCH_ID_SHAPE.test(sessionId)) return null;
6844
+ return path.join(glimmervoidHomeDir$1(), GUARDRAILS_TEMP_FOLDER, sessionId);
6845
+ }
6846
+ async function removeSessionTempFolder(sessionId, log = console) {
6847
+ const sessionTempFolder = sessionTempFolderFor(sessionId);
6848
+ if (!sessionTempFolder) return;
6849
+ await rm(sessionTempFolder, {
6850
+ recursive: true,
6851
+ force: true
6852
+ }).catch((error) => log.warn(`[guardrails] could not delete session temp folder ${sessionTempFolder}: ${errorMessage(error)}`));
6853
+ }
6854
+ function launchTempDirFor(glimmervoidHome, launchId, tempDir, keptTempFolderName) {
6855
+ if (tempDir !== void 0) return path.resolve(tempDir);
6856
+ return path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER, keptTempFolderName ?? launchId);
6857
+ }
6858
+ async function prepareGuardrailsLaunch({ role, launchId, tempDir, keptTempFolderName, enterDir }) {
6859
+ if (!LAUNCH_ID_SHAPE.test(launchId)) return {
6860
+ ok: false,
6861
+ reason: "guardrails launch id is invalid"
6862
+ };
6863
+ if (keptTempFolderName !== void 0 && !LAUNCH_ID_SHAPE.test(keptTempFolderName)) return {
6864
+ ok: false,
6865
+ reason: "guardrails temp folder name is invalid"
6866
+ };
6867
+ try {
6868
+ const policyDir = path.join(glimmervoidHomeDir$1(), POLICY_FOLDER);
6869
+ await mkdir(policyDir, {
6870
+ recursive: true,
6871
+ mode: 448
6872
+ });
6873
+ const [homeDir, glimmervoidHome, realRole, ownerPidNamespace] = await Promise.all([
6874
+ realpath(os.homedir()),
6875
+ realpath(glimmervoidHomeDir$1()),
6876
+ withRealRoots(role),
6877
+ readOwnPidNamespace()
6878
+ ]);
6879
+ const ownsTempDir = tempDir === void 0 && keptTempFolderName === void 0;
6880
+ const launchTempDir = launchTempDirFor(glimmervoidHome, launchId, tempDir, keptTempFolderName);
6881
+ const launchHomeDir = path.join(glimmervoidHome, LAUNCH_HOME_FOLDER, launchId);
6882
+ const vendorLocations = await resolveVendorLocations(process.env, homeDir);
6883
+ if (vendorLocations === null) return {
6884
+ ok: false,
6885
+ reason: "CODEX_HOME names no folder"
6886
+ };
6887
+ const xdgConfigHomeOverride = rawTextOr(process.env.XDG_CONFIG_HOME, null);
6888
+ const stableHostPaths = {
6889
+ homeDir,
6890
+ glimmervoidHome,
6891
+ glimmervoidConfigFile: await configuredConfigFile(glimmervoidHome),
6892
+ tempDir: launchTempDir,
6893
+ launchHomeDir,
6894
+ vendorLocations,
6895
+ unwrappedVendorHomes: await realPathsWhenPresent(grokHomes(process.env, homeDir)),
6896
+ relocatedXdgConfigHome: xdgConfigHomeOverride === null ? null : await realPathWhenPresent(xdgConfigHomeOverride)
6897
+ };
6898
+ const buildPlanFromCurrentDisk = async () => {
6899
+ const [homeEntryNames, glimmervoidHomeEntryNames] = await Promise.all([readdir(homeDir), readdir(glimmervoidHome)]);
6900
+ const hostPaths = {
6901
+ ...stableHostPaths,
6902
+ homeEntryNames,
6903
+ glimmervoidHomeEntryNames
6904
+ };
6905
+ const [existingPaths, writeBlockedPaths] = await Promise.all([presentPaths$1(guardrailsPolicyProbePaths(realRole, hostPaths)), blockedPathsWithRealTargets(standardWriteBlockCandidates(realRole, hostPaths), realRole.blockedPaths ?? [])]);
6906
+ return buildGuardrailsLaunchPlan(realRole, {
6907
+ ...hostPaths,
6908
+ existingPaths,
6909
+ writeBlockedPaths
6910
+ });
6911
+ };
6912
+ const built = await buildPlanFromCurrentDisk();
6913
+ if (!built.ok) return built;
6914
+ const { plan } = built;
6915
+ const policyPath = path.join(policyDir, `${launchId}.json`);
6916
+ const launcher = launcherCommand(plan, policyPath);
6917
+ if (!launcher) return {
6918
+ ok: false,
6919
+ reason: "the sandbox runtime CLI could not be resolved"
6920
+ };
6921
+ await Promise.all(plan.requiredDirectories.map((directory) => mkdir(directory, { recursive: true })));
6922
+ const startDir = enterDir === void 0 ? void 0 : path.join(launchTempDir, START_FOLDER);
6923
+ if (startDir !== void 0) await mkdir(startDir, { recursive: true });
6924
+ await Promise.all(plan.launchHomeLinks.map((link) => symlink(link.targetPath, link.linkPath)));
6925
+ await writeJsonAtomic(policyPath, plan.policy);
6926
+ const folders = {
6927
+ policyPath,
6928
+ ownerPath: path.join(policyDir, `${launchId}${OWNER_FILE_SUFFIX}`),
6929
+ launchHomeDir,
6930
+ ownedTempDir: ownsTempDir ? launchTempDir : null
6931
+ };
6932
+ const owner = {
6933
+ ownerPid: process.pid,
6934
+ ownerHost: os.hostname(),
6935
+ ownerPidNamespace,
6936
+ ownsTempDir,
6937
+ ...keptTempFolderName === void 0 ? {} : { keptTempFolderName },
6938
+ logins: plan.launchHomeLinks.filter((link) => link.isLogin).map(({ linkPath, targetPath }) => ({
6939
+ linkPath,
6940
+ targetPath
6941
+ })),
6942
+ placeholderPaths: []
6943
+ };
6944
+ await writeJsonAtomic(folders.ownerPath, owner);
6945
+ const envPrefix = guardedEnvPrefix(plan);
6946
+ return {
6947
+ ok: true,
6948
+ launch: {
6949
+ wrap: async (file, args, { hasTerminal }) => {
6950
+ const rebuilt = await buildPlanFromCurrentDisk();
6951
+ if (!rebuilt.ok) throw new Error(rebuilt.reason);
6952
+ await writeJsonAtomic(policyPath, {
6953
+ ...rebuilt.plan.policy,
6954
+ allowPty: hasTerminal && rebuilt.plan.launcher === "open-network"
6955
+ });
6956
+ owner.placeholderPaths = await absentPaths(guardrailsPlaceholderPaths(realRole));
6957
+ await writeJsonAtomic(folders.ownerPath, owner);
6958
+ await createMissingMountPoints(lockedClaudeMountPoints(realRole));
6959
+ return {
6960
+ file: launcher.file,
6961
+ args: [
6962
+ ...launcher.args,
6963
+ ...envPrefix,
6964
+ ...enteringFolder(enterDir, file, args)
6965
+ ]
6966
+ };
6967
+ },
6968
+ env: {
6969
+ ...plan.launchEnv,
6970
+ ...bridgeSocketLauncherEnv(os.tmpdir(), process.platform)
6971
+ },
6972
+ ...startDir === void 0 ? {} : { cwd: startDir },
6973
+ dispose: () => removeLaunch(folders, owner, launchId, { onlyNewerLogins: false })
6974
+ }
6975
+ };
6976
+ } catch (error) {
6977
+ return {
6978
+ ok: false,
6979
+ reason: errorMessage(error)
6980
+ };
6981
+ }
6982
+ }
6983
+ //#endregion
5822
6984
  //#region server/session/session-registry.ts
5823
6985
  function runAutoResume(sessions, config, spawnGate, logger = console) {
5824
6986
  const ids = pickAutoResume(config.projects, config, Date.now());
@@ -5968,7 +7130,7 @@ function createSessionRegistry(dependencies) {
5968
7130
  if (ingestLane) ingestLane.detachSessionTap(session);
5969
7131
  if (ingestLane) ingestLane.releaseSessionRoots(session);
5970
7132
  session.destroy();
5971
- Promise.resolve(session._killReap).catch(() => {}).then(() => session.discardWorktree?.()).catch(() => {});
7133
+ Promise.resolve(session._killReap).catch(() => {}).then(() => session.discardWorktree?.()).catch(() => {}).then(() => removeSessionTempFolder(id, dependencies.logger));
5972
7134
  sessions.delete(id);
5973
7135
  capturedAgentFingerprints.delete(id);
5974
7136
  dependencies.broadcastControl({
@@ -9233,8 +10395,10 @@ var QUICK_RETRY_DELAYS_MS = Object.freeze([
9233
10395
  3e4,
9234
10396
  9e4
9235
10397
  ]);
10398
+ var TRANSIENT_BACKOFF_MAX_MS = 3e5;
9236
10399
  function nextRetrySchedule({ failureStreak, quickRetryCount, quickRetries, retryAfterMs, baseMs, maxMs, random }) {
9237
- const quickRetryDelayMs = quickRetries && !(typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0) ? QUICK_RETRY_DELAYS_MS[quickRetryCount] : void 0;
10400
+ const hasRateLimitWait = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0;
10401
+ const quickRetryDelayMs = quickRetries && !hasRateLimitWait ? QUICK_RETRY_DELAYS_MS[quickRetryCount] : void 0;
9238
10402
  if (quickRetryDelayMs !== void 0) return {
9239
10403
  waitMs: quickRetryDelayMs,
9240
10404
  retry: {
@@ -9242,11 +10406,12 @@ function nextRetrySchedule({ failureStreak, quickRetryCount, quickRetries, retry
9242
10406
  limit: QUICK_RETRY_DELAYS_MS.length
9243
10407
  }
9244
10408
  };
10409
+ const backoffCeilingMs = quickRetries && !hasRateLimitWait ? Math.min(maxMs, TRANSIENT_BACKOFF_MAX_MS) : maxMs;
9245
10410
  return {
9246
10411
  waitMs: nextBackoffMs({
9247
10412
  attempt: Math.max(1, failureStreak - quickRetryCount),
9248
10413
  baseMs,
9249
- maxMs,
10414
+ maxMs: backoffCeilingMs,
9250
10415
  retryAfterMs,
9251
10416
  random
9252
10417
  }),
@@ -9302,434 +10467,6 @@ function buildLanePermissions({ denyTools = [], allowTools = [] } = {}) {
9302
10467
  };
9303
10468
  }
9304
10469
  //#endregion
9305
- //#region server/guardrails/core/guardrails-policy-core.ts
9306
- var VENDOR_PROFILES = Object.freeze({
9307
- claude: {
9308
- homeEntries: [".claude", ".claude.json"],
9309
- launchWritableFolders: ({ cwd, agentSessionId }) => [path.join("projects", encodeProjectDir(cwd)), ...agentSessionId === null ? [] : [path.join("session-env", agentSessionId)]],
9310
- launchPrivateFolders: ["shell-snapshots"],
9311
- launchHomeEnvName: null,
9312
- loginFiles: [".credentials.json"],
9313
- configEntries: [
9314
- "settings.json",
9315
- "settings.local.json",
9316
- "hooks",
9317
- "skills",
9318
- "plugins",
9319
- "commands",
9320
- "agents",
9321
- "CLAUDE.md",
9322
- "AGENTS.md"
9323
- ],
9324
- apiDomains: ["api.anthropic.com", "platform.claude.com"],
9325
- launchEnv: { DISABLE_AUTOUPDATER: "1" }
9326
- },
9327
- codex: {
9328
- homeEntries: [".codex"],
9329
- launchWritableFolders: () => [],
9330
- launchPrivateFolders: [],
9331
- launchHomeEnvName: "CODEX_HOME",
9332
- loginFiles: ["auth.json"],
9333
- configEntries: [
9334
- "config.toml",
9335
- "AGENTS.md",
9336
- "skills",
9337
- "rules",
9338
- "prompts",
9339
- "hooks.json"
9340
- ],
9341
- apiDomains: [
9342
- "chatgpt.com",
9343
- "*.chatgpt.com",
9344
- "auth.openai.com",
9345
- "api.openai.com",
9346
- "*.openai.com"
9347
- ],
9348
- launchEnv: {}
9349
- }
9350
- });
9351
- var GUARDRAILS_VENDORS = Object.freeze(["claude", "codex"]);
9352
- var UNWRAPPED_VENDOR_HOME_ENTRIES = Object.freeze([".grok"]);
9353
- var CREDENTIAL_HOME_ENTRIES = Object.freeze([
9354
- ".ssh",
9355
- ".config/gh",
9356
- ".config/coderv2",
9357
- "Library/Application Support/coderv2",
9358
- "Library/Keychains",
9359
- ".git-credentials"
9360
- ]);
9361
- var CLOUD_CREDENTIAL_HOME_ENTRIES = Object.freeze([
9362
- ".aws",
9363
- ".azure",
9364
- ".config/gcloud",
9365
- ".kube",
9366
- ".docker",
9367
- ".gnupg",
9368
- ".netrc",
9369
- ".npmrc"
9370
- ]);
9371
- var STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES = Object.freeze(["Library/Keychains"]);
9372
- var XDG_CONFIG_DEFAULT_HOME_PREFIX = ".config/";
9373
- var SHARED_TEMP_DIRS = Object.freeze(["/tmp/claude", "/private/tmp/claude"]);
9374
- var SHARED_HOME_WRITE_ENTRIES = Object.freeze([".npm/_logs"]);
9375
- var GUARDRAILS_PLACEHOLDER_NAMES = Object.freeze([
9376
- ".bash_profile",
9377
- ".bashrc",
9378
- ".claude",
9379
- ".gitconfig",
9380
- ".gitmodules",
9381
- ".idea",
9382
- ".mcp.json",
9383
- ".profile",
9384
- ".ripgreprc",
9385
- ".vscode",
9386
- ".zprofile",
9387
- ".zshrc"
9388
- ]);
9389
- var WHOLE_FILESYSTEM = "/";
9390
- var GUARDRAILS_TEMP_FOLDER = "guardrails-temp";
9391
- var AGENT_LOGINS_SIBLING_ENTRY = "agent-logins";
9392
- var GLIMMERVOID_CONFIG_SIBLING_ENTRIES = Object.freeze([
9393
- AGENT_LOGINS_SIBLING_ENTRY,
9394
- "bin",
9395
- "pairings.json",
9396
- "pairings-seen.json",
9397
- "plans",
9398
- "telegram-outbox.json",
9399
- "traces",
9400
- "uploads",
9401
- "usage-budget-state.json",
9402
- "usage-lanes.json",
9403
- "usage-warehouse.json",
9404
- "visions-intent.json"
9405
- ]);
9406
- var GLIMMERVOID_HOME_STATE_ENTRIES = Object.freeze([
9407
- "benchmark-runs",
9408
- "benchmarks",
9409
- "config.json",
9410
- "issues-cache.json",
9411
- "litellm-pricing.json",
9412
- "my-prs-state.json",
9413
- "my-prs-work",
9414
- "posthog-reports",
9415
- "posthog-state.json",
9416
- "posthog-work",
9417
- "recordings",
9418
- "guardrails-homes",
9419
- "guardrails-policies",
9420
- "sane-yolo",
9421
- "scratch",
9422
- "sounds",
9423
- "team-review-repos",
9424
- "team-review-state.json",
9425
- "team-review-work",
9426
- "team-review-worktrees",
9427
- "telemetry-pending-crash.json",
9428
- "telemetry.json",
9429
- "tmp",
9430
- "update-check.json",
9431
- "update-journal.json",
9432
- "workflows-state.json",
9433
- "workflows-work"
9434
- ]);
9435
- var RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS = Object.freeze(["commands", "agents"]);
9436
- var GUARDED_PROXY_BYPASS = "localhost,::1,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16";
9437
- var HOOK_LOOPBACK_HOST = "127.0.0.1";
9438
- var AGENT_SESSION_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
9439
- var STANDARD_OPEN_NETWORK = Object.freeze({
9440
- allowAllUnixSockets: true,
9441
- allowMachLookup: ["*"]
9442
- });
9443
- var STRICT_OPEN_NETWORK = Object.freeze({ allowAllUnixSockets: false });
9444
- function unique(entries) {
9445
- return [...new Set(entries)];
9446
- }
9447
- function literalEntries(entryPaths) {
9448
- return unique(entryPaths).map((entryPath) => ({
9449
- path: entryPath,
9450
- literal: true
9451
- }));
9452
- }
9453
- function homePaths(host, homeEntries) {
9454
- return homeEntries.map((entry) => path.join(host.homeDir, entry));
9455
- }
9456
- function isInsideAny(parents, child) {
9457
- return parents.some((parent) => isPathInside(parent, child));
9458
- }
9459
- function vendorStatePaths(host, vendor, stateFolderEntries) {
9460
- return stateFolderEntries.map((entry) => path.join(host.vendorLocations[vendor].stateFolder, entry));
9461
- }
9462
- function vendorHeldPaths(host, vendor) {
9463
- const { stateFolder, configFiles, otherHomes } = host.vendorLocations[vendor];
9464
- return [
9465
- stateFolder,
9466
- ...configFiles,
9467
- ...otherHomes
9468
- ];
9469
- }
9470
- function launchHomeOf(host, vendor) {
9471
- return path.join(host.launchHomeDir, vendor);
9472
- }
9473
- function vendorsWithLaunchHome(role) {
9474
- if (role.vendorHome.scope === "state") return [];
9475
- return role.vendors.filter((vendor) => VENDOR_PROFILES[vendor].launchHomeEnvName !== null);
9476
- }
9477
- function vendorWritableFolders(role, host) {
9478
- const { vendorHome } = role;
9479
- if (vendorHome.scope === "state") return role.vendors.map((vendor) => host.vendorLocations[vendor].stateFolder);
9480
- return role.vendors.flatMap((vendor) => {
9481
- const profile = VENDOR_PROFILES[vendor];
9482
- if (profile.launchHomeEnvName !== null) return [launchHomeOf(host, vendor)];
9483
- return vendorStatePaths(host, vendor, profile.launchWritableFolders(vendorHome));
9484
- });
9485
- }
9486
- function launchPrivateFolders(role, host) {
9487
- if (role.vendorHome.scope === "state") return [];
9488
- return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].launchPrivateFolders));
9489
- }
9490
- function launchHomeLinkCandidates(role, host) {
9491
- return vendorsWithLaunchHome(role).flatMap((vendor) => {
9492
- const { configEntries, loginFiles } = VENDOR_PROFILES[vendor];
9493
- const linkFor = (entry, isLogin) => ({
9494
- linkPath: path.join(launchHomeOf(host, vendor), entry),
9495
- targetPath: path.join(host.vendorLocations[vendor].stateFolder, entry),
9496
- isLogin
9497
- });
9498
- return [...configEntries.map((entry) => linkFor(entry, false)), ...loginFiles.map((entry) => linkFor(entry, true))];
9499
- });
9500
- }
9501
- function launchHomeEnv(role, host) {
9502
- return Object.fromEntries(vendorsWithLaunchHome(role).flatMap((vendor) => {
9503
- const envName = VENDOR_PROFILES[vendor].launchHomeEnvName;
9504
- return envName === null ? [] : [[envName, launchHomeOf(host, vendor)]];
9505
- }));
9506
- }
9507
- function vendorLoginFiles(role, host) {
9508
- return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].loginFiles));
9509
- }
9510
- function roleWritableRoots(role) {
9511
- return [
9512
- ...role.writableRoots,
9513
- ...role.lockedCheckouts,
9514
- ...role.commitCheckouts.flatMap(({ checkout, gitDir }) => [checkout, gitDir])
9515
- ];
9516
- }
9517
- function alwaysWritablePaths(role, host) {
9518
- return [
9519
- host.tempDir,
9520
- ...roleWritableRoots(role),
9521
- ...vendorWritableFolders(role, host)
9522
- ];
9523
- }
9524
- function commitCheckoutWriteDenies({ checkout, gitDir }) {
9525
- const gitPointer = path.join(checkout, ".git");
9526
- const gitDirDenies = [path.join(gitDir, "hooks"), path.join(gitDir, "config")];
9527
- if (path.resolve(gitPointer) === path.resolve(gitDir)) return gitDirDenies;
9528
- return [gitPointer, ...gitDirDenies];
9529
- }
9530
- function writeDeniesWhenPresent(role, host) {
9531
- const writablePaths = alwaysWritablePaths(role, host);
9532
- const sharedHomeWrites = homePaths(host, SHARED_HOME_WRITE_ENTRIES).filter((sharedPath) => !isInsideAny(roleWritableRoots(role), sharedPath));
9533
- const vendorConfig = role.vendors.flatMap((vendor) => [...vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].configEntries), ...host.vendorLocations[vendor].configFiles]).filter((configPath) => isInsideAny(writablePaths, configPath));
9534
- return [
9535
- ...SHARED_TEMP_DIRS,
9536
- ...sharedHomeWrites,
9537
- ...vendorConfig,
9538
- ...role.commitCheckouts.flatMap(commitCheckoutWriteDenies)
9539
- ];
9540
- }
9541
- function lockedCheckoutWriteDenies(role) {
9542
- return role.lockedCheckouts.flatMap((checkout) => [path.join(checkout, ".git"), path.join(checkout, ".claude")]);
9543
- }
9544
- function lockedClaudeMountPoints(role) {
9545
- return role.lockedCheckouts.flatMap((checkout) => RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS.map((folder) => path.join(checkout, ".claude", folder)));
9546
- }
9547
- function guardrailsPlaceholderPaths(role) {
9548
- return unique([...(role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : []).flatMap((workingFolder) => GUARDRAILS_PLACEHOLDER_NAMES.map((placeholderName) => path.join(workingFolder, placeholderName))), ...lockedCheckoutWriteDenies(role)]);
9549
- }
9550
- function homeEntriesNamedLike(host, homeEntries) {
9551
- return host.homeEntryNames.filter((entryName) => homeEntries.some((homeEntry) => entryName.startsWith(homeEntry)));
9552
- }
9553
- function relocatedXdgConfigPaths(host, homeEntries) {
9554
- const xdgConfigHome = host.relocatedXdgConfigHome;
9555
- if (xdgConfigHome === null) return [];
9556
- return homeEntries.filter((entry) => entry.startsWith(XDG_CONFIG_DEFAULT_HOME_PREFIX)).map((entry) => path.join(xdgConfigHome, entry.slice(8)));
9557
- }
9558
- function isStandardLevel(role) {
9559
- return role.guardrailLevel === "standard";
9560
- }
9561
- function blockedCredentialHomeEntries(role) {
9562
- const credentialHomeEntries = [...CREDENTIAL_HOME_ENTRIES, ...CLOUD_CREDENTIAL_HOME_ENTRIES];
9563
- if (!isStandardLevel(role)) return credentialHomeEntries;
9564
- return credentialHomeEntries.filter((entry) => !STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES.includes(entry));
9565
- }
9566
- function credentialWriteBlocks(role, host) {
9567
- const credentialHomeEntries = blockedCredentialHomeEntries(role);
9568
- return [...homePaths(host, credentialHomeEntries), ...relocatedXdgConfigPaths(host, credentialHomeEntries)];
9569
- }
9570
- function glimmervoidStateWriteBlocks(role, host) {
9571
- const keptWritable = alwaysWritablePaths(role, host);
9572
- const configFolder = path.dirname(host.glimmervoidConfigFile);
9573
- const homeEntries = [
9574
- ...GLIMMERVOID_HOME_STATE_ENTRIES,
9575
- ...GLIMMERVOID_CONFIG_SIBLING_ENTRIES,
9576
- ...host.glimmervoidHomeEntryNames
9577
- ].map((entryName) => path.join(host.glimmervoidHome, entryName));
9578
- const configSiblings = GLIMMERVOID_CONFIG_SIBLING_ENTRIES.map((entryName) => path.join(configFolder, entryName));
9579
- return unique([
9580
- host.glimmervoidConfigFile,
9581
- ...homeEntries,
9582
- ...configSiblings
9583
- ]).filter((entryPath) => !keptWritable.some((writable) => isPathInside(entryPath, writable)));
9584
- }
9585
- function standardWriteBlockCandidates(role, host) {
9586
- if (!isStandardLevel(role)) return [];
9587
- return unique([
9588
- ...credentialWriteBlocks(role, host),
9589
- ...glimmervoidStateWriteBlocks(role, host),
9590
- ...role.blockedPaths ?? []
9591
- ]);
9592
- }
9593
- function readDeniedPaths(role, host) {
9594
- const otherVendors = GUARDRAILS_VENDORS.filter((vendor) => !role.vendors.includes(vendor));
9595
- const otherVendorHomeEntries = [...otherVendors.flatMap((vendor) => VENDOR_PROFILES[vendor].homeEntries), ...UNWRAPPED_VENDOR_HOME_ENTRIES];
9596
- const credentialHomeEntries = blockedCredentialHomeEntries(role);
9597
- return [
9598
- ...homePaths(host, [
9599
- ...credentialHomeEntries,
9600
- ...otherVendorHomeEntries,
9601
- ...homeEntriesNamedLike(host, otherVendorHomeEntries)
9602
- ]),
9603
- ...relocatedXdgConfigPaths(host, credentialHomeEntries),
9604
- ...otherVendors.flatMap((vendor) => vendorHeldPaths(host, vendor)),
9605
- ...host.unwrappedVendorHomes,
9606
- host.glimmervoidHome,
9607
- path.join(path.dirname(host.glimmervoidConfigFile), AGENT_LOGINS_SIBLING_ENTRY),
9608
- ...launchPrivateFolders(role, host),
9609
- ...role.readDenied
9610
- ];
9611
- }
9612
- function guardrailsPolicyProbePaths(role, host) {
9613
- return unique([
9614
- ...writeDeniesWhenPresent(role, host),
9615
- ...vendorLoginFiles(role, host),
9616
- ...launchHomeLinkCandidates(role, host).map((link) => link.targetPath)
9617
- ]);
9618
- }
9619
- function isValidPort(port) {
9620
- return Number.isInteger(port) && port >= 1 && port <= 65535;
9621
- }
9622
- function hostNamedPaths(host) {
9623
- const relocatedXdgConfigHomes = host.relocatedXdgConfigHome === null ? [] : [host.relocatedXdgConfigHome];
9624
- return [
9625
- host.homeDir,
9626
- host.glimmervoidHome,
9627
- host.glimmervoidConfigFile,
9628
- host.tempDir,
9629
- host.launchHomeDir,
9630
- ...relocatedXdgConfigHomes,
9631
- ...host.unwrappedVendorHomes,
9632
- ...GUARDRAILS_VENDORS.flatMap((vendor) => vendorHeldPaths(host, vendor))
9633
- ];
9634
- }
9635
- function guardrailsRoleRefusal(role, host) {
9636
- const launchCwds = role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : [];
9637
- const relativePath = [
9638
- ...hostNamedPaths(host),
9639
- ...roleWritableRoots(role),
9640
- ...role.readDenied,
9641
- ...role.readableWithinDenied,
9642
- ...launchCwds
9643
- ].find((namedPath) => !path.isAbsolute(namedPath));
9644
- if (relativePath !== void 0) return `guardrails policy path is not absolute: ${relativePath}`;
9645
- const rootOverProtectedHome = [...roleWritableRoots(role), ...vendorWritableFolders(role, host)].find((root) => isPathInside(root, host.homeDir) || isPathInside(root, host.glimmervoidHome));
9646
- if (rootOverProtectedHome !== void 0) return `writable root ${rootOverProtectedHome} contains the home folder or the Glimmervoid home`;
9647
- const writablePaths = alwaysWritablePaths(role, host);
9648
- const reallowedAncestor = role.readableWithinDenied.find((readable) => writablePaths.some((writable) => isPathInside(readable, writable, { allowEqual: false })));
9649
- if (reallowedAncestor !== void 0) return `readable path ${reallowedAncestor} is an ancestor of a writable root`;
9650
- if (role.network.access === "allowlist" && role.network.hookPort !== null && !isValidPort(role.network.hookPort)) return "hook listener port is invalid";
9651
- const agentSessionId = role.vendorHome.scope === "launch" ? role.vendorHome.agentSessionId : null;
9652
- if (agentSessionId !== null && !AGENT_SESSION_ID_SHAPE.test(agentSessionId)) return "agent session id is invalid";
9653
- return null;
9654
- }
9655
- function networkPolicy(role) {
9656
- if (role.network.access === "open") return isStandardLevel(role) ? { ...STANDARD_OPEN_NETWORK } : { ...STRICT_OPEN_NETWORK };
9657
- if (role.network.access === "none") return {
9658
- allowedDomains: [],
9659
- deniedDomains: [],
9660
- allowLocalBinding: false,
9661
- allowAllUnixSockets: false
9662
- };
9663
- const hookEndpoint = role.network.hookPort === null ? [] : [`${HOOK_LOOPBACK_HOST}:${role.network.hookPort}`];
9664
- const vendorDomains = role.vendors.flatMap((vendor) => VENDOR_PROFILES[vendor].apiDomains);
9665
- return {
9666
- allowedDomains: unique([
9667
- ...hookEndpoint,
9668
- ...vendorDomains,
9669
- ...role.network.domains
9670
- ]),
9671
- deniedDomains: [],
9672
- strictAllowlist: true,
9673
- allowLocalBinding: false,
9674
- allowAllUnixSockets: false
9675
- };
9676
- }
9677
- function guardedEnvFor(role, host) {
9678
- if (role.network.access === "allowlist") return {
9679
- NO_PROXY: GUARDED_PROXY_BYPASS,
9680
- no_proxy: GUARDED_PROXY_BYPASS,
9681
- [HOOK_VIA_GUARDRAILS_PROXY_ENV]: "1"
9682
- };
9683
- if (role.network.access === "open") return { TMPDIR: host.tempDir };
9684
- return {};
9685
- }
9686
- function filesystemWrites(role, host, writablePaths) {
9687
- if (isStandardLevel(role)) return {
9688
- allowWrite: literalEntries([WHOLE_FILESYSTEM, ...writablePaths]),
9689
- denyWrite: literalEntries(host.writeBlockedPaths)
9690
- };
9691
- const isPresent = (candidate) => host.existingPaths.has(candidate);
9692
- return {
9693
- allowWrite: literalEntries(writablePaths),
9694
- denyWrite: literalEntries([...writeDeniesWhenPresent(role, host).filter(isPresent), ...lockedCheckoutWriteDenies(role)])
9695
- };
9696
- }
9697
- function buildGuardrailsLaunchPlan(role, host) {
9698
- const refusal = guardrailsRoleRefusal(role, host);
9699
- if (refusal !== null) return {
9700
- ok: false,
9701
- reason: refusal
9702
- };
9703
- const isPresent = (candidate) => host.existingPaths.has(candidate);
9704
- const writablePaths = [...alwaysWritablePaths(role, host), ...vendorLoginFiles(role, host).filter(isPresent)];
9705
- const readDenied = readDeniedPaths(role, host);
9706
- const writableWithinDenied = writablePaths.filter((writable) => isInsideAny(readDenied, writable));
9707
- return {
9708
- ok: true,
9709
- plan: {
9710
- launcher: role.network.access === "open" ? "open-network" : "runtime-cli",
9711
- policy: {
9712
- network: networkPolicy(role),
9713
- filesystem: {
9714
- denyRead: literalEntries(readDenied),
9715
- allowRead: literalEntries([...writableWithinDenied, ...role.readableWithinDenied]),
9716
- ...filesystemWrites(role, host, writablePaths)
9717
- },
9718
- terminalScope: isStandardLevel(role) ? "any" : "own",
9719
- allowAppleEvents: isStandardLevel(role)
9720
- },
9721
- launchEnv: Object.assign({ CLAUDE_CODE_TMPDIR: host.tempDir }, ...role.vendors.map((vendor) => VENDOR_PROFILES[vendor].launchEnv), launchHomeEnv(role, host)),
9722
- guardedEnv: guardedEnvFor(role, host),
9723
- requiredDirectories: unique([
9724
- host.tempDir,
9725
- ...vendorWritableFolders(role, host),
9726
- ...launchPrivateFolders(role, host)
9727
- ]),
9728
- launchHomeLinks: launchHomeLinkCandidates(role, host).filter((link) => isPresent(link.targetPath))
9729
- }
9730
- };
9731
- }
9732
- //#endregion
9733
10470
  //#region shared/my-pr-merge.ts
9734
10471
  var FAILING_CHECK_STATES$1 = /* @__PURE__ */ new Set(["FAILURE", "ERROR"]);
9735
10472
  function myPrMergeBlocker(pr) {
@@ -10500,6 +11237,7 @@ function createGithubStorePoller({ github, now, isDashboardConnected, exclusive,
10500
11237
  let backoffUntil = 0;
10501
11238
  let rateLimitedUntil = 0;
10502
11239
  let failureStreak = 0;
11240
+ let quickRetryCount = 0;
10503
11241
  const unavailableKeys = /* @__PURE__ */ new Set();
10504
11242
  function getSnapshot() {
10505
11243
  const watchSnapshots = Object.fromEntries([...watches].map(([name, watch]) => [name, {
@@ -10568,19 +11306,21 @@ function createGithubStorePoller({ github, now, isDashboardConnected, exclusive,
10568
11306
  const retryAfterMs = secondaryRateLimitWaitMs(pollingError) ?? void 0;
10569
11307
  const schedule = nextRetrySchedule({
10570
11308
  failureStreak,
10571
- quickRetryCount: 0,
10572
- quickRetries: false,
11309
+ quickRetryCount,
11310
+ quickRetries: true,
10573
11311
  retryAfterMs,
10574
11312
  baseMs: 6e4,
10575
11313
  maxMs: GITHUB_RATE_LIMIT_WINDOW_MS,
10576
11314
  random: () => 1
10577
11315
  });
11316
+ if (schedule.retry) quickRetryCount += 1;
10578
11317
  backoffUntil = now() + schedule.waitMs;
10579
11318
  rateLimitedUntil = retryAfterMs === void 0 ? 0 : backoffUntil;
10580
11319
  log.warn(`[github-store] ${pollingError}`);
10581
11320
  return {
10582
11321
  failed: true,
10583
- retryAfterMs: schedule.waitMs
11322
+ retryAfterMs: schedule.waitMs,
11323
+ error: pollingError
10584
11324
  };
10585
11325
  }
10586
11326
  function recordReadFailure(error) {
@@ -10589,6 +11329,7 @@ function createGithubStorePoller({ github, now, isDashboardConnected, exclusive,
10589
11329
  function recordSuccess() {
10590
11330
  pollingError = null;
10591
11331
  failureStreak = 0;
11332
+ quickRetryCount = 0;
10592
11333
  backoffUntil = 0;
10593
11334
  rateLimitedUntil = 0;
10594
11335
  }
@@ -10787,11 +11528,15 @@ function createGithubStorePoller({ github, now, isDashboardConnected, exclusive,
10787
11528
  function tick(watchNames) {
10788
11529
  return exclusive(async () => {
10789
11530
  const tickStartedAt = now();
10790
- if (shouldSkipTick({
11531
+ if (watchNames !== void 0 && rateLimitedUntil > tickStartedAt) return {
11532
+ failed: true,
11533
+ retryAfterMs: rateLimitedUntil - tickStartedAt
11534
+ };
11535
+ if (watchNames === void 0 && shouldSkipTick({
10791
11536
  now: tickStartedAt,
10792
11537
  backoffUntil
10793
11538
  })) return {
10794
- failed: watchNames !== void 0,
11539
+ failed: false,
10795
11540
  retryAfterMs: backoffUntil - tickStartedAt
10796
11541
  };
10797
11542
  const previousError = pollingError;
@@ -10825,7 +11570,7 @@ function createGithubStorePoller({ github, now, isDashboardConnected, exclusive,
10825
11570
  } finally {
10826
11571
  publishChanges([...details, ...behindChangedPrs], removedKeys, previousError, hasWatchChanges);
10827
11572
  }
10828
- });
11573
+ }, { isPriority: watchNames !== void 0 });
10829
11574
  }
10830
11575
  async function refreshWatches(names) {
10831
11576
  if ((await tick(names)).failed) return {
@@ -11054,7 +11799,8 @@ function createGithubStorePoller({ github, now, isDashboardConnected, exclusive,
11054
11799
  function storeReadingLaneClock(clock) {
11055
11800
  return clock ? {
11056
11801
  schedule: clock.schedule,
11057
- exclusive: async (work) => work()
11802
+ exclusive: async (work) => work(),
11803
+ githubStatus: clock.githubStatus
11058
11804
  } : void 0;
11059
11805
  }
11060
11806
  function createGithubStoreWiring({ github, clock, now = Date.now, isDashboardConnected, broadcast, log }) {
@@ -11137,6 +11883,8 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11137
11883
  let rateLimitedUntil = 0;
11138
11884
  let isRefreshing = false;
11139
11885
  let refreshNotice = null;
11886
+ let lastRefreshedAt = null;
11887
+ let hasTransientFailure = false;
11140
11888
  const running = /* @__PURE__ */ new Set();
11141
11889
  function persist() {
11142
11890
  return persistQueue.run(() => writeState()).catch((e) => {
@@ -11165,14 +11913,17 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11165
11913
  retryTimer.unref?.();
11166
11914
  }
11167
11915
  function scheduleStatus() {
11916
+ const incident = hasTransientFailure ? clock?.githubStatus?.incident() ?? null : null;
11168
11917
  return {
11169
11918
  nextAttemptAt,
11170
11919
  retry,
11171
11920
  isRefreshing,
11172
- refreshNotice
11921
+ refreshNotice,
11922
+ lastRefreshedAt,
11923
+ incident
11173
11924
  };
11174
11925
  }
11175
- async function runTick(trigger) {
11926
+ async function runTick(trigger, beforeTick) {
11176
11927
  const isManual = trigger === "manual";
11177
11928
  if (stopped) return {
11178
11929
  ok: false,
@@ -11220,6 +11971,15 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11220
11971
  };
11221
11972
  }
11222
11973
  }
11974
+ if (isManual && beforeTick) {
11975
+ onScheduleChange();
11976
+ const refreshed = await beforeTick();
11977
+ if (stopped) return {
11978
+ ok: false,
11979
+ error: "Reviews polling is stopped."
11980
+ };
11981
+ if (!refreshed.ok) return refreshed;
11982
+ }
11223
11983
  clearRetryTimer();
11224
11984
  nextAttemptAt = null;
11225
11985
  retry = null;
@@ -11230,6 +11990,8 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11230
11990
  error: "Reviews polling is stopped."
11231
11991
  };
11232
11992
  if (outcome?.failed !== true) {
11993
+ lastRefreshedAt = now();
11994
+ hasTransientFailure = false;
11233
11995
  failureStreak = 0;
11234
11996
  quickRetryCount = 0;
11235
11997
  backoffUntil = 0;
@@ -11238,6 +12000,8 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11238
12000
  return { ok: true };
11239
12001
  }
11240
12002
  failureStreak += 1;
12003
+ hasTransientFailure = outcome.retryAfterMs === void 0;
12004
+ if (hasTransientFailure) clock?.githubStatus?.noteTransientFailure();
11241
12005
  const scheduled = nextRetrySchedule({
11242
12006
  failureStreak,
11243
12007
  quickRetryCount,
@@ -11250,7 +12014,7 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11250
12014
  if (scheduled.retry) quickRetryCount += 1;
11251
12015
  if (outcome.retryAfterMs && outcome.retryAfterMs > 0) rateLimitedUntil = now() + outcome.retryAfterMs;
11252
12016
  scheduleAttempt(scheduled.waitMs, scheduled.retry);
11253
- log.warn(`[${tag}] poll failed (${failureStreak} in a row) - backing off ${Math.round(scheduled.waitMs / 1e3)}s`);
12017
+ log.warn(`[${tag}] poll failed (${failureStreak} in a row)${outcome.error ? `: ${outcome.error}` : ""} - backing off ${Math.round(scheduled.waitMs / 1e3)}s`);
11254
12018
  return {
11255
12019
  ok: false,
11256
12020
  error: "Could not refresh from GitHub."
@@ -11270,8 +12034,8 @@ function createTickLoop({ tag, quickRetries = false, onScheduleChange = () => {}
11270
12034
  if (tickRunning) return;
11271
12035
  runTick("interval");
11272
12036
  }
11273
- function refresh() {
11274
- return runTick("manual");
12037
+ function refresh(beforeTick) {
12038
+ return runTick("manual", beforeTick);
11275
12039
  }
11276
12040
  async function start(prelude = null) {
11277
12041
  stopped = false;
@@ -11429,9 +12193,13 @@ function createIssuesPoller(dependencies) {
11429
12193
  }
11430
12194
  async function failedOutcome(error) {
11431
12195
  const waitMs = await rateLimitWaitMs() ?? secondaryRateLimitWaitMs(error);
11432
- return waitMs === null ? { failed: true } : {
12196
+ return waitMs === null ? {
12197
+ failed: true,
12198
+ error
12199
+ } : {
11433
12200
  failed: true,
11434
- retryAfterMs: waitMs
12201
+ retryAfterMs: waitMs,
12202
+ error
11435
12203
  };
11436
12204
  }
11437
12205
  async function runTick() {
@@ -11877,7 +12645,7 @@ async function runCommandSafely(command, args, { env, timeoutMs, signal }) {
11877
12645
  }
11878
12646
  }
11879
12647
  async function readTextFileOrNull$1(filePath) {
11880
- return fsp.readFile(filePath, "utf8").catch(() => null);
12648
+ return fs$1.readFile(filePath, "utf8").catch(() => null);
11881
12649
  }
11882
12650
  function sleepUnlessAborted(durationMs, signal) {
11883
12651
  return new Promise((resolve) => {
@@ -16609,11 +17377,6 @@ async function writeWhenAbsent(filePath, contents) {
16609
17377
  var WORKSPACE_MAP_FILE = "AGENTS.md";
16610
17378
  var WORKSPACE_POINTER_FILE = "CLAUDE.md";
16611
17379
  var WORKSPACE_MAP_HASH_FILE = ".glimmervoid-map-hash";
16612
- var GENERATED_WORKSPACE_FILES = /* @__PURE__ */ new Set([
16613
- WORKSPACE_MAP_FILE,
16614
- WORKSPACE_POINTER_FILE,
16615
- WORKSPACE_MAP_HASH_FILE
16616
- ]);
16617
17380
  function hashWorkspaceMap(contents) {
16618
17381
  return crypto.createHash("sha256").update(contents).digest("hex");
16619
17382
  }
@@ -16634,15 +17397,20 @@ async function writeWorkspaceMap(folder, contents) {
16634
17397
  await fs.promises.writeFile(mapPath, contents);
16635
17398
  await fs.promises.writeFile(hashPath, `${renderedHash}\n`);
16636
17399
  }
16637
- function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorkspace }) {
17400
+ function createSessionWorkspaceMembers({ plan, owner, sessionName, shareList, gitWorkspace }) {
16638
17401
  let activeProvision = null;
16639
17402
  async function provisionBody() {
16640
17403
  try {
16641
17404
  await fs.promises.mkdir(plan.folder, { recursive: true });
17405
+ await gitWorkspace.recordOwnedFolder({
17406
+ folderPath: plan.folder,
17407
+ owner
17408
+ });
16642
17409
  const members = [];
16643
17410
  for (const member of plan.members) {
16644
17411
  const ensured = await gitWorkspace.ensureWorkspaceMember({
16645
17412
  projectPath: member.repoPath,
17413
+ owner,
16646
17414
  wtDir: member.dir,
16647
17415
  branch: plan.branch,
16648
17416
  shareList
@@ -16682,28 +17450,68 @@ function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorksp
16682
17450
  });
16683
17451
  return attempt;
16684
17452
  }
16685
- async function release({ keepRepoPaths = [] } = {}) {
17453
+ const pathExists = (candidatePath) => fs.promises.stat(candidatePath).then(() => true, () => false);
17454
+ async function findMemberWork(member) {
17455
+ return gitWorkspace.describeWorkspaceMemberWork({
17456
+ projectPath: member.repoPath,
17457
+ cwd: member.dir,
17458
+ branch: plan.branch
17459
+ }).catch((error) => `its work could not be checked: ${errorMessage(error)}`);
17460
+ }
17461
+ async function findKeptWork() {
17462
+ if (activeProvision) await activeProvision;
17463
+ const kept = [];
17464
+ for (const member of plan.members) {
17465
+ if (!await pathExists(member.dir)) continue;
17466
+ const reason = await findMemberWork(member);
17467
+ if (reason) kept.push({
17468
+ path: member.dir,
17469
+ reason
17470
+ });
17471
+ }
17472
+ return kept;
17473
+ }
17474
+ async function releaseMember(member, discardWork) {
17475
+ if (!await pathExists(member.dir)) return null;
17476
+ const reason = discardWork ? null : await findMemberWork(member);
17477
+ if (reason) return {
17478
+ path: member.dir,
17479
+ reason
17480
+ };
17481
+ const removed = await gitWorkspace.removeWorkspaceMember({
17482
+ projectPath: member.repoPath,
17483
+ cwd: member.dir,
17484
+ shareList,
17485
+ discardWork
17486
+ });
17487
+ if (removed.ok) return null;
17488
+ return {
17489
+ path: member.dir,
17490
+ reason: removed.err?.split("\n")[0] || "git refused to remove it"
17491
+ };
17492
+ }
17493
+ async function release({ keepRepoPaths = [], discardWork = false } = {}) {
16686
17494
  if (activeProvision) await activeProvision;
16687
17495
  const keptRepoKeys = new Set(keepRepoPaths.map((repoPath) => caseFoldedPathKey(path.resolve(repoPath))));
16688
- const keptDirs = [];
17496
+ const kept = [];
16689
17497
  for (const member of plan.members) {
16690
17498
  if (keptRepoKeys.has(caseFoldedPathKey(member.repoPath))) continue;
16691
- if (!await fs.promises.stat(member.dir).then(() => true, () => false)) continue;
16692
- if (!(await gitWorkspace.removeWorkspaceMember({
16693
- projectPath: member.repoPath,
16694
- cwd: member.dir,
16695
- shareList
16696
- })).ok) keptDirs.push(member.dir);
17499
+ const keptMember = await releaseMember(member, discardWork);
17500
+ if (keptMember) kept.push(keptMember);
16697
17501
  }
16698
- const entries = await fs.promises.readdir(plan.folder).catch(() => []);
16699
- if (entries.some((entry) => !GENERATED_WORKSPACE_FILES.has(entry))) return { keptDirs };
16700
- for (const entry of entries) await fs.promises.rm(path.join(plan.folder, entry), { force: true });
16701
- await fs.promises.rmdir(plan.folder).catch(() => {});
16702
- return { keptDirs };
17502
+ if (keptRepoKeys.size > 0) return { kept };
17503
+ for (const member of plan.members) if (await pathExists(member.dir)) return { kept };
17504
+ await fs.promises.rm(plan.folder, {
17505
+ recursive: true,
17506
+ force: true
17507
+ });
17508
+ await gitWorkspace.forgetRemovedPath(plan.folder);
17509
+ return { kept };
16703
17510
  }
16704
17511
  return {
16705
17512
  provision,
16706
17513
  release,
17514
+ findKeptWork,
16707
17515
  branch: plan.branch
16708
17516
  };
16709
17517
  }
@@ -16711,6 +17519,18 @@ function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorksp
16711
17519
  //#region session/session-worktree-lifecycle.ts
16712
17520
  var WORKTREE_CHECK_DEBOUNCE_MS = 400;
16713
17521
  var GIT_NOT_FOUND_EXIT_CODE = 1;
17522
+ function workspaceMemberGit(gitWorkspace) {
17523
+ if (!gitWorkspace) return null;
17524
+ const { ensureWorkspaceMember, removeWorkspaceMember, describeWorkspaceMemberWork, recordOwnedFolder, forgetRemovedPath } = gitWorkspace;
17525
+ if (!ensureWorkspaceMember || !removeWorkspaceMember || !describeWorkspaceMemberWork || !recordOwnedFolder || !forgetRemovedPath) return null;
17526
+ return {
17527
+ ensureWorkspaceMember,
17528
+ removeWorkspaceMember,
17529
+ describeWorkspaceMemberWork,
17530
+ recordOwnedFolder,
17531
+ forgetRemovedPath
17532
+ };
17533
+ }
16714
17534
  async function readGitStrict(args, options) {
16715
17535
  const command = await runGit(args, {
16716
17536
  ...options,
@@ -16750,9 +17570,8 @@ function setUpWorkspaceMembers({ folder, sessionId, sessionName, repoPaths, shar
16750
17570
  repoPaths
16751
17571
  });
16752
17572
  if (!planned.ok) return planned;
16753
- const ensureWorkspaceMember = gitWorkspace?.ensureWorkspaceMember;
16754
- const removeWorkspaceMember = gitWorkspace?.removeWorkspaceMember;
16755
- if (!ensureWorkspaceMember || !removeWorkspaceMember) return {
17573
+ const memberGit = workspaceMemberGit(gitWorkspace);
17574
+ if (!memberGit) return {
16756
17575
  ok: false,
16757
17576
  error: "Git workspace is unavailable"
16758
17577
  };
@@ -16760,12 +17579,10 @@ function setUpWorkspaceMembers({ folder, sessionId, sessionName, repoPaths, shar
16760
17579
  ok: true,
16761
17580
  members: createSessionWorkspaceMembers({
16762
17581
  plan: planned.plan,
17582
+ owner: `session:${sessionId}`,
16763
17583
  sessionName,
16764
17584
  shareList,
16765
- gitWorkspace: {
16766
- ensureWorkspaceMember,
16767
- removeWorkspaceMember
16768
- }
17585
+ gitWorkspace: memberGit
16769
17586
  })
16770
17587
  };
16771
17588
  }
@@ -17060,6 +17877,7 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
17060
17877
  try {
17061
17878
  workspace = await gitWorkspace.create({
17062
17879
  projectPath: currentProjectPath(),
17880
+ owner: `session:${id}`,
17063
17881
  teamId: "session",
17064
17882
  label: id,
17065
17883
  baseBranch,
@@ -17162,9 +17980,21 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
17162
17980
  lifecycleState.isWorktree = false;
17163
17981
  setMergeStatus(status);
17164
17982
  }
17983
+ let isWorkspaceWorkDiscardConfirmed = false;
17984
+ function confirmWorkspaceWorkDiscard() {
17985
+ isWorkspaceWorkDiscardConfirmed = true;
17986
+ }
17987
+ async function findWorkspaceKeptWork() {
17988
+ if (!workspaceMembers?.ok) return [];
17989
+ return workspaceMembers.members.findKeptWork();
17990
+ }
17165
17991
  async function releaseWorkspaceMembers(members, keepRepoPaths = []) {
17166
- const released = await members.release({ keepRepoPaths });
17167
- if (released.keptDirs.length > 0) console.warn(`[session ${id}] kept workspace members with uncommitted work: ${released.keptDirs.join(", ")}`);
17992
+ const released = await members.release({
17993
+ keepRepoPaths,
17994
+ discardWork: isWorkspaceWorkDiscardConfirmed
17995
+ });
17996
+ if (released.kept.length === 0) return;
17997
+ console.warn(`[session ${id}] kept workspace members: ${released.kept.map((kept) => `${kept.path} (${kept.reason})`).join(", ")}`);
17168
17998
  }
17169
17999
  async function releaseDroppedWorkspaceMembers(keepRepoPaths) {
17170
18000
  if (!workspaceMembers?.ok) return;
@@ -17242,7 +18072,7 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
17242
18072
  "--quiet",
17243
18073
  candidate
17244
18074
  ], opts) !== null) return {
17245
- ref: candidate,
18075
+ ref: await freshestBaseRef(candidate, opts),
17246
18076
  verified: true
17247
18077
  };
17248
18078
  return {
@@ -17250,6 +18080,23 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
17250
18080
  verified: false
17251
18081
  };
17252
18082
  }
18083
+ async function freshestBaseRef(baseBranch, opts) {
18084
+ const localRef = `refs/heads/${baseBranch}`;
18085
+ const originRef = `refs/remotes/origin/${baseBranch}`;
18086
+ const existingRefs = (await gitOut([
18087
+ "for-each-ref",
18088
+ "--format=%(refname)",
18089
+ localRef,
18090
+ originRef
18091
+ ], opts)).split("\n");
18092
+ if (!existingRefs.includes(localRef) || !existingRefs.includes(originRef)) return baseBranch;
18093
+ return await gitLookup([
18094
+ "merge-base",
18095
+ "--is-ancestor",
18096
+ localRef,
18097
+ originRef
18098
+ ], opts) !== null ? `origin/${baseBranch}` : baseBranch;
18099
+ }
17253
18100
  function diffGitOptions(cwd) {
17254
18101
  return {
17255
18102
  cwd,
@@ -17318,7 +18165,7 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
17318
18165
  async function memberMergeBase(member) {
17319
18166
  const opts = diffGitOptions(member.dir);
17320
18167
  const candidates = member.base ? [
17321
- member.base,
18168
+ await freshestBaseRef(member.base, opts),
17322
18169
  `origin/${member.base}`,
17323
18170
  "origin/HEAD"
17324
18171
  ] : ["origin/HEAD"];
@@ -17930,6 +18777,8 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
17930
18777
  setMergeStatus,
17931
18778
  pasteMergePrompt,
17932
18779
  hasUnmergedWork,
18780
+ findWorkspaceKeptWork,
18781
+ confirmWorkspaceWorkDiscard,
17933
18782
  getDiff,
17934
18783
  getChangeScopes,
17935
18784
  resolveEffectiveBase,
@@ -19301,6 +20150,12 @@ var Session = class extends EventEmitter {
19301
20150
  discardWorktree() {
19302
20151
  return this.worktreeLifecycle.discardWorktree();
19303
20152
  }
20153
+ findWorkspaceKeptWork() {
20154
+ return this.worktreeLifecycle.findWorkspaceKeptWork();
20155
+ }
20156
+ confirmWorkspaceWorkDiscard() {
20157
+ this.worktreeLifecycle.confirmWorkspaceWorkDiscard();
20158
+ }
19304
20159
  getDetectionStats() {
19305
20160
  return {
19306
20161
  lastSignal: this._lastSignal,
@@ -20851,760 +21706,200 @@ function boundedToolCallInput(input) {
20851
21706
  return {
20852
21707
  input: bounded.text,
20853
21708
  truncated: true
20854
- };
20855
- }
20856
- if (!input || typeof input !== "object") return { input };
20857
- const bounded = Array.isArray(input) ? {
20858
- input,
20859
- hasCutProperty: false
20860
- } : boundedInputProperties(input);
20861
- const serialized = serializedInputText(bounded.input);
20862
- if (serialized.length > MAX_TRACE_CALL_INPUT_CHARS) return {
20863
- input: serialized.slice(0, MAX_TRACE_BODY_CHARS),
20864
- truncated: true
20865
- };
20866
- if (!bounded.hasCutProperty) return { input };
20867
- return {
20868
- input: bounded.input,
20869
- truncated: true
20870
- };
20871
- }
20872
- function everyTextBlockJoined(blocks) {
20873
- const blockTexts = blocks.flatMap((block) => firstTextBlock([block]) ?? []);
20874
- if (blockTexts.length === 0) return null;
20875
- return blockTexts.join("\n");
20876
- }
20877
- function isTaskNotificationLine(line) {
20878
- return line.origin?.kind === "task-notification" || line.turnOrigin?.kind === "task_notification";
20879
- }
20880
- function mapUserLine(rawLine, line, context) {
20881
- const base = baseRecord(line, context);
20882
- const content = line.message?.content;
20883
- const blocks = contentBlocks(line);
20884
- const toolResult = blocks.find((block) => block.type === "tool_result");
20885
- if (toolResult) {
20886
- const toolUseId = rawTextOr(toolResult.tool_use_id, null);
20887
- if (!toolUseId) return [rawRecord(rawLine, line, context)];
20888
- const bounded = boundedText(textContent(toolResult.content));
20889
- return [{
20890
- ...base,
20891
- kind: "tool_result",
20892
- toolUseId,
20893
- content: bounded.text,
20894
- isError: toolResult.is_error === true,
20895
- truncated: bounded.truncated
20896
- }];
20897
- }
20898
- if (line.isMeta === true) {
20899
- const expansionText = typeof content === "string" ? content : everyTextBlockJoined(blocks);
20900
- if (!expansionText) return [rawRecord(rawLine, line, context)];
20901
- const sourceToolUseId = rawTextOr(line.sourceToolUseID, null);
20902
- if (!sourceToolUseId) return [{
20903
- ...base,
20904
- kind: "expansion",
20905
- ...boundedTextFields(expansionText)
20906
- }];
20907
- return [{
20908
- ...base,
20909
- kind: "expansion",
20910
- toolUseId: sourceToolUseId,
20911
- ...boundedTextFields(expansionText)
20912
- }];
20913
- }
20914
- const text = typeof content === "string" ? content : firstTextBlock(blocks);
20915
- if (!text) return [rawRecord(rawLine, line, context)];
20916
- if (isTaskNotificationLine(line)) return [{
20917
- ...base,
20918
- kind: "expansion",
20919
- ...boundedTextFields(text)
20920
- }];
20921
- if (typeof content === "string" && /<command-name>[\s\S]*?<\/command-name>/.test(content)) return [{
20922
- ...base,
20923
- kind: "expansion",
20924
- ...boundedTextFields(content)
20925
- }];
20926
- return [{
20927
- ...base,
20928
- kind: "prompt",
20929
- ...boundedTextFields(text)
20930
- }];
20931
- }
20932
- function queuedCommandText(prompt) {
20933
- if (typeof prompt === "string") return prompt || null;
20934
- return firstTextBlock(objectBlocks(prompt));
20935
- }
20936
- function queuedCommandRecords(line, context) {
20937
- const attachment = line.attachment;
20938
- if (line.type !== "attachment" || attachment?.type !== "queued_command") return null;
20939
- const text = queuedCommandText(attachment.prompt);
20940
- if (!text) return null;
20941
- if (attachment.commandMode === "prompt" && attachment.origin?.kind === "human") return [{
20942
- ...baseRecord(line, context),
20943
- kind: "prompt",
20944
- ...boundedTextFields(text)
20945
- }];
20946
- if (attachment.commandMode === "task-notification") return [{
20947
- ...baseRecord(line, context),
20948
- kind: "expansion",
20949
- ...boundedTextFields(text)
20950
- }];
20951
- return null;
20952
- }
20953
- function mapAssistantLine(rawLine, line, context) {
20954
- const base = baseRecord(line, context);
20955
- const records = [];
20956
- let hasSkippedThinkingBlock = false;
20957
- for (const block of contentBlocks(line)) {
20958
- if (block.type === "thinking" && typeof block.thinking === "string") {
20959
- if (block.thinking.length === 0) {
20960
- hasSkippedThinkingBlock = true;
20961
- continue;
20962
- }
20963
- records.push({
20964
- ...base,
20965
- kind: "thinking",
20966
- ...boundedTextFields(block.thinking)
20967
- });
20968
- continue;
20969
- }
20970
- if (block.type === "text") {
20971
- const text = firstTextBlock([block]);
20972
- if (text) records.push({
20973
- ...base,
20974
- kind: "assistant",
20975
- ...boundedTextFields(text)
20976
- });
20977
- continue;
20978
- }
20979
- if (block.type !== "tool_use") continue;
20980
- const toolUseId = rawTextOr(block.id, null);
20981
- const name = rawTextOr(block.name, null);
20982
- if (!toolUseId || !name) return [rawRecord(rawLine, line, context)];
20983
- records.push({
20984
- ...base,
20985
- kind: "tool_call",
20986
- toolUseId,
20987
- name,
20988
- ...boundedToolCallInput(block.input)
20989
- });
20990
- }
20991
- if (records.length === 0 && hasSkippedThinkingBlock) return [];
20992
- if (records.length === 0) return [rawRecord(rawLine, line, context)];
20993
- return records;
20994
- }
20995
- function traceRecordsFromTranscriptLine(rawLine, context) {
20996
- const line = parseTranscriptLine(rawLine);
20997
- if (!line) return [rawRecord(rawLine, null, context)];
20998
- const queuedRecords = queuedCommandRecords(line, context);
20999
- if (queuedRecords) return queuedRecords;
21000
- if (isDroppedLine(line)) return [];
21001
- if (line.type === "user") return mapUserLine(rawLine, line, context);
21002
- if (line.type === "assistant") return mapAssistantLine(rawLine, line, context);
21003
- return [rawRecord(rawLine, line, context)];
21004
- }
21005
- //#endregion
21006
- //#region server/core/investigation-trail-core.ts
21007
- var TRAIL_MAX_STEPS = 80;
21008
- var TRAIL_TOOL_MAX_CHARS = 64;
21009
- var TRAIL_NOTE_MAX_CHARS = 600;
21010
- function describeToolStep(toolName, toolInput) {
21011
- const trimmed = typeof toolName === "string" ? toolName.trim() : "";
21012
- if (!trimmed) return null;
21013
- const tool = trimmed.slice(0, TRAIL_TOOL_MAX_CHARS);
21014
- return {
21015
- tool,
21016
- detail: toolDetailLine(tool, toolInput)
21017
- };
21018
- }
21019
- function trailStepFromHook(event, payload) {
21020
- if (String(event ?? "").toLowerCase() !== "pretooluse") return null;
21021
- return describeToolStep(payload.tool_name, payload.tool_input);
21022
- }
21023
- function trailNotesFromTranscriptLines(lines, now) {
21024
- return lines.flatMap((line) => traceRecordsFromTranscriptLine(line, {
21025
- vendorSessionId: "",
21026
- now
21027
- })).flatMap((record) => record.kind === "assistant" ? [record.text.trim().slice(0, TRAIL_NOTE_MAX_CHARS)] : []).filter((note) => note !== "");
21028
- }
21029
- function createInvestigationTrail(startedAt) {
21030
- return {
21031
- startedAt,
21032
- steps: []
21033
- };
21034
- }
21035
- function appendTrailStep(trail, step, maxSteps = TRAIL_MAX_STEPS) {
21036
- const isAppendingNote = isTrailNote(step);
21037
- const sameKindEntries = trail.steps.filter((entry) => isTrailNote(entry) === isAppendingNote);
21038
- const evictedCount = Math.max(0, sameKindEntries.length + 1 - maxSteps);
21039
- const evictedEntries = new Set(sameKindEntries.slice(0, evictedCount));
21040
- const keptEntries = trail.steps.filter((entry) => !evictedEntries.has(entry));
21041
- return {
21042
- startedAt: trail.startedAt,
21043
- steps: [...keptEntries, step]
21044
- };
21045
- }
21046
- function isTrailNote(entry) {
21047
- return "note" in entry;
21048
- }
21049
- //#endregion
21050
- //#region shared/contracts/guardrails-launch.ts
21051
- var GuardrailsLaunchLogin = z.object({
21052
- linkPath: z.string().min(1),
21053
- targetPath: z.string().min(1)
21054
- }).strict();
21055
- var GuardrailsLaunchOwner = z.object({
21056
- ownerPid: z.number().int().positive(),
21057
- ownerHost: z.string(),
21058
- ownerPidNamespace: z.string().nullable(),
21059
- ownsTempDir: z.boolean(),
21060
- keptTempFolderName: z.string().min(1).optional(),
21061
- logins: z.array(GuardrailsLaunchLogin),
21062
- placeholderPaths: z.array(z.string().min(1))
21063
- }).strict();
21064
- //#endregion
21065
- //#region server/core/claude-trust-core.ts
21066
- var CLAUDE_GLOBAL_CONFIG_FILE_NAME = ".claude.json";
21067
- var CLAUDE_LEGACY_CONFIG_FILE_NAME = ".config.json";
21068
- var CLAUDE_CONFIG_LOCK_SUFFIX = ".lock";
21069
- var CLAUDE_CONFIG_LOCK_STALE_MS = 1e4;
21070
- var CLAUDE_CONFIG_LOCK_RETRY_DELAYS_MS = Object.freeze([
21071
- 200,
21072
- 400,
21073
- 800,
21074
- 1600
21075
- ]);
21076
- var GRANTED_KEYS = Object.freeze([
21077
- "hasTrustDialogAccepted",
21078
- "hasClaudeMdExternalIncludesApproved",
21079
- "hasClaudeMdExternalIncludesWarningShown"
21080
- ]);
21081
- var TRUST_ONLY_KEYS = Object.freeze(["hasTrustDialogAccepted"]);
21082
- function isPlainRecord(value) {
21083
- return typeof value === "object" && value !== null && !Array.isArray(value);
21084
- }
21085
- function newProjectEntry() {
21086
- return {
21087
- allowedTools: [],
21088
- mcpContextUris: [],
21089
- mcpServers: {},
21090
- enabledMcpjsonServers: [],
21091
- disabledMcpjsonServers: []
21092
- };
21093
- }
21094
- function listClaudeGlobalConfigPathCandidates(env, homeDir) {
21095
- const configuredDir = env.CLAUDE_CONFIG_DIR?.trim();
21096
- const legacyConfigHome = (configuredDir || path.join(homeDir, ".claude")).normalize("NFC");
21097
- return [path.join(legacyConfigHome, CLAUDE_LEGACY_CONFIG_FILE_NAME), path.join(configuredDir || homeDir, CLAUDE_GLOBAL_CONFIG_FILE_NAME)];
21098
- }
21099
- function claudeProjectKeyOf(folderPath, platform) {
21100
- if (platform !== "win32") return path.posix.normalize(folderPath);
21101
- return path.win32.normalize(folderPath).replaceAll("\\", "/");
21102
- }
21103
- function repositoryRootOfCommonGitDir(commonGitDir) {
21104
- if (!path.isAbsolute(commonGitDir) || path.basename(commonGitDir) !== ".git") return null;
21105
- return path.dirname(commonGitDir);
21106
- }
21107
- function isConfigLockStale(lockModifiedMs, nowMs) {
21108
- return nowMs - lockModifiedMs > CLAUDE_CONFIG_LOCK_STALE_MS;
21109
- }
21110
- function hasRecordedExternalImportsDecline(existingEntry) {
21111
- return existingEntry?.hasClaudeMdExternalIncludesWarningShown === true && existingEntry.hasClaudeMdExternalIncludesApproved !== true;
21112
- }
21113
- function decideFolderTrust(configText, repositoryRoot, platform) {
21114
- const projectKey = claudeProjectKeyOf(repositoryRoot, platform);
21115
- let config;
21116
- try {
21117
- config = JSON.parse(configText);
21118
- } catch {
21119
- return {
21120
- kind: "unreadable",
21121
- reason: "it is not valid JSON"
21122
- };
21123
- }
21124
- if (!isPlainRecord(config)) return {
21125
- kind: "unreadable",
21126
- reason: "it is not a JSON object"
21127
- };
21128
- const projects = config.projects ?? {};
21129
- if (!isPlainRecord(projects)) return {
21130
- kind: "unreadable",
21131
- reason: "its projects key is not an object"
21132
- };
21133
- const existingEntry = projects[projectKey];
21134
- if (existingEntry !== void 0 && !isPlainRecord(existingEntry)) return {
21135
- kind: "unreadable",
21136
- reason: "its entry for this folder is not an object"
21137
- };
21138
- const keysToGrant = hasRecordedExternalImportsDecline(existingEntry) ? TRUST_ONLY_KEYS : GRANTED_KEYS;
21139
- if (keysToGrant.every((key) => existingEntry?.[key] === true)) return { kind: "trusted" };
21140
- const trustedEntry = {
21141
- ...existingEntry ?? newProjectEntry(),
21142
- ...Object.fromEntries(keysToGrant.map((key) => [key, true]))
21143
- };
21144
- const nextConfigText = JSON.stringify({
21145
- ...config,
21146
- projects: {
21147
- ...projects,
21148
- [projectKey]: trustedEntry
21149
- }
21150
- }, null, 2);
21151
- return {
21152
- kind: "grant",
21153
- nextConfigText: configText.endsWith("\n") ? `${nextConfigText}\n` : nextConfigText
21154
- };
21155
- }
21156
- //#endregion
21157
- //#region server/guardrails/core/guardrails-bridge-socket-core.ts
21158
- var LONGEST_BRIDGE_SOCKET_NAME = "claude-socks-0123456789abcdef.sock";
21159
- var UNIX_SOCKET_PATH_BYTE_LIMIT = 107;
21160
- var SHORT_BRIDGE_SOCKET_FOLDER = "/tmp";
21161
- function bridgeSocketPathBytes(tempDirectory) {
21162
- return Buffer.byteLength(path.join(tempDirectory, LONGEST_BRIDGE_SOCKET_NAME));
21163
- }
21164
- function hasRoomForBridgeSocket(tempDirectory, platform) {
21165
- return platform !== "linux" || bridgeSocketPathBytes(tempDirectory) <= UNIX_SOCKET_PATH_BYTE_LIMIT;
21166
- }
21167
- function bridgeSocketLauncherEnv(inheritedTempDirectory, platform) {
21168
- if (hasRoomForBridgeSocket(inheritedTempDirectory, platform)) return { TMPDIR: inheritedTempDirectory };
21169
- return { TMPDIR: SHORT_BRIDGE_SOCKET_FOLDER };
21170
- }
21171
- //#endregion
21172
- //#region server/prune-files.ts
21173
- var MS_PER_DAY = 864e5;
21174
- function idForEntry(entry, suffixes) {
21175
- for (const suffix of suffixes) {
21176
- if (suffix.length === 0) return entry;
21177
- if (entry.endsWith(suffix)) return entry.slice(0, -suffix.length);
21178
- }
21179
- return null;
21180
- }
21181
- async function pruneAgedFiles({ directory, suffixes, retainDays, now = Date.now(), isRetainedId = () => false, entryMode = "file", fsPromises = fs.promises }) {
21182
- let entries;
21183
- try {
21184
- entries = await fsPromises.readdir(directory);
21185
- } catch {
21186
- return [];
21187
- }
21188
- const cutoff = now - retainDays * MS_PER_DAY;
21189
- const removedIds = [];
21190
- for (const entry of entries) {
21191
- const id = idForEntry(entry, suffixes);
21192
- if (!id || isRetainedId(id)) continue;
21193
- const filePath = path.join(directory, entry);
21194
- try {
21195
- if ((await fsPromises.stat(filePath)).mtimeMs >= cutoff) continue;
21196
- if (entryMode === "directory") await fsPromises.rm(filePath, {
21197
- recursive: true,
21198
- force: true
21199
- });
21200
- if (entryMode === "file") await fsPromises.unlink(filePath);
21201
- removedIds.push(id);
21202
- } catch {}
21203
- }
21204
- return removedIds;
21205
- }
21206
- //#endregion
21207
- //#region server/guardrails/guardrails-launch.ts
21208
- var LAUNCH_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
21209
- var GUARDED_ENV_COMMAND = "/usr/bin/env";
21210
- var POLICY_FOLDER = "guardrails-policies";
21211
- var LAUNCH_HOME_FOLDER = "guardrails-homes";
21212
- var START_FOLDER = "start";
21213
- var OWNER_FILE_SUFFIX = ".owner.json";
21214
- var ENTER_FOLDER_SCRIPT = "cd \"$1\" && shift && exec \"$@\"";
21215
- var LOGIN_FILE_MODE = 384;
21216
- var ABSENT_PATH_DENY_PLATFORM = "darwin";
21217
- var OWN_PID_NAMESPACE_LINK = "/proc/self/ns/pid";
21218
- var SESSION_TEMP_RETAIN_DAYS = 7;
21219
- async function isPresent(candidate) {
21220
- try {
21221
- await access(candidate);
21222
- return true;
21223
- } catch (error) {
21224
- if (!isMissingFileError(error)) throw error;
21225
- return false;
21226
- }
21227
- }
21228
- async function presentPaths$1(candidates) {
21229
- const presence = await Promise.all(candidates.map(isPresent));
21230
- return new Set(candidates.filter((_candidate, index) => presence[index]));
21231
- }
21232
- async function realPathWhenPresent(candidate) {
21233
- if (!path.isAbsolute(candidate)) return candidate;
21234
- try {
21235
- return await realpath(candidate);
21236
- } catch (error) {
21237
- if (!isMissingFileError(error)) throw error;
21238
- return candidate;
21239
- }
21240
- }
21241
- function realPathsWhenPresent(candidates) {
21242
- return Promise.all(candidates.map(realPathWhenPresent));
21243
- }
21244
- async function symlinkTargetsInside(folder) {
21245
- const symlinkEntries = (await readdir(folder, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isSymbolicLink());
21246
- return (await Promise.all(symlinkEntries.map((entry) => realpath(path.join(folder, entry.name)).catch(() => null)))).filter((target) => target !== null);
21247
- }
21248
- async function blockedPathsWithRealTargets(candidates, operatorBlockedPaths) {
21249
- const resolved = await Promise.all(candidates.map(async (candidate) => {
21250
- const isPresentEntry = await lstat(candidate).then(() => true, (error) => !isMissingFileError(error));
21251
- const isKeptWhenAbsent = process.platform === ABSENT_PATH_DENY_PLATFORM || operatorBlockedPaths.includes(candidate);
21252
- if (!isPresentEntry) return isKeptWhenAbsent ? [candidate] : [];
21253
- const realCandidate = await realpath(candidate).catch(() => candidate);
21254
- return [
21255
- candidate,
21256
- realCandidate,
21257
- ...await symlinkTargetsInside(realCandidate)
21258
- ];
21259
- }));
21260
- return [...new Set(resolved.flat())];
21261
- }
21262
- async function configuredConfigFile(glimmervoidHome) {
21263
- const { envPath, homePath } = decideConfigPath({
21264
- env: process.env,
21265
- homeDir: glimmervoidHome
21266
- }, () => false);
21267
- const configFile = envPath ?? homePath;
21268
- return path.join(await realPathWhenPresent(path.dirname(configFile)), path.basename(configFile));
21269
- }
21270
- function scannedClaudeHomes(env, homeDir) {
21271
- return [env, {
21272
- ...env,
21273
- CLAUDE_CONFIG_DIR: void 0
21274
- }].flatMap((scannedEnv) => projectDirCandidates(scannedEnv, [], homeDir)).map((projectsDir) => path.dirname(projectsDir));
21275
- }
21276
- async function resolveVendorLocations(env, homeDir) {
21277
- const [legacyClaudeConfigPath, claudeConfigPath] = listClaudeGlobalConfigPathCandidates(env, homeDir);
21278
- const [codexStateFolder, ...otherCodexHomes] = codexHomes(env, homeDir);
21279
- if (codexStateFolder === void 0) return null;
21280
- return {
21281
- claude: {
21282
- stateFolder: await realPathWhenPresent(path.dirname(legacyClaudeConfigPath)),
21283
- configFiles: [await realPathWhenPresent(claudeConfigPath)],
21284
- otherHomes: await realPathsWhenPresent(scannedClaudeHomes(env, homeDir))
21285
- },
21286
- codex: {
21287
- stateFolder: await realPathWhenPresent(codexStateFolder),
21288
- configFiles: [],
21289
- otherHomes: await realPathsWhenPresent(otherCodexHomes)
21290
- }
21291
- };
21292
- }
21293
- async function withRealRoots(role) {
21294
- const [writableRoots, lockedCheckouts, commitCheckouts] = await Promise.all([
21295
- Promise.all(role.writableRoots.map((root) => realpath(root))),
21296
- Promise.all(role.lockedCheckouts.map((checkout) => realpath(checkout))),
21297
- Promise.all(role.commitCheckouts.map(async ({ checkout, gitDir }) => ({
21298
- checkout: await realpath(checkout),
21299
- gitDir: await realpath(gitDir)
21300
- })))
21301
- ]);
21302
- const vendorHome = role.vendorHome.scope === "launch" ? {
21303
- ...role.vendorHome,
21304
- cwd: await realPathWhenPresent(role.vendorHome.cwd)
21305
- } : role.vendorHome;
21306
- return {
21307
- ...role,
21308
- vendorHome,
21309
- writableRoots,
21310
- lockedCheckouts,
21311
- commitCheckouts,
21312
- readableWithinDenied: await realPathsWhenPresent(role.readableWithinDenied)
21313
- };
21314
- }
21315
- async function lstatWhenPresent(candidate) {
21316
- try {
21317
- return await lstat(candidate);
21318
- } catch (error) {
21319
- if (!isMissingFileError(error)) throw error;
21320
- return null;
21321
- }
21322
- }
21323
- async function isRegularFile(candidate) {
21324
- return (await lstatWhenPresent(candidate))?.isFile() ?? false;
21325
- }
21326
- async function isRealDirectory$1(candidate) {
21327
- return (await lstatWhenPresent(candidate))?.isDirectory() ?? false;
21328
- }
21329
- async function absentPaths(candidates) {
21330
- const presentCandidates = await presentPaths$1(candidates);
21331
- return candidates.filter((candidate) => !presentCandidates.has(candidate));
21332
- }
21333
- async function removeLeftoverPlaceholders(placeholderPaths) {
21334
- for (const placeholderPath of placeholderPaths) {
21335
- const placeholderStats = await lstat(placeholderPath).catch(() => null);
21336
- if (placeholderStats?.isFile() && placeholderStats.size === 0) await rm(placeholderPath, { force: true });
21709
+ };
21337
21710
  }
21711
+ if (!input || typeof input !== "object") return { input };
21712
+ const bounded = Array.isArray(input) ? {
21713
+ input,
21714
+ hasCutProperty: false
21715
+ } : boundedInputProperties(input);
21716
+ const serialized = serializedInputText(bounded.input);
21717
+ if (serialized.length > MAX_TRACE_CALL_INPUT_CHARS) return {
21718
+ input: serialized.slice(0, MAX_TRACE_BODY_CHARS),
21719
+ truncated: true
21720
+ };
21721
+ if (!bounded.hasCutProperty) return { input };
21722
+ return {
21723
+ input: bounded.input,
21724
+ truncated: true
21725
+ };
21338
21726
  }
21339
- async function createMissingMountPoints(mountPoints) {
21340
- for (const mountPoint of mountPoints) {
21341
- if (!await isRealDirectory$1(path.dirname(mountPoint))) continue;
21342
- await mkdir(mountPoint).catch((error) => {
21343
- if (errorCode(error) !== "EEXIST") throw error;
21344
- });
21345
- }
21727
+ function everyTextBlockJoined(blocks) {
21728
+ const blockTexts = blocks.flatMap((block) => firstTextBlock([block]) ?? []);
21729
+ if (blockTexts.length === 0) return null;
21730
+ return blockTexts.join("\n");
21346
21731
  }
21347
- async function isNewerThanTarget(linkPath, targetPath) {
21348
- const targetStats = await stat(targetPath).catch(() => null);
21349
- if (targetStats === null) return true;
21350
- return (await lstat(linkPath)).mtimeMs > targetStats.mtimeMs;
21732
+ function isTaskNotificationLine(line) {
21733
+ return line.origin?.kind === "task-notification" || line.turnOrigin?.kind === "task_notification";
21351
21734
  }
21352
- async function keepRefreshedLogins(logins, launchId, { onlyWhenNewer }) {
21353
- for (const { linkPath, targetPath } of logins) {
21354
- if (!await isRegularFile(linkPath)) continue;
21355
- if (onlyWhenNewer && !await isNewerThanTarget(linkPath, targetPath)) continue;
21356
- const stagedPath = `${targetPath}.${launchId}`;
21357
- await copyFile(linkPath, stagedPath);
21358
- await chmod(stagedPath, LOGIN_FILE_MODE);
21359
- await rename(stagedPath, targetPath);
21735
+ function mapUserLine(rawLine, line, context) {
21736
+ const base = baseRecord(line, context);
21737
+ const content = line.message?.content;
21738
+ const blocks = contentBlocks(line);
21739
+ const toolResult = blocks.find((block) => block.type === "tool_result");
21740
+ if (toolResult) {
21741
+ const toolUseId = rawTextOr(toolResult.tool_use_id, null);
21742
+ if (!toolUseId) return [rawRecord(rawLine, line, context)];
21743
+ const bounded = boundedText(textContent(toolResult.content));
21744
+ return [{
21745
+ ...base,
21746
+ kind: "tool_result",
21747
+ toolUseId,
21748
+ content: bounded.text,
21749
+ isError: toolResult.is_error === true,
21750
+ truncated: bounded.truncated
21751
+ }];
21360
21752
  }
21361
- }
21362
- async function removeLaunch(folders, owner, launchId, { onlyNewerLogins }) {
21363
- await rm(folders.policyPath, { force: true });
21364
- await removeLeftoverPlaceholders(owner.placeholderPaths);
21365
- await keepRefreshedLogins(owner.logins.filter((login) => isPathInside(folders.launchHomeDir, login.linkPath, { allowEqual: false })), launchId, { onlyWhenNewer: onlyNewerLogins });
21366
- await rm(folders.launchHomeDir, {
21367
- recursive: true,
21368
- force: true
21369
- });
21370
- if (folders.ownedTempDir !== null) await rm(folders.ownedTempDir, {
21371
- recursive: true,
21372
- force: true
21373
- });
21374
- await rm(folders.ownerPath, { force: true });
21375
- }
21376
- function isProcessAlive$1(pid) {
21377
- try {
21378
- process.kill(pid, 0);
21379
- return true;
21380
- } catch (error) {
21381
- return errorCode(error) === "EPERM";
21753
+ if (line.isMeta === true) {
21754
+ const expansionText = typeof content === "string" ? content : everyTextBlockJoined(blocks);
21755
+ if (!expansionText) return [rawRecord(rawLine, line, context)];
21756
+ const sourceToolUseId = rawTextOr(line.sourceToolUseID, null);
21757
+ if (!sourceToolUseId) return [{
21758
+ ...base,
21759
+ kind: "expansion",
21760
+ ...boundedTextFields(expansionText)
21761
+ }];
21762
+ return [{
21763
+ ...base,
21764
+ kind: "expansion",
21765
+ toolUseId: sourceToolUseId,
21766
+ ...boundedTextFields(expansionText)
21767
+ }];
21382
21768
  }
21769
+ const text = typeof content === "string" ? content : firstTextBlock(blocks);
21770
+ if (!text) return [rawRecord(rawLine, line, context)];
21771
+ if (isTaskNotificationLine(line)) return [{
21772
+ ...base,
21773
+ kind: "expansion",
21774
+ ...boundedTextFields(text)
21775
+ }];
21776
+ if (typeof content === "string" && /<command-name>[\s\S]*?<\/command-name>/.test(content)) return [{
21777
+ ...base,
21778
+ kind: "expansion",
21779
+ ...boundedTextFields(content)
21780
+ }];
21781
+ return [{
21782
+ ...base,
21783
+ kind: "prompt",
21784
+ ...boundedTextFields(text)
21785
+ }];
21383
21786
  }
21384
- function readOwnPidNamespace() {
21385
- return readlink(OWN_PID_NAMESPACE_LINK).catch(() => null);
21787
+ function queuedCommandText(prompt) {
21788
+ if (typeof prompt === "string") return prompt || null;
21789
+ return firstTextBlock(objectBlocks(prompt));
21386
21790
  }
21387
- async function readOwnerFile(ownerPath) {
21388
- const outcome = await loadJsonStateFile({
21389
- filePath: ownerPath,
21390
- quarantine: false,
21391
- parse: (raw) => GuardrailsLaunchOwner.safeParse(raw).data ?? null
21392
- });
21393
- return outcome.status === "loaded" ? outcome.value : null;
21791
+ function queuedCommandRecords(line, context) {
21792
+ const attachment = line.attachment;
21793
+ if (line.type !== "attachment" || attachment?.type !== "queued_command") return null;
21794
+ const text = queuedCommandText(attachment.prompt);
21795
+ if (!text) return null;
21796
+ if (attachment.commandMode === "prompt" && attachment.origin?.kind === "human") return [{
21797
+ ...baseRecord(line, context),
21798
+ kind: "prompt",
21799
+ ...boundedTextFields(text)
21800
+ }];
21801
+ if (attachment.commandMode === "task-notification") return [{
21802
+ ...baseRecord(line, context),
21803
+ kind: "expansion",
21804
+ ...boundedTextFields(text)
21805
+ }];
21806
+ return null;
21394
21807
  }
21395
- async function sweepOrphanedGuardrailsLaunches(log = console) {
21396
- try {
21397
- const policyDir = path.join(glimmervoidHomeDir$1(), POLICY_FOLDER);
21398
- const entryNames = await readdir(policyDir).catch((error) => {
21399
- if (isMissingFileError(error)) return [];
21400
- throw error;
21401
- });
21402
- const glimmervoidHome = await realpath(glimmervoidHomeDir$1());
21403
- const sweeperPidNamespace = await readOwnPidNamespace();
21404
- let removedLaunchCount = 0;
21405
- for (const entryName of entryNames) {
21406
- if (!entryName.endsWith(OWNER_FILE_SUFFIX)) continue;
21407
- const launchId = entryName.slice(0, -11);
21408
- if (!LAUNCH_ID_SHAPE.test(launchId)) continue;
21409
- const ownerPath = path.join(policyDir, entryName);
21410
- const owner = await readOwnerFile(ownerPath);
21411
- if (owner === null || owner.ownerHost !== os.hostname() || owner.ownerPidNamespace !== sweeperPidNamespace || isProcessAlive$1(owner.ownerPid)) continue;
21412
- try {
21413
- await removeLaunch({
21414
- policyPath: path.join(policyDir, `${launchId}.json`),
21415
- ownerPath,
21416
- launchHomeDir: path.join(glimmervoidHome, LAUNCH_HOME_FOLDER, launchId),
21417
- ownedTempDir: owner.ownsTempDir ? path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER, launchId) : null
21418
- }, owner, launchId, { onlyNewerLogins: true });
21419
- removedLaunchCount += 1;
21420
- } catch (error) {
21421
- log.warn(`[guardrails] could not remove the leftover launch ${launchId}: ${errorMessage(error)}`);
21808
+ function mapAssistantLine(rawLine, line, context) {
21809
+ const base = baseRecord(line, context);
21810
+ const records = [];
21811
+ let hasSkippedThinkingBlock = false;
21812
+ for (const block of contentBlocks(line)) {
21813
+ if (block.type === "thinking" && typeof block.thinking === "string") {
21814
+ if (block.thinking.length === 0) {
21815
+ hasSkippedThinkingBlock = true;
21816
+ continue;
21422
21817
  }
21818
+ records.push({
21819
+ ...base,
21820
+ kind: "thinking",
21821
+ ...boundedTextFields(block.thinking)
21822
+ });
21823
+ continue;
21423
21824
  }
21424
- if (removedLaunchCount > 0) log.log(`[guardrails] removed ${removedLaunchCount} launch folders left by sessions that ended without a clean shutdown`);
21425
- } catch (error) {
21426
- log.warn(`[guardrails] could not sweep leftover launch folders: ${errorMessage(error)}`);
21825
+ if (block.type === "text") {
21826
+ const text = firstTextBlock([block]);
21827
+ if (text) records.push({
21828
+ ...base,
21829
+ kind: "assistant",
21830
+ ...boundedTextFields(text)
21831
+ });
21832
+ continue;
21833
+ }
21834
+ if (block.type !== "tool_use") continue;
21835
+ const toolUseId = rawTextOr(block.id, null);
21836
+ const name = rawTextOr(block.name, null);
21837
+ if (!toolUseId || !name) return [rawRecord(rawLine, line, context)];
21838
+ records.push({
21839
+ ...base,
21840
+ kind: "tool_call",
21841
+ toolUseId,
21842
+ name,
21843
+ ...boundedToolCallInput(block.input)
21844
+ });
21427
21845
  }
21846
+ if (records.length === 0 && hasSkippedThinkingBlock) return [];
21847
+ if (records.length === 0) return [rawRecord(rawLine, line, context)];
21848
+ return records;
21428
21849
  }
21429
- async function pruneLeftoverSessionTempFolders(glimmervoidHome, liveSessionIds, log = console) {
21430
- const policyEntryNames = await readdir(path.join(glimmervoidHome, POLICY_FOLDER)).catch((error) => {
21431
- if (isMissingFileError(error)) return [];
21432
- log.warn(`[guardrails] kept every session temp folder because the launch list could not be read: ${errorMessage(error)}`);
21433
- return null;
21434
- });
21435
- if (policyEntryNames === null) return;
21436
- const ownerEntryNames = policyEntryNames.filter((entryName) => entryName.endsWith(OWNER_FILE_SUFFIX));
21437
- const owners = await Promise.all(ownerEntryNames.map((entryName) => readOwnerFile(path.join(glimmervoidHome, POLICY_FOLDER, entryName))));
21438
- const tempFolderNamesWithOwners = /* @__PURE__ */ new Set([...ownerEntryNames.map((entryName) => entryName.slice(0, -11)), ...owners.flatMap((owner) => owner?.keptTempFolderName === void 0 ? [] : [owner.keptTempFolderName])]);
21439
- await pruneAgedFiles({
21440
- directory: path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER),
21441
- suffixes: [""],
21442
- retainDays: SESSION_TEMP_RETAIN_DAYS,
21443
- entryMode: "directory",
21444
- isRetainedId: (id) => liveSessionIds.has(id) || tempFolderNamesWithOwners.has(id)
21445
- });
21850
+ function traceRecordsFromTranscriptLine(rawLine, context) {
21851
+ const line = parseTranscriptLine(rawLine);
21852
+ if (!line) return [rawRecord(rawLine, null, context)];
21853
+ const queuedRecords = queuedCommandRecords(line, context);
21854
+ if (queuedRecords) return queuedRecords;
21855
+ if (isDroppedLine(line)) return [];
21856
+ if (line.type === "user") return mapUserLine(rawLine, line, context);
21857
+ if (line.type === "assistant") return mapAssistantLine(rawLine, line, context);
21858
+ return [rawRecord(rawLine, line, context)];
21446
21859
  }
21447
- function launcherCommand(plan, policyPath) {
21448
- if (plan.launcher === "open-network") return {
21449
- file: process.execPath,
21450
- args: [relayPath("guardrails-open-launcher"), policyPath]
21451
- };
21452
- const runtimeCliPath = resolvePackageBin("@anthropic-ai/sandbox-runtime", "srt");
21453
- if (!runtimeCliPath) return null;
21860
+ //#endregion
21861
+ //#region server/core/investigation-trail-core.ts
21862
+ var TRAIL_MAX_STEPS = 80;
21863
+ var TRAIL_TOOL_MAX_CHARS = 64;
21864
+ var TRAIL_NOTE_MAX_CHARS = 600;
21865
+ function describeToolStep(toolName, toolInput) {
21866
+ const trimmed = typeof toolName === "string" ? toolName.trim() : "";
21867
+ if (!trimmed) return null;
21868
+ const tool = trimmed.slice(0, TRAIL_TOOL_MAX_CHARS);
21454
21869
  return {
21455
- file: process.execPath,
21456
- args: [
21457
- runtimeCliPath,
21458
- "--settings",
21459
- policyPath,
21460
- "--"
21461
- ]
21870
+ tool,
21871
+ detail: toolDetailLine(tool, toolInput)
21462
21872
  };
21463
21873
  }
21464
- function guardedEnvPrefix(plan) {
21465
- const assignments = Object.entries(plan.guardedEnv).map(([name, value]) => `${name}=${value}`);
21466
- return assignments.length === 0 ? [] : [GUARDED_ENV_COMMAND, ...assignments];
21467
- }
21468
- function enteringFolder(enterDir, file, args) {
21469
- if (enterDir === void 0) return [file, ...args];
21470
- return [
21471
- "/bin/sh",
21472
- "-c",
21473
- ENTER_FOLDER_SCRIPT,
21474
- "sh",
21475
- enterDir,
21476
- file,
21477
- ...args
21478
- ];
21874
+ function trailStepFromHook(event, payload) {
21875
+ if (String(event ?? "").toLowerCase() !== "pretooluse") return null;
21876
+ return describeToolStep(payload.tool_name, payload.tool_input);
21479
21877
  }
21480
- function launchTempDirFor(glimmervoidHome, launchId, tempDir, keptTempFolderName) {
21481
- if (tempDir !== void 0) return path.resolve(tempDir);
21482
- return path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER, keptTempFolderName ?? launchId);
21878
+ function trailNotesFromTranscriptLines(lines, now) {
21879
+ return lines.flatMap((line) => traceRecordsFromTranscriptLine(line, {
21880
+ vendorSessionId: "",
21881
+ now
21882
+ })).flatMap((record) => record.kind === "assistant" ? [record.text.trim().slice(0, TRAIL_NOTE_MAX_CHARS)] : []).filter((note) => note !== "");
21483
21883
  }
21484
- async function prepareGuardrailsLaunch({ role, launchId, tempDir, keptTempFolderName, enterDir }) {
21485
- if (!LAUNCH_ID_SHAPE.test(launchId)) return {
21486
- ok: false,
21487
- reason: "guardrails launch id is invalid"
21884
+ function createInvestigationTrail(startedAt) {
21885
+ return {
21886
+ startedAt,
21887
+ steps: []
21488
21888
  };
21489
- if (keptTempFolderName !== void 0 && !LAUNCH_ID_SHAPE.test(keptTempFolderName)) return {
21490
- ok: false,
21491
- reason: "guardrails temp folder name is invalid"
21889
+ }
21890
+ function appendTrailStep(trail, step, maxSteps = TRAIL_MAX_STEPS) {
21891
+ const isAppendingNote = isTrailNote(step);
21892
+ const sameKindEntries = trail.steps.filter((entry) => isTrailNote(entry) === isAppendingNote);
21893
+ const evictedCount = Math.max(0, sameKindEntries.length + 1 - maxSteps);
21894
+ const evictedEntries = new Set(sameKindEntries.slice(0, evictedCount));
21895
+ const keptEntries = trail.steps.filter((entry) => !evictedEntries.has(entry));
21896
+ return {
21897
+ startedAt: trail.startedAt,
21898
+ steps: [...keptEntries, step]
21492
21899
  };
21493
- try {
21494
- const policyDir = path.join(glimmervoidHomeDir$1(), POLICY_FOLDER);
21495
- await mkdir(policyDir, {
21496
- recursive: true,
21497
- mode: 448
21498
- });
21499
- const [homeDir, glimmervoidHome, realRole, ownerPidNamespace] = await Promise.all([
21500
- realpath(os.homedir()),
21501
- realpath(glimmervoidHomeDir$1()),
21502
- withRealRoots(role),
21503
- readOwnPidNamespace()
21504
- ]);
21505
- const ownsTempDir = tempDir === void 0 && keptTempFolderName === void 0;
21506
- const launchTempDir = launchTempDirFor(glimmervoidHome, launchId, tempDir, keptTempFolderName);
21507
- const launchHomeDir = path.join(glimmervoidHome, LAUNCH_HOME_FOLDER, launchId);
21508
- const vendorLocations = await resolveVendorLocations(process.env, homeDir);
21509
- if (vendorLocations === null) return {
21510
- ok: false,
21511
- reason: "CODEX_HOME names no folder"
21512
- };
21513
- const xdgConfigHomeOverride = rawTextOr(process.env.XDG_CONFIG_HOME, null);
21514
- const stableHostPaths = {
21515
- homeDir,
21516
- glimmervoidHome,
21517
- glimmervoidConfigFile: await configuredConfigFile(glimmervoidHome),
21518
- tempDir: launchTempDir,
21519
- launchHomeDir,
21520
- vendorLocations,
21521
- unwrappedVendorHomes: await realPathsWhenPresent(grokHomes(process.env, homeDir)),
21522
- relocatedXdgConfigHome: xdgConfigHomeOverride === null ? null : await realPathWhenPresent(xdgConfigHomeOverride)
21523
- };
21524
- const buildPlanFromCurrentDisk = async () => {
21525
- const [homeEntryNames, glimmervoidHomeEntryNames] = await Promise.all([readdir(homeDir), readdir(glimmervoidHome)]);
21526
- const hostPaths = {
21527
- ...stableHostPaths,
21528
- homeEntryNames,
21529
- glimmervoidHomeEntryNames
21530
- };
21531
- const [existingPaths, writeBlockedPaths] = await Promise.all([presentPaths$1(guardrailsPolicyProbePaths(realRole, hostPaths)), blockedPathsWithRealTargets(standardWriteBlockCandidates(realRole, hostPaths), realRole.blockedPaths ?? [])]);
21532
- return buildGuardrailsLaunchPlan(realRole, {
21533
- ...hostPaths,
21534
- existingPaths,
21535
- writeBlockedPaths
21536
- });
21537
- };
21538
- const built = await buildPlanFromCurrentDisk();
21539
- if (!built.ok) return built;
21540
- const { plan } = built;
21541
- const policyPath = path.join(policyDir, `${launchId}.json`);
21542
- const launcher = launcherCommand(plan, policyPath);
21543
- if (!launcher) return {
21544
- ok: false,
21545
- reason: "the sandbox runtime CLI could not be resolved"
21546
- };
21547
- await Promise.all(plan.requiredDirectories.map((directory) => mkdir(directory, { recursive: true })));
21548
- const startDir = enterDir === void 0 ? void 0 : path.join(launchTempDir, START_FOLDER);
21549
- if (startDir !== void 0) await mkdir(startDir, { recursive: true });
21550
- await Promise.all(plan.launchHomeLinks.map((link) => symlink(link.targetPath, link.linkPath)));
21551
- await writeJsonAtomic(policyPath, plan.policy);
21552
- const folders = {
21553
- policyPath,
21554
- ownerPath: path.join(policyDir, `${launchId}${OWNER_FILE_SUFFIX}`),
21555
- launchHomeDir,
21556
- ownedTempDir: ownsTempDir ? launchTempDir : null
21557
- };
21558
- const owner = {
21559
- ownerPid: process.pid,
21560
- ownerHost: os.hostname(),
21561
- ownerPidNamespace,
21562
- ownsTempDir,
21563
- ...keptTempFolderName === void 0 ? {} : { keptTempFolderName },
21564
- logins: plan.launchHomeLinks.filter((link) => link.isLogin).map(({ linkPath, targetPath }) => ({
21565
- linkPath,
21566
- targetPath
21567
- })),
21568
- placeholderPaths: []
21569
- };
21570
- await writeJsonAtomic(folders.ownerPath, owner);
21571
- const envPrefix = guardedEnvPrefix(plan);
21572
- return {
21573
- ok: true,
21574
- launch: {
21575
- wrap: async (file, args, { hasTerminal }) => {
21576
- const rebuilt = await buildPlanFromCurrentDisk();
21577
- if (!rebuilt.ok) throw new Error(rebuilt.reason);
21578
- await writeJsonAtomic(policyPath, {
21579
- ...rebuilt.plan.policy,
21580
- allowPty: hasTerminal && rebuilt.plan.launcher === "open-network"
21581
- });
21582
- owner.placeholderPaths = await absentPaths(guardrailsPlaceholderPaths(realRole));
21583
- await writeJsonAtomic(folders.ownerPath, owner);
21584
- await createMissingMountPoints(lockedClaudeMountPoints(realRole));
21585
- return {
21586
- file: launcher.file,
21587
- args: [
21588
- ...launcher.args,
21589
- ...envPrefix,
21590
- ...enteringFolder(enterDir, file, args)
21591
- ]
21592
- };
21593
- },
21594
- env: {
21595
- ...plan.launchEnv,
21596
- ...bridgeSocketLauncherEnv(os.tmpdir(), process.platform)
21597
- },
21598
- ...startDir === void 0 ? {} : { cwd: startDir },
21599
- dispose: () => removeLaunch(folders, owner, launchId, { onlyNewerLogins: false })
21600
- }
21601
- };
21602
- } catch (error) {
21603
- return {
21604
- ok: false,
21605
- reason: errorMessage(error)
21606
- };
21607
- }
21900
+ }
21901
+ function isTrailNote(entry) {
21902
+ return "note" in entry;
21608
21903
  }
21609
21904
  //#endregion
21610
21905
  //#region server/lanes/lane-spawn.ts
@@ -21625,7 +21920,7 @@ var LANE_SPAWN_DENY_TOOLS = Object.freeze([
21625
21920
  async function writeStandaloneDenySettings(permissions, userHooks) {
21626
21921
  const settingsDirectory = await makeHostScratchDirectory(SETTINGS_DIR_PREFIX);
21627
21922
  const settingsPath = path.join(settingsDirectory, "settings.json");
21628
- const removeSettingsDirectory = () => fsp.rm(settingsDirectory, {
21923
+ const removeSettingsDirectory = () => fs$1.rm(settingsDirectory, {
21629
21924
  recursive: true,
21630
21925
  force: true
21631
21926
  }).catch(() => {});
@@ -21725,7 +22020,7 @@ function createLaneSpawn({ sessions = /* @__PURE__ */ new Map(), closeSessionDat
21725
22020
  }
21726
22021
  async function readLaneResultFile(resultPath) {
21727
22022
  try {
21728
- return JSON.parse(await fsp.readFile(resultPath, "utf8"));
22023
+ return JSON.parse(await fs$1.readFile(resultPath, "utf8"));
21729
22024
  } catch {
21730
22025
  return null;
21731
22026
  }
@@ -21736,12 +22031,12 @@ var THREAD_JUDGE_TOOLS = Object.freeze(["Read", "Write"]);
21736
22031
  var THREAD_JUDGE_TIMEOUT_MS = 12e4;
21737
22032
  function createThreadJudge(spawn, shutdownSignal) {
21738
22033
  return async (prompt) => {
21739
- const workDir = await fsp.mkdtemp(path.join(os.tmpdir(), "glimmervoid-thread-judge-"));
22034
+ const workDir = await fs$1.mkdtemp(path.join(os.tmpdir(), "glimmervoid-thread-judge-"));
21740
22035
  const controller = new AbortController();
21741
22036
  const timeout = setTimeout(() => controller.abort(), THREAD_JUDGE_TIMEOUT_MS);
21742
22037
  timeout.unref();
21743
22038
  try {
21744
- await fsp.writeFile(path.join(workDir, "thread-prompt.txt"), prompt, "utf8");
22039
+ await fs$1.writeFile(path.join(workDir, "thread-prompt.txt"), prompt, "utf8");
21745
22040
  const signal = shutdownSignal ? AbortSignal.any([controller.signal, shutdownSignal]) : controller.signal;
21746
22041
  if (signal.aborted) return null;
21747
22042
  await spawn({
@@ -21756,7 +22051,7 @@ function createThreadJudge(spawn, shutdownSignal) {
21756
22051
  return parseThreadJudgeResult(await readLaneResultFile(path.join(workDir, "thread-result.json")));
21757
22052
  } finally {
21758
22053
  clearTimeout(timeout);
21759
- await fsp.rm(workDir, {
22054
+ await fs$1.rm(workDir, {
21760
22055
  recursive: true,
21761
22056
  force: true
21762
22057
  });
@@ -21773,13 +22068,14 @@ var GH_MERGE_FLAGS = {
21773
22068
  var MY_PR_MERGE_STATE_QUERY = `query($owner: String!, $name: String!, $number: Int!) {
21774
22069
  repository(owner: $owner, name: $name) { pullRequest(number: $number) { state isInMergeQueue autoMergeRequest { enabledAt } } }
21775
22070
  }`;
21776
- var GH_TIMEOUT_MS = 3e4;
22071
+ var GH_READ_TIMEOUT_MS = 15e3;
22072
+ var GH_WRITE_TIMEOUT_MS = 3e4;
21777
22073
  var GH_MAX_BUFFER_BYTES = 2097153;
21778
- function run(cmd, args, cwd, input, preserveOutput = false) {
22074
+ function run(cmd, args, cwd, input, preserveOutput = false, timeoutMs = GH_READ_TIMEOUT_MS) {
21779
22075
  return runCommand(cmd, args, {
21780
22076
  cwd,
21781
22077
  input,
21782
- timeoutMs: GH_TIMEOUT_MS,
22078
+ timeoutMs,
21783
22079
  maxBuffer: GH_MAX_BUFFER_BYTES,
21784
22080
  trim: !preserveOutput,
21785
22081
  keepStdoutOnFailure: true,
@@ -22084,9 +22380,9 @@ function conditionalGetResult(response) {
22084
22380
  }
22085
22381
  }
22086
22382
  function createPrGh(cwd, commandRunner = run) {
22087
- async function runGh(args, input, preserveOutput = false) {
22383
+ async function runGh(args, input, preserveOutput = false, timeoutMs = GH_READ_TIMEOUT_MS) {
22088
22384
  try {
22089
- return await commandRunner("gh", args, cwd, input, preserveOutput);
22385
+ return await commandRunner("gh", args, cwd, input, preserveOutput, timeoutMs);
22090
22386
  } catch (error) {
22091
22387
  return {
22092
22388
  ok: false,
@@ -22416,7 +22712,7 @@ function createPrGh(cwd, commandRunner = run) {
22416
22712
  repo,
22417
22713
  "--add-label",
22418
22714
  label.data
22419
- ]);
22715
+ ], void 0, false, GH_WRITE_TIMEOUT_MS);
22420
22716
  return {
22421
22717
  ok: response.ok,
22422
22718
  err: response.ok ? "" : response.err.trim() || "gh pr edit failed"
@@ -22440,7 +22736,7 @@ function createPrGh(cwd, commandRunner = run) {
22440
22736
  repo,
22441
22737
  "--body-file",
22442
22738
  "-"
22443
- ], comment.data);
22739
+ ], comment.data, false, GH_WRITE_TIMEOUT_MS);
22444
22740
  return {
22445
22741
  ok: response.ok,
22446
22742
  err: response.ok ? "" : response.err.trim() || "gh pr comment failed"
@@ -22513,7 +22809,7 @@ function createPrGh(cwd, commandRunner = run) {
22513
22809
  `query=${RESOLVE_THREAD_MUTATION}`,
22514
22810
  "-f",
22515
22811
  `id=${threadId}`
22516
- ]);
22812
+ ], void 0, false, GH_WRITE_TIMEOUT_MS);
22517
22813
  const parsed = TeamReviewResolveResponse.safeParse(parseJsonOrNull(response.out));
22518
22814
  const isResolved = response.ok && parsed.success && !parsed.data.errors?.length && parsed.data.data?.resolveReviewThread.thread.id === threadId;
22519
22815
  return {
@@ -22674,7 +22970,7 @@ function createPrGh(cwd, commandRunner = run) {
22674
22970
  `id=${pullRequestId}`,
22675
22971
  "-f",
22676
22972
  `head=${expectedHeadSha}`
22677
- ]);
22973
+ ], void 0, false, GH_WRITE_TIMEOUT_MS);
22678
22974
  if (!response.ok) return {
22679
22975
  ok: false,
22680
22976
  err: response.err.trim() || "gh graphql rebase failed"
@@ -22713,7 +23009,7 @@ function createPrGh(cwd, commandRunner = run) {
22713
23009
  GH_MERGE_FLAGS[parsedMethod.data],
22714
23010
  "--match-head-commit",
22715
23011
  headSha
22716
- ]);
23012
+ ], void 0, false, GH_WRITE_TIMEOUT_MS);
22717
23013
  if (!response.ok) return {
22718
23014
  ok: false,
22719
23015
  err: response.err.trim() || "gh pr merge failed"
@@ -22949,7 +23245,7 @@ function createPrGh(cwd, commandRunner = run) {
22949
23245
  `repos/${parts[0]}/${parts[1]}/pulls/${number}/reviews`,
22950
23246
  "--input",
22951
23247
  "-"
22952
- ], input);
23248
+ ], input, false, GH_WRITE_TIMEOUT_MS);
22953
23249
  if (!response.ok) return {
22954
23250
  ok: false,
22955
23251
  err: response.err.trim() || "gh review post failed",
@@ -22987,7 +23283,7 @@ function createPrGh(cwd, commandRunner = run) {
22987
23283
  `repos/${parts[0]}/${parts[1]}/pulls/${number}/reviews/${reviewId}/dismissals`,
22988
23284
  "--input",
22989
23285
  "-"
22990
- ], input);
23286
+ ], input, false, GH_WRITE_TIMEOUT_MS);
22991
23287
  return {
22992
23288
  ok: response.ok,
22993
23289
  err: response.ok ? "" : response.err.trim() || "gh review dismissal failed"
@@ -23341,7 +23637,7 @@ var PROCESS_LIST_TIMEOUT_MS = 5e3;
23341
23637
  var TERMINATION_GRACE_MS = 2e3;
23342
23638
  var EXIT_POLL_MS = 100;
23343
23639
  async function resolvedPath(directory) {
23344
- return fsp.realpath(directory).catch(() => path.resolve(directory));
23640
+ return fs$1.realpath(directory).catch(() => path.resolve(directory));
23345
23641
  }
23346
23642
  async function listTeamReviewProcesses() {
23347
23643
  if (process.platform !== "darwin" && process.platform !== "linux") return [];
@@ -23358,7 +23654,7 @@ async function listTeamReviewProcesses() {
23358
23654
  const rows = parseProcessTable(stdout);
23359
23655
  if (process.platform === "linux") return Promise.all(rows.map(async (row) => ({
23360
23656
  ...row,
23361
- cwd: await fsp.readlink(`/proc/${row.pid}/cwd`).then((cwd) => path.resolve(cwd)).catch(() => null)
23657
+ cwd: await fs$1.readlink(`/proc/${row.pid}/cwd`).then((cwd) => path.resolve(cwd)).catch(() => null)
23362
23658
  })));
23363
23659
  const { stdout: cwdOutput } = await execFileAsync("lsof", [
23364
23660
  "-a",
@@ -23373,7 +23669,7 @@ async function listTeamReviewProcesses() {
23373
23669
  const cwdByPid = parseCwdTable(cwdOutput);
23374
23670
  return Promise.all(rows.map(async (row) => ({
23375
23671
  ...row,
23376
- cwd: await fsp.realpath(cwdByPid.get(row.pid) ?? "").catch(() => null)
23672
+ cwd: await fs$1.realpath(cwdByPid.get(row.pid) ?? "").catch(() => null)
23377
23673
  })));
23378
23674
  }
23379
23675
  function isMissingProcess(error) {
@@ -24120,9 +24416,13 @@ function createTeamReviewPoller(deps) {
24120
24416
  }
24121
24417
  async function rateLimitedOutcome() {
24122
24418
  const rateLimitWaitMs = await store.rateLimitWaitMs(now(), TEAM_REVIEW_RATE_LIMIT_RESOURCES) ?? secondaryRateLimitWaitMs(pollingError);
24123
- return rateLimitWaitMs === null ? { failed: true } : {
24419
+ return rateLimitWaitMs === null ? {
24124
24420
  failed: true,
24125
- retryAfterMs: rateLimitWaitMs
24421
+ error: pollingError ?? void 0
24422
+ } : {
24423
+ failed: true,
24424
+ retryAfterMs: rateLimitWaitMs,
24425
+ error: pollingError ?? void 0
24126
24426
  };
24127
24427
  }
24128
24428
  async function runTick() {
@@ -24137,7 +24437,8 @@ function createTeamReviewPoller(deps) {
24137
24437
  pollingError = "GitHub rate limit asks to wait.";
24138
24438
  return {
24139
24439
  failed: true,
24140
- retryAfterMs: tickRateLimitWaitMs
24440
+ retryAfterMs: tickRateLimitWaitMs,
24441
+ error: pollingError
24141
24442
  };
24142
24443
  }
24143
24444
  if (collected === null) {
@@ -24155,7 +24456,8 @@ function createTeamReviewPoller(deps) {
24155
24456
  pollingError = "GitHub rate limit asks to wait.";
24156
24457
  return {
24157
24458
  failed: true,
24158
- retryAfterMs: rateLimitWaitMs
24459
+ retryAfterMs: rateLimitWaitMs,
24460
+ error: pollingError
24159
24461
  };
24160
24462
  }
24161
24463
  const isPruned = await pruneDeparted(new Set(candidates.map((candidate) => candidate.key)), isComplete);
@@ -24168,7 +24470,8 @@ function createTeamReviewPoller(deps) {
24168
24470
  pollingError = "GitHub rate limit asks to wait.";
24169
24471
  return {
24170
24472
  failed: true,
24171
- retryAfterMs: tickRateLimitWaitMs
24473
+ retryAfterMs: tickRateLimitWaitMs,
24474
+ error: pollingError
24172
24475
  };
24173
24476
  }
24174
24477
  if (hasSlotFreedSinceSlotCount && waitingForSlot.length > 0 && !loop.isStopped()) setTimeoutFn(() => {
@@ -24421,10 +24724,11 @@ function createTeamReviewPoller(deps) {
24421
24724
  error: "Reviews polling is stopped."
24422
24725
  };
24423
24726
  if (watches.size === 0) await collectCandidates();
24424
- const refreshed = await store.refreshWatches([...watches.keys()]);
24425
- rebuild();
24426
- if (!refreshed.ok) return refreshed;
24427
- return loop.refresh();
24727
+ return loop.refresh(async () => {
24728
+ const refreshed = await store.refreshWatches([...watches.keys()]);
24729
+ rebuild();
24730
+ return refreshed;
24731
+ });
24428
24732
  }
24429
24733
  async function stop() {
24430
24734
  hasLoadedState = false;
@@ -24819,7 +25123,7 @@ function listHomeWorktreePathsMissingLock(porcelain, glimmervoidHomes) {
24819
25123
  }
24820
25124
  //#endregion
24821
25125
  //#region server/git/git-workspace.ts
24822
- var fsp$1 = fs.promises;
25126
+ var fsp = fs.promises;
24823
25127
  var MERGE_PROBE_TIMEOUT_MS = 3e4;
24824
25128
  var REMOTE_REF_PREFIX = "refs/remotes/origin/";
24825
25129
  var REMOTE_BRANCH_LISTING_MAX_BUFFER = 67108864;
@@ -24891,7 +25195,7 @@ function comparableGlimmervoidHomes(glimmervoidHome) {
24891
25195
  }
24892
25196
  async function directoryExists$1(candidatePath) {
24893
25197
  try {
24894
- await fsp$1.access(candidatePath);
25198
+ await fsp.access(candidatePath);
24895
25199
  return true;
24896
25200
  } catch {
24897
25201
  return false;
@@ -25051,13 +25355,19 @@ function createGitWorkspace(opts = {}) {
25051
25355
  }
25052
25356
  }
25053
25357
  const runInProject = (projectPath) => (args) => run(args, projectPath);
25054
- async function addWorktreeEntry(runGitInProject, worktreePath, addArgs) {
25358
+ async function addWorktreeEntry(runGitInProject, worktreePath, addArgs, ownership) {
25055
25359
  const added = await runGitInProject([
25056
25360
  "worktree",
25057
25361
  "add",
25058
25362
  ...addArgs
25059
25363
  ]);
25060
- if (!added.ok || !isWorktreeHiddenFromGuardedSessions(worktreePath, glimmervoidHomes)) return added;
25364
+ if (!added.ok) return added;
25365
+ await opts.ownedPaths?.record({
25366
+ path: worktreePath,
25367
+ kind: "git-worktree",
25368
+ ...ownership
25369
+ });
25370
+ if (!isWorktreeHiddenFromGuardedSessions(worktreePath, glimmervoidHomes)) return added;
25061
25371
  await lockWorktreeEntry(runGitInProject, worktreePath);
25062
25372
  return added;
25063
25373
  }
@@ -25083,12 +25393,27 @@ function createGitWorkspace(opts = {}) {
25083
25393
  "unlock",
25084
25394
  worktreePath
25085
25395
  ]);
25086
- return runGitInProject([
25396
+ const removed = await runGitInProject([
25087
25397
  "worktree",
25088
25398
  "remove",
25089
25399
  ...removeFlags,
25090
25400
  worktreePath
25091
25401
  ]);
25402
+ await forgetRemovedPath(worktreePath);
25403
+ return removed;
25404
+ }
25405
+ async function forgetRemovedPath(ownedPath) {
25406
+ if (await directoryExists$1(ownedPath)) return;
25407
+ await opts.ownedPaths?.forget(ownedPath);
25408
+ }
25409
+ async function recordOwnedFolder({ folderPath, owner }) {
25410
+ await opts.ownedPaths?.record({
25411
+ path: folderPath,
25412
+ owner,
25413
+ kind: "folder",
25414
+ projectPath: null,
25415
+ branch: null
25416
+ });
25092
25417
  }
25093
25418
  async function pruneWorktreeEntries(runGitInProject) {
25094
25419
  const listed = await runGitInProject([
@@ -25326,7 +25651,7 @@ function createGitWorkspace(opts = {}) {
25326
25651
  }
25327
25652
  return null;
25328
25653
  }
25329
- async function createBody({ projectPath, teamId, label, baseBranch = null, configuredIntegrationBranch = null, forkFromHead = false, worktreeBase, shareList }) {
25654
+ async function createBody({ projectPath, owner, teamId, label, baseBranch = null, configuredIntegrationBranch = null, forkFromHead = false, worktreeBase, shareList }) {
25330
25655
  const inside = await run(["rev-parse", "--is-inside-work-tree"], projectPath);
25331
25656
  if (!inside.ok || inside.out !== "true") return {
25332
25657
  cwd: projectPath,
@@ -25405,7 +25730,11 @@ function createGitWorkspace(opts = {}) {
25405
25730
  branch,
25406
25731
  wtDir,
25407
25732
  baseSha
25408
- ]);
25733
+ ], {
25734
+ owner,
25735
+ projectPath,
25736
+ branch
25737
+ });
25409
25738
  if (!add.ok) {
25410
25739
  try {
25411
25740
  fs.rmSync(wtDir, {
@@ -25453,7 +25782,7 @@ function createGitWorkspace(opts = {}) {
25453
25782
  if (keepTrackableLinks) return;
25454
25783
  await refuseTrackableLinks(wtDir, ignored);
25455
25784
  }
25456
- async function ensureWorkspaceMemberBody({ projectPath, wtDir, branch, shareList }) {
25785
+ async function ensureWorkspaceMemberBody({ projectPath, owner, wtDir, branch, shareList }) {
25457
25786
  if (!wtDir || !branch) return {
25458
25787
  cwd: projectPath,
25459
25788
  isGit: false,
@@ -25504,7 +25833,11 @@ function createGitWorkspace(opts = {}) {
25504
25833
  "--quiet",
25505
25834
  `refs/heads/${branch}`
25506
25835
  ], projectPath)).ok) {
25507
- const attached = await addWorktreeEntry(runInProject(projectPath), wtDir, [wtDir, branch]);
25836
+ const attached = await addWorktreeEntry(runInProject(projectPath), wtDir, [wtDir, branch], {
25837
+ owner,
25838
+ projectPath,
25839
+ branch
25840
+ });
25508
25841
  if (!attached.ok) return {
25509
25842
  cwd: projectPath,
25510
25843
  isGit: false,
@@ -25555,7 +25888,11 @@ function createGitWorkspace(opts = {}) {
25555
25888
  branch,
25556
25889
  wtDir,
25557
25890
  baseSha
25558
- ]);
25891
+ ], {
25892
+ owner,
25893
+ projectPath,
25894
+ branch
25895
+ });
25559
25896
  if (!added.ok) return {
25560
25897
  cwd: projectPath,
25561
25898
  isGit: false,
@@ -25584,11 +25921,11 @@ function createGitWorkspace(opts = {}) {
25584
25921
  rel
25585
25922
  ], wtDir)).ok) continue;
25586
25923
  const target = path.join(wtDir, rel);
25587
- const stat = await fsp$1.lstat(target).catch(() => null);
25924
+ const stat = await fsp.lstat(target).catch(() => null);
25588
25925
  if (!stat || !stat.isSymbolicLink()) continue;
25589
25926
  console.warn(`[git-workspace] not sharing ${rel}: git does not ignore it as a link, so a commit in the worktree would carry it (use a slash-free .gitignore entry)`);
25590
25927
  try {
25591
- await fsp$1.rm(target, { force: true });
25928
+ await fsp.rm(target, { force: true });
25592
25929
  } catch {}
25593
25930
  }
25594
25931
  }
@@ -25849,7 +26186,7 @@ function createGitWorkspace(opts = {}) {
25849
26186
  for (const [index, segment] of pathSegments.entries()) {
25850
26187
  if (!segment || segment === "." || segment === "..") return false;
25851
26188
  checkedPath = path.join(checkedPath, segment);
25852
- const entryStats = await fsp$1.lstat(checkedPath).catch(() => null);
26189
+ const entryStats = await fsp.lstat(checkedPath).catch(() => null);
25853
26190
  if (!entryStats) return false;
25854
26191
  if (index === pathSegments.length - 1) return entryStats.isFile();
25855
26192
  if (!entryStats.isDirectory()) return false;
@@ -26079,7 +26416,7 @@ function createGitWorkspace(opts = {}) {
26079
26416
  ], projectPath);
26080
26417
  await pruneWorktreeEntries(runInProject(projectPath));
26081
26418
  }
26082
- async function probeWorktreeWork({ projectPath, cwd, branch, integrationBranch, configuredIntegrationBranch }) {
26419
+ async function probeWorktreeWork({ projectPath, cwd, branch, measuredTip = branch, integrationBranch, configuredIntegrationBranch }) {
26083
26420
  const { base: resolvedIntegrationBranch, measureRef } = await migrateMarkerBase(projectPath, branch, integrationBranch, configuredIntegrationBranch);
26084
26421
  const dirty = await run(WORK_PRESENCE_STATUS_ARGS, cwd);
26085
26422
  return {
@@ -26087,11 +26424,32 @@ function createGitWorkspace(opts = {}) {
26087
26424
  ahead: !isDirtyResult(dirty) && resolvedIntegrationBranch ? await run([
26088
26425
  "rev-list",
26089
26426
  "--count",
26090
- `${measureRef || resolvedIntegrationBranch}..${branch}`
26427
+ `${measureRef || resolvedIntegrationBranch}..${measuredTip}`
26091
26428
  ], projectPath) : null,
26092
26429
  integrationBranch: resolvedIntegrationBranch ?? null
26093
26430
  };
26094
26431
  }
26432
+ async function describeWorkspaceMemberWorkBody({ projectPath, cwd, branch }) {
26433
+ const memberHead = await run([
26434
+ "rev-parse",
26435
+ "--verify",
26436
+ "HEAD"
26437
+ ], cwd);
26438
+ if (!memberHead.ok || !memberHead.out) return "its checked-out commit could not be read";
26439
+ const integrationBranch = await detectDefaultBranch({ projectPath });
26440
+ const { dirty, ahead, integrationBranch: comparedBranch } = await probeWorktreeWork({
26441
+ projectPath,
26442
+ cwd,
26443
+ branch,
26444
+ measuredTip: memberHead.out,
26445
+ integrationBranch
26446
+ });
26447
+ if (!dirty.ok) return "its git status could not be read";
26448
+ if (isDirtyResult(dirty)) return "uncommitted changes";
26449
+ if (!ahead?.ok) return "its commits could not be compared with the base branch";
26450
+ if (!ahead.out || ahead.out === "0") return null;
26451
+ return `${ahead.out} ${ahead.out === "1" ? "commit" : "commits"} not on ${comparedBranch}`;
26452
+ }
26095
26453
  async function hasUnmergedWorkBody({ projectPath, workspace, integrationBranch, configuredIntegrationBranch }) {
26096
26454
  if (!workspace || !workspace.isGit || !workspace.cwd || !workspace.branch) return true;
26097
26455
  const { dirty, ahead } = await probeWorktreeWork({
@@ -26297,7 +26655,7 @@ function createGitWorkspace(opts = {}) {
26297
26655
  for (const rel of shareList ?? []) {
26298
26656
  if (!rel || String(rel).includes("..")) continue;
26299
26657
  const linkPath = path.join(wtDir, rel);
26300
- const stat = await fsp$1.lstat(linkPath).catch(() => null);
26658
+ const stat = await fsp.lstat(linkPath).catch(() => null);
26301
26659
  if (!stat || !stat.isSymbolicLink()) continue;
26302
26660
  if (!(await run([
26303
26661
  "check-ignore",
@@ -26305,21 +26663,30 @@ function createGitWorkspace(opts = {}) {
26305
26663
  "--",
26306
26664
  rel
26307
26665
  ], wtDir)).ok) continue;
26308
- await fsp$1.rm(linkPath, {
26666
+ await fsp.rm(linkPath, {
26309
26667
  recursive: false,
26310
26668
  force: true
26311
- }).catch(() => fsp$1.rmdir(linkPath)).catch(() => {});
26669
+ }).catch(() => fsp.rmdir(linkPath)).catch(() => {});
26312
26670
  }
26313
26671
  }
26314
- async function removeWorkspaceMemberBody({ projectPath, cwd, shareList }) {
26672
+ async function removeWorkspaceMemberBody({ projectPath, cwd, shareList, discardWork = false }) {
26315
26673
  if (!cwd) return {
26316
26674
  ok: false,
26317
26675
  out: "",
26318
26676
  err: "a workspace member removal needs a path"
26319
26677
  };
26320
26678
  await removeSharedLinks(cwd, shareList);
26321
- const removed = await removeWorktreeEntry(runInProject(projectPath), cwd, []);
26679
+ const removed = await removeWorktreeEntry(runInProject(projectPath), cwd, discardWork ? ["--force", "--force"] : []);
26680
+ if (discardWork && await directoryExists$1(cwd)) await fsp.rm(cwd, {
26681
+ recursive: true,
26682
+ force: true
26683
+ });
26322
26684
  await pruneWorktreeEntries(runInProject(projectPath));
26685
+ await forgetRemovedPath(cwd);
26686
+ if (discardWork && !await directoryExists$1(cwd)) return {
26687
+ ok: true,
26688
+ out: removed.out
26689
+ };
26323
26690
  return removed;
26324
26691
  }
26325
26692
  async function listWorktreeBranches({ projectPath }) {
@@ -26440,7 +26807,7 @@ function createGitWorkspace(opts = {}) {
26440
26807
  if (!updated.ok) return updated;
26441
26808
  return okResult(originSha);
26442
26809
  }
26443
- async function stageDetachedWorktreeBody({ projectPath, worktreePath, sha, disableHooks, replaceEnv }) {
26810
+ async function stageDetachedWorktreeBody({ projectPath, worktreePath, sha, owner, disableHooks, replaceEnv }) {
26444
26811
  if (!worktreePath) return {
26445
26812
  ok: false,
26446
26813
  out: "",
@@ -26458,7 +26825,11 @@ function createGitWorkspace(opts = {}) {
26458
26825
  "--detach",
26459
26826
  worktreePath,
26460
26827
  sha
26461
- ]);
26828
+ ], {
26829
+ owner,
26830
+ projectPath,
26831
+ branch: null
26832
+ });
26462
26833
  }
26463
26834
  async function checkoutDetachedBody({ worktreePath, sha, ...isolation }) {
26464
26835
  if (!worktreePath) return {
@@ -26517,8 +26888,8 @@ function createGitWorkspace(opts = {}) {
26517
26888
  err: commonDir.err || "the source repository has no git dir"
26518
26889
  };
26519
26890
  const sourceObjectsDir = path.join(path.resolve(projectPath, commonDir.out), "objects");
26520
- await fsp$1.mkdir(path.dirname(checkoutPath), { recursive: true });
26521
- await fsp$1.mkdir(checkoutPath);
26891
+ await fsp.mkdir(path.dirname(checkoutPath), { recursive: true });
26892
+ await fsp.mkdir(checkoutPath);
26522
26893
  const initialized = await run([
26523
26894
  "init",
26524
26895
  "--quiet",
@@ -26526,8 +26897,8 @@ function createGitWorkspace(opts = {}) {
26526
26897
  ], checkoutPath);
26527
26898
  if (!initialized.ok) return initialized;
26528
26899
  const alternatesPath = path.join(checkoutPath, ".git", "objects", "info", "alternates");
26529
- await fsp$1.mkdir(path.dirname(alternatesPath), { recursive: true });
26530
- await fsp$1.writeFile(alternatesPath, `${sourceObjectsDir}\n`, "utf8");
26900
+ await fsp.mkdir(path.dirname(alternatesPath), { recursive: true });
26901
+ await fsp.writeFile(alternatesPath, `${sourceObjectsDir}\n`, "utf8");
26531
26902
  for (const [ref, refSha] of [[ISOLATED_CHECKOUT_REVIEW_REF, sha], [ISOLATED_CHECKOUT_BASE_REF, baseSha]]) {
26532
26903
  const updated = await run([
26533
26904
  "update-ref",
@@ -26713,7 +27084,7 @@ function createGitWorkspace(opts = {}) {
26713
27084
  };
26714
27085
  const addedPaths = added.out.split("\0").filter(Boolean);
26715
27086
  const collidingPaths = [];
26716
- for (const addedPath of addedPaths) if (await fsp$1.lstat(path.join(checkoutPath, addedPath)).then(() => true, (error) => !isMissingFileError(error, { includeNotDir: false }))) collidingPaths.push(addedPath);
27087
+ for (const addedPath of addedPaths) if (await fsp.lstat(path.join(checkoutPath, addedPath)).then(() => true, (error) => !isMissingFileError(error, { includeNotDir: false }))) collidingPaths.push(addedPath);
26717
27088
  return {
26718
27089
  ok: true,
26719
27090
  collidingPaths
@@ -27049,6 +27420,9 @@ function createGitWorkspace(opts = {}) {
27049
27420
  pruneWorktrees: serialized(pruneWorktreesBody),
27050
27421
  discardSessionBranch: serialized(discardSessionBranchBody),
27051
27422
  stageDetachedWorktree: serialized(stageDetachedWorktreeBody),
27423
+ forgetRemovedPath,
27424
+ recordOwnedFolder,
27425
+ describeWorkspaceMemberWork: serialized(describeWorkspaceMemberWorkBody),
27052
27426
  checkoutDetached: serialized(checkoutDetachedBody),
27053
27427
  stageIsolatedCheckout,
27054
27428
  mergeFastForwardTo,
@@ -27214,6 +27588,7 @@ function createGitWorkspaceSync(opts = {}) {
27214
27588
  "--force",
27215
27589
  cwd
27216
27590
  ], projectPath);
27591
+ if (!fs.existsSync(cwd)) opts.ownedPaths?.forget(cwd);
27217
27592
  }
27218
27593
  if (branch) run([
27219
27594
  "branch",
@@ -27272,10 +27647,10 @@ async function populateWorktree(projectPath, wtDir, shareList) {
27272
27647
  const src = path.join(projectPath, rel);
27273
27648
  const dst = path.join(wtDir, rel);
27274
27649
  try {
27275
- const srcStat = await fsp$1.stat(src).catch(() => null);
27650
+ const srcStat = await fsp.stat(src).catch(() => null);
27276
27651
  if (!srcStat) continue;
27277
- if (await fsp$1.access(dst).then(() => true, (error) => !isMissingFileError(error, { includeNotDir: false }))) continue;
27278
- await fsp$1.mkdir(path.dirname(dst), { recursive: true });
27652
+ if (await fsp.access(dst).then(() => true, (error) => !isMissingFileError(error, { includeNotDir: false }))) continue;
27653
+ await fsp.mkdir(path.dirname(dst), { recursive: true });
27279
27654
  if (srcStat.isDirectory()) {
27280
27655
  if (process.platform === "win32") {
27281
27656
  await execFileAsync("cmd", [
@@ -27287,10 +27662,10 @@ async function populateWorktree(projectPath, wtDir, shareList) {
27287
27662
  ]);
27288
27663
  continue;
27289
27664
  }
27290
- await fsp$1.symlink(src, dst, "dir");
27665
+ await fsp.symlink(src, dst, "dir");
27291
27666
  continue;
27292
27667
  }
27293
- await fsp$1.copyFile(src, dst);
27668
+ await fsp.copyFile(src, dst);
27294
27669
  } catch {}
27295
27670
  }
27296
27671
  }
@@ -27443,7 +27818,7 @@ async function describeTeamReviewRole({ checkoutPath, cachedClone, linkedCheckou
27443
27818
  }
27444
27819
  async function linkedCheckoutUnreadablePaths(linkedCheckout) {
27445
27820
  if (linkedCheckout === null) return [];
27446
- return (await fsp.readdir(linkedCheckout)).filter((entryName) => LINKED_CHECKOUT_UNREADABLE_ENTRY.test(entryName)).map((entryName) => path.join(linkedCheckout, entryName));
27821
+ return (await fs$1.readdir(linkedCheckout)).filter((entryName) => LINKED_CHECKOUT_UNREADABLE_ENTRY.test(entryName)).map((entryName) => path.join(linkedCheckout, entryName));
27447
27822
  }
27448
27823
  function teamReviewClaudeArgs(tier, readable) {
27449
27824
  const model = tier === "full" ? FULL_MODEL : STAMP_MODEL;
@@ -27494,11 +27869,11 @@ function hooksPathPinnedSpawnEnv(workDir) {
27494
27869
  }
27495
27870
  async function makeTeamReviewWorkDir(root, prefix) {
27496
27871
  const safePrefix = `glimmervoid-wt-${TEAM_REVIEW_LANE_ID}-${prefix}`.replace(/[^\w.-]+/g, "-");
27497
- await fsp.mkdir(root, { recursive: true });
27498
- const dir = await fsp.mkdtemp(path.join(root, `${safePrefix}-`));
27872
+ await fs$1.mkdir(root, { recursive: true });
27873
+ const dir = await fs$1.mkdtemp(path.join(root, `${safePrefix}-`));
27499
27874
  return {
27500
27875
  dir,
27501
- cleanup: () => fsp.rm(dir, {
27876
+ cleanup: () => fs$1.rm(dir, {
27502
27877
  recursive: true,
27503
27878
  force: true
27504
27879
  }).catch(() => {})
@@ -27507,11 +27882,11 @@ async function makeTeamReviewWorkDir(root, prefix) {
27507
27882
  async function readReviewReport(reportPath, expectedHead, isReReview) {
27508
27883
  let report;
27509
27884
  try {
27510
- if ((await fsp.stat(reportPath)).size > RESULT_MAX_BYTES$1) return {
27885
+ if ((await fs$1.stat(reportPath)).size > RESULT_MAX_BYTES$1) return {
27511
27886
  ok: false,
27512
27887
  reason: "the review report is too large"
27513
27888
  };
27514
- report = await fsp.readFile(reportPath, "utf8");
27889
+ report = await fs$1.readFile(reportPath, "utf8");
27515
27890
  } catch {
27516
27891
  return {
27517
27892
  ok: false,
@@ -27532,11 +27907,11 @@ async function readReviewReport(reportPath, expectedHead, isReReview) {
27532
27907
  async function readPostingPlan(postingPath, expectedHead, log) {
27533
27908
  let json;
27534
27909
  try {
27535
- if ((await fsp.stat(postingPath)).size > RESULT_MAX_BYTES$1) {
27910
+ if ((await fs$1.stat(postingPath)).size > RESULT_MAX_BYTES$1) {
27536
27911
  log.warn(`[${TEAM_REVIEW_LANE_ID}] the posting plan is too large, rendering from the findings instead`);
27537
27912
  return null;
27538
27913
  }
27539
- json = await fsp.readFile(postingPath, "utf8");
27914
+ json = await fs$1.readFile(postingPath, "utf8");
27540
27915
  } catch {
27541
27916
  return null;
27542
27917
  }
@@ -27549,7 +27924,7 @@ function worktreeDirName(repo, number, suffix) {
27549
27924
  return `glimmervoid-wt-${TEAM_REVIEW_LANE_ID}-${repo.replace(/[^\w.-]+/g, "-")}-${number}-${suffix}`;
27550
27925
  }
27551
27926
  async function pathExists(candidatePath) {
27552
- return fsp.lstat(candidatePath).then(() => true, () => false);
27927
+ return fs$1.lstat(candidatePath).then(() => true, () => false);
27553
27928
  }
27554
27929
  function isDirectChildOf(root, candidatePath) {
27555
27930
  return path.dirname(path.resolve(candidatePath)) === path.resolve(root);
@@ -27559,10 +27934,10 @@ function isOwnedResumable(record, roots) {
27559
27934
  }
27560
27935
  async function isRealChildDirectoryOrMissing(root, candidatePath) {
27561
27936
  if (!isDirectChildOf(root, candidatePath)) return false;
27562
- const candidateStat = await fsp.lstat(candidatePath).catch((error) => isMissingFileError(error, { includeNotDir: false }) ? "missing" : null);
27937
+ const candidateStat = await fs$1.lstat(candidatePath).catch((error) => isMissingFileError(error, { includeNotDir: false }) ? "missing" : null);
27563
27938
  if (candidateStat === "missing") return true;
27564
27939
  if (!candidateStat?.isDirectory()) return false;
27565
- const realPaths = await Promise.all([fsp.realpath(candidatePath), fsp.realpath(root)]).catch(() => null);
27940
+ const realPaths = await Promise.all([fs$1.realpath(candidatePath), fs$1.realpath(root)]).catch(() => null);
27566
27941
  if (!realPaths) return false;
27567
27942
  const [realCandidatePath, realRootPath] = realPaths;
27568
27943
  return path.dirname(realCandidatePath) === realRootPath;
@@ -27579,13 +27954,17 @@ async function pruneCachedClone(gitWorkspace, projectPath, log) {
27579
27954
  if (!pruned.ok) log.warn(`[${TEAM_REVIEW_LANE_ID}] worktree prune failed in ${projectPath}: ${firstLine$1(pruned.err ?? "")}`);
27580
27955
  }
27581
27956
  async function deleteDirectory(directory, log) {
27582
- await fsp.rm(directory, {
27957
+ await fs$1.rm(directory, {
27583
27958
  recursive: true,
27584
27959
  force: true
27585
27960
  }).catch((error) => log.warn(`[${TEAM_REVIEW_LANE_ID}] could not delete ${directory}: ${errorMessage(error)}`));
27586
27961
  }
27962
+ async function deleteCheckout(gitWorkspace, worktreePath, log) {
27963
+ await deleteDirectory(worktreePath, log);
27964
+ await gitWorkspace.forgetRemovedPath?.(worktreePath);
27965
+ }
27587
27966
  async function isDirectory(candidatePath) {
27588
- return (await fsp.stat(candidatePath).catch(() => null))?.isDirectory() === true;
27967
+ return (await fs$1.stat(candidatePath).catch(() => null))?.isDirectory() === true;
27589
27968
  }
27590
27969
  async function mainCheckoutOf(checkoutPath) {
27591
27970
  const gitDirs = await readGitDirsOfOwnCheckout(checkoutPath).catch(() => null);
@@ -27597,17 +27976,17 @@ async function mainCheckoutOf(checkoutPath) {
27597
27976
  async function configuredProjectPathsByRealPath(projects) {
27598
27977
  const configuredPathByRealPath = /* @__PURE__ */ new Map();
27599
27978
  for (const project of projects) {
27600
- const projectRealPath = await fsp.realpath(project.path).catch(() => null);
27979
+ const projectRealPath = await fs$1.realpath(project.path).catch(() => null);
27601
27980
  if (projectRealPath === null || configuredPathByRealPath.has(projectRealPath)) continue;
27602
27981
  configuredPathByRealPath.set(projectRealPath, project.path);
27603
27982
  }
27604
27983
  return configuredPathByRealPath;
27605
27984
  }
27606
27985
  async function findLocalCheckout({ repo, config, excludedRoots, gitWorkspace, log, requireInstalledModules = true, resolveCheckout }) {
27607
- const resolvedExcludedRoots = await Promise.all(excludedRoots.map(async (root) => fsp.realpath(root).catch(() => path.resolve(root))));
27986
+ const resolvedExcludedRoots = await Promise.all(excludedRoots.map(async (root) => fs$1.realpath(root).catch(() => path.resolve(root))));
27608
27987
  const candidatePaths = (config.projects ?? []).map((project) => project.path);
27609
27988
  for (const root of config.repoRoots ?? []) {
27610
- const childNames = (await fsp.readdir(root, { withFileTypes: true }).catch((error) => {
27989
+ const childNames = (await fs$1.readdir(root, { withFileTypes: true }).catch((error) => {
27611
27990
  log.warn(`[${TEAM_REVIEW_LANE_ID}] could not list local repositories in ${root}: ${errorMessage(error)}`);
27612
27991
  return [];
27613
27992
  })).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules").map((entry) => entry.name).sort();
@@ -27615,7 +27994,7 @@ async function findLocalCheckout({ repo, config, excludedRoots, gitWorkspace, lo
27615
27994
  }
27616
27995
  const seenPaths = /* @__PURE__ */ new Set();
27617
27996
  for (const candidatePath of candidatePaths) {
27618
- const checkoutPath = await fsp.realpath(candidatePath).catch(() => null);
27997
+ const checkoutPath = await fs$1.realpath(candidatePath).catch(() => null);
27619
27998
  if (!checkoutPath || seenPaths.has(checkoutPath)) continue;
27620
27999
  seenPaths.add(checkoutPath);
27621
28000
  if (resolvedExcludedRoots.some((root) => isPathInside(root, checkoutPath))) continue;
@@ -27629,9 +28008,9 @@ async function findLocalCheckout({ repo, config, excludedRoots, gitWorkspace, lo
27629
28008
  }
27630
28009
  async function isLinkedToCheckout(worktreePath, localCheckout) {
27631
28010
  const modulesPath = path.join(worktreePath, "node_modules");
27632
- if (!(await fsp.lstat(modulesPath).catch(() => null))?.isSymbolicLink()) return false;
27633
- const linkedModules = await fsp.realpath(modulesPath).catch(() => null);
27634
- const checkoutModules = await fsp.realpath(path.join(localCheckout, "node_modules")).catch(() => null);
28011
+ if (!(await fs$1.lstat(modulesPath).catch(() => null))?.isSymbolicLink()) return false;
28012
+ const linkedModules = await fs$1.realpath(modulesPath).catch(() => null);
28013
+ const checkoutModules = await fs$1.realpath(path.join(localCheckout, "node_modules")).catch(() => null);
27635
28014
  return linkedModules !== null && linkedModules === checkoutModules;
27636
28015
  }
27637
28016
  async function sweepLeftoverCheckouts({ worktreeRoot, workRoot, keepPaths, repoCache, gitWorkspace, reapProcesses = reapTeamReviewProcesses, log }) {
@@ -27642,11 +28021,11 @@ async function sweepLeftoverCheckouts({ worktreeRoot, workRoot, keepPaths, repoC
27642
28021
  log
27643
28022
  }).catch((error) => log.warn(`[${TEAM_REVIEW_LANE_ID}] process reap failed: ${errorMessage(error)}`));
27644
28023
  for (const root of [worktreeRoot, workRoot]) {
27645
- const leftoverNames = await fsp.readdir(root).catch(() => []);
28024
+ const leftoverNames = await fs$1.readdir(root).catch(() => []);
27646
28025
  for (const leftoverName of leftoverNames) {
27647
28026
  const directory = path.join(root, leftoverName);
27648
28027
  if (keepPaths.has(directory)) continue;
27649
- await deleteDirectory(directory, log);
28028
+ await deleteCheckout(gitWorkspace, directory, log);
27650
28029
  }
27651
28030
  }
27652
28031
  const cachedClones = await repoCache.listRepos().catch((error) => {
@@ -27666,7 +28045,7 @@ function createTeamReviewDispatcher({ store, repoCache, gitWorkspace, spawnSessi
27666
28045
  }));
27667
28046
  if (removal.ok && !await pathExists(worktreePath)) return;
27668
28047
  log.warn(`[${TEAM_REVIEW_LANE_ID}] worktree removal failed for ${worktreePath}, deleting it directly: ${firstLine$1(removal.err ?? "") || "the directory is still present"}`);
27669
- await deleteDirectory(worktreePath, log);
28048
+ await deleteCheckout(gitWorkspace, worktreePath, log);
27670
28049
  await pruneCachedClone(gitWorkspace, projectPath, log);
27671
28050
  }
27672
28051
  async function discoverLocalCheckout(repo) {
@@ -27713,7 +28092,7 @@ function createTeamReviewDispatcher({ store, repoCache, gitWorkspace, spawnSessi
27713
28092
  return null;
27714
28093
  }
27715
28094
  const scratchObjectsDir = path.join(workDir, REMERGE_OBJECTS_DIRNAME);
27716
- await fsp.mkdir(scratchObjectsDir, { recursive: true });
28095
+ await fs$1.mkdir(scratchObjectsDir, { recursive: true });
27717
28096
  return {
27718
28097
  ...isolation.range,
27719
28098
  scratchObjectsDir
@@ -27823,7 +28202,7 @@ function createTeamReviewDispatcher({ store, repoCache, gitWorkspace, spawnSessi
27823
28202
  }
27824
28203
  };
27825
28204
  if (hasWorkDir) await deleteDirectory(args.resume.workDir, log);
27826
- if (hasWorktree) await deleteDirectory(args.resume.worktreePath, log);
28205
+ if (hasWorktree) await deleteCheckout(gitWorkspace, args.resume.worktreePath, log);
27827
28206
  return {
27828
28207
  kind: "stopped",
27829
28208
  resumable: null
@@ -27914,7 +28293,7 @@ function createTeamReviewDispatcher({ store, repoCache, gitWorkspace, spawnSessi
27914
28293
  projectPath,
27915
28294
  worktreePath: args.resume.worktreePath
27916
28295
  });
27917
- if (!projectPath) await deleteDirectory(args.resume.worktreePath, log);
28296
+ if (!projectPath) await deleteCheckout(gitWorkspace, args.resume.worktreePath, log);
27918
28297
  }
27919
28298
  if (hasWorkDir) await deleteDirectory(args.resume.workDir, log);
27920
28299
  sessionId = null;
@@ -27938,9 +28317,10 @@ function createTeamReviewDispatcher({ store, repoCache, gitWorkspace, spawnSessi
27938
28317
  projectPath: staged.projectPath,
27939
28318
  worktreePath
27940
28319
  };
27941
- await fsp.mkdir(worktreeRoot, { recursive: true });
28320
+ await fs$1.mkdir(worktreeRoot, { recursive: true });
27942
28321
  const created = await gitWorkspace.stageDetachedWorktree({
27943
28322
  projectPath: staged.projectPath,
28323
+ owner: "lane:team-review",
27944
28324
  worktreePath,
27945
28325
  sha: detail.headRefOid
27946
28326
  });
@@ -27981,8 +28361,8 @@ function createTeamReviewDispatcher({ store, repoCache, gitWorkspace, spawnSessi
27981
28361
  priorReview,
27982
28362
  newWork
27983
28363
  });
27984
- await fsp.writeFile(path.join(workDir, REVIEW_PROMPT_FILENAME), prompt, "utf8");
27985
- await fsp.mkdir(emptyGhConfigDir(workDir), { recursive: true });
28364
+ await fs$1.writeFile(path.join(workDir, REVIEW_PROMPT_FILENAME), prompt, "utf8");
28365
+ await fs$1.mkdir(emptyGhConfigDir(workDir), { recursive: true });
27986
28366
  reportProgress({
27987
28367
  kind: "phase",
27988
28368
  phase: "reviewing",
@@ -28500,7 +28880,7 @@ function createTeamReviewWiring({ config, store, reviewSessions, closeSessionDat
28500
28880
  scope: "run",
28501
28881
  log
28502
28882
  }).catch((error) => log.warn(`[${TEAM_REVIEW_LANE_ID}] process reap failed: ${errorMessage(error)}`));
28503
- await deleteDirectory(record.worktreePath, log);
28883
+ await deleteCheckout(gitWorkspace, record.worktreePath, log);
28504
28884
  await deleteDirectory(record.workDir, log);
28505
28885
  const cachedClones = await repoCache.listRepos();
28506
28886
  for (const projectPath of cachedClones) await pruneCachedClone(gitWorkspace, projectPath, log);
@@ -28567,7 +28947,7 @@ function createTeamReviewWiring({ config, store, reviewSessions, closeSessionDat
28567
28947
  worktreeRoot,
28568
28948
  workRoot
28569
28949
  ];
28570
- const resolvedExcludedRoots = await Promise.all(excludedRoots.map((root) => fsp.realpath(root).catch(() => path.resolve(root))));
28950
+ const resolvedExcludedRoots = await Promise.all(excludedRoots.map((root) => fs$1.realpath(root).catch(() => path.resolve(root))));
28571
28951
  const configuredPathByRealPath = await configuredProjectPathsByRealPath(config.projects ?? []);
28572
28952
  return findLocalCheckout({
28573
28953
  repo,
@@ -28861,18 +29241,18 @@ function worktreeOwnerRepo(gitFileText) {
28861
29241
  async function readJsonFile$1(filePath) {
28862
29242
  return loadedJsonValue(await loadJsonStateFile({
28863
29243
  filePath,
28864
- fsPromises: fsp,
29244
+ fsPromises: fs$1,
28865
29245
  parse: (raw) => raw,
28866
29246
  quarantine: false
28867
29247
  }));
28868
29248
  }
28869
29249
  async function jsonFileNames(directory) {
28870
- return (await fsp.readdir(directory, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
29250
+ return (await fs$1.readdir(directory, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
28871
29251
  }
28872
29252
  async function readBoundedText(filePath) {
28873
- const stat = await fsp.stat(filePath).catch(() => null);
29253
+ const stat = await fs$1.stat(filePath).catch(() => null);
28874
29254
  if (!stat?.isFile() || stat.size > RESULT_MAX_BYTES) return null;
28875
- return fsp.readFile(filePath, "utf8").catch(() => null);
29255
+ return fs$1.readFile(filePath, "utf8").catch(() => null);
28876
29256
  }
28877
29257
  function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast, store, repoCache, repoCacheRoot, gitWorkspace, spawnSubject, spawnJudge, credentials, claudeCommand, runArmCommand = runArmCommandSafely, guardrailsRefusal = allowGuardedSpawn, baseEnv = process.env, now = () => Date.now(), randomSuffix = () => randomBytes(4).toString("hex"), log = console }) {
28878
29258
  let activeRun = null;
@@ -28881,7 +29261,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
28881
29261
  let leftoverSweep = Promise.resolve();
28882
29262
  const suiteDir = (suiteId) => path.join(benchmarksRoot, suiteId);
28883
29263
  async function removeDirectoryOrWarn(directory) {
28884
- await fsp.rm(directory, {
29264
+ await fs$1.rm(directory, {
28885
29265
  recursive: true,
28886
29266
  force: true
28887
29267
  }).catch((error) => log.warn(`[${BENCHMARK_LANE_ID}] could not remove ${directory}: ${firstLine(errorMessage(error))}`));
@@ -28980,7 +29360,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
28980
29360
  return refreshed;
28981
29361
  }
28982
29362
  async function summarizeAndBroadcast() {
28983
- const suiteIds = (await fsp.readdir(benchmarksRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory() && BenchmarkId.safeParse(entry.name).success).map((entry) => entry.name).sort();
29363
+ const suiteIds = (await fs$1.readdir(benchmarksRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory() && BenchmarkId.safeParse(entry.name).success).map((entry) => entry.name).sort();
28984
29364
  const summaries = [];
28985
29365
  for (const suiteId of suiteIds) summaries.push(await summarizeSuite(suiteId).catch((error) => unreadableSuiteSummary(suiteId, errorMessage(error))));
28986
29366
  suites = summaries;
@@ -29037,7 +29417,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29037
29417
  error: mined.reason
29038
29418
  };
29039
29419
  const candidatesDir = path.join(suiteDir(suiteId), "candidates");
29040
- await fsp.mkdir(candidatesDir, { recursive: true });
29420
+ await fs$1.mkdir(candidatesDir, { recursive: true });
29041
29421
  for (const outcome of mined.outcomes) {
29042
29422
  if (!outcome.candidate) {
29043
29423
  log.warn(`[${BENCHMARK_LANE_ID}] ${caseSource.repo}#${outcome.number} not mined: ${outcome.refusal}`);
@@ -29133,7 +29513,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29133
29513
  reason: "the reviewed commit could not be fetched, or the base is not its ancestor"
29134
29514
  };
29135
29515
  const checkoutPath = path.join(staged.caseDir, "checkout");
29136
- const cleared = await fsp.rm(checkoutPath, {
29516
+ const cleared = await fs$1.rm(checkoutPath, {
29137
29517
  recursive: true,
29138
29518
  force: true
29139
29519
  }).then(() => null, (error) => errorMessage(error));
@@ -29154,7 +29534,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29154
29534
  reason: `could not stage a checkout: ${firstLine(created.err ?? "") || "the isolated checkout failed"}`
29155
29535
  };
29156
29536
  }
29157
- const sharedObjectsPath = firstLine(await fsp.readFile(path.join(checkoutPath, ".git", "objects", "info", "alternates"), "utf8").catch(() => ""));
29537
+ const sharedObjectsPath = firstLine(await fs$1.readFile(path.join(checkoutPath, ".git", "objects", "info", "alternates"), "utf8").catch(() => ""));
29158
29538
  if (!sharedObjectsPath) {
29159
29539
  await removeDirectoryOrWarn(checkoutPath);
29160
29540
  return {
@@ -29172,7 +29552,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29172
29552
  if (existing) return existing;
29173
29553
  const caseDir = path.join(runDir, benchmarkCase.id);
29174
29554
  const workDir = path.join(caseDir, "work");
29175
- await fsp.mkdir(workDir, { recursive: true });
29555
+ await fs$1.mkdir(workDir, { recursive: true });
29176
29556
  const staged = {
29177
29557
  checkoutPath: null,
29178
29558
  sharedObjectsPath: null,
@@ -29255,7 +29635,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29255
29635
  },
29256
29636
  judgeSeed: (cell) => cell.index + 1,
29257
29637
  async persist(run) {
29258
- await fsp.mkdir(runsDir, { recursive: true });
29638
+ await fs$1.mkdir(runsDir, { recursive: true });
29259
29639
  await writeJsonAtomic(path.join(runsDir, `${runId}.json`), redactedRun(run, usedTokens));
29260
29640
  },
29261
29641
  reportProgress
@@ -29282,10 +29662,10 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29282
29662
  };
29283
29663
  usedTokens.add(token.token);
29284
29664
  const resultPath = path.join(staged.workDir, SUBJECT_RESULT_FILENAME);
29285
- await fsp.rm(resultPath, { force: true });
29286
- await fsp.writeFile(path.join(staged.workDir, SUBJECT_PROMPT_FILENAME), prompt, "utf8");
29665
+ await fs$1.rm(resultPath, { force: true });
29666
+ await fs$1.writeFile(path.join(staged.workDir, SUBJECT_PROMPT_FILENAME), prompt, "utf8");
29287
29667
  const baseSpawnEnv = hooksPathPinnedSpawnEnv(staged.workDir);
29288
- await fsp.mkdir(baseSpawnEnv.GH_CONFIG_DIR, { recursive: true });
29668
+ await fs$1.mkdir(baseSpawnEnv.GH_CONFIG_DIR, { recursive: true });
29289
29669
  const subjectController = new AbortController();
29290
29670
  const stopSubject = () => subjectController.abort();
29291
29671
  let hasTimedOut = false;
@@ -29347,8 +29727,8 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29347
29727
  };
29348
29728
  }
29349
29729
  async function runJudgeSession({ cell, prompt, model, signal, runDir }) {
29350
- await fsp.mkdir(runDir, { recursive: true });
29351
- const judgeDir = await fsp.mkdtemp(path.join(runDir, `judge-${cell.index}-`));
29730
+ await fs$1.mkdir(runDir, { recursive: true });
29731
+ const judgeDir = await fs$1.mkdtemp(path.join(runDir, `judge-${cell.index}-`));
29352
29732
  const resultPath = path.join(judgeDir, JUDGE_RESULT_FILENAME);
29353
29733
  try {
29354
29734
  await spawnJudge({
@@ -29377,7 +29757,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29377
29757
  costUsd: null
29378
29758
  };
29379
29759
  } finally {
29380
- await fsp.rm(judgeDir, {
29760
+ await fs$1.rm(judgeDir, {
29381
29761
  recursive: true,
29382
29762
  force: true
29383
29763
  }).catch(() => {});
@@ -29463,7 +29843,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29463
29843
  return respond(outcome);
29464
29844
  }
29465
29845
  async function removeLeftoverWorktree(worktreePath) {
29466
- const projectPath = worktreeOwnerRepo(await fsp.readFile(path.join(worktreePath, ".git"), "utf8").catch(() => ""));
29846
+ const projectPath = worktreeOwnerRepo(await fs$1.readFile(path.join(worktreePath, ".git"), "utf8").catch(() => ""));
29467
29847
  if (projectPath) {
29468
29848
  const removal = await gitWorkspace.removeWorktreeByPath({
29469
29849
  projectPath,
@@ -29490,7 +29870,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29490
29870
  }
29491
29871
  async function sweepSuiteLeftovers(suiteId) {
29492
29872
  const worktreesDir = path.join(suiteDir(suiteId), "worktrees");
29493
- const worktreeEntries = await fsp.readdir(worktreesDir, { withFileTypes: true }).catch(() => []);
29873
+ const worktreeEntries = await fs$1.readdir(worktreesDir, { withFileTypes: true }).catch(() => []);
29494
29874
  for (const entry of worktreeEntries) if (entry.isDirectory()) await removeLeftoverWorktree(path.join(worktreesDir, entry.name));
29495
29875
  await removeDirectoryOrWarn(worktreesDir);
29496
29876
  await removeDirectoryOrWarn(path.join(suiteDir(suiteId), "work"));
@@ -29499,7 +29879,7 @@ function createBenchmarkWiring({ benchmarksRoot, runsRoot, isEnabled, broadcast,
29499
29879
  async function sweepAllLeftovers() {
29500
29880
  if (activeRun) return;
29501
29881
  await removeDirectoryOrWarn(runsRoot);
29502
- const suiteIds = (await fsp.readdir(benchmarksRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory() && BenchmarkId.safeParse(entry.name).success).map((entry) => entry.name);
29882
+ const suiteIds = (await fs$1.readdir(benchmarksRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory() && BenchmarkId.safeParse(entry.name).success).map((entry) => entry.name);
29503
29883
  for (const suiteId of suiteIds) await sweepSuiteLeftovers(suiteId).catch((error) => log.warn(`[${BENCHMARK_LANE_ID}] could not sweep ${suiteId}: ${errorMessage(error)}`));
29504
29884
  }
29505
29885
  function sweepLeftovers() {
@@ -30645,7 +31025,7 @@ function createCoderEnvWiring({ config, persistMapping, onReconciled = () => {},
30645
31025
  var DEFAULT_INTERVAL_MS$1 = 216e5;
30646
31026
  var BRANCH_GC_FETCH_TIMEOUT_MS = 6e4;
30647
31027
  function createBranchGcPoller(deps) {
30648
- const { gitWorkspace, getConfig, liveSessionIds, liveWorktreePaths, staleDays = 14, deleteUnmerged = false, prefixes = DEFAULT_BRANCH_GC_PREFIXES, pruneWorktrees = true, dryRun = false, intervalMs = DEFAULT_INTERVAL_MS$1, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, log = console, decisionTrace = () => {}, onTickComplete = () => {}, now = () => Date.now(), statProjectPath = (projectPath) => fsp.stat(projectPath) } = deps;
31028
+ const { gitWorkspace, getConfig, liveSessionIds, liveWorktreePaths, staleDays = 14, deleteUnmerged = false, prefixes = DEFAULT_BRANCH_GC_PREFIXES, pruneWorktrees = true, dryRun = false, intervalMs = DEFAULT_INTERVAL_MS$1, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, log = console, decisionTrace = () => {}, onTickComplete = () => {}, now = () => Date.now(), statProjectPath = (projectPath) => fs$1.stat(projectPath) } = deps;
30649
31029
  const skippedProjectPaths = /* @__PURE__ */ new Set();
30650
31030
  async function callGit(method, args) {
30651
31031
  try {
@@ -33386,7 +33766,7 @@ function classifyGitStatusFailure(error) {
33386
33766
  var DEFAULT_MAX_REPOS = 16;
33387
33767
  var DEFAULT_GIT_TIMEOUT_MS = 15e3;
33388
33768
  var MAX_GIT_BUFFER_BYTES = 8388608;
33389
- function createGitIngest({ publish, sourceConfig = {}, reposProvider = null, logger = console, execFileFn = execFileAsync, createWatch = createWatchDebounce, canonicalize = canonicalizePath, statRepoDir = (dir) => fsp.stat(dir), nowFn = Date.now, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, maxRepos = DEFAULT_MAX_REPOS, gitTimeoutMs = DEFAULT_GIT_TIMEOUT_MS, gitPath = "git" } = {}) {
33769
+ function createGitIngest({ publish, sourceConfig = {}, reposProvider = null, logger = console, execFileFn = execFileAsync, createWatch = createWatchDebounce, canonicalize = canonicalizePath, statRepoDir = (dir) => fs$1.stat(dir), nowFn = Date.now, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, maxRepos = DEFAULT_MAX_REPOS, gitTimeoutMs = DEFAULT_GIT_TIMEOUT_MS, gitPath = "git" } = {}) {
33390
33770
  if (typeof publish !== "function") throw new Error("createGitIngest requires publish");
33391
33771
  const publishEvent = publish;
33392
33772
  const settleMs = positiveIntOr(sourceConfig.debounceMs, DEFAULT_DEBOUNCE_MS);
@@ -34809,10 +35189,10 @@ function hasAutoSessionName(session) {
34809
35189
  return isAutoNameOf(session.name, path.basename(session.path));
34810
35190
  }
34811
35191
  async function refineTaskTitle(request, model, spawnLane, signal) {
34812
- const workDir = await fsp.mkdtemp(path.join(os.tmpdir(), "glimmervoid-task-title-"));
35192
+ const workDir = await fs$1.mkdtemp(path.join(os.tmpdir(), "glimmervoid-task-title-"));
34813
35193
  const resultPath = path.join(workDir, RESULT_FILE$1);
34814
35194
  try {
34815
- await fsp.writeFile(path.join(workDir, PROMPT_FILE$1), buildTaskTitleRefinementPrompt({
35195
+ await fs$1.writeFile(path.join(workDir, PROMPT_FILE$1), buildTaskTitleRefinementPrompt({
34816
35196
  currentTitle: request.currentTitle,
34817
35197
  recentPrompts: request.recentPrompts,
34818
35198
  resultPath,
@@ -34835,7 +35215,7 @@ async function refineTaskTitle(request, model, spawnLane, signal) {
34835
35215
  proposedSessionName: request.wantsSessionName ? parseRefinedSessionName(laneResult) : null
34836
35216
  };
34837
35217
  } finally {
34838
- await fsp.rm(workDir, {
35218
+ await fs$1.rm(workDir, {
34839
35219
  recursive: true,
34840
35220
  force: true
34841
35221
  });
@@ -37922,6 +38302,7 @@ function createRadarWiring({ config, investigationSessions, closeSessionDataClie
37922
38302
  const issueId = safeIssueId(issue.issueId);
37923
38303
  const workspace = await Promise.resolve(gitWorkspace.create({
37924
38304
  projectPath: repoPath,
38305
+ owner: "lane:radar-fix",
37925
38306
  teamId: "radar-fix",
37926
38307
  label: `${safeIssueId(projectId)}-${issueId}-${newFixDiscriminator()}`,
37927
38308
  worktreeBase: worktreeBaseFor(repoPath),
@@ -38429,9 +38810,13 @@ function createMyPrsPoller(dependencies) {
38429
38810
  });
38430
38811
  async function failedOutcome(errorText) {
38431
38812
  const rateLimitWaitMs = await store.rateLimitWaitMs(now(), MY_PRS_RATE_LIMIT_RESOURCES) ?? secondaryRateLimitWaitMs(errorText);
38432
- return rateLimitWaitMs === null ? { failed: true } : {
38813
+ return rateLimitWaitMs === null ? {
38433
38814
  failed: true,
38434
- retryAfterMs: rateLimitWaitMs
38815
+ error: errorText
38816
+ } : {
38817
+ failed: true,
38818
+ retryAfterMs: rateLimitWaitMs,
38819
+ error: errorText
38435
38820
  };
38436
38821
  }
38437
38822
  async function runTick() {
@@ -38758,10 +39143,11 @@ function createMyPrsPoller(dependencies) {
38758
39143
  error: "Reviews polling is stopped."
38759
39144
  };
38760
39145
  registerWatches();
38761
- const refreshed = await store.refreshWatches(watchNames);
38762
- rebuild();
38763
- if (!refreshed.ok) return refreshed;
38764
- return loop.refresh();
39146
+ return loop.refresh(async () => {
39147
+ const refreshed = await store.refreshWatches(watchNames);
39148
+ rebuild();
39149
+ return refreshed;
39150
+ });
38765
39151
  }
38766
39152
  return {
38767
39153
  start,
@@ -38784,10 +39170,10 @@ function defaultAgentSearchRoots() {
38784
39170
  return roots.filter((root, index) => roots.indexOf(root) === index);
38785
39171
  }
38786
39172
  async function readEntryNames(directory) {
38787
- return fsp.readdir(directory).catch(() => []);
39173
+ return fs$1.readdir(directory).catch(() => []);
38788
39174
  }
38789
39175
  async function ownedSocketAt(socketPath, ownerUid) {
38790
- const stats = await fsp.lstat(socketPath).catch(() => null);
39176
+ const stats = await fs$1.lstat(socketPath).catch(() => null);
38791
39177
  if (!stats?.isSocket()) return null;
38792
39178
  if (ownerUid !== null && stats.uid !== ownerUid) return null;
38793
39179
  return {
@@ -38835,12 +39221,12 @@ function createSshSigner({ env = process.env, agentSearchRoots = defaultAgentSea
38835
39221
  ok: false,
38836
39222
  error: NO_AGENT_HOLDS_KEY
38837
39223
  };
38838
- const workDir = await fsp.mkdtemp(path.join(os.tmpdir(), "glimmervoid-sign-"));
39224
+ const workDir = await fs$1.mkdtemp(path.join(os.tmpdir(), "glimmervoid-sign-"));
38839
39225
  try {
38840
39226
  const keyPath = path.join(workDir, "signing-key.pub");
38841
39227
  const payloadPath = path.join(workDir, "payload");
38842
- await fsp.writeFile(keyPath, `${formatSshPublicKey(publicKey)}\n`, { mode: 384 });
38843
- await fsp.writeFile(payloadPath, payload, { mode: 384 });
39228
+ await fs$1.writeFile(keyPath, `${formatSshPublicKey(publicKey)}\n`, { mode: 384 });
39229
+ await fs$1.writeFile(payloadPath, payload, { mode: 384 });
38844
39230
  await execFileAsync("ssh-keygen", [
38845
39231
  "-Y",
38846
39232
  "sign",
@@ -38860,7 +39246,7 @@ function createSshSigner({ env = process.env, agentSearchRoots = defaultAgentSea
38860
39246
  });
38861
39247
  return {
38862
39248
  ok: true,
38863
- signature: await fsp.readFile(`${payloadPath}.sig`, "utf8")
39249
+ signature: await fs$1.readFile(`${payloadPath}.sig`, "utf8")
38864
39250
  };
38865
39251
  } catch (error) {
38866
39252
  const stderr = error?.stderr;
@@ -38869,7 +39255,7 @@ function createSshSigner({ env = process.env, agentSearchRoots = defaultAgentSea
38869
39255
  error: `ssh-keygen could not sign: ${typeof stderr === "string" && stderr.trim() ? stderr.trim() : errorMessage(error)}`
38870
39256
  };
38871
39257
  } finally {
38872
- await fsp.rm(workDir, {
39258
+ await fs$1.rm(workDir, {
38873
39259
  recursive: true,
38874
39260
  force: true
38875
39261
  });
@@ -38884,7 +39270,7 @@ async function readSigningKeySetting(setting, cwd) {
38884
39270
  const literalKey = parseSshPublicKey(setting);
38885
39271
  if (literalKey) return literalKey;
38886
39272
  const keyPath = path.resolve(cwd, setting.replace(/^~(?=\/|$)/, os.homedir()));
38887
- return parseSshPublicKey(await fsp.readFile(keyPath, "utf8").catch(() => ""));
39273
+ return parseSshPublicKey(await fs$1.readFile(keyPath, "utf8").catch(() => ""));
38888
39274
  }
38889
39275
  function readTextOrNull(filePath) {
38890
39276
  try {
@@ -39072,8 +39458,8 @@ function createGuardedPrStaging({ spawnSession, repoCache, describeRole = guarde
39072
39458
  if (!staged.ok) return { error: `could not stage the checkout ${staged.err}` };
39073
39459
  }
39074
39460
  const excludePath = path.join(checkoutPath, ".git", "info", "exclude");
39075
- await fsp.mkdir(path.dirname(excludePath), { recursive: true });
39076
- await fsp.appendFile(excludePath, keepMergeableExcludeLines(), "utf8");
39461
+ await fs$1.mkdir(path.dirname(excludePath), { recursive: true });
39462
+ await fs$1.appendFile(excludePath, keepMergeableExcludeLines(), "utf8");
39077
39463
  return {
39078
39464
  projectPath,
39079
39465
  baseSha: baseSha.data
@@ -39266,7 +39652,7 @@ function createMyPrMergeabilityFix({ spawnSession, repoCache, workRoot, makeWork
39266
39652
  };
39267
39653
  }
39268
39654
  async function fetchSessionCommits(staged, checkoutPath, headSha, handoffRef, signal) {
39269
- const bundleDir = await fsp.mkdtemp(path.join(os.tmpdir(), "glimmervoid-keep-mergeable-"));
39655
+ const bundleDir = await fs$1.mkdtemp(path.join(os.tmpdir(), "glimmervoid-keep-mergeable-"));
39270
39656
  try {
39271
39657
  const bundlePath = path.join(bundleDir, "session.bundle");
39272
39658
  const bundled = await runGit([
@@ -39288,7 +39674,7 @@ function createMyPrMergeabilityFix({ spawnSession, repoCache, workRoot, makeWork
39288
39674
  `+${KEEP_MERGEABLE_WORK_BRANCH_REF}:${handoffRef}`
39289
39675
  ], staged.projectPath, signal);
39290
39676
  } finally {
39291
- await fsp.rm(bundleDir, {
39677
+ await fs$1.rm(bundleDir, {
39292
39678
  recursive: true,
39293
39679
  force: true
39294
39680
  });
@@ -39373,8 +39759,8 @@ function createMyPrMergeabilityFix({ spawnSession, repoCache, workRoot, makeWork
39373
39759
  if ("error" in staged) return reportRepairFailure(pr, `not started: ${staged.error}`);
39374
39760
  projectPath = staged.projectPath;
39375
39761
  if (signal.aborted) return stopped;
39376
- await fsp.writeFile(path.join(workDir.dir, MY_PRS_FIX_PROMPT_FILENAME), keepMergeablePrompt(pr), "utf8");
39377
- await fsp.mkdir(emptyGhConfigDir(workDir.dir), { recursive: true });
39762
+ await fs$1.writeFile(path.join(workDir.dir, MY_PRS_FIX_PROMPT_FILENAME), keepMergeablePrompt(pr), "utf8");
39763
+ await fs$1.mkdir(emptyGhConfigDir(workDir.dir), { recursive: true });
39378
39764
  const outcome = await runSession({
39379
39765
  idPrefix: MY_PRS_LANE_ID,
39380
39766
  name: `Keep mergeable ${pr.key}`,
@@ -40213,12 +40599,16 @@ function createWorkflowsPoller(dependencies) {
40213
40599
  return stateLoad;
40214
40600
  }
40215
40601
  function publishStatus() {
40602
+ const { nextAttemptAt, retry, isRefreshing, refreshNotice } = loop.scheduleStatus();
40216
40603
  onTickComplete({
40217
40604
  type: "workflows-status",
40218
40605
  ts: now(),
40219
40606
  configured: true,
40220
40607
  error: pollingError,
40221
- ...loop.scheduleStatus()
40608
+ nextAttemptAt,
40609
+ retry,
40610
+ isRefreshing,
40611
+ refreshNotice
40222
40612
  });
40223
40613
  }
40224
40614
  const loop = createTickLoop({
@@ -40398,8 +40788,8 @@ function createWorkflowSpawn({ staging, workRoot, makeWorkDir = makeTeamReviewWo
40398
40788
  const staged = await staging.stageCheckout(pr, workDir.dir, signal);
40399
40789
  if (signal.aborted) return;
40400
40790
  if ("error" in staged) return warn(`not started: ${staged.error}`);
40401
- await fsp.writeFile(path.join(workDir.dir, WORKFLOW_PROMPT_FILENAME), workflowSpawnPrompt(action.promptTemplate, event, MY_PRS_FIX_CHECKOUT_DIRNAME), "utf8");
40402
- await fsp.mkdir(emptyGhConfigDir(workDir.dir), { recursive: true });
40791
+ await fs$1.writeFile(path.join(workDir.dir, WORKFLOW_PROMPT_FILENAME), workflowSpawnPrompt(action.promptTemplate, event, MY_PRS_FIX_CHECKOUT_DIRNAME), "utf8");
40792
+ await fs$1.mkdir(emptyGhConfigDir(workDir.dir), { recursive: true });
40403
40793
  if (await staging.runSession({
40404
40794
  idPrefix: "workflows",
40405
40795
  name: workflowSessionName({
@@ -40490,15 +40880,28 @@ function createWorkflowsWiring({ config, notificationManager, spawnSession, log
40490
40880
  }
40491
40881
  //#endregion
40492
40882
  //#region server/github/github-clock.ts
40493
- function createGithubClock({ baseIntervalMs, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, log = console }) {
40883
+ function createGithubClock({ baseIntervalMs, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, log = console, githubStatus }) {
40494
40884
  const subscriptions = /* @__PURE__ */ new Set();
40495
40885
  let timer = null;
40496
40886
  let isSweeping = false;
40497
- let exclusiveChain = Promise.resolve();
40498
- function exclusive(work) {
40499
- const outcome = exclusiveChain.then(() => work());
40500
- exclusiveChain = outcome.catch(() => void 0);
40501
- return outcome;
40887
+ let isExclusiveRunning = false;
40888
+ const priorityJobs = [];
40889
+ const backgroundJobs = [];
40890
+ function runNextExclusiveJob() {
40891
+ if (isExclusiveRunning) return;
40892
+ const job = priorityJobs.shift() ?? backgroundJobs.shift();
40893
+ if (!job) return;
40894
+ isExclusiveRunning = true;
40895
+ job().finally(() => {
40896
+ isExclusiveRunning = false;
40897
+ runNextExclusiveJob();
40898
+ });
40899
+ }
40900
+ function exclusive(work, { isPriority = false } = {}) {
40901
+ return new Promise((resolve, reject) => {
40902
+ (isPriority ? priorityJobs : backgroundJobs).push(() => Promise.resolve().then(work).then(resolve, reject));
40903
+ runNextExclusiveJob();
40904
+ });
40502
40905
  }
40503
40906
  async function sweep() {
40504
40907
  if (isSweeping) return;
@@ -40540,7 +40943,56 @@ function createGithubClock({ baseIntervalMs, setIntervalFn = DEFAULT_TIMER_FNS.s
40540
40943
  return {
40541
40944
  schedule,
40542
40945
  exclusive,
40543
- sweep
40946
+ sweep,
40947
+ githubStatus
40948
+ };
40949
+ }
40950
+ //#endregion
40951
+ //#region server/github/core/github-status-core.ts
40952
+ var GITHUB_STATUS_CACHE_MS = 3e5;
40953
+ var GithubStatusSummary = z.object({ incidents: z.array(z.object({
40954
+ name: z.string(),
40955
+ status: z.string(),
40956
+ updated_at: z.iso.datetime({ offset: true })
40957
+ })) });
40958
+ function openIncidentName(body) {
40959
+ const summary = GithubStatusSummary.safeParse(body);
40960
+ if (!summary.success) return null;
40961
+ const openIncidents = summary.data.incidents.filter((incident) => incident.status !== "resolved" && incident.status !== "postmortem");
40962
+ openIncidents.sort((first, second) => Date.parse(second.updated_at) - Date.parse(first.updated_at));
40963
+ return openIncidents[0]?.name ?? null;
40964
+ }
40965
+ function isStatusReadDue(lastReadAtMs, nowMs) {
40966
+ return lastReadAtMs === null || nowMs - lastReadAtMs >= GITHUB_STATUS_CACHE_MS;
40967
+ }
40968
+ //#endregion
40969
+ //#region server/github/github-status.ts
40970
+ function createGithubStatus({ fetchFn = fetch, now = Date.now, log }) {
40971
+ let lastReadAtMs = null;
40972
+ let cachedIncident = null;
40973
+ let hasWarned = false;
40974
+ async function readStatus() {
40975
+ try {
40976
+ const response = await fetchFn("https://www.githubstatus.com/api/v2/summary.json", { signal: AbortSignal.timeout(5e3) });
40977
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
40978
+ cachedIncident = openIncidentName(GithubStatusSummary.parse(await response.json()));
40979
+ hasWarned = false;
40980
+ } catch (error) {
40981
+ cachedIncident = null;
40982
+ if (hasWarned) return;
40983
+ hasWarned = true;
40984
+ log.warn(`[github-status] read failed: ${errorMessage(error)}`);
40985
+ }
40986
+ }
40987
+ function noteTransientFailure() {
40988
+ const nowMs = now();
40989
+ if (!isStatusReadDue(lastReadAtMs, nowMs)) return;
40990
+ lastReadAtMs = nowMs;
40991
+ readStatus();
40992
+ }
40993
+ return {
40994
+ noteTransientFailure,
40995
+ incident: () => cachedIncident
40544
40996
  };
40545
40997
  }
40546
40998
  //#endregion
@@ -41594,7 +42046,7 @@ function isFresh(fetchedAt, nowMs) {
41594
42046
  if (!Number.isFinite(fetchedMs)) return false;
41595
42047
  return nowMs - fetchedMs < CACHE_TTL_MS;
41596
42048
  }
41597
- async function loadPricing({ fetchEnabled, fsPromises = fsp, fetchFn = globalThis.fetch, cachePath = path.join(glimmervoidHomeDir$1(), "litellm-pricing.json"), nowFn = Date.now, timeoutMs = 15e3, logger = null } = {}) {
42049
+ async function loadPricing({ fetchEnabled, fsPromises = fs$1, fetchFn = globalThis.fetch, cachePath = path.join(glimmervoidHomeDir$1(), "litellm-pricing.json"), nowFn = Date.now, timeoutMs = 15e3, logger = null } = {}) {
41598
42050
  if (!fetchEnabled) return {
41599
42051
  table: normalizePricingTable(claude_pricing_default),
41600
42052
  source: "snapshot",
@@ -42293,7 +42745,7 @@ async function walkSourceFiles(roots, fsPromises, laneLog) {
42293
42745
  };
42294
42746
  }
42295
42747
  function createUsageScanner(deps = {}) {
42296
- const { fsPromises = fsp, env = process.env, homeDir = os.homedir(), nowFn = Date.now, pricingTable, aliases = {}, costMode = "auto", blockHours = 5, retainDays = 90, extraProjectsDirs = [], vendors = {
42748
+ const { fsPromises = fs$1, env = process.env, homeDir = os.homedir(), nowFn = Date.now, pricingTable, aliases = {}, costMode = "auto", blockHours = 5, retainDays = 90, extraProjectsDirs = [], vendors = {
42297
42749
  codex: true,
42298
42750
  grok: true
42299
42751
  }, warehousePath = null, warehouseRetainDays = 365, budget: budgetDep = null, laneMap = null, logger = noopLogger, byteBudget = DEFAULT_BYTE_BUDGET, chunkSize = DEFAULT_CHUNK_SIZE, yieldNowFn = yieldNow } = deps;
@@ -43127,7 +43579,7 @@ function formatBudgetUsd(value) {
43127
43579
  function budgetAlertText({ scope, threshold, spentUsd, budgetUsd }) {
43128
43580
  return `Usage budget: ${scope === "monthly" ? "monthly" : "daily"} spend ${formatBudgetUsd(spentUsd)} reached ${threshold}% of ${formatBudgetUsd(budgetUsd)}`;
43129
43581
  }
43130
- function createUsageWiring({ config, sessions = /* @__PURE__ */ new Map(), broadcast = () => {}, controlClientCount = () => 0, warehousePath = null, budgetStatePath = null, laneMap = null, telemetry = null, sendTelegram = sendTelegramMessage, telegramTimeoutMs = TELEGRAM_TIMEOUT_MS, fsPromises = fsp, createScanner = createUsageScanner, loadPricingFn = loadPricing, execFileAsync: execFileAsync$1 = execFileAsync, rtkPathFn = defaultRtkPath, scannerDeps = {}, nowFn = Date.now, partialContinueMs = PARTIAL_CONTINUE_MS, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, logger = console, debug = false }) {
43582
+ function createUsageWiring({ config, sessions = /* @__PURE__ */ new Map(), broadcast = () => {}, controlClientCount = () => 0, warehousePath = null, budgetStatePath = null, laneMap = null, telemetry = null, sendTelegram = sendTelegramMessage, telegramTimeoutMs = TELEGRAM_TIMEOUT_MS, fsPromises = fs$1, createScanner = createUsageScanner, loadPricingFn = loadPricing, execFileAsync: execFileAsync$1 = execFileAsync, rtkPathFn = defaultRtkPath, scannerDeps = {}, nowFn = Date.now, partialContinueMs = PARTIAL_CONTINUE_MS, setIntervalFn = DEFAULT_TIMER_FNS.setIntervalFn, clearIntervalFn = DEFAULT_TIMER_FNS.clearIntervalFn, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, logger = console, debug = false }) {
43131
43583
  const laneLog = createLaneLog({
43132
43584
  prefix: "[usage]",
43133
43585
  logger,
@@ -43667,7 +44119,7 @@ function createUsageWiring({ config, sessions = /* @__PURE__ */ new Map(), broad
43667
44119
  }
43668
44120
  //#endregion
43669
44121
  //#region server/usage/usage-lane-ledger.ts
43670
- function createLaneLedger({ ledgerPath = null, fsPromises = fsp, nowFn = Date.now, retainDays = 365, logger = null } = {}) {
44122
+ function createLaneLedger({ ledgerPath = null, fsPromises = fs$1, nowFn = Date.now, retainDays = 365, logger = null } = {}) {
43671
44123
  const laneLog = createLaneLog({
43672
44124
  prefix: "[usage]",
43673
44125
  logger
@@ -44699,7 +45151,7 @@ function errorResult(reason, errorSource = ERROR_SOURCE_TRANSPORT) {
44699
45151
  async function readCommentsResult(resultPath, { lineCount = 0, onBytesRead = null } = {}) {
44700
45152
  let raw = "";
44701
45153
  try {
44702
- raw = await fsp.readFile(resultPath, "utf8");
45154
+ raw = await fs$1.readFile(resultPath, "utf8");
44703
45155
  } catch {
44704
45156
  return errorResult("no readable result file");
44705
45157
  }
@@ -44795,11 +45247,11 @@ function createVisionsSpawn({ sessions = /* @__PURE__ */ new Map(), closeSession
44795
45247
  };
44796
45248
  }
44797
45249
  function makeVisionsWorkDir() {
44798
- return fsp.mkdtemp(path.join(os.tmpdir(), "glimmervoid-visions-"));
45250
+ return fs$1.mkdtemp(path.join(os.tmpdir(), "glimmervoid-visions-"));
44799
45251
  }
44800
45252
  function createVisionsDispatcher({ spawnSession, timeoutSeconds = 180, model = null, logger = console, nowFn = Date.now, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, makeWorkDir = makeVisionsWorkDir, removeWorkDir = async (dir) => {
44801
45253
  try {
44802
- await fsp.rm(dir, {
45254
+ await fs$1.rm(dir, {
44803
45255
  recursive: true,
44804
45256
  force: true
44805
45257
  });
@@ -44869,7 +45321,7 @@ function createVisionsDispatcher({ spawnSession, timeoutSeconds = 180, model = n
44869
45321
  });
44870
45322
  const sizeDecision = decidePromptSize(generatedPrompt);
44871
45323
  if (!sizeDecision.dispatch) return errorResult(sizeDecision.gate);
44872
- await fsp.writeFile(path.join(workDir, PROMPT_FILE), generatedPrompt, "utf8");
45324
+ await fs$1.writeFile(path.join(workDir, PROMPT_FILE), generatedPrompt, "utf8");
44873
45325
  return await spawnWithTimeout({
44874
45326
  id: idFor(uri),
44875
45327
  name: `visions ${uri}`,
@@ -45276,7 +45728,7 @@ function changeFailureReason(uri, version, result) {
45276
45728
  if (result.reason === "stale-version") return `stale-version (uri=${uri} incoming=${result.version} current=${result.currentVersion})`;
45277
45729
  return `${result.reason} (uri=${uri} version=${version})`;
45278
45730
  }
45279
- function createVisionsWiring({ debounceMs = 300, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, nowFn = Date.now, sweep = sweepMarkdownWithFixes, maxPayload = MAX_FRAME_BYTES, autoFix = false, fixLogMax = 20, applyEditTimeoutMs = APPLY_EDIT_TIMEOUT_MS, logger = console, broadcast = null, dispatchConfig = null, dispatchHistory = [], dispatch = null, contextDigest = null, contextSeq = null, scopeProjects = [], pathsFoldCase = process.platform === "darwin", knownProjectIds = null, onEditorEvent = null, intentStatePath = null, intentThreadTtlMs = DEFAULT_THREAD_TTL_MS, fsFns = fs, fsPromises = fsp, digestBudgetChars = DIGEST_BUDGET_CHARS, hashFn = hashText$1, buildPrompt = buildVisionsPrompt, debug = false } = {}) {
45731
+ function createVisionsWiring({ debounceMs = 300, setTimeoutFn = DEFAULT_TIMER_FNS.setTimeoutFn, clearTimeoutFn = DEFAULT_TIMER_FNS.clearTimeoutFn, nowFn = Date.now, sweep = sweepMarkdownWithFixes, maxPayload = MAX_FRAME_BYTES, autoFix = false, fixLogMax = 20, applyEditTimeoutMs = APPLY_EDIT_TIMEOUT_MS, logger = console, broadcast = null, dispatchConfig = null, dispatchHistory = [], dispatch = null, contextDigest = null, contextSeq = null, scopeProjects = [], pathsFoldCase = process.platform === "darwin", knownProjectIds = null, onEditorEvent = null, intentStatePath = null, intentThreadTtlMs = DEFAULT_THREAD_TTL_MS, fsFns = fs, fsPromises = fs$1, digestBudgetChars = DIGEST_BUDGET_CHARS, hashFn = hashText$1, buildPrompt = buildVisionsPrompt, debug = false } = {}) {
45280
45732
  const wss = new WebSocketServer({
45281
45733
  noServer: true,
45282
45734
  maxPayload
@@ -46147,8 +46599,15 @@ function createBackendLanes(dependencies) {
46147
46599
  warn: (message) => logger.warn(message)
46148
46600
  });
46149
46601
  const spawnGate = createSpawnGate({ memoryAdmission });
46150
- const gitWorkspace = createGitWorkspace({ rerere: config.worktreeRerere !== false });
46151
- const gitWorkspaceSync = createGitWorkspaceSync();
46602
+ const ownedPaths = createOwnedPathsLedger({
46603
+ filePath: ownedPathsLedgerPath(),
46604
+ log: logger
46605
+ });
46606
+ const gitWorkspace = createGitWorkspace({
46607
+ rerere: config.worktreeRerere !== false,
46608
+ ownedPaths
46609
+ });
46610
+ const gitWorkspaceSync = createGitWorkspaceSync({ ownedPaths });
46152
46611
  const laneLedger = createLaneLedger({
46153
46612
  ledgerPath: configSiblingPath(configStore.configPath, "usage-lanes.json"),
46154
46613
  retainDays: resolveUsageConfig(config.usage).warehouseRetainDays,
@@ -46242,7 +46701,8 @@ function createBackendLanes(dependencies) {
46242
46701
  });
46243
46702
  const githubClock = createGithubClock({
46244
46703
  baseIntervalMs: 6e4,
46245
- log: logger
46704
+ log: logger,
46705
+ githubStatus: createGithubStatus({ log: logger })
46246
46706
  });
46247
46707
  const glimmervoidHome = glimmervoidHomeDir$1();
46248
46708
  const github = createPrGh(glimmervoidHome);
@@ -46636,6 +47096,7 @@ function createBackendLanes(dependencies) {
46636
47096
  currentVisions,
46637
47097
  gitWorkspace,
46638
47098
  gitWorkspaceSync,
47099
+ ownedPaths,
46639
47100
  githubStore,
46640
47101
  investigationSessions,
46641
47102
  planReview,
@@ -48834,7 +49295,7 @@ var SessionRecorder = class {
48834
49295
  if (this._retainDays <= 0 && this._retainFiles <= 0 && this._retainBytes <= 0) return;
48835
49296
  let entries;
48836
49297
  try {
48837
- entries = await fsp.readdir(this._baseDir);
49298
+ entries = await fs$1.readdir(this._baseDir);
48838
49299
  } catch {
48839
49300
  return;
48840
49301
  }
@@ -48852,7 +49313,7 @@ var SessionRecorder = class {
48852
49313
  for (const entry of recordings) {
48853
49314
  if (doomed.has(entry)) continue;
48854
49315
  try {
48855
- if ((await fsp.stat(path.join(this._baseDir, entry))).mtimeMs < cutoff) doomed.add(entry);
49316
+ if ((await fs$1.stat(path.join(this._baseDir, entry))).mtimeMs < cutoff) doomed.add(entry);
48856
49317
  } catch {}
48857
49318
  }
48858
49319
  }
@@ -48860,14 +49321,14 @@ var SessionRecorder = class {
48860
49321
  const filepath = path.join(this._baseDir, entry);
48861
49322
  if (filepath === this._filepath || openRecordingPaths.has(filepath)) continue;
48862
49323
  try {
48863
- await fsp.unlink(filepath);
49324
+ await fs$1.unlink(filepath);
48864
49325
  } catch {}
48865
49326
  }
48866
49327
  if (this._retainBytes <= 0) return;
48867
49328
  const current = this._filepath ? path.basename(this._filepath) : null;
48868
49329
  const measured = (await Promise.all(recordings.filter((entry) => !doomed.has(entry) && entry !== current).map(async (entry) => {
48869
49330
  try {
48870
- const stat = await fsp.stat(path.join(this._baseDir, entry));
49331
+ const stat = await fs$1.stat(path.join(this._baseDir, entry));
48871
49332
  return {
48872
49333
  entry,
48873
49334
  size: stat.size,
@@ -48882,7 +49343,7 @@ var SessionRecorder = class {
48882
49343
  for (const entry of evictable) {
48883
49344
  if (totalBytes <= this._retainBytes) return;
48884
49345
  try {
48885
- await fsp.unlink(path.join(this._baseDir, entry.entry));
49346
+ await fs$1.unlink(path.join(this._baseDir, entry.entry));
48886
49347
  totalBytes -= entry.size;
48887
49348
  } catch (err) {
48888
49349
  if (isMissingFileError(err, { includeNotDir: false })) totalBytes -= entry.size;
@@ -49010,6 +49471,8 @@ function createSessionFactory(dependencies) {
49010
49471
  isSettingOn: (dependencies.getConfig?.() ?? config).coherence?.enabled === true
49011
49472
  });
49012
49473
  const builtMapping = project.environment;
49474
+ const sessionTempFolder = builtMapping ? null : sessionTempFolderFor(project.id);
49475
+ if (sessionTempFolder) fs.mkdirSync(sessionTempFolder, { recursive: true });
49013
49476
  const session = new Session({
49014
49477
  id: project.id,
49015
49478
  name: project.name,
@@ -49047,6 +49510,10 @@ function createSessionFactory(dependencies) {
49047
49510
  commitSigningProgram: dependencies.commitSigningProgram ?? null,
49048
49511
  getRemoteLaunch: builtMapping ? () => remoteLaunchFor(project, builtMapping, dependencies.getConfig?.() ?? config) : null,
49049
49512
  ...overrides,
49513
+ spawnEnv: sessionTempFolder ? {
49514
+ CLAUDE_CODE_TMPDIR: sessionTempFolder,
49515
+ ...overrides.spawnEnv ?? {}
49516
+ } : overrides.spawnEnv,
49050
49517
  prepareGuardrails: "prepareGuardrails" in overrides ? overrides.prepareGuardrails : defaultGuardrailsFor(project, config, overrides)
49051
49518
  });
49052
49519
  const captureConfig = {
@@ -50906,22 +51373,37 @@ function registerControlHandlers(controlWss, deps) {
50906
51373
  console.log(`[control] Removed spawned session via UI: ${sess.name}`);
50907
51374
  return { ok: true };
50908
51375
  }
51376
+ const isDiscardingWorkspaceWork = sess.isWorkspace && msg.discardWork === true;
51377
+ if (isDiscardingWorkspaceWork) sess.killSession();
51378
+ const keptPaths = sess.isWorkspace ? await sess.findWorkspaceKeptWork() : [];
51379
+ const confirmedKeptPaths = new Set(isDiscardingWorkspaceWork ? msg.confirmedKeptPaths ?? [] : []);
51380
+ if (keptPaths.some((kept) => !confirmedKeptPaths.has(kept.path))) return {
51381
+ ok: false,
51382
+ error: "Workspace members hold work that is not saved",
51383
+ canDiscardWork: true,
51384
+ keptPaths
51385
+ };
50909
51386
  if (config.projects.some((project) => project.id === sess.id && project.environment) && coderEnv) {
50910
51387
  sess.killSession();
50911
51388
  const settlement = await coderEnv.settleRemoval({
50912
51389
  projectId: sess.id,
50913
- discardRemoteWork: msg.discardRemoteWork === true
51390
+ discardRemoteWork: msg.discardWork === true
50914
51391
  });
50915
51392
  if (!settlement.ok) return {
50916
51393
  ok: false,
50917
51394
  error: settlement.reason,
50918
- canDiscardRemoteWork: settlement.canDiscardRemoteWork
51395
+ canDiscardWork: settlement.canDiscardRemoteWork
50919
51396
  };
50920
51397
  }
50921
51398
  const freshConfig = configStore.save((cfg) => {
50922
51399
  cfg.projects = cfg.projects.filter((p) => p.id !== sess.id);
50923
51400
  });
50924
- if (freshConfig) applyConfigReload(freshConfig);
51401
+ if (!freshConfig) return {
51402
+ ok: false,
51403
+ error: `Could not save the removal of session "${sess.name}"`
51404
+ };
51405
+ if (isDiscardingWorkspaceWork) sess.confirmWorkspaceWorkDiscard();
51406
+ applyConfigReload(freshConfig);
50925
51407
  console.log(`[control] Removed session via UI: ${sess.name}`);
50926
51408
  return { ok: true };
50927
51409
  }
@@ -53782,7 +54264,7 @@ async function downloadCapped(url, { fetchImpl, timeoutMs = DOWNLOAD_TIMEOUT_MS
53782
54264
  }
53783
54265
  }
53784
54266
  async function findBinary(dir, platform) {
53785
- const entries = await fsp.readdir(dir, { withFileTypes: true });
54267
+ const entries = await fs$1.readdir(dir, { withFileTypes: true });
53786
54268
  const nested = [];
53787
54269
  for (const entry of entries) {
53788
54270
  const full = path.join(dir, entry.name);
@@ -53800,13 +54282,13 @@ async function findBinary(dir, platform) {
53800
54282
  }
53801
54283
  async function removeQuietly(target) {
53802
54284
  try {
53803
- await fsp.rm(target, {
54285
+ await fs$1.rm(target, {
53804
54286
  recursive: true,
53805
54287
  force: true
53806
54288
  });
53807
54289
  } catch {}
53808
54290
  }
53809
- async function moveIntoPlace(source, target, renameImpl = fsp.rename) {
54291
+ async function moveIntoPlace(source, target, renameImpl = fs$1.rename) {
53810
54292
  try {
53811
54293
  await renameImpl(source, target);
53812
54294
  return;
@@ -53815,15 +54297,15 @@ async function moveIntoPlace(source, target, renameImpl = fsp.rename) {
53815
54297
  }
53816
54298
  const partial = `${target}.partial`;
53817
54299
  try {
53818
- await fsp.copyFile(source, partial);
54300
+ await fs$1.copyFile(source, partial);
53819
54301
  await renameImpl(partial, target);
53820
54302
  } catch (err) {
53821
54303
  await removeQuietly(partial);
53822
54304
  throw err;
53823
54305
  }
53824
- await fsp.unlink(source);
54306
+ await fs$1.unlink(source);
53825
54307
  }
53826
- async function installRtk({ homeDir = os.homedir(), glimmervoidHome = glimmervoidHomeDir(homeDir, process.env), platform = process.platform, arch = process.arch, fetchImpl = globalThis.fetch, execFileImpl = execFileAsync, renameImpl = fsp.rename, timeoutMs = DOWNLOAD_TIMEOUT_MS, log = console, asset = assetForPlatform(platform, arch) } = {}) {
54308
+ async function installRtk({ homeDir = os.homedir(), glimmervoidHome = glimmervoidHomeDir(homeDir, process.env), platform = process.platform, arch = process.arch, fetchImpl = globalThis.fetch, execFileImpl = execFileAsync, renameImpl = fs$1.rename, timeoutMs = DOWNLOAD_TIMEOUT_MS, log = console, asset = assetForPlatform(platform, arch) } = {}) {
53827
54309
  if (!asset) return {
53828
54310
  ok: false,
53829
54311
  reason: `unsupported platform ${platform}-${arch}`
@@ -53834,7 +54316,7 @@ async function installRtk({ homeDir = os.homedir(), glimmervoidHome = glimmervoi
53834
54316
  };
53835
54317
  const stagingDir = path.join(glimmervoidHome, "tmp", `rtk-${crypto.randomBytes(6).toString("hex")}`);
53836
54318
  try {
53837
- await fsp.mkdir(stagingDir, { recursive: true });
54319
+ await fs$1.mkdir(stagingDir, { recursive: true });
53838
54320
  } catch (err) {
53839
54321
  return {
53840
54322
  ok: false,
@@ -53857,9 +54339,9 @@ async function installRtk({ homeDir = os.homedir(), glimmervoidHome = glimmervoi
53857
54339
  reason: `sha256 mismatch for ${asset.file}: expected ${asset.sha256}, got ${actualHex}`
53858
54340
  };
53859
54341
  const archivePath = path.join(stagingDir, asset.file);
53860
- await fsp.writeFile(archivePath, downloaded.bytes);
54342
+ await fs$1.writeFile(archivePath, downloaded.bytes);
53861
54343
  const extractDir = path.join(stagingDir, "extract");
53862
- await fsp.mkdir(extractDir, { recursive: true });
54344
+ await fs$1.mkdir(extractDir, { recursive: true });
53863
54345
  try {
53864
54346
  const listing = await execFileImpl("tar", ["-tf", archivePath]);
53865
54347
  const escaping = findEscapingArchiveMember(listing.stdout);
@@ -53884,13 +54366,13 @@ async function installRtk({ homeDir = os.homedir(), glimmervoidHome = glimmervoi
53884
54366
  ok: false,
53885
54367
  reason: `extract failed: no rtk binary inside ${asset.file}`
53886
54368
  };
53887
- if (!(await fsp.lstat(extracted)).isFile()) return {
54369
+ if (!(await fs$1.lstat(extracted)).isFile()) return {
53888
54370
  ok: false,
53889
54371
  reason: `extract failed: rtk inside ${asset.file} is not a regular file`
53890
54372
  };
53891
- if (platform !== "win32") await fsp.chmod(extracted, 493);
54373
+ if (platform !== "win32") await fs$1.chmod(extracted, 493);
53892
54374
  const target = installTargetPath(glimmervoidHome, platform);
53893
- await fsp.mkdir(path.dirname(target), { recursive: true });
54375
+ await fs$1.mkdir(path.dirname(target), { recursive: true });
53894
54376
  await removeQuietly(target);
53895
54377
  await moveIntoPlace(extracted, target, renameImpl);
53896
54378
  log?.log?.(`[rtk] installed rtk ${asset.version} at ${target}`);
@@ -53981,13 +54463,13 @@ function sleepFor(durationMs) {
53981
54463
  function createClaudeFolderTrust({ env = process.env, homeDir = os.homedir(), now = Date.now, platform = process.platform, sleep = sleepFor } = {}) {
53982
54464
  async function resolveConfiguredPath() {
53983
54465
  const [legacyConfigPath, currentConfigPath] = listClaudeGlobalConfigPathCandidates(env, homeDir);
53984
- return await fsp.access(legacyConfigPath).then(() => true, () => false) ? legacyConfigPath : currentConfigPath;
54466
+ return await fs$1.access(legacyConfigPath).then(() => true, () => false) ? legacyConfigPath : currentConfigPath;
53985
54467
  }
53986
54468
  function refusal(repositoryRoot, configPath, reason) {
53987
54469
  return /* @__PURE__ */ new Error(`Could not trust ${repositoryRoot} for Claude Code: ${configPath} was left unchanged because ${reason}`);
53988
54470
  }
53989
54471
  async function readTrustDecision(repositoryRoot, configPath) {
53990
- const decision = decideFolderTrust(await fsp.readFile(configPath, "utf8").catch((error) => {
54472
+ const decision = decideFolderTrust(await fs$1.readFile(configPath, "utf8").catch((error) => {
53991
54473
  throw refusal(repositoryRoot, configPath, `it could not be read (${errorCode(error) ?? "unknown error"})`);
53992
54474
  }), repositoryRoot, platform);
53993
54475
  if (decision.kind === "unreadable") throw refusal(repositoryRoot, configPath, decision.reason);
@@ -53995,13 +54477,13 @@ function createClaudeFolderTrust({ env = process.env, homeDir = os.homedir(), no
53995
54477
  }
53996
54478
  async function tryTakeConfigLock(lockPath) {
53997
54479
  try {
53998
- await fsp.mkdir(lockPath);
54480
+ await fs$1.mkdir(lockPath);
53999
54481
  return true;
54000
54482
  } catch (error) {
54001
54483
  if (errorCode(error) !== "EEXIST") throw error;
54002
54484
  }
54003
- const heldLock = await fsp.stat(lockPath).catch(() => null);
54004
- if (heldLock && isConfigLockStale(heldLock.mtimeMs, now())) await fsp.rmdir(lockPath).catch(() => {});
54485
+ const heldLock = await fs$1.stat(lockPath).catch(() => null);
54486
+ if (heldLock && isConfigLockStale(heldLock.mtimeMs, now())) await fs$1.rmdir(lockPath).catch(() => {});
54005
54487
  return false;
54006
54488
  }
54007
54489
  async function takeConfigLock(repositoryRoot, configuredPath) {
@@ -54014,17 +54496,17 @@ function createClaudeFolderTrust({ env = process.env, homeDir = os.homedir(), no
54014
54496
  }
54015
54497
  async function ensureTrusted(repositoryRoot) {
54016
54498
  const configuredPath = await resolveConfiguredPath();
54017
- const configPath = await fsp.realpath(configuredPath).catch(() => configuredPath);
54499
+ const configPath = await fs$1.realpath(configuredPath).catch(() => configuredPath);
54018
54500
  if ((await readTrustDecision(repositoryRoot, configPath)).kind === "trusted") return "already-trusted";
54019
54501
  const lockPath = await takeConfigLock(repositoryRoot, configuredPath);
54020
54502
  try {
54021
54503
  const decision = await readTrustDecision(repositoryRoot, configPath);
54022
54504
  if (decision.kind === "trusted") return "already-trusted";
54023
- const { mode } = await fsp.stat(configPath);
54505
+ const { mode } = await fs$1.stat(configPath);
54024
54506
  await writeTextAtomic(configPath, decision.nextConfigText, { mode: mode & 511 });
54025
54507
  return "granted";
54026
54508
  } finally {
54027
- await fsp.rmdir(lockPath).catch(() => {});
54509
+ await fs$1.rmdir(lockPath).catch(() => {});
54028
54510
  }
54029
54511
  }
54030
54512
  return { ensureTrusted };
@@ -54266,11 +54748,11 @@ function spawnConnectPty(file, args, options) {
54266
54748
  return pty.spawn(file, args, options);
54267
54749
  }
54268
54750
  async function makePrivateDir(directory) {
54269
- await fsp.mkdir(directory, {
54751
+ await fs$1.mkdir(directory, {
54270
54752
  recursive: true,
54271
54753
  mode: 448
54272
54754
  });
54273
- await fsp.chmod(directory, 448);
54755
+ await fs$1.chmod(directory, 448);
54274
54756
  }
54275
54757
  function createAgentConnect({ loginsRoot, loginSource, launchFor, onChange, ptySpawn = spawnConnectPty, makeHomeDir = makePrivateDir, setTimeoutFn = setTimeout, clearTimeoutFn = clearTimeout }) {
54276
54758
  const statusByAgent = new Map(CONNECTABLE_AGENTS.map((agent) => [agent, idleLoginStatus(agent, null)]));
@@ -54475,7 +54957,7 @@ function chatgptAuthTokensRefreshResult(login) {
54475
54957
  //#region server/codex-credentials.ts
54476
54958
  var HOST_REFRESH_TIMEOUT_MS = 6e4;
54477
54959
  async function readTextFileOrNull(filePath) {
54478
- return fsp.readFile(filePath, "utf8").catch(() => null);
54960
+ return fs$1.readFile(filePath, "utf8").catch(() => null);
54479
54961
  }
54480
54962
  function codexHomeDir(env, homeDir) {
54481
54963
  const override = env.CODEX_HOME?.trim();
@@ -55084,7 +55566,8 @@ function createUpdateApplyLane(dependencies) {
55084
55566
  await runWorkspaceStep("stage", () => dependencies.gitWorkspace.stageDetachedWorktree({
55085
55567
  projectPath: dependencies.packageRoot,
55086
55568
  worktreePath: stagingPath,
55087
- sha: status.latestSha || void 0
55569
+ sha: status.latestSha || void 0,
55570
+ owner: "lane:update-apply"
55088
55571
  }));
55089
55572
  const lockfileDiff = await gitCommand([
55090
55573
  "diff",
@@ -55455,19 +55938,19 @@ async function collectWorktreePaths(projects) {
55455
55938
  }
55456
55939
  async function readFileNames(folder) {
55457
55940
  try {
55458
- return (await fsp.readdir(folder, { withFileTypes: true })).filter((entry) => entry.isFile()).map((entry) => entry.name);
55941
+ return (await fs$1.readdir(folder, { withFileTypes: true })).filter((entry) => entry.isFile()).map((entry) => entry.name);
55459
55942
  } catch (error) {
55460
55943
  if (isMissingFileError(error)) return null;
55461
55944
  throw error;
55462
55945
  }
55463
55946
  }
55464
55947
  async function removeFolderIfEmpty(folder) {
55465
- if ((await fsp.readdir(folder)).length > 0) return;
55466
- await fsp.rmdir(folder);
55948
+ if ((await fs$1.readdir(folder)).length > 0) return;
55949
+ await fs$1.rmdir(folder);
55467
55950
  }
55468
55951
  async function isRealDirectory(folder) {
55469
55952
  try {
55470
- return (await fsp.lstat(folder)).isDirectory();
55953
+ return (await fs$1.lstat(folder)).isDirectory();
55471
55954
  } catch (error) {
55472
55955
  if (isMissingFileError(error)) return false;
55473
55956
  throw error;
@@ -55475,10 +55958,10 @@ async function isRealDirectory(folder) {
55475
55958
  }
55476
55959
  async function isReportFolderOwnedByWorktree(worktreePath, reportFolder) {
55477
55960
  if (!await isRealDirectory(path.dirname(reportFolder)) || !await isRealDirectory(reportFolder)) return false;
55478
- const realWorktreePath = await fsp.realpath(worktreePath);
55479
- if (!isPathInside(realWorktreePath, await fsp.realpath(reportFolder), { allowEqual: false })) return false;
55961
+ const realWorktreePath = await fs$1.realpath(worktreePath);
55962
+ if (!isPathInside(realWorktreePath, await fs$1.realpath(reportFolder), { allowEqual: false })) return false;
55480
55963
  const reportFolderTopLevel = (await gitOutput(["rev-parse", "--show-toplevel"], reportFolder)).trim();
55481
- return equalsIgnoringCaseOnWindows(await fsp.realpath(reportFolderTopLevel), realWorktreePath);
55964
+ return equalsIgnoringCaseOnWindows(await fs$1.realpath(reportFolderTopLevel), realWorktreePath);
55482
55965
  }
55483
55966
  async function listTrackedReportGitPaths(worktreePath) {
55484
55967
  return (await gitOutput([
@@ -55495,7 +55978,7 @@ async function cleanWorktree(worktreePath) {
55495
55978
  if (fileNames === null) return NOTHING_CLEANED;
55496
55979
  const trackedReportGitPaths = await listTrackedReportGitPaths(worktreePath);
55497
55980
  const deletableFileNames = untrackedReportFileNames(fileNames, trackedReportGitPaths);
55498
- for (const fileName of deletableFileNames) await fsp.rm(path.join(reportFolder, fileName), { force: true });
55981
+ for (const fileName of deletableFileNames) await fs$1.rm(path.join(reportFolder, fileName), { force: true });
55499
55982
  await removeFolderIfEmpty(reportFolder);
55500
55983
  await removeFolderIfEmpty(path.dirname(reportFolder));
55501
55984
  return {
@@ -56549,6 +57032,12 @@ function createBackend(httpServer, options = {}) {
56549
57032
  const reconcileProjectsOnReload = sessionRegistry.applyConfigReload;
56550
57033
  rtkInstall.maybeInstall();
56551
57034
  sweepOrphanedGuardrailsLaunches();
57035
+ reconcileOwnedPaths({
57036
+ ledger: laneAssembly.ownedPaths,
57037
+ configuredSessionIds: new Set(config.projects.map((project) => project.id)),
57038
+ git: laneAssembly.gitWorkspace,
57039
+ shareList: config.worktreeShare || DEFAULT_CONFIG.worktreeShare
57040
+ });
56552
57041
  laneAssembly.startRuntimeLanes();
56553
57042
  function applyCustomAgents(sourceConfig) {
56554
57043
  setCustomAgents(sourceConfig.customAgents ?? []);