glimmervoid 0.33.0 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/glimmervoid.js +5 -5
- package/dist/chunks/{adapters-C9gI2MHS.js → adapters-CgbcceU3.js} +1 -1
- package/dist/chunks/{adapters-CUBEhjOR.js → adapters-D-cRFZ_Q.js} +1 -1
- package/dist/chunks/{config-Cneb8Ujj.js → config-DTwMFUjx.js} +13 -9
- package/dist/chunks/{config-store-DYsZJDux.js → config-store-D0lRWsAM.js} +17 -9
- package/dist/chunks/config-store-DwTxLe8Y.js +2 -0
- package/dist/chunks/{contracts-DWv6q8ir.js → contracts-DZV9H8px.js} +25 -1
- package/dist/chunks/{knowledge-graph-cli-C7G-x5sY.js → knowledge-graph-cli-BBE3R9DJ.js} +1 -1
- package/dist/chunks/{main-J6y2RTri.js → main-VMWdsGC6.js} +347 -225
- package/dist/chunks/{pair-cli-BuyzST-U.js → pair-cli-CI848omy.js} +2 -2
- package/dist/chunks/{remote-config-DJHVb-HU.js → remote-config-Y6YtqoiO.js} +1 -1
- package/dist/chunks/{sandbox-deps-DuaNFq7n.js → sandbox-deps-C63o3mZs.js} +4 -4
- package/dist/client/assets/index-b9goyXSa.js +254 -0
- package/dist/client/index.html +1 -1
- package/dist/scripts/postinstall-path-check.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/session/sandbox-open-launcher.js +22 -8
- package/package.json +1 -1
- package/dist/chunks/config-store-DaRS2c2d.js +0 -2
- package/dist/client/assets/index-CoFsm_PF.js +0 -254
|
@@ -4,8 +4,8 @@ import { a as isPathInside, c as sanitizeWorktreeName, n as caseFoldedPathKey, o
|
|
|
4
4
|
import { a as packageRoot, n as cliPath, o as relayPath, r as clientDir, s as resolvePackageBin, t as bundled } from "./runtime-paths-BPoxENmK.js";
|
|
5
5
|
import { A as KILLABLE_STATES, C as SshSignRequest, E as isSamePromptQuestion, M as RESTARTABLE_STATES, N as STATES, T as TaskTitle, _ as SIGN_URL_ENV, a as AgentDispatchRequest, c as AgentTicketRequest, h as SESSION_DOC_BODY_CAP_BYTES, j as MERGEABLE_LIVE_STATES, k as toolDetailLine, l as ORCHESTRATOR_AGENT_VERBS, m as RefinedTaskTitle, n as AGENT_URL_ENV, r as ASK_USER_QUESTION_TOOL_NAME, v as SSH_SIGN_BODY_CAP_BYTES, w as TASK_TITLE_CONTROL_CHARACTERS } from "./session-C7rstCmA.js";
|
|
6
6
|
import { n as execFileAsync, o as spawn, r as execFileSync, t as execFile } from "./child-process-safe-DDELk9XC.js";
|
|
7
|
-
import { n as glimmervoidHomeDir } from "./config-path-core-DFt-TemS.js";
|
|
8
|
-
import { n as checkSandboxDependencies, t as allowSandboxedSpawn } from "./sandbox-deps-
|
|
7
|
+
import { n as glimmervoidHomeDir, t as decideConfigPath } from "./config-path-core-DFt-TemS.js";
|
|
8
|
+
import { n as checkSandboxDependencies, t as allowSandboxedSpawn } from "./sandbox-deps-C63o3mZs.js";
|
|
9
9
|
import { n as warnWhenGitIsTooOld } from "./git-version-CrLW4a6r.js";
|
|
10
10
|
import { t as HOOK_URL_ENV } from "./hook-relay-core-DA_bz2KA.js";
|
|
11
11
|
import { t as HOOK_VIA_SANDBOX_PROXY_ENV } from "./sandbox-proxy-core-hnQgKR0T.js";
|
|
@@ -19,13 +19,13 @@ import { n as unrefTimer, t as DEFAULT_TIMER_FNS } from "./timer-deps-u2DAQLok.j
|
|
|
19
19
|
import { a as decideTicketAction, i as decideSpawnAllowance, l as isOrchestratorAgentVerb, n as REFUSAL_REASON, o as deriveChildSessionName, r as decideAgentRequest, s as describePushLanding, t as PUSH_UNAVAILABLE_REASON, u as parseAgentVerb } from "./agent-api-core-Ddg15j2j.js";
|
|
20
20
|
import { s as GLIMMERVOID_SECRET_KEYS } from "./grok-BYKnBgdr.js";
|
|
21
21
|
import { _ as isQueueAdmissionTimeout, a as jsonStateLoadError, c as loadedJsonValue, d as writeJsonAtomicSync, f as writeTextAtomic, g as createSpawnGate, h as createSerialQueue, 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 } from "./json-file-oEH9vt-0.js";
|
|
22
|
-
import { $ as TeamReviewCompareFiles, A as MyPrSearchResponse, At as CoherenceWorkInspect, B as PostingPlan, C as MyPrMergeMethod, Ct as KEEP_MERGEABLE_TIMEOUT_MINUTES_RANGE, D as MyPrMergeWhenReadyRequest, E as MyPrMergeStateResponse, F as CommitSha, G as ReviewDraft, H as QueuedReview, I as DECIDING_REVIEW_STATES, J as ReviewThreadId, K as ReviewFinding, L as FindingSeverity, M as MyPrThreadsResponse, N as MyPrsState, Ot as CoherenceTicketCreated, P as MyPrsStatus, R as GithubReviewDecision, Tt as CoherenceOrient, U as ReviewChecksState, V as PrDetail, W as ReviewComment, X as SearchedPr, Y as ReviewVerdict, Z as TeamReviewActionRequest, _ as WorkflowSearchNode, a as ConfigUpdate, at as TeamReviewThreadsRepository, b as MyPrAutoRebase, bt as USAGE_COST_MODES, c as TASK_TITLE_SOURCE_PRIORITY, ct as hasStandingViewerApproval, d as BRANCH_GC_CONTROL_NUMERIC_KEYS, dt as shortSha$1, et as TeamReviewResolveResponse, ft as GH_SEGMENT, g as WorkflowLabelName, h as WorkflowCommentBody, ht as repoParts, it as TeamReviewThreadResult, j as MyPrThreadNode, k as MyPrSearchNode, kt as CoherenceWorkCreated, l as configIssueMessage, lt as FULL_SHA_RE, m as DEFAULT_FACTORY_PROTECTED_PATHS, mt as REPO_SLUG_RE, nt as TeamReviewStatus, o as PersistedTaskTitle, ot as canApproveAfterComment, p as DEFAULT_FACTORY_CHECKS, pt as NODE_ID_RE, q as ReviewResult, r as BrowserConfig, rt as TeamReviewThreadCommentsResponse, s as RUNTIME_CONFIG_SCALAR_KEYS, st as decisionAsIfApprovalRequired, tt as TeamReviewStateEntry, u as BRANCH_GC_CONTROL_BOOLEAN_KEYS, ut as HEX_SHA_RE, v as WorkflowsSettings, w as MyPrMergeRequest, wt as USAGE_INTEGER_RANGES, x as MyPrKeepMergeableRequest, xt as USAGE_VENDOR_KEYS, y as WorkflowsState, yt as USAGE_BUDGET_KEYS, z as GithubReviewState } from "./config-
|
|
23
|
-
import { $ as sessionIdFromBranch, A as snapshotEvents, B as classifySessionExit, C as createIngestStore, D as resolveIngestConfig, E as publishEvent, F as adapterBucket, G as nodeMajorVersion, H as decideRemoteTelemetryState, I as buildAiGenerationEvents, J as stableConfigKey, K as parsePosthogReleaseId, L as buildBrowserExceptionProperties, M as FIRST_RUN_NOTICE, N as TELEMETRY_BATCH_URL, O as ringStats, P as TELEMETRY_FLAGS_URL, Q as planWorktreeGc, R as buildExceptionProperties, S as buildContextDigest, T as latestSeq, U as decideTelemetryConsent, V as decideIsDevInstall, W as exceptionFingerprint, X as matchedPrefix, Y as DEFAULT_BRANCH_GC_PREFIXES, Z as planBranchGc, _ as INGEST_SPEC, a as ensureProjectIds, b as DEFAULT_DIGEST_BUDGET_CHARS, d as assetForPlatform, et as usablePrefixes, f as decideRtkInstall, g as verifyDigest, h as isRtkBinaryName, i as createConfigStore, j as localDayKey, k as scrubText, m as installTargetPath, n as DEFAULT_CONFIG, o as generateProjectId, p as findEscapingArchiveMember, q as resolveProjectToken, s as glimmervoidHomeDir$1, t as ABORT_CONFIG_SAVE, tt as worktreeIntegrationTips, v as mergeSettingsBlock, w as enabledSourceNames, x as SOURCE_DEFAULTS, y as validateSettingsBlock, z as buildFactoryDecisionEvent } from "./config-store-
|
|
24
|
-
import { $ as FactoryHarnessVerdict, A as BenchmarkActionRequest, B as PrCheckoutCaseInput, C as IssueKey, D as IssuesStatus, E as IssuesState, F as BenchmarkStatus, G as TelemetryState, H as PendingCrashReport, I as BenchmarkSuite, J as FACTORY_ERROR_MAX_CHARS, K as FACTORY_DECISION_OUTPUT_MAX_BYTES, L as CommitComparison, M as BenchmarkId, N as BenchmarkJudgement, O as ChangeMap, P as BenchmarkRun, Q as FactoryHarnessStateLine, R as MergedPrListing, S as GithubIssueResponse, T as IssuesSearchResponse, U as TELEMETRY_EVENT_SCHEMAS, X as FactoryConsequences, Y as FACTORY_PROTECTED_PATH_FLOOR, Z as FactoryControlRequest, _ as PlanDecision, a as ClientMessage, at as FactoryWorkerEvent, b as planTitle, c as UpdateJournal, d as TraceRecord, et as FactoryLaneState, f as PLAN_BODY_CAP_BYTES, g as PLAN_TOOL_NAME, h as PLAN_RESULT_HOOK_EVENT, i as CONTROL_FRAME_MAX_BYTES, it as FactoryReviewerOutput, j as BenchmarkCase, k as changeMapFactId, l as MAX_RAW_LINE_CHARS, m as PLAN_HOOK_OUTPUT_MAX_CHARS, n as HookEnvelope, nt as FactoryQueueIntentRequest, o as DIFF_ANNOTATION_NOTE_MAX_CHARS, ot as isSingleFactoryPathSegment, p as PLAN_HOOK_EVENT, q as FactoryDecisionLogLine, r as parseDataClientMessage, rt as FactoryReviewVerdict, s as InstallFlavor, t as HTTP_URL_RE, tt as FactoryProjectState, u as TraceCheckpoint, v as PlanRevision, w as IssueUpdate, x as GithubIssuePullRequestsRepository, y as parseExitPlanModeHookPayload, z as MinedPrReviewData } from "./contracts-
|
|
25
|
-
import { a as describeAgentResolvability, c as isKnownAgentId, d as setCustomAgents, f as claudeCode, i as customAgentFingerprint, l as listAgentIds, n as cachedAgentResolvability, o as getAdapter, r as commandFor, s as hookProfileOf, t as DEFAULT_AGENT_ID, u as resolveAdapter } from "./adapters-
|
|
22
|
+
import { $ as TeamReviewCompareFiles, A as MyPrSearchResponse, At as CoherenceWorkInspect, B as PostingPlan, C as MyPrMergeMethod, Ct as KEEP_MERGEABLE_TIMEOUT_MINUTES_RANGE, D as MyPrMergeWhenReadyRequest, E as MyPrMergeStateResponse, F as CommitSha, G as ReviewDraft, H as QueuedReview, I as DECIDING_REVIEW_STATES, J as ReviewThreadId, K as ReviewFinding, L as FindingSeverity, M as MyPrThreadsResponse, N as MyPrsState, Ot as CoherenceTicketCreated, P as MyPrsStatus, R as GithubReviewDecision, Tt as CoherenceOrient, U as ReviewChecksState, V as PrDetail, W as ReviewComment, X as SearchedPr, Y as ReviewVerdict, Z as TeamReviewActionRequest, _ as WorkflowSearchNode, a as ConfigUpdate, at as TeamReviewThreadsRepository, b as MyPrAutoRebase, bt as USAGE_COST_MODES, c as TASK_TITLE_SOURCE_PRIORITY, ct as hasStandingViewerApproval, d as BRANCH_GC_CONTROL_NUMERIC_KEYS, dt as shortSha$1, et as TeamReviewResolveResponse, ft as GH_SEGMENT, g as WorkflowLabelName, h as WorkflowCommentBody, ht as repoParts, it as TeamReviewThreadResult, j as MyPrThreadNode, k as MyPrSearchNode, kt as CoherenceWorkCreated, l as configIssueMessage, lt as FULL_SHA_RE, m as DEFAULT_FACTORY_PROTECTED_PATHS, mt as REPO_SLUG_RE, nt as TeamReviewStatus, o as PersistedTaskTitle, ot as canApproveAfterComment, p as DEFAULT_FACTORY_CHECKS, pt as NODE_ID_RE, q as ReviewResult, r as BrowserConfig, rt as TeamReviewThreadCommentsResponse, s as RUNTIME_CONFIG_SCALAR_KEYS, st as decisionAsIfApprovalRequired, tt as TeamReviewStateEntry, u as BRANCH_GC_CONTROL_BOOLEAN_KEYS, ut as HEX_SHA_RE, v as WorkflowsSettings, w as MyPrMergeRequest, wt as USAGE_INTEGER_RANGES, x as MyPrKeepMergeableRequest, xt as USAGE_VENDOR_KEYS, y as WorkflowsState, yt as USAGE_BUDGET_KEYS, z as GithubReviewState } from "./config-DTwMFUjx.js";
|
|
23
|
+
import { $ as sessionIdFromBranch, A as snapshotEvents, B as classifySessionExit, C as createIngestStore, D as resolveIngestConfig, E as publishEvent, F as adapterBucket, G as nodeMajorVersion, H as decideRemoteTelemetryState, I as buildAiGenerationEvents, J as stableConfigKey, K as parsePosthogReleaseId, L as buildBrowserExceptionProperties, M as FIRST_RUN_NOTICE, N as TELEMETRY_BATCH_URL, O as ringStats, P as TELEMETRY_FLAGS_URL, Q as planWorktreeGc, R as buildExceptionProperties, S as buildContextDigest, T as latestSeq, U as decideTelemetryConsent, V as decideIsDevInstall, W as exceptionFingerprint, X as matchedPrefix, Y as DEFAULT_BRANCH_GC_PREFIXES, Z as planBranchGc, _ as INGEST_SPEC, a as ensureProjectIds, b as DEFAULT_DIGEST_BUDGET_CHARS, d as assetForPlatform, et as usablePrefixes, f as decideRtkInstall, g as verifyDigest, h as isRtkBinaryName, i as createConfigStore, j as localDayKey, k as scrubText, m as installTargetPath, n as DEFAULT_CONFIG, o as generateProjectId, p as findEscapingArchiveMember, q as resolveProjectToken, s as glimmervoidHomeDir$1, t as ABORT_CONFIG_SAVE, tt as worktreeIntegrationTips, v as mergeSettingsBlock, w as enabledSourceNames, x as SOURCE_DEFAULTS, y as validateSettingsBlock, z as buildFactoryDecisionEvent } from "./config-store-D0lRWsAM.js";
|
|
24
|
+
import { $ as FactoryHarnessVerdict, A as BenchmarkActionRequest, B as PrCheckoutCaseInput, C as IssueKey, D as IssuesStatus, E as IssuesState, F as BenchmarkStatus, G as TelemetryState, H as PendingCrashReport, I as BenchmarkSuite, J as FACTORY_ERROR_MAX_CHARS, K as FACTORY_DECISION_OUTPUT_MAX_BYTES, L as CommitComparison, M as BenchmarkId, N as BenchmarkJudgement, O as ChangeMap, P as BenchmarkRun, Q as FactoryHarnessStateLine, R as MergedPrListing, S as GithubIssueResponse, T as IssuesSearchResponse, U as TELEMETRY_EVENT_SCHEMAS, X as FactoryConsequences, Y as FACTORY_PROTECTED_PATH_FLOOR, Z as FactoryControlRequest, _ as PlanDecision, a as ClientMessage, at as FactoryWorkerEvent, b as planTitle, c as UpdateJournal, d as TraceRecord, et as FactoryLaneState, f as PLAN_BODY_CAP_BYTES, g as PLAN_TOOL_NAME, h as PLAN_RESULT_HOOK_EVENT, i as CONTROL_FRAME_MAX_BYTES, it as FactoryReviewerOutput, j as BenchmarkCase, k as changeMapFactId, l as MAX_RAW_LINE_CHARS, m as PLAN_HOOK_OUTPUT_MAX_CHARS, n as HookEnvelope, nt as FactoryQueueIntentRequest, o as DIFF_ANNOTATION_NOTE_MAX_CHARS, ot as isSingleFactoryPathSegment, p as PLAN_HOOK_EVENT, q as FactoryDecisionLogLine, r as parseDataClientMessage, rt as FactoryReviewVerdict, s as InstallFlavor, t as HTTP_URL_RE, tt as FactoryProjectState, u as TraceCheckpoint, v as PlanRevision, w as IssueUpdate, x as GithubIssuePullRequestsRepository, y as parseExitPlanModeHookPayload, z as MinedPrReviewData } from "./contracts-DZV9H8px.js";
|
|
25
|
+
import { a as describeAgentResolvability, c as isKnownAgentId, d as setCustomAgents, f as claudeCode, i as customAgentFingerprint, l as listAgentIds, n as cachedAgentResolvability, o as getAdapter, r as commandFor, s as hookProfileOf, t as DEFAULT_AGENT_ID, u as resolveAdapter } from "./adapters-D-cRFZ_Q.js";
|
|
26
26
|
import { t as HOOK_TOOLS } from "./hook-tools-UX2fmt81.js";
|
|
27
27
|
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";
|
|
28
|
-
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-
|
|
28
|
+
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-Y6YtqoiO.js";
|
|
29
29
|
import { _ as escapeMarkup, g as createLaneLog, n as createVisionsSetup } from "./visions-setup-CfgNHiG3.js";
|
|
30
30
|
import { t as getRtkPath } from "./rtk-resolver-jJxy_Mrt.js";
|
|
31
31
|
import { createRequire } from "node:module";
|
|
@@ -37,7 +37,7 @@ import { z } from "zod";
|
|
|
37
37
|
import http from "node:http";
|
|
38
38
|
import { WebSocketServer } from "ws";
|
|
39
39
|
import crypto, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
40
|
-
import fsp, { access, chmod, copyFile, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm,
|
|
40
|
+
import fsp, { access, chmod, copyFile, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, symlink } from "node:fs/promises";
|
|
41
41
|
import { pipeline } from "node:stream";
|
|
42
42
|
import express from "express";
|
|
43
43
|
import pty from "node-pty";
|
|
@@ -2039,7 +2039,6 @@ function projectSessionSnapshots(source) {
|
|
|
2039
2039
|
//#region server/core/sandbox-roles-core.ts
|
|
2040
2040
|
var SESSION_VENDORS = Object.freeze(["claude", "codex"]);
|
|
2041
2041
|
var CONFINED_SESSION_VENDORS = Object.freeze(["claude"]);
|
|
2042
|
-
var UNSHARED_WORKTREE_ENTRIES = Object.freeze([".claude"]);
|
|
2043
2042
|
var LANE_CREDENTIAL_ENV = Object.freeze({
|
|
2044
2043
|
SSH_AUTH_SOCK: "",
|
|
2045
2044
|
SSH_ASKPASS: "",
|
|
@@ -2088,14 +2087,16 @@ function workRole({ vendor, cwd, checkout, readablePaths, writablePaths = [], ag
|
|
|
2088
2087
|
readableWithinDenied: [...readablePaths]
|
|
2089
2088
|
};
|
|
2090
2089
|
}
|
|
2091
|
-
function sessionRole({
|
|
2090
|
+
function sessionRole({ writableRoots, readDenied, readablePaths, blockedPaths }) {
|
|
2092
2091
|
return {
|
|
2092
|
+
guardrailLevel: "standard",
|
|
2093
|
+
blockedPaths: [...blockedPaths],
|
|
2093
2094
|
vendors: SESSION_VENDORS,
|
|
2094
2095
|
vendorHome: { scope: "state" },
|
|
2095
2096
|
network: { access: "open" },
|
|
2096
2097
|
writableRoots: [...new Set(writableRoots)],
|
|
2097
2098
|
lockedCheckouts: [],
|
|
2098
|
-
commitCheckouts,
|
|
2099
|
+
commitCheckouts: [],
|
|
2099
2100
|
readDenied: [...readDenied],
|
|
2100
2101
|
readableWithinDenied: [...readablePaths]
|
|
2101
2102
|
};
|
|
@@ -2298,7 +2299,7 @@ function createAgentApiWiring({ config, agentSessions, listAllSessions, listBoar
|
|
|
2298
2299
|
name,
|
|
2299
2300
|
path: parent.path,
|
|
2300
2301
|
dangerouslySkipPermissions: parent.dangerouslySkipPermissions,
|
|
2301
|
-
|
|
2302
|
+
unguarded: !parent.isConfined
|
|
2302
2303
|
};
|
|
2303
2304
|
let child = null;
|
|
2304
2305
|
let released = false;
|
|
@@ -3464,6 +3465,11 @@ function decideWasActiveFlip(to, event, pendingRestart) {
|
|
|
3464
3465
|
if (!pendingRestart && (event === "user_kill" || to === STATES.DONE || to === STATES.FAILED)) return false;
|
|
3465
3466
|
return null;
|
|
3466
3467
|
}
|
|
3468
|
+
function haveSameWorkspaceRepos(projectRepos, sessionRepos) {
|
|
3469
|
+
const configured = projectRepos ?? [];
|
|
3470
|
+
const running = sessionRepos ?? [];
|
|
3471
|
+
return configured.length === running.length && configured.every((repoPath, index) => repoPath === running[index]);
|
|
3472
|
+
}
|
|
3467
3473
|
function shouldStartAfterModify(previousState) {
|
|
3468
3474
|
return previousState !== STATES.DORMANT;
|
|
3469
3475
|
}
|
|
@@ -3491,7 +3497,8 @@ function diffProjects(currentSessions, newProjects, dependencies) {
|
|
|
3491
3497
|
const resolvedAgentId = dependencies.resolveAgentId(project.agent);
|
|
3492
3498
|
const agentChanged = resolvedAgentId !== session.agentId || agentFingerprintOf(resolvedAgentId) !== capturedAgentFingerprintOf(id);
|
|
3493
3499
|
const hookTrustChanged = project.codexBypassHookTrust === true !== session.bypassHookTrust;
|
|
3494
|
-
|
|
3500
|
+
const workspaceReposChanged = !haveSameWorkspaceRepos(project.repos, session.workspaceRepos);
|
|
3501
|
+
if (pathChanged || permissionsChanged || agentChanged || hookTrustChanged || workspaceReposChanged) {
|
|
3495
3502
|
modified.push(project);
|
|
3496
3503
|
continue;
|
|
3497
3504
|
}
|
|
@@ -3975,7 +3982,7 @@ function runGh(args, options = {}) {
|
|
|
3975
3982
|
}
|
|
3976
3983
|
//#endregion
|
|
3977
3984
|
//#region server/post-turn-checker.ts
|
|
3978
|
-
var GIT_TIMEOUT_MS$
|
|
3985
|
+
var GIT_TIMEOUT_MS$1 = 5e3;
|
|
3979
3986
|
var DEFAULTS = Object.freeze({
|
|
3980
3987
|
enabled: true,
|
|
3981
3988
|
mode: "report",
|
|
@@ -4077,7 +4084,7 @@ var GIT_MAX_BUFFER_BYTES$1 = 8388608;
|
|
|
4077
4084
|
async function execGit(args, cwd) {
|
|
4078
4085
|
const result = await runGit(args, {
|
|
4079
4086
|
cwd,
|
|
4080
|
-
timeoutMs: GIT_TIMEOUT_MS$
|
|
4087
|
+
timeoutMs: GIT_TIMEOUT_MS$1,
|
|
4081
4088
|
maxBuffer: GIT_MAX_BUFFER_BYTES$1,
|
|
4082
4089
|
trim: false
|
|
4083
4090
|
});
|
|
@@ -4792,7 +4799,15 @@ function runAutoResume(sessions, config, spawnGate, logger = console) {
|
|
|
4792
4799
|
}
|
|
4793
4800
|
return Promise.all(runs);
|
|
4794
4801
|
}
|
|
4795
|
-
function
|
|
4802
|
+
function releaseDroppedWorkspaceMembers(oldSession, newSession, currentSessionFor) {
|
|
4803
|
+
return Promise.resolve(oldSession._killReap).catch(() => {}).then(() => {
|
|
4804
|
+
const liveSession = currentSessionFor?.(oldSession.id) ?? newSession;
|
|
4805
|
+
const keepRepoPaths = isSameDirectoryPath(liveSession.path, oldSession.path) ? liveSession.workspaceRepos ?? [] : [];
|
|
4806
|
+
return oldSession.releaseDroppedWorkspaceMembers(keepRepoPaths);
|
|
4807
|
+
}).catch((error) => console.warn(`[config] releasing dropped workspace members failed for ${oldSession.name}: ${errorMessage(error)}`));
|
|
4808
|
+
}
|
|
4809
|
+
function carryWorktreeAcrossRecreate(oldSession, newSession, currentSessionFor) {
|
|
4810
|
+
if (oldSession?.workspaceRepos) return releaseDroppedWorkspaceMembers(oldSession, newSession, currentSessionFor);
|
|
4796
4811
|
const carry = oldSession?.getWorktreeCarry?.();
|
|
4797
4812
|
if (!oldSession || !carry) return;
|
|
4798
4813
|
if (isSameDirectoryPath(newSession.path, oldSession.path)) {
|
|
@@ -4960,7 +4975,7 @@ function createSessionRegistry(dependencies) {
|
|
|
4960
4975
|
sessions.set(project.id, newSession);
|
|
4961
4976
|
captureAgentFingerprint(project);
|
|
4962
4977
|
dependencies.wireSessionEvents(newSession);
|
|
4963
|
-
dependencies.carryWorktreeAcrossRecreate(oldSession, newSession);
|
|
4978
|
+
dependencies.carryWorktreeAcrossRecreate(oldSession, newSession, getSession);
|
|
4964
4979
|
dependencies.broadcastControl({
|
|
4965
4980
|
type: "session-modified",
|
|
4966
4981
|
...projectSessionCard(newSession, {
|
|
@@ -14091,6 +14106,7 @@ var CLOUD_CREDENTIAL_HOME_ENTRIES = Object.freeze([
|
|
|
14091
14106
|
".netrc",
|
|
14092
14107
|
".npmrc"
|
|
14093
14108
|
]);
|
|
14109
|
+
var STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES = Object.freeze(["Library/Keychains"]);
|
|
14094
14110
|
var XDG_CONFIG_DEFAULT_HOME_PREFIX = ".config/";
|
|
14095
14111
|
var SHARED_TEMP_DIRS = Object.freeze(["/tmp/claude", "/private/tmp/claude"]);
|
|
14096
14112
|
var SHARED_HOME_WRITE_ENTRIES = Object.freeze([".npm/_logs"]);
|
|
@@ -14108,10 +14124,60 @@ var SANDBOX_PLACEHOLDER_NAMES = Object.freeze([
|
|
|
14108
14124
|
".zprofile",
|
|
14109
14125
|
".zshrc"
|
|
14110
14126
|
]);
|
|
14127
|
+
var WHOLE_FILESYSTEM = "/";
|
|
14128
|
+
var GLIMMERVOID_CONFIG_SIBLING_ENTRIES = Object.freeze([
|
|
14129
|
+
"bin",
|
|
14130
|
+
"pairings.json",
|
|
14131
|
+
"pairings-seen.json",
|
|
14132
|
+
"plans",
|
|
14133
|
+
"telegram-outbox.json",
|
|
14134
|
+
"traces",
|
|
14135
|
+
"uploads",
|
|
14136
|
+
"usage-budget-state.json",
|
|
14137
|
+
"usage-lanes.json",
|
|
14138
|
+
"usage-warehouse.json",
|
|
14139
|
+
"visions-intent.json"
|
|
14140
|
+
]);
|
|
14141
|
+
var GLIMMERVOID_HOME_STATE_ENTRIES = Object.freeze([
|
|
14142
|
+
"benchmark-runs",
|
|
14143
|
+
"benchmarks",
|
|
14144
|
+
"config.json",
|
|
14145
|
+
"factory",
|
|
14146
|
+
"issues-cache.json",
|
|
14147
|
+
"knowledge-graph",
|
|
14148
|
+
"litellm-pricing.json",
|
|
14149
|
+
"my-prs-state.json",
|
|
14150
|
+
"my-prs-work",
|
|
14151
|
+
"posthog-reports",
|
|
14152
|
+
"posthog-state.json",
|
|
14153
|
+
"posthog-work",
|
|
14154
|
+
"recordings",
|
|
14155
|
+
"sandbox-homes",
|
|
14156
|
+
"sandbox-policies",
|
|
14157
|
+
"sane-yolo",
|
|
14158
|
+
"scratch",
|
|
14159
|
+
"sounds",
|
|
14160
|
+
"team-review-repos",
|
|
14161
|
+
"team-review-state.json",
|
|
14162
|
+
"team-review-work",
|
|
14163
|
+
"team-review-worktrees",
|
|
14164
|
+
"telemetry-pending-crash.json",
|
|
14165
|
+
"telemetry.json",
|
|
14166
|
+
"tmp",
|
|
14167
|
+
"update-check.json",
|
|
14168
|
+
"update-journal.json",
|
|
14169
|
+
"workflows-state.json",
|
|
14170
|
+
"workflows-work"
|
|
14171
|
+
]);
|
|
14111
14172
|
var RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS = Object.freeze(["commands", "agents"]);
|
|
14112
14173
|
var SANDBOXED_PROXY_BYPASS = "localhost,::1,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16";
|
|
14113
14174
|
var HOOK_LOOPBACK_HOST = "127.0.0.1";
|
|
14114
14175
|
var AGENT_SESSION_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
14176
|
+
var STANDARD_OPEN_NETWORK = Object.freeze({
|
|
14177
|
+
allowAllUnixSockets: true,
|
|
14178
|
+
allowMachLookup: ["*"]
|
|
14179
|
+
});
|
|
14180
|
+
var STRICT_OPEN_NETWORK = Object.freeze({ allowAllUnixSockets: false });
|
|
14115
14181
|
function unique(entries) {
|
|
14116
14182
|
return [...new Set(entries)];
|
|
14117
14183
|
}
|
|
@@ -14226,10 +14292,45 @@ function relocatedXdgConfigPaths(host, homeEntries) {
|
|
|
14226
14292
|
if (xdgConfigHome === null) return [];
|
|
14227
14293
|
return homeEntries.filter((entry) => entry.startsWith(XDG_CONFIG_DEFAULT_HOME_PREFIX)).map((entry) => path.join(xdgConfigHome, entry.slice(8)));
|
|
14228
14294
|
}
|
|
14295
|
+
function isStandardLevel(role) {
|
|
14296
|
+
return role.guardrailLevel === "standard";
|
|
14297
|
+
}
|
|
14298
|
+
function blockedCredentialHomeEntries(role) {
|
|
14299
|
+
const credentialHomeEntries = [...CREDENTIAL_HOME_ENTRIES, ...CLOUD_CREDENTIAL_HOME_ENTRIES];
|
|
14300
|
+
if (!isStandardLevel(role)) return credentialHomeEntries;
|
|
14301
|
+
return credentialHomeEntries.filter((entry) => !STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES.includes(entry));
|
|
14302
|
+
}
|
|
14303
|
+
function credentialWriteBlocks(role, host) {
|
|
14304
|
+
const credentialHomeEntries = blockedCredentialHomeEntries(role);
|
|
14305
|
+
return [...homePaths(host, credentialHomeEntries), ...relocatedXdgConfigPaths(host, credentialHomeEntries)];
|
|
14306
|
+
}
|
|
14307
|
+
function glimmervoidStateWriteBlocks(role, host) {
|
|
14308
|
+
const keptWritable = alwaysWritablePaths(role, host);
|
|
14309
|
+
const configFolder = path.dirname(host.glimmervoidConfigFile);
|
|
14310
|
+
const homeEntries = [
|
|
14311
|
+
...GLIMMERVOID_HOME_STATE_ENTRIES,
|
|
14312
|
+
...GLIMMERVOID_CONFIG_SIBLING_ENTRIES,
|
|
14313
|
+
...host.glimmervoidHomeEntryNames
|
|
14314
|
+
].map((entryName) => path.join(host.glimmervoidHome, entryName));
|
|
14315
|
+
const configSiblings = GLIMMERVOID_CONFIG_SIBLING_ENTRIES.map((entryName) => path.join(configFolder, entryName));
|
|
14316
|
+
return unique([
|
|
14317
|
+
host.glimmervoidConfigFile,
|
|
14318
|
+
...homeEntries,
|
|
14319
|
+
...configSiblings
|
|
14320
|
+
]).filter((entryPath) => !keptWritable.some((writable) => isPathInside(entryPath, writable)));
|
|
14321
|
+
}
|
|
14322
|
+
function standardWriteBlockCandidates(role, host) {
|
|
14323
|
+
if (!isStandardLevel(role)) return [];
|
|
14324
|
+
return unique([
|
|
14325
|
+
...credentialWriteBlocks(role, host),
|
|
14326
|
+
...glimmervoidStateWriteBlocks(role, host),
|
|
14327
|
+
...role.blockedPaths ?? []
|
|
14328
|
+
]);
|
|
14329
|
+
}
|
|
14229
14330
|
function readDeniedPaths(role, host) {
|
|
14230
14331
|
const otherVendors = SANDBOX_VENDORS.filter((vendor) => !role.vendors.includes(vendor));
|
|
14231
14332
|
const otherVendorHomeEntries = [...otherVendors.flatMap((vendor) => VENDOR_PROFILES[vendor].homeEntries), ...UNWRAPPED_VENDOR_HOME_ENTRIES];
|
|
14232
|
-
const credentialHomeEntries =
|
|
14333
|
+
const credentialHomeEntries = blockedCredentialHomeEntries(role);
|
|
14233
14334
|
return [
|
|
14234
14335
|
...homePaths(host, [
|
|
14235
14336
|
...credentialHomeEntries,
|
|
@@ -14259,6 +14360,7 @@ function hostNamedPaths(host) {
|
|
|
14259
14360
|
return [
|
|
14260
14361
|
host.homeDir,
|
|
14261
14362
|
host.glimmervoidHome,
|
|
14363
|
+
host.glimmervoidConfigFile,
|
|
14262
14364
|
host.tempDir,
|
|
14263
14365
|
host.launchHomeDir,
|
|
14264
14366
|
...relocatedXdgConfigHomes,
|
|
@@ -14287,7 +14389,7 @@ function sandboxRoleRefusal(role, host) {
|
|
|
14287
14389
|
return null;
|
|
14288
14390
|
}
|
|
14289
14391
|
function networkPolicy(role) {
|
|
14290
|
-
if (role.network.access === "open") return {
|
|
14392
|
+
if (role.network.access === "open") return isStandardLevel(role) ? { ...STANDARD_OPEN_NETWORK } : { ...STRICT_OPEN_NETWORK };
|
|
14291
14393
|
if (role.network.access === "none") return {
|
|
14292
14394
|
allowedDomains: [],
|
|
14293
14395
|
deniedDomains: [],
|
|
@@ -14317,6 +14419,17 @@ function sandboxedEnvFor(role, host) {
|
|
|
14317
14419
|
if (role.network.access === "open") return { TMPDIR: host.tempDir };
|
|
14318
14420
|
return {};
|
|
14319
14421
|
}
|
|
14422
|
+
function filesystemWrites(role, host, writablePaths) {
|
|
14423
|
+
if (isStandardLevel(role)) return {
|
|
14424
|
+
allowWrite: literalEntries([WHOLE_FILESYSTEM, ...writablePaths]),
|
|
14425
|
+
denyWrite: literalEntries(host.writeBlockedPaths)
|
|
14426
|
+
};
|
|
14427
|
+
const isPresent = (candidate) => host.existingPaths.has(candidate);
|
|
14428
|
+
return {
|
|
14429
|
+
allowWrite: literalEntries(writablePaths),
|
|
14430
|
+
denyWrite: literalEntries([...writeDeniesWhenPresent(role, host).filter(isPresent), ...lockedCheckoutWriteDenies(role)])
|
|
14431
|
+
};
|
|
14432
|
+
}
|
|
14320
14433
|
function buildSandboxLaunchPlan(role, host) {
|
|
14321
14434
|
const refusal = sandboxRoleRefusal(role, host);
|
|
14322
14435
|
if (refusal !== null) return {
|
|
@@ -14336,9 +14449,10 @@ function buildSandboxLaunchPlan(role, host) {
|
|
|
14336
14449
|
filesystem: {
|
|
14337
14450
|
denyRead: literalEntries(readDenied),
|
|
14338
14451
|
allowRead: literalEntries([...writableWithinDenied, ...role.readableWithinDenied]),
|
|
14339
|
-
|
|
14340
|
-
|
|
14341
|
-
|
|
14452
|
+
...filesystemWrites(role, host, writablePaths)
|
|
14453
|
+
},
|
|
14454
|
+
terminalScope: isStandardLevel(role) ? "any" : "own",
|
|
14455
|
+
allowAppleEvents: isStandardLevel(role)
|
|
14342
14456
|
},
|
|
14343
14457
|
launchEnv: Object.assign({ CLAUDE_CODE_TMPDIR: host.tempDir }, ...role.vendors.map((vendor) => VENDOR_PROFILES[vendor].launchEnv), launchHomeEnv(role, host)),
|
|
14344
14458
|
sandboxedEnv: sandboxedEnvFor(role, host),
|
|
@@ -14386,33 +14500,6 @@ function parseTagVersion(ref) {
|
|
|
14386
14500
|
if (!matched) return null;
|
|
14387
14501
|
return matched[1];
|
|
14388
14502
|
}
|
|
14389
|
-
function parseLsRemoteTags(stdout) {
|
|
14390
|
-
if (typeof stdout !== "string") return null;
|
|
14391
|
-
const tagsByVersion = /* @__PURE__ */ new Map();
|
|
14392
|
-
for (const line of stdout.split("\n")) {
|
|
14393
|
-
const fields = line.trim().split(/\s+/);
|
|
14394
|
-
if (fields.length < 2) continue;
|
|
14395
|
-
const sha = normalizeSha(fields[0]);
|
|
14396
|
-
if (!sha) continue;
|
|
14397
|
-
const ref = fields[1];
|
|
14398
|
-
const version = parseTagVersion(ref);
|
|
14399
|
-
if (!version) continue;
|
|
14400
|
-
if (tagsByVersion.get(version) && !ref.endsWith("^{}")) continue;
|
|
14401
|
-
tagsByVersion.set(version, {
|
|
14402
|
-
version,
|
|
14403
|
-
sha
|
|
14404
|
-
});
|
|
14405
|
-
}
|
|
14406
|
-
let latest = null;
|
|
14407
|
-
for (const entry of tagsByVersion.values()) {
|
|
14408
|
-
if (!latest) {
|
|
14409
|
-
latest = entry;
|
|
14410
|
-
continue;
|
|
14411
|
-
}
|
|
14412
|
-
if (compareSemver(entry.version, latest.version) > 0) latest = entry;
|
|
14413
|
-
}
|
|
14414
|
-
return latest;
|
|
14415
|
-
}
|
|
14416
14503
|
function isNpxCachePath(packageRoot) {
|
|
14417
14504
|
if (typeof packageRoot !== "string") return false;
|
|
14418
14505
|
return packageRoot.split(/[\\/]/).includes(NPX_CACHE_DIRECTORY_NAME);
|
|
@@ -14487,19 +14574,6 @@ function compareSemver(a, b) {
|
|
|
14487
14574
|
}
|
|
14488
14575
|
return 0;
|
|
14489
14576
|
}
|
|
14490
|
-
function parseLatestReleaseTag(doc) {
|
|
14491
|
-
if (!doc || typeof doc !== "object") return null;
|
|
14492
|
-
const version = parseTagVersion(doc.tag_name);
|
|
14493
|
-
if (!version) return null;
|
|
14494
|
-
return {
|
|
14495
|
-
version,
|
|
14496
|
-
sha: null
|
|
14497
|
-
};
|
|
14498
|
-
}
|
|
14499
|
-
function decideReleaseSource(flavor) {
|
|
14500
|
-
if (flavor === "npm-global" || flavor === "npx") return "npm-registry";
|
|
14501
|
-
return "github-tags";
|
|
14502
|
-
}
|
|
14503
14577
|
function parseRegistryLatest(doc) {
|
|
14504
14578
|
if (!doc || typeof doc !== "object") return null;
|
|
14505
14579
|
const registryDocument = doc;
|
|
@@ -17182,6 +17256,10 @@ function planWorkspaceMembers({ folder, sessionId, repoPaths }) {
|
|
|
17182
17256
|
}
|
|
17183
17257
|
};
|
|
17184
17258
|
}
|
|
17259
|
+
function listDroppedRepoPaths(previousRepoPaths, nextRepoPaths) {
|
|
17260
|
+
const nextRepoKeys = new Set(nextRepoPaths.map((repoPath) => caseFoldedPathKey(path.resolve(repoPath))));
|
|
17261
|
+
return previousRepoPaths.filter((repoPath) => !nextRepoKeys.has(caseFoldedPathKey(path.resolve(repoPath))));
|
|
17262
|
+
}
|
|
17185
17263
|
function renderWorkspaceAgentsMd({ sessionName, branch, members }) {
|
|
17186
17264
|
const lines = [
|
|
17187
17265
|
`# ${sessionName}`,
|
|
@@ -17204,6 +17282,34 @@ async function writeWhenAbsent(filePath, contents) {
|
|
|
17204
17282
|
if (error.code !== "EEXIST") throw error;
|
|
17205
17283
|
});
|
|
17206
17284
|
}
|
|
17285
|
+
var WORKSPACE_MAP_FILE = "AGENTS.md";
|
|
17286
|
+
var WORKSPACE_POINTER_FILE = "CLAUDE.md";
|
|
17287
|
+
var WORKSPACE_MAP_HASH_FILE = ".glimmervoid-map-hash";
|
|
17288
|
+
var GENERATED_WORKSPACE_FILES = /* @__PURE__ */ new Set([
|
|
17289
|
+
WORKSPACE_MAP_FILE,
|
|
17290
|
+
WORKSPACE_POINTER_FILE,
|
|
17291
|
+
WORKSPACE_MAP_HASH_FILE
|
|
17292
|
+
]);
|
|
17293
|
+
function hashWorkspaceMap(contents) {
|
|
17294
|
+
return crypto.createHash("sha256").update(contents).digest("hex");
|
|
17295
|
+
}
|
|
17296
|
+
async function readWhenPresent(filePath) {
|
|
17297
|
+
return fs.promises.readFile(filePath, "utf8").catch((error) => {
|
|
17298
|
+
if (error.code === "ENOENT") return null;
|
|
17299
|
+
throw error;
|
|
17300
|
+
});
|
|
17301
|
+
}
|
|
17302
|
+
async function writeWorkspaceMap(folder, contents) {
|
|
17303
|
+
const mapPath = path.join(folder, WORKSPACE_MAP_FILE);
|
|
17304
|
+
const hashPath = path.join(folder, WORKSPACE_MAP_HASH_FILE);
|
|
17305
|
+
const existingMap = await readWhenPresent(mapPath);
|
|
17306
|
+
const recordedHash = (await readWhenPresent(hashPath))?.trim() ?? null;
|
|
17307
|
+
const renderedHash = hashWorkspaceMap(contents);
|
|
17308
|
+
if (existingMap !== null && existingMap !== contents && hashWorkspaceMap(existingMap) !== recordedHash) return;
|
|
17309
|
+
if (existingMap === contents && recordedHash === renderedHash) return;
|
|
17310
|
+
await fs.promises.writeFile(mapPath, contents);
|
|
17311
|
+
await fs.promises.writeFile(hashPath, `${renderedHash}\n`);
|
|
17312
|
+
}
|
|
17207
17313
|
function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorkspace }) {
|
|
17208
17314
|
let activeProvision = null;
|
|
17209
17315
|
async function provisionBody() {
|
|
@@ -17226,12 +17332,12 @@ function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorksp
|
|
|
17226
17332
|
base: ensured.base
|
|
17227
17333
|
});
|
|
17228
17334
|
}
|
|
17229
|
-
await
|
|
17335
|
+
await writeWorkspaceMap(plan.folder, renderWorkspaceAgentsMd({
|
|
17230
17336
|
sessionName,
|
|
17231
17337
|
branch: plan.branch,
|
|
17232
17338
|
members
|
|
17233
17339
|
}));
|
|
17234
|
-
await writeWhenAbsent(path.join(plan.folder,
|
|
17340
|
+
await writeWhenAbsent(path.join(plan.folder, WORKSPACE_POINTER_FILE), WORKSPACE_CLAUDE_MD);
|
|
17235
17341
|
return {
|
|
17236
17342
|
ok: true,
|
|
17237
17343
|
members
|
|
@@ -17252,10 +17358,12 @@ function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorksp
|
|
|
17252
17358
|
});
|
|
17253
17359
|
return attempt;
|
|
17254
17360
|
}
|
|
17255
|
-
async function release() {
|
|
17361
|
+
async function release({ keepRepoPaths = [] } = {}) {
|
|
17256
17362
|
if (activeProvision) await activeProvision;
|
|
17363
|
+
const keptRepoKeys = new Set(keepRepoPaths.map((repoPath) => caseFoldedPathKey(path.resolve(repoPath))));
|
|
17257
17364
|
const keptDirs = [];
|
|
17258
17365
|
for (const member of plan.members) {
|
|
17366
|
+
if (keptRepoKeys.has(caseFoldedPathKey(member.repoPath))) continue;
|
|
17259
17367
|
if (!await fs.promises.stat(member.dir).then(() => true, () => false)) continue;
|
|
17260
17368
|
if (!(await gitWorkspace.removeWorkspaceMember({
|
|
17261
17369
|
projectPath: member.repoPath,
|
|
@@ -17264,7 +17372,7 @@ function createSessionWorkspaceMembers({ plan, sessionName, shareList, gitWorksp
|
|
|
17264
17372
|
})).ok) keptDirs.push(member.dir);
|
|
17265
17373
|
}
|
|
17266
17374
|
const entries = await fs.promises.readdir(plan.folder).catch(() => []);
|
|
17267
|
-
if (entries.some((entry) =>
|
|
17375
|
+
if (entries.some((entry) => !GENERATED_WORKSPACE_FILES.has(entry))) return { keptDirs };
|
|
17268
17376
|
for (const entry of entries) await fs.promises.rm(path.join(plan.folder, entry), { force: true });
|
|
17269
17377
|
await fs.promises.rmdir(plan.folder).catch(() => {});
|
|
17270
17378
|
return { keptDirs };
|
|
@@ -17738,10 +17846,14 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
|
|
|
17738
17846
|
lifecycleState.isWorktree = false;
|
|
17739
17847
|
setMergeStatus(status);
|
|
17740
17848
|
}
|
|
17741
|
-
async function releaseWorkspaceMembers(members) {
|
|
17742
|
-
const released = await members.release();
|
|
17849
|
+
async function releaseWorkspaceMembers(members, keepRepoPaths = []) {
|
|
17850
|
+
const released = await members.release({ keepRepoPaths });
|
|
17743
17851
|
if (released.keptDirs.length > 0) console.warn(`[session ${id}] kept workspace members with uncommitted work: ${released.keptDirs.join(", ")}`);
|
|
17744
17852
|
}
|
|
17853
|
+
async function releaseDroppedWorkspaceMembers(keepRepoPaths) {
|
|
17854
|
+
if (!workspaceMembers?.ok) return;
|
|
17855
|
+
await releaseWorkspaceMembers(workspaceMembers.members, keepRepoPaths);
|
|
17856
|
+
}
|
|
17745
17857
|
async function discardWorktree() {
|
|
17746
17858
|
if (workspaceMembers?.ok) return releaseWorkspaceMembers(workspaceMembers.members);
|
|
17747
17859
|
stopWatching();
|
|
@@ -18514,7 +18626,8 @@ function createSessionWorktreeLifecycle({ id, projectPath, integrationBranch = n
|
|
|
18514
18626
|
mergeWorktree,
|
|
18515
18627
|
mergeAndContinue,
|
|
18516
18628
|
adoptWorktree,
|
|
18517
|
-
discardWorktree
|
|
18629
|
+
discardWorktree,
|
|
18630
|
+
releaseDroppedWorkspaceMembers
|
|
18518
18631
|
};
|
|
18519
18632
|
return api;
|
|
18520
18633
|
}
|
|
@@ -18935,8 +19048,8 @@ var KILL_MAX_WAIT_MS = 3e3;
|
|
|
18935
19048
|
var KILL_REAP_MAX_WAIT_MS = 2400;
|
|
18936
19049
|
var SLEEP_KILL_TIMEOUT_MS = 9e5;
|
|
18937
19050
|
var MAX_PENDING_ATTENTION_NOTES = 5;
|
|
18938
|
-
var SANDBOX_UNAPPLIED_ERROR = "
|
|
18939
|
-
var SANDBOX_REFUSED_PREFIX = "session not started, the
|
|
19051
|
+
var SANDBOX_UNAPPLIED_ERROR = "guardrail settings could not be applied, session not started";
|
|
19052
|
+
var SANDBOX_REFUSED_PREFIX = "session not started, the guardrails refused: ";
|
|
18940
19053
|
var INNER_SANDBOX_OFF = Object.freeze({ enabled: false });
|
|
18941
19054
|
function settingsSandboxForHooks(adapter, hasOuterSandbox, requestedSettingsSandbox) {
|
|
18942
19055
|
if (!hasOuterSandbox) return requestedSettingsSandbox;
|
|
@@ -19019,6 +19132,7 @@ var Session = class extends EventEmitter {
|
|
|
19019
19132
|
_initialPrompt;
|
|
19020
19133
|
_extraClaudeArgs;
|
|
19021
19134
|
_resumeSessionId;
|
|
19135
|
+
workspaceRepos;
|
|
19022
19136
|
_transcriptPath;
|
|
19023
19137
|
_lastClaudeSessionReport;
|
|
19024
19138
|
_suppressResumeCapture;
|
|
@@ -19152,6 +19266,7 @@ var Session = class extends EventEmitter {
|
|
|
19152
19266
|
this._initialPrompt = initialPrompt;
|
|
19153
19267
|
this._extraClaudeArgs = Array.isArray(extraClaudeArgs) ? extraClaudeArgs : [];
|
|
19154
19268
|
this._resumeSessionId = resumeSessionId || null;
|
|
19269
|
+
this.workspaceRepos = workspaceRepos ? [...workspaceRepos] : null;
|
|
19155
19270
|
this._transcriptPath = null;
|
|
19156
19271
|
this._lastClaudeSessionReport = null;
|
|
19157
19272
|
this._suppressResumeCapture = false;
|
|
@@ -19762,6 +19877,9 @@ var Session = class extends EventEmitter {
|
|
|
19762
19877
|
discardWorktreeIfClean() {
|
|
19763
19878
|
return this.worktreeLifecycle.discardIfClean();
|
|
19764
19879
|
}
|
|
19880
|
+
releaseDroppedWorkspaceMembers(keepRepoPaths) {
|
|
19881
|
+
return this.worktreeLifecycle.releaseDroppedWorkspaceMembers(keepRepoPaths);
|
|
19882
|
+
}
|
|
19765
19883
|
pasteMergePrompt() {
|
|
19766
19884
|
return this.worktreeLifecycle.pasteMergePrompt();
|
|
19767
19885
|
}
|
|
@@ -20128,7 +20246,7 @@ var Session = class extends EventEmitter {
|
|
|
20128
20246
|
if (!launch || launch !== this._sandboxLaunch) return;
|
|
20129
20247
|
this._sandboxLaunch = null;
|
|
20130
20248
|
launch.dispose().catch((error) => {
|
|
20131
|
-
console.warn(`[session ${this.id}]
|
|
20249
|
+
console.warn(`[session ${this.id}] guardrails cleanup failed: ${errorMessage(error)}`);
|
|
20132
20250
|
});
|
|
20133
20251
|
}
|
|
20134
20252
|
_guardPtyInputSocket() {
|
|
@@ -20689,6 +20807,7 @@ var LAUNCH_HOME_FOLDER = "sandbox-homes";
|
|
|
20689
20807
|
var START_FOLDER = "start";
|
|
20690
20808
|
var ENTER_FOLDER_SCRIPT = "cd \"$1\" && shift && exec \"$@\"";
|
|
20691
20809
|
var LOGIN_FILE_MODE = 384;
|
|
20810
|
+
var ABSENT_PATH_DENY_PLATFORM = "darwin";
|
|
20692
20811
|
async function isPresent(candidate) {
|
|
20693
20812
|
try {
|
|
20694
20813
|
await access(candidate);
|
|
@@ -20714,6 +20833,32 @@ async function realPathWhenPresent(candidate) {
|
|
|
20714
20833
|
function realPathsWhenPresent(candidates) {
|
|
20715
20834
|
return Promise.all(candidates.map(realPathWhenPresent));
|
|
20716
20835
|
}
|
|
20836
|
+
async function symlinkTargetsInside(folder) {
|
|
20837
|
+
const symlinkEntries = (await readdir(folder, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isSymbolicLink());
|
|
20838
|
+
return (await Promise.all(symlinkEntries.map((entry) => realpath(path.join(folder, entry.name)).catch(() => null)))).filter((target) => target !== null);
|
|
20839
|
+
}
|
|
20840
|
+
async function blockedPathsWithRealTargets(candidates, operatorBlockedPaths) {
|
|
20841
|
+
const resolved = await Promise.all(candidates.map(async (candidate) => {
|
|
20842
|
+
const isPresentEntry = await lstat(candidate).then(() => true, (error) => !isMissingFileError(error));
|
|
20843
|
+
const isKeptWhenAbsent = process.platform === ABSENT_PATH_DENY_PLATFORM || operatorBlockedPaths.includes(candidate);
|
|
20844
|
+
if (!isPresentEntry) return isKeptWhenAbsent ? [candidate] : [];
|
|
20845
|
+
const realCandidate = await realpath(candidate).catch(() => candidate);
|
|
20846
|
+
return [
|
|
20847
|
+
candidate,
|
|
20848
|
+
realCandidate,
|
|
20849
|
+
...await symlinkTargetsInside(realCandidate)
|
|
20850
|
+
];
|
|
20851
|
+
}));
|
|
20852
|
+
return [...new Set(resolved.flat())];
|
|
20853
|
+
}
|
|
20854
|
+
async function configuredConfigFile(glimmervoidHome) {
|
|
20855
|
+
const { envPath, homePath } = decideConfigPath({
|
|
20856
|
+
env: process.env,
|
|
20857
|
+
homeDir: glimmervoidHome
|
|
20858
|
+
}, () => false);
|
|
20859
|
+
const configFile = envPath ?? homePath;
|
|
20860
|
+
return path.join(await realPathWhenPresent(path.dirname(configFile)), path.basename(configFile));
|
|
20861
|
+
}
|
|
20717
20862
|
function scannedClaudeHomes(env, homeDir) {
|
|
20718
20863
|
return [env, {
|
|
20719
20864
|
...env,
|
|
@@ -20858,20 +21003,30 @@ async function prepareSandboxLaunch({ role, launchId, tempDir, enterDir }) {
|
|
|
20858
21003
|
reason: "CODEX_HOME names no folder"
|
|
20859
21004
|
};
|
|
20860
21005
|
const xdgConfigHomeOverride = rawTextOr(process.env.XDG_CONFIG_HOME, null);
|
|
20861
|
-
const
|
|
21006
|
+
const stableHostPaths = {
|
|
20862
21007
|
homeDir,
|
|
20863
21008
|
glimmervoidHome,
|
|
21009
|
+
glimmervoidConfigFile: await configuredConfigFile(glimmervoidHome),
|
|
20864
21010
|
tempDir: launchTempDir,
|
|
20865
21011
|
launchHomeDir,
|
|
20866
|
-
homeEntryNames: await readdir(homeDir),
|
|
20867
21012
|
vendorLocations,
|
|
20868
21013
|
unwrappedVendorHomes: await realPathsWhenPresent(grokHomes(process.env, homeDir)),
|
|
20869
21014
|
relocatedXdgConfigHome: xdgConfigHomeOverride === null ? null : await realPathWhenPresent(xdgConfigHomeOverride)
|
|
20870
21015
|
};
|
|
20871
|
-
const buildPlanFromCurrentDisk = async () =>
|
|
20872
|
-
|
|
20873
|
-
|
|
20874
|
-
|
|
21016
|
+
const buildPlanFromCurrentDisk = async () => {
|
|
21017
|
+
const [homeEntryNames, glimmervoidHomeEntryNames] = await Promise.all([readdir(homeDir), readdir(glimmervoidHome)]);
|
|
21018
|
+
const hostPaths = {
|
|
21019
|
+
...stableHostPaths,
|
|
21020
|
+
homeEntryNames,
|
|
21021
|
+
glimmervoidHomeEntryNames
|
|
21022
|
+
};
|
|
21023
|
+
const [existingPaths, writeBlockedPaths] = await Promise.all([presentPaths$1(sandboxPolicyProbePaths(realRole, hostPaths)), blockedPathsWithRealTargets(standardWriteBlockCandidates(realRole, hostPaths), realRole.blockedPaths ?? [])]);
|
|
21024
|
+
return buildSandboxLaunchPlan(realRole, {
|
|
21025
|
+
...hostPaths,
|
|
21026
|
+
existingPaths,
|
|
21027
|
+
writeBlockedPaths
|
|
21028
|
+
});
|
|
21029
|
+
};
|
|
20875
21030
|
const built = await buildPlanFromCurrentDisk();
|
|
20876
21031
|
if (!built.ok) return built;
|
|
20877
21032
|
const { plan } = built;
|
|
@@ -46850,7 +47005,7 @@ function computeCrossRepoLinks(repos) {
|
|
|
46850
47005
|
}
|
|
46851
47006
|
//#endregion
|
|
46852
47007
|
//#region server/change-map-wiring.ts
|
|
46853
|
-
var GIT_TIMEOUT_MS
|
|
47008
|
+
var GIT_TIMEOUT_MS = 15e3;
|
|
46854
47009
|
var GIT_MAX_BUFFER_BYTES = 67108864;
|
|
46855
47010
|
var FILE_READ_BATCH = 64;
|
|
46856
47011
|
var MAX_CACHED_FILES = 5e4;
|
|
@@ -46862,11 +47017,11 @@ var MAX_MEMOIZED_REPO_FACTS = 64;
|
|
|
46862
47017
|
async function runGitAsync(args, cwd) {
|
|
46863
47018
|
const result = await runGit(args, {
|
|
46864
47019
|
cwd,
|
|
46865
|
-
timeoutMs: GIT_TIMEOUT_MS
|
|
47020
|
+
timeoutMs: GIT_TIMEOUT_MS,
|
|
46866
47021
|
maxBuffer: GIT_MAX_BUFFER_BYTES,
|
|
46867
47022
|
trim: false
|
|
46868
47023
|
});
|
|
46869
|
-
if (!result.ok) throw gitCommandFailure(args, result, GIT_TIMEOUT_MS
|
|
47024
|
+
if (!result.ok) throw gitCommandFailure(args, result, GIT_TIMEOUT_MS);
|
|
46870
47025
|
return result.out;
|
|
46871
47026
|
}
|
|
46872
47027
|
function yieldToEventLoop() {
|
|
@@ -47371,9 +47526,9 @@ Object.freeze([
|
|
|
47371
47526
|
...USAGE_BUDGET_KEYS.map((key) => `usage.budget.${key}`),
|
|
47372
47527
|
...TELEGRAM_STRING_KEYS.map((key) => `telegram.${key}`),
|
|
47373
47528
|
"agentApi.enabled",
|
|
47374
|
-
"
|
|
47375
|
-
"
|
|
47376
|
-
"
|
|
47529
|
+
"guardrails.unguardedRepos",
|
|
47530
|
+
"guardrails.blockedPaths",
|
|
47531
|
+
"guardrails.unreadablePaths",
|
|
47377
47532
|
"telemetry.enabled"
|
|
47378
47533
|
]);
|
|
47379
47534
|
var USAGE_REPORT_MAX_DAYS = 3650;
|
|
@@ -47759,6 +47914,89 @@ function registerControlHandlers(controlWss, deps) {
|
|
|
47759
47914
|
});
|
|
47760
47915
|
if (freshConfig) applyConfigReload(freshConfig);
|
|
47761
47916
|
}
|
|
47917
|
+
function handleGetWorkspaceRepos(msg, ws) {
|
|
47918
|
+
const project = findConfiguredProject(msg.id);
|
|
47919
|
+
if (!project?.repos) {
|
|
47920
|
+
replyTo(ws, msg, "workspace-repos", {
|
|
47921
|
+
id: msg.id,
|
|
47922
|
+
ok: false,
|
|
47923
|
+
repos: [],
|
|
47924
|
+
error: "This session is not a workspace"
|
|
47925
|
+
});
|
|
47926
|
+
return;
|
|
47927
|
+
}
|
|
47928
|
+
replyTo(ws, msg, "workspace-repos", {
|
|
47929
|
+
id: msg.id,
|
|
47930
|
+
ok: true,
|
|
47931
|
+
repos: project.repos,
|
|
47932
|
+
error: null
|
|
47933
|
+
});
|
|
47934
|
+
}
|
|
47935
|
+
async function findDroppedMemberWithUncommittedWork(workspaceFolder, droppedRepoPaths) {
|
|
47936
|
+
for (const repoPath of droppedRepoPaths) {
|
|
47937
|
+
const memberName = path.basename(path.resolve(repoPath));
|
|
47938
|
+
const memberDir = path.join(workspaceFolder, memberName);
|
|
47939
|
+
if (!await fs.promises.stat(memberDir).then(() => true, () => false)) continue;
|
|
47940
|
+
const memberStatus = await runGit([
|
|
47941
|
+
"--no-optional-locks",
|
|
47942
|
+
"status",
|
|
47943
|
+
"--porcelain"
|
|
47944
|
+
], { cwd: memberDir });
|
|
47945
|
+
if (!memberStatus.ok) throw memberStatus.error;
|
|
47946
|
+
if (memberStatus.out !== "") return memberName;
|
|
47947
|
+
}
|
|
47948
|
+
return null;
|
|
47949
|
+
}
|
|
47950
|
+
async function handleSetWorkspaceRepos(msg, ws) {
|
|
47951
|
+
const reply = (error) => replyTo(ws, msg, "set-workspace-repos-result", {
|
|
47952
|
+
id: msg.id,
|
|
47953
|
+
ok: error === null,
|
|
47954
|
+
error
|
|
47955
|
+
});
|
|
47956
|
+
const project = findConfiguredProject(msg.id);
|
|
47957
|
+
const session = sessions.get(msg.id);
|
|
47958
|
+
if (!project?.repos || !session) {
|
|
47959
|
+
reply("This session is not a workspace");
|
|
47960
|
+
return;
|
|
47961
|
+
}
|
|
47962
|
+
const missingRepo = msg.repos.find((repoPath) => !isExistingDirectory(repoPath));
|
|
47963
|
+
if (missingRepo) {
|
|
47964
|
+
reply(`Repository path does not exist: ${missingRepo}`);
|
|
47965
|
+
return;
|
|
47966
|
+
}
|
|
47967
|
+
const planned = planWorkspaceMembers({
|
|
47968
|
+
folder: project.path,
|
|
47969
|
+
sessionId: project.id,
|
|
47970
|
+
repoPaths: msg.repos
|
|
47971
|
+
});
|
|
47972
|
+
if (!planned.ok) {
|
|
47973
|
+
reply(planned.error);
|
|
47974
|
+
return;
|
|
47975
|
+
}
|
|
47976
|
+
const nextRepos = planned.plan.members.map((member) => member.repoPath);
|
|
47977
|
+
try {
|
|
47978
|
+
const dirtyMemberName = await findDroppedMemberWithUncommittedWork(project.path, listDroppedRepoPaths(project.repos, nextRepos));
|
|
47979
|
+
if (dirtyMemberName) {
|
|
47980
|
+
reply(`${dirtyMemberName} has uncommitted changes. Commit or discard them before removing it from the workspace.`);
|
|
47981
|
+
return;
|
|
47982
|
+
}
|
|
47983
|
+
} catch (error) {
|
|
47984
|
+
reply(`Could not check the workspace for uncommitted changes: ${errorMessage(error)}`);
|
|
47985
|
+
return;
|
|
47986
|
+
}
|
|
47987
|
+
const freshConfig = configStore.save((cfg) => {
|
|
47988
|
+
const configured = cfg.projects.find((entry) => entry.id === project.id);
|
|
47989
|
+
if (!configured) return ABORT_CONFIG_SAVE;
|
|
47990
|
+
configured.repos = nextRepos;
|
|
47991
|
+
});
|
|
47992
|
+
if (!freshConfig) {
|
|
47993
|
+
reply(`Could not save session "${project.name}"`);
|
|
47994
|
+
return;
|
|
47995
|
+
}
|
|
47996
|
+
applyConfigReload(freshConfig);
|
|
47997
|
+
console.log(`[control] Workspace repositories updated via UI: ${project.name} (${nextRepos.length} repos)`);
|
|
47998
|
+
reply(null);
|
|
47999
|
+
}
|
|
47762
48000
|
function handleSetSessionTitle(msg, ws) {
|
|
47763
48001
|
const session = findSession(msg);
|
|
47764
48002
|
const parsedTitle = TaskTitle.safeParse(msg.title);
|
|
@@ -47954,7 +48192,7 @@ function registerControlHandlers(controlWss, deps) {
|
|
|
47954
48192
|
if (incoming.ingest != null) cfg.ingest = mergeSettingsBlock(cfg.ingest, incoming.ingest, INGEST_SPEC);
|
|
47955
48193
|
if (s.telegram != null) cfg.telegram = mergeSettingsBlockOverStored(cfg.telegram, s.telegram);
|
|
47956
48194
|
if (s.agentApi != null) cfg.agentApi = mergeSettingsBlockOverStored(cfg.agentApi, s.agentApi);
|
|
47957
|
-
if (s.
|
|
48195
|
+
if (s.guardrails != null) cfg.guardrails = mergeSettingsBlockOverStored(cfg.guardrails, s.guardrails);
|
|
47958
48196
|
if (s.telemetry != null) cfg.telemetry = mergeSettingsBlockOverStored(cfg.telemetry, s.telemetry);
|
|
47959
48197
|
if (!workflowsUpdate) return void 0;
|
|
47960
48198
|
const storedWorkflowsMerge = mergeWorkflowsUpdateOverStored(cfg.workflows, workflowsUpdate);
|
|
@@ -48108,7 +48346,7 @@ function registerControlHandlers(controlWss, deps) {
|
|
|
48108
48346
|
};
|
|
48109
48347
|
if (workspaceRepos) project.repos = workspaceRepos;
|
|
48110
48348
|
if (typeof dangerouslySkipPermissions === "boolean") project.dangerouslySkipPermissions = dangerouslySkipPermissions;
|
|
48111
|
-
if (unconfined) project.
|
|
48349
|
+
if (unconfined) project.unguarded = true;
|
|
48112
48350
|
if (agent) project.agent = agent;
|
|
48113
48351
|
const freshConfig = configStore.save((cfg) => {
|
|
48114
48352
|
cfg.projects.push(project);
|
|
@@ -48222,7 +48460,7 @@ function registerControlHandlers(controlWss, deps) {
|
|
|
48222
48460
|
path: project.path,
|
|
48223
48461
|
agent: project.agent,
|
|
48224
48462
|
dangerouslySkipPermissions: project.dangerouslySkipPermissions,
|
|
48225
|
-
unconfined: project.
|
|
48463
|
+
unconfined: project.unguarded
|
|
48226
48464
|
});
|
|
48227
48465
|
if (!created.ok) {
|
|
48228
48466
|
reply({ error: created.error });
|
|
@@ -48716,6 +48954,8 @@ function registerControlHandlers(controlWss, deps) {
|
|
|
48716
48954
|
"resume-conversation": handleResumeConversation,
|
|
48717
48955
|
"remove-session": handleRemoveSession,
|
|
48718
48956
|
"rename-session": handleRenameSession,
|
|
48957
|
+
"get-workspace-repos": handleGetWorkspaceRepos,
|
|
48958
|
+
"set-workspace-repos": handleSetWorkspaceRepos,
|
|
48719
48959
|
"set-session-title": handleSetSessionTitle,
|
|
48720
48960
|
"reorder-sessions": handleReorderSessions,
|
|
48721
48961
|
"ping": handlePing,
|
|
@@ -49477,12 +49717,9 @@ function markInterrupted(journal, { reason, now }) {
|
|
|
49477
49717
|
}
|
|
49478
49718
|
//#endregion
|
|
49479
49719
|
//#region server/update-check.ts
|
|
49480
|
-
var GIT_REMOTE_URL = `https://github.com/${REPO_SLUG}.git`;
|
|
49481
|
-
var GITHUB_LATEST_RELEASE_URL = `https://api.github.com/repos/${REPO_SLUG}/releases/latest`;
|
|
49482
49720
|
var NPM_REGISTRY_LATEST_URL = "https://registry.npmjs.org/glimmervoid/latest";
|
|
49483
49721
|
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
49484
49722
|
var GIT_HEAD_TIMEOUT_MS = 3e3;
|
|
49485
|
-
var LS_REMOTE_TIMEOUT_MS = 5e3;
|
|
49486
49723
|
var RELEASE_ANCESTRY_TIMEOUT_MS = 3e3;
|
|
49487
49724
|
var MAIN_CHANNEL_BUDGET_MS = DEFAULT_TIMEOUT_MS;
|
|
49488
49725
|
var MAIN_FETCH_TIMEOUT_MS = Math.floor(MAIN_CHANNEL_BUDGET_MS / 2);
|
|
@@ -49490,6 +49727,7 @@ var MAIN_REMOTE_TIP_TIMEOUT_MS = Math.floor(MAIN_CHANNEL_BUDGET_MS / 4);
|
|
|
49490
49727
|
var MAIN_BEHIND_COUNT_TIMEOUT_MS = Math.floor(MAIN_CHANNEL_BUDGET_MS / 4);
|
|
49491
49728
|
var STATE_FILE_NAME = "update-check.json";
|
|
49492
49729
|
var STATE_TTL_MS = 216e5;
|
|
49730
|
+
var RELEASE_SOURCE = "npm-registry";
|
|
49493
49731
|
function defaultStatePath() {
|
|
49494
49732
|
return path.join(glimmervoidHomeDir$1(), STATE_FILE_NAME);
|
|
49495
49733
|
}
|
|
@@ -49633,59 +49871,6 @@ async function resolveLatestRegistryVersion({ fetchFn, signal }) {
|
|
|
49633
49871
|
};
|
|
49634
49872
|
}
|
|
49635
49873
|
}
|
|
49636
|
-
async function resolveLatestRelease({ flavor, runCommand, fetchFn, signal }) {
|
|
49637
|
-
if (decideReleaseSource(flavor) === "npm-registry") return resolveLatestRegistryVersion({
|
|
49638
|
-
fetchFn,
|
|
49639
|
-
signal
|
|
49640
|
-
});
|
|
49641
|
-
const fromRemote = parseLsRemoteTags((await runGitProbe(runCommand, [
|
|
49642
|
-
"ls-remote",
|
|
49643
|
-
"--tags",
|
|
49644
|
-
GIT_REMOTE_URL
|
|
49645
|
-
], {
|
|
49646
|
-
timeout: LS_REMOTE_TIMEOUT_MS,
|
|
49647
|
-
signal
|
|
49648
|
-
})).out);
|
|
49649
|
-
if (fromRemote) return {
|
|
49650
|
-
...fromRemote,
|
|
49651
|
-
behindCount: null,
|
|
49652
|
-
reason: null
|
|
49653
|
-
};
|
|
49654
|
-
try {
|
|
49655
|
-
const response = await fetchFn(GITHUB_LATEST_RELEASE_URL, {
|
|
49656
|
-
signal,
|
|
49657
|
-
headers: {
|
|
49658
|
-
Accept: "application/vnd.github+json",
|
|
49659
|
-
"User-Agent": "glimmervoid-update-check"
|
|
49660
|
-
}
|
|
49661
|
-
});
|
|
49662
|
-
if (!response?.ok) return {
|
|
49663
|
-
version: null,
|
|
49664
|
-
sha: null,
|
|
49665
|
-
behindCount: null,
|
|
49666
|
-
reason: "release-check-failed"
|
|
49667
|
-
};
|
|
49668
|
-
const release = parseLatestReleaseTag(await response.json());
|
|
49669
|
-
if (!release) return {
|
|
49670
|
-
version: null,
|
|
49671
|
-
sha: null,
|
|
49672
|
-
behindCount: null,
|
|
49673
|
-
reason: "release-check-failed"
|
|
49674
|
-
};
|
|
49675
|
-
return {
|
|
49676
|
-
...release,
|
|
49677
|
-
behindCount: null,
|
|
49678
|
-
reason: null
|
|
49679
|
-
};
|
|
49680
|
-
} catch {
|
|
49681
|
-
return {
|
|
49682
|
-
version: null,
|
|
49683
|
-
sha: null,
|
|
49684
|
-
behindCount: null,
|
|
49685
|
-
reason: "release-check-failed"
|
|
49686
|
-
};
|
|
49687
|
-
}
|
|
49688
|
-
}
|
|
49689
49874
|
function upstreamBranch(upstream) {
|
|
49690
49875
|
const slashIndex = upstream.indexOf("/");
|
|
49691
49876
|
if (slashIndex < 0 || slashIndex === upstream.length - 1) return null;
|
|
@@ -49858,13 +50043,11 @@ async function checkForUpdate({ currentVersion, updateChannel = "release", fetch
|
|
|
49858
50043
|
});
|
|
49859
50044
|
const cached = readCheckState(statePath);
|
|
49860
50045
|
const cacheOutrunByInstall = normalizeSha(cached?.latestSha) !== null && normalizeSha(cached?.latestSha) === installed.installedSha;
|
|
49861
|
-
const expectedReleaseSource = updateChannel === "release" ?
|
|
50046
|
+
const expectedReleaseSource = updateChannel === "release" ? RELEASE_SOURCE : null;
|
|
49862
50047
|
const isCacheFromSameSource = expectedReleaseSource === null || cached?.releaseSource === expectedReleaseSource;
|
|
49863
50048
|
if (cached?.channel === updateChannel && isCacheFromSameSource && !cacheOutrunByInstall && isCheckFresh(cached.lastCheckAt, now, ttlMs)) return finish(installed, targetFromCache(cached), currentVersion, updateChannel, platform, now, packageRoot$1, runCommand, signal);
|
|
49864
50049
|
signal.throwIfAborted();
|
|
49865
|
-
const latestTarget = updateChannel === "main" ? await resolveLatestMain(installed, packageRoot$1, runCommand, fetchOrigin, signal) : await
|
|
49866
|
-
flavor: installed.flavor,
|
|
49867
|
-
runCommand,
|
|
50050
|
+
const latestTarget = updateChannel === "main" ? await resolveLatestMain(installed, packageRoot$1, runCommand, fetchOrigin, signal) : await resolveLatestRegistryVersion({
|
|
49868
50051
|
fetchFn,
|
|
49869
50052
|
signal
|
|
49870
50053
|
});
|
|
@@ -50769,10 +50952,10 @@ function createSessionFactory(dependencies) {
|
|
|
50769
50952
|
}
|
|
50770
50953
|
function defaultSandboxFor(project, config, overrides) {
|
|
50771
50954
|
if (!dependencies.sessionSandbox) return null;
|
|
50772
|
-
const unconfinedRepos = (config.
|
|
50955
|
+
const unconfinedRepos = (config.guardrails?.unguardedRepos ?? []).map((repo) => expandTilde(repo, process.env, dependencies.homeDir ?? null));
|
|
50773
50956
|
return isSessionConfined({
|
|
50774
50957
|
usageVendor: getAdapter(overrides.agent ?? project.agent)?.usageVendor ?? null,
|
|
50775
|
-
isMarkedUnconfined: project.
|
|
50958
|
+
isMarkedUnconfined: project.unguarded === true,
|
|
50776
50959
|
sessionFolders: [project.path, ...project.repos ?? []],
|
|
50777
50960
|
unconfinedRepos
|
|
50778
50961
|
}) ? dependencies.sessionSandbox.prepareFor({
|
|
@@ -50829,8 +51012,7 @@ function createSessionFactory(dependencies) {
|
|
|
50829
51012
|
//#region server/session-sandbox.ts
|
|
50830
51013
|
var UNWRAPPED_PLATFORM = "win32";
|
|
50831
51014
|
var GITHUB_TOKEN_TIMEOUT_MS = 5e3;
|
|
50832
|
-
var
|
|
50833
|
-
var OPT_OUT_HINT = "Mark the session or its repository unconfined to start it outside the sandbox.";
|
|
51015
|
+
var OPT_OUT_HINT = "Mark the session or its repository unguarded to start it without guardrails.";
|
|
50834
51016
|
async function readGithubCliToken(env) {
|
|
50835
51017
|
if (rawTextOr(env.GH_TOKEN, null) || rawTextOr(env.GITHUB_TOKEN, null)) return null;
|
|
50836
51018
|
return await execFileAsync("gh", ["auth", "token"], {
|
|
@@ -50838,65 +51020,9 @@ async function readGithubCliToken(env) {
|
|
|
50838
51020
|
encoding: "utf8"
|
|
50839
51021
|
}).then(({ stdout }) => stdout.trim(), () => "") || null;
|
|
50840
51022
|
}
|
|
50841
|
-
async function
|
|
50842
|
-
const
|
|
50843
|
-
|
|
50844
|
-
timeout: GIT_TIMEOUT_MS
|
|
50845
|
-
}).then(({ stdout }) => stdout.trim(), () => "");
|
|
50846
|
-
if (!toplevel) return null;
|
|
50847
|
-
const checkout = await existingRealPath(toplevel);
|
|
50848
|
-
if (checkout === null || !isPathInside(checkout, startFolder)) return null;
|
|
50849
|
-
return checkout;
|
|
50850
|
-
}
|
|
50851
|
-
async function isRegisteredGitEntry(gitEntry, worktreeAdminDir) {
|
|
50852
|
-
return await readFile(path.join(worktreeAdminDir, "gitdir"), "utf8").then((registeredPath) => realpath(path.resolve(worktreeAdminDir, registeredPath.trim()))).catch(() => null) === gitEntry;
|
|
50853
|
-
}
|
|
50854
|
-
async function ownGitDirOf(checkout, startFolder) {
|
|
50855
|
-
const gitDirs = await readGitDirsOfOwnCheckout(startFolder).catch(() => null);
|
|
50856
|
-
if (gitDirs === null) return null;
|
|
50857
|
-
const { commonGitDir, worktreeAdminDir } = gitDirs;
|
|
50858
|
-
const gitEntry = path.join(checkout, ".git");
|
|
50859
|
-
const gitEntryStats = await lstat(gitEntry).catch(() => null);
|
|
50860
|
-
if (gitEntryStats?.isDirectory()) return worktreeAdminDir === gitEntry && commonGitDir === gitEntry ? commonGitDir : null;
|
|
50861
|
-
const isLinkedWorktree = worktreeAdminDir !== commonGitDir;
|
|
50862
|
-
if (!gitEntryStats?.isFile() || !isLinkedWorktree) return null;
|
|
50863
|
-
if ((checkout === startFolder ? gitDirs : await readGitDirsOfOwnCheckout(checkout).catch(() => null))?.worktreeAdminDir !== worktreeAdminDir) return null;
|
|
50864
|
-
return await isRegisteredGitEntry(gitEntry, worktreeAdminDir) ? commonGitDir : null;
|
|
50865
|
-
}
|
|
50866
|
-
async function commitCheckoutOf(startFolder) {
|
|
50867
|
-
const checkout = await gitCheckoutOf(startFolder);
|
|
50868
|
-
if (checkout === null) return null;
|
|
50869
|
-
const gitDir = await ownGitDirOf(checkout, startFolder);
|
|
50870
|
-
return gitDir === null ? null : {
|
|
50871
|
-
checkout,
|
|
50872
|
-
gitDir
|
|
50873
|
-
};
|
|
50874
|
-
}
|
|
50875
|
-
async function memberCommitCheckoutOf(memberFolder) {
|
|
50876
|
-
const commitCheckout = await commitCheckoutOf(memberFolder);
|
|
50877
|
-
return commitCheckout?.checkout === memberFolder ? commitCheckout : null;
|
|
50878
|
-
}
|
|
50879
|
-
async function workspaceMemberCheckouts(workspaceFolder) {
|
|
50880
|
-
const memberFolders = (await readdir(workspaceFolder, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => path.join(workspaceFolder, entry.name));
|
|
50881
|
-
const gitPointers = await Promise.all(memberFolders.map((memberFolder) => existingRealPath(path.join(memberFolder, ".git"))));
|
|
50882
|
-
return (await Promise.all(memberFolders.filter((_memberFolder, index) => gitPointers[index] !== null).map(memberCommitCheckoutOf))).filter((commitCheckout) => commitCheckout !== null);
|
|
50883
|
-
}
|
|
50884
|
-
async function sessionCheckouts(cwd, isWorkspace) {
|
|
50885
|
-
if (isWorkspace) return workspaceMemberCheckouts(cwd);
|
|
50886
|
-
const commitCheckout = await commitCheckoutOf(cwd);
|
|
50887
|
-
return commitCheckout === null ? [] : [commitCheckout];
|
|
50888
|
-
}
|
|
50889
|
-
async function sharedFolderBehind(linkPath, repositoryFolder) {
|
|
50890
|
-
if (!(await lstat(linkPath).catch(() => null))?.isSymbolicLink()) return null;
|
|
50891
|
-
const sharedPath = await existingRealPath(linkPath);
|
|
50892
|
-
if (sharedPath !== repositoryFolder) return null;
|
|
50893
|
-
return (await stat(sharedPath)).isDirectory() ? sharedPath : null;
|
|
50894
|
-
}
|
|
50895
|
-
async function sharedFoldersOf({ checkout, gitDir }, worktreeShare) {
|
|
50896
|
-
const repositoryRoot = repositoryRootOfCommonGitDir(gitDir);
|
|
50897
|
-
if (repositoryRoot === null) return [];
|
|
50898
|
-
const sharedEntries = worktreeShare.filter((entry) => !UNSHARED_WORKTREE_ENTRIES.includes(entry));
|
|
50899
|
-
return (await Promise.all(sharedEntries.map((entry) => sharedFolderBehind(path.join(checkout, entry), path.resolve(path.join(repositoryRoot, entry)))))).filter((sharedFolder) => sharedFolder !== null);
|
|
51023
|
+
async function repositoryRootOf(cwd) {
|
|
51024
|
+
const gitDirs = await readGitDirsOfOwnCheckout(cwd).catch(() => null);
|
|
51025
|
+
return gitDirs === null ? null : repositoryRootOfCommonGitDir(gitDirs.commonGitDir);
|
|
50900
51026
|
}
|
|
50901
51027
|
function createSessionSandbox({ getSettings, uploadsRoot, sandboxRefusal = allowSandboxedSpawn, prepareSandbox = prepareSandboxLaunch, trustClaudeFolder, platform = process.platform, homeDir = os.homedir(), env = process.env, readGithubToken = () => readGithubCliToken(env), log = console }) {
|
|
50902
51028
|
const expandHome = (candidates) => candidates.map((candidate) => expandTilde(candidate.trim(), env, homeDir)).filter(Boolean);
|
|
@@ -50906,27 +51032,24 @@ function createSessionSandbox({ getSettings, uploadsRoot, sandboxRefusal = allow
|
|
|
50906
51032
|
const sessionUploads = path.join(uploadsRoot, sessionId);
|
|
50907
51033
|
await mkdir(sessionUploads, { recursive: true });
|
|
50908
51034
|
const cwd = await realpath(facts.cwd);
|
|
50909
|
-
const
|
|
50910
|
-
const
|
|
50911
|
-
const
|
|
51035
|
+
const ownRepositoryRoot = isWorkspace ? null : await repositoryRootOf(cwd);
|
|
51036
|
+
const expandedBlockedPaths = expandHome(settings.blockedPaths);
|
|
51037
|
+
const ignoredBlockedPaths = expandedBlockedPaths.filter((blockedPath) => !path.isAbsolute(blockedPath));
|
|
51038
|
+
if (ignoredBlockedPaths.length > 0) log.warn(`[guardrails] ignoring guardrails.blockedPaths entries that are not absolute paths: ${ignoredBlockedPaths.join(", ")}`);
|
|
50912
51039
|
return {
|
|
50913
51040
|
cwd,
|
|
50914
|
-
trustFolder:
|
|
51041
|
+
trustFolder: ownRepositoryRoot ?? cwd,
|
|
50915
51042
|
role: sessionRole({
|
|
50916
|
-
|
|
50917
|
-
writableRoots: [
|
|
50918
|
-
...startFolderRoots,
|
|
50919
|
-
...sharedFolders,
|
|
50920
|
-
...await existingRealPaths([...expandHome(settings.writablePaths), ...facts.writablePaths])
|
|
50921
|
-
],
|
|
51043
|
+
writableRoots: await existingRealPaths(facts.writablePaths),
|
|
50922
51044
|
readDenied: expandHome(settings.unreadablePaths).filter((unreadablePath) => path.isAbsolute(unreadablePath)),
|
|
51045
|
+
blockedPaths: expandedBlockedPaths.filter((blockedPath) => path.isAbsolute(blockedPath)),
|
|
50923
51046
|
readablePaths: [...facts.readablePaths, ...await existingRealPaths([sessionUploads, githubCliConfigDir()])]
|
|
50924
51047
|
})
|
|
50925
51048
|
};
|
|
50926
51049
|
}
|
|
50927
51050
|
async function recordClaudeFolderTrust(folder) {
|
|
50928
51051
|
if (!trustClaudeFolder) return;
|
|
50929
|
-
await trustClaudeFolder(folder).catch((error) => log.warn(`[
|
|
51052
|
+
await trustClaudeFolder(folder).catch((error) => log.warn(`[guardrails] ${errorMessage(error)}`));
|
|
50930
51053
|
}
|
|
50931
51054
|
function prepareFor(request) {
|
|
50932
51055
|
if (platform === UNWRAPPED_PLATFORM) return null;
|
|
@@ -51023,11 +51146,10 @@ function createBackendSessionRuntime(dependencies) {
|
|
|
51023
51146
|
getUserHooks: (projectId) => hooksForProject(dependencies.config.hooks, projectId),
|
|
51024
51147
|
sessionSandbox: createSessionSandbox({
|
|
51025
51148
|
getSettings: () => {
|
|
51026
|
-
const {
|
|
51149
|
+
const { guardrails } = dependencies.configStore.config;
|
|
51027
51150
|
return {
|
|
51028
|
-
|
|
51029
|
-
unreadablePaths:
|
|
51030
|
-
worktreeShare: worktreeShare ?? DEFAULT_CONFIG.worktreeShare
|
|
51151
|
+
blockedPaths: guardrails?.blockedPaths ?? DEFAULT_CONFIG.guardrails.blockedPaths,
|
|
51152
|
+
unreadablePaths: guardrails?.unreadablePaths ?? DEFAULT_CONFIG.guardrails.unreadablePaths
|
|
51031
51153
|
};
|
|
51032
51154
|
},
|
|
51033
51155
|
uploadsRoot: configSiblingPath(dependencies.configStore.configPath, "uploads"),
|