glimmervoid 0.38.0 → 0.38.2
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/dist/bin/glimmervoid.js +17 -15
- package/dist/chunks/{adapters-B-IkWl-r.js → adapters-CAHxZYT3.js} +4 -4
- package/dist/chunks/{adapters-Dt3vwxwY.js → adapters-DDjC7_vG.js} +1 -1
- package/dist/chunks/{agent-api-cli-BcZ9DLCF.js → agent-api-cli-B5Tm0wXO.js} +27 -8
- package/dist/chunks/{agent-api-cli-3hryuewm.js → agent-api-cli-BDu1CxZf.js} +1 -1
- package/dist/chunks/{agent-api-core--8WtU1xU.js → agent-api-core-B_mUSenR.js} +36 -4
- package/dist/chunks/{agent-setup-cli-BixDoCkF.js → agent-setup-cli-DmMfCw5O.js} +1 -1
- package/dist/chunks/{config-BHBZsCBc.js → browser-config-BrBT8269.js} +2 -217
- package/dist/chunks/config-CjawSOBk.js +219 -0
- package/dist/chunks/{config-store-DbfMbz4j.js → config-store-BUNZs4j7.js} +4 -3
- package/dist/chunks/config-store-MAVQhGMh.js +1 -0
- package/dist/chunks/{contracts-u40eJhaf.js → contracts-HVCEJfxs.js} +6 -239
- package/dist/chunks/factory-D7ryES9n.js +240 -0
- package/dist/chunks/{git-version-BpnTd8sU.js → git-version-rWZjF2Px.js} +1 -1
- package/dist/chunks/{grok-xFs6zIu4.js → grok-B6bsCgdd.js} +2 -2
- package/dist/chunks/{hook-tools-BkxllUHE.js → hook-tools-Dl7-r2Eb.js} +1 -1
- package/dist/chunks/{knowledge-graph-cli-DcspNqhz.js → knowledge-graph-cli-ByUJoKw_.js} +1 -1
- package/dist/chunks/{main-w01-P1oZ.js → main-BNSbP-Yk.js} +689 -523
- package/dist/chunks/{pair-cli-BdoyrDCr.js → pair-cli-DNp8i5L4.js} +2 -2
- package/dist/chunks/{remote-config-61zJ0hME.js → remote-config-C_s2pnLC.js} +1 -1
- package/dist/chunks/{rtk-hook-core-VrUafGAp.js → rtk-hook-core-B-MpzPin.js} +89 -83
- package/dist/chunks/rtk-resolver-BGE6Hd_L.js +1 -0
- package/dist/chunks/{rtk-resolver-C_micGrL.js → rtk-resolver-BgoPsEhT.js} +1 -1
- package/dist/chunks/{session-8Pv0y1vz.js → session-BlT68ppa.js} +5 -2
- package/dist/chunks/{session-routes-D-GZC-Sy.js → session-routes-CT1JrjoT.js} +1 -1
- package/dist/chunks/{settings-cli-DKJsm3AP.js → settings-cli-BbzxCyG5.js} +3 -3
- package/dist/chunks/{ssh-sign-cli-Dc2gOCwE.js → ssh-sign-cli-C74BGTQS.js} +2 -2
- package/dist/client/assets/index-B5uVtedd.css +1 -0
- package/dist/client/assets/index-b13-NGGS.js +275 -0
- package/dist/client/index.html +3 -2
- package/dist/server/index.js +1 -1
- package/dist/session/hook-tool-relay.js +1 -1
- package/package.json +3 -2
- package/dist/chunks/config-store-DYj3wYgw.js +0 -1
- package/dist/chunks/rtk-resolver-B8BPgN9L.js +0 -1
- package/dist/client/assets/index-BfqmOGgc.js +0 -275
- package/dist/client/assets/index-DxABp5yJ.css +0 -1
|
@@ -2,34 +2,36 @@ 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 { At as
|
|
5
|
+
import { At as FULL_SHA_RE, Bt as KILLABLE_STATES, Ct as TeamReviewThreadCommentsResponse, D as SSH_SIGN_BODY_CAP_BYTES, Dt as decisionAsIfApprovalRequired, E as SIGN_URL_ENV, Et as canApproveAfterComment, F as LinkedPr, Ft as REPO_SLUG_RE, G as MyPrMergeWhenReadyRequest, H as MyPrMergeRequest, Ht as RESTARTABLE_STATES, I as MyPrAutoRebase, It as repoParts, J as MyPrSearchResponse, L as MyPrCheckContext, M as SshSignRequest, Mt as shortSha$1, N as TASK_TITLE_CONTROL_CHARACTERS, Nt as GH_SEGMENT, P as TaskTitle, Pt as NODE_ID_RE, Q as MyPrsStatus, R as MyPrCheckContextsResponse, S as RefinedTaskTitle, St as TeamReviewStatus, Tt as TeamReviewThreadsRepository, Ut as STATES, V as MyPrMergeMethod, Vt as MERGEABLE_LIVE_STATES, W as MyPrMergeStateResponse, X as MyPrThreadsResponse, Y as MyPrThreadNode, Z as MyPrsState, _t as TeamReviewActionRequest, a as AgentDispatchRequest, at as GithubReviewState, b as ORCHESTRATOR_AGENT_VERBS, bt as TeamReviewResolveResponse, ct as QueuedReview, dt as ReviewDraft, f as AgentTicketRequest, ft as ReviewFinding, gt as SearchedPr, h as CONVERSATION_TOOL_RESULT_HOOK_EVENT, ht as ReviewVerdict, it as GithubReviewDecision, jt as HEX_SHA_RE, kt as hasStandingViewerApproval, lt as ReviewChecksState, m as CONVERSATION_PERMISSION_HOOK_EVENT, mt as ReviewThreadId, n as AGENT_URL_ENV, nt as DECIDING_REVIEW_STATES, ot as PostingPlan, p as CONVERSATION_APPROVAL_SUMMARY_MAX_CHARS, pt as ReviewResult, q as MyPrSearchNode, r as ASK_USER_QUESTION_TOOL_NAME, rt as FindingSeverity, st as PrDetail, tt as CommitSha, ut as ReviewComment, w as SESSION_DOC_BODY_CAP_BYTES, wt as TeamReviewThreadResult, xt as TeamReviewStateEntry, y as ConversationQuestion, yt as TeamReviewCompareFiles, z as MyPrKeepMergeableRequest } from "./session-BlT68ppa.js";
|
|
6
6
|
import { n as execFileAsync, o as spawn, r as execFileSync, t as execFile } from "./child-process-safe-CbQnyh7D.js";
|
|
7
7
|
import { n as glimmervoidHomeDir, t as decideConfigPath } from "./config-path-core-DFt-TemS.js";
|
|
8
|
-
import { i as parseCommandLine, n as warnWhenGitIsTooOld } from "./git-version-
|
|
8
|
+
import { i as parseCommandLine, n as warnWhenGitIsTooOld } from "./git-version-rWZjF2Px.js";
|
|
9
9
|
import { n as checkGuardrailsDependencies, t as allowGuardedSpawn } from "./guardrails-deps-Cb-ki4EU.js";
|
|
10
10
|
import { t as HOOK_URL_ENV } from "./hook-relay-core-DA_bz2KA.js";
|
|
11
11
|
import { t as HOOK_VIA_GUARDRAILS_PROXY_ENV } from "./guardrails-proxy-core-BI3rdY-m.js";
|
|
12
12
|
import { t as refocusReplyFor } from "./refocus-core-BKQKllq7.js";
|
|
13
13
|
import { a as positiveIntOr, c as textOr, i as numberOr, n as isRecord, o as positiveNumberOr, r as nonNegativeIntOr, s as rawTextOr, t as coercedNumberOr } from "./coerce-NSst8oRP.js";
|
|
14
14
|
import { n as parseJsonRecord, t as parseJsonOrNull } from "./json-core-dfa_7Fak.js";
|
|
15
|
-
import {
|
|
15
|
+
import { s as saneYoloFiles } from "./rtk-hook-core-B-MpzPin.js";
|
|
16
16
|
import { _ as lineStartOffsets, a as projectForUri, b as replacedSpanOfWholeTextChange, c as visionsLaneReloadSignature, d as applyDidOpen, f as createDocStore, g as lineOfOffset, h as getDoc, i as isUriInProjects, l as applyDidChange, m as formatRange, n as applyEditorNotification, o as resolveVisionsScopeProjects, p as detectBlankLineBoundary, r as createEditorState, s as scopePathsOf, t as ACTIVITY_METHOD, u as applyDidClose, v as listDocs, x as uriOfParams, y as offsetOfPosition } from "./ingest-editor-core-B2tycW_m.js";
|
|
17
17
|
import { n as DEFAULT_MAX_MS, r as nextBackoffMs, t as DEFAULT_BASE_MS } from "./backoff-DjVpfHk7.js";
|
|
18
18
|
import { n as unrefTimer, t as DEFAULT_TIMER_FNS } from "./timer-deps-u2DAQLok.js";
|
|
19
|
-
import { o as permitsHelpCommand, r as describeSessionLimits } from "./session-routes-
|
|
20
|
-
import {
|
|
21
|
-
import { s as
|
|
19
|
+
import { o as permitsHelpCommand, r as describeSessionLimits } from "./session-routes-CT1JrjoT.js";
|
|
20
|
+
import { $ as CoherenceTicketCreated, C as WorkflowsState, G as USAGE_INTEGER_RANGES, N as KEEP_MERGEABLE_TIMEOUT_MINUTES_RANGE, T as USAGE_VENDOR_KEYS, X as CoherenceOrient, a as DEFAULT_FACTORY_CHECKS, b as WorkflowSearchNode, et as CoherenceWorkCreated, o as DEFAULT_FACTORY_PROTECTED_PATHS, tt as CoherenceWorkInspect, v as WorkflowCommentBody, w as USAGE_COST_MODES, x as WorkflowsSettings, y as WorkflowLabelName } from "./browser-config-BrBT8269.js";
|
|
21
|
+
import { _ as isSingleFactoryPathSegment, a as FactoryControlRequest, c as FactoryHarnessVerdict, d as FactoryQueueIntentRequest, g as FactoryWorkerEvent, i as FactoryConsequences, l as FactoryLaneState, m as FactoryReviewerOutput, n as FACTORY_ERROR_MAX_CHARS, p as FactoryReviewVerdict, r as FACTORY_PROTECTED_PATH_FLOOR, s as FactoryHarnessStateLine, u as FactoryProjectState } from "./factory-D7ryES9n.js";
|
|
22
|
+
import { _ as parseAgentVerb, a as decideFactoryControlAllowance, c as deriveChildSessionName, d as describePushRouteRefusal, f as describeUnavailableFactoryState, g as isOrchestratorAgentVerb, i as decideEditAllowance, l as describeFactorySetupProfile, m as formatFactoryStatus, n as decideAgentRequest, o as decideSpawnAllowance, p as findSessionProjectId, r as decideAttentionAllowance, s as decideTicketAction, t as REFUSAL_REASON, u as describePushLanding } from "./agent-api-core-B_mUSenR.js";
|
|
23
|
+
import { s as GLIMMERVOID_SECRET_KEYS } from "./grok-B6bsCgdd.js";
|
|
22
24
|
import { n as shellQuote } from "./hook-command-core-qTNK-xMF.js";
|
|
23
25
|
import { C as headroomFromReadings, D as parseMemAvailableBytes, E as parseCgroupV2Path, S as cgroupLimitBytes, T as parseCgroupBytes, _ as createSpawnGate, a as jsonStateLoadError, 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 isQueueAdmissionAbandoned, w as memoryReserveBytes, x as cgroupAncestorPaths, y as isQueueAdmissionTimeout } from "./json-file-CIJf0Cel.js";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { A as shouldPersistWarehouse, C as isUsageFile, D as resolveProjectsDirs, E as projectDirCandidates, M as claudeCode, O as scopedClaudeRoots, S as grokRootCandidates, T as passOutcome, _ as continuationDelayMs, a as describeAgentResolvability, b as expandTilde, c as isKnownAgentId, d as resolveAdapter, f as setCustomAgents, g as codexSessionIdFromPath, h as codexRootCandidates, i as customAgentFingerprint, j as splitLines$1, k as shouldEvaluateDespiteIoFailures, l as listAgentIds, m as codexHomes, n as cachedAgentResolvability, o as getAdapter, p as codexFallbackRoots, r as commandFor, s as hookProfileOf, t as DEFAULT_AGENT_ID, u as resetCommandCache, v as decideFileRead, w as laneSpendStatus, x as grokHomes, y as dedupeCodexFiles } from "./adapters-
|
|
28
|
-
import { t as HOOK_TOOLS } from "./hook-tools-
|
|
26
|
+
import { B as buildExceptionProperties, F as TELEMETRY_BATCH_URL, G as decideTelemetryConsent, H as classifySessionExit, I as TELEMETRY_FLAGS_URL, J as parsePosthogReleaseId, K as exceptionFingerprint, L as adapterBucket, P as FIRST_RUN_NOTICE, Q as stableConfigKey, R as buildAiGenerationEvents, U as decideIsDevInstall, V as buildFactoryDecisionEvent, W as decideRemoteTelemetryState, Y as resolveProjectToken, a as generateProjectId, at as usablePrefixes, b as validateSettingsBlock, ct as comparableDirectoryPath, d as assetForPlatform, et as DEFAULT_BRANCH_GC_PREFIXES, f as decideRtkInstall, g as verifyDigest, h as isRtkBinaryName, i as ensureProjectIds, it as sessionIdFromBranch, lt as isSameDirectoryPath, m as installTargetPath, n as DEFAULT_CONFIG, nt as planBranchGc, o as glimmervoidHomeDir$1, ot as worktreeIntegrationTips, p as findEscapingArchiveMember, q as nodeMajorVersion, r as createConfigStore, rt as planWorktreeGc, st as canonicalizePath, t as ABORT_CONFIG_SAVE, tt as matchedPrefix, v as mergeSettingsBlock, y as settingsBlockSpecFor, z as buildBrowserExceptionProperties } from "./config-store-BUNZs4j7.js";
|
|
27
|
+
import { a as ConfigUpdate, c as RUNTIME_CONFIG_SCALAR_KEYS, l as TASK_TITLE_SOURCE_PRIORITY, o as PersistedTaskTitle, r as BrowserConfig, s as ProjectConfig, u as configIssueMessage } from "./config-CjawSOBk.js";
|
|
28
|
+
import { A as ChangeMap, B as MergedPrListing, C as GithubIssuePullRequestsRepository, D as IssuesSearchResponse, E as IssueUpdate, F as BenchmarkJudgement, G as TELEMETRY_EVENT_SCHEMAS, H as PrCheckoutCaseInput, I as BenchmarkRun, J as FACTORY_DECISION_OUTPUT_MAX_BYTES, L as BenchmarkStatus, M as BenchmarkActionRequest, N as BenchmarkCase, O as IssuesState, P as BenchmarkId, R as BenchmarkSuite, S as planTitle, T as IssueKey, V as MinedPrReviewData, W as PendingCrashReport, Y as FactoryDecisionLogLine, _ as PLAN_RESULT_HOOK_EVENT, a as parseDataClientMessage, b as PlanRevision, c as DIFF_ANNOTATION_NOTE_MAX_CHARS, d as MAX_RAW_LINE_CHARS, f as TraceCheckpoint, g as PLAN_HOOK_OUTPUT_MAX_CHARS, h as PLAN_HOOK_EVENT, i as parseDataAttachHistory, j as changeMapFactId, k as IssuesStatus, l as InstallFlavor, m as PLAN_BODY_CAP_BYTES, n as HookEnvelope, o as CONTROL_FRAME_MAX_BYTES, p as TraceRecord, q as TelemetryState, r as DEEP_HISTORY_SCROLLBACK_LINES, s as ClientMessage, t as HTTP_URL_RE, u as UpdateJournal, v as PLAN_TOOL_NAME, w as GithubIssueResponse, x as parseExitPlanModeHookPayload, y as PlanDecision, z as CommitComparison } from "./contracts-HVCEJfxs.js";
|
|
29
|
+
import { A as shouldPersistWarehouse, C as isUsageFile, D as resolveProjectsDirs, E as projectDirCandidates, M as claudeCode, O as scopedClaudeRoots, S as grokRootCandidates, T as passOutcome, _ as continuationDelayMs, a as describeAgentResolvability, b as expandTilde, c as isKnownAgentId, d as resolveAdapter, f as setCustomAgents, g as codexSessionIdFromPath, h as codexRootCandidates, i as customAgentFingerprint, j as splitLines$1, k as shouldEvaluateDespiteIoFailures, l as listAgentIds, m as codexHomes, n as cachedAgentResolvability, o as getAdapter, p as codexFallbackRoots, r as commandFor, s as hookProfileOf, t as DEFAULT_AGENT_ID, u as resetCommandCache, v as decideFileRead, w as laneSpendStatus, x as grokHomes, y as dedupeCodexFiles } from "./adapters-CAHxZYT3.js";
|
|
30
|
+
import { t as HOOK_TOOLS } from "./hook-tools-Dl7-r2Eb.js";
|
|
29
31
|
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";
|
|
30
|
-
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-
|
|
32
|
+
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-C_s2pnLC.js";
|
|
31
33
|
import { _ as escapeMarkup, g as createLaneLog, n as createVisionsSetup } from "./visions-setup-B-ZeRdsi.js";
|
|
32
|
-
import { t as getRtkPath } from "./rtk-resolver-
|
|
34
|
+
import { t as getRtkPath } from "./rtk-resolver-BgoPsEhT.js";
|
|
33
35
|
import { createRequire } from "node:module";
|
|
34
36
|
import fs, { constants, readFileSync } from "node:fs";
|
|
35
37
|
import path, { join, resolve } from "node:path";
|
|
@@ -198,6 +200,7 @@ function createLifecycle({ shutdown, httpServer, extraServers = [], onRestart =
|
|
|
198
200
|
warn: log
|
|
199
201
|
});
|
|
200
202
|
closeExtraServers(extraServers);
|
|
203
|
+
await prepareHandOffOnce();
|
|
201
204
|
let exited = false;
|
|
202
205
|
const doExit = () => {
|
|
203
206
|
if (exited) return;
|
|
@@ -5008,6 +5011,70 @@ function createAgentApiWiring({ config, agentSessions, listAllSessions, listBoar
|
|
|
5008
5011
|
if (routeRefusal) return routeRefusal;
|
|
5009
5012
|
return describePushLanding(await session.mergeAndContinue({ force: true }));
|
|
5010
5013
|
}
|
|
5014
|
+
async function setUpFactoryProject(session, factoryPort, projects) {
|
|
5015
|
+
const projectId = findSessionProjectId(config.projects, session.path);
|
|
5016
|
+
if (!projectId) return {
|
|
5017
|
+
status: 404,
|
|
5018
|
+
body: {
|
|
5019
|
+
ok: false,
|
|
5020
|
+
error: `no configured project has the path ${session.path}, so the operator has to add this repository as a project first`
|
|
5021
|
+
}
|
|
5022
|
+
};
|
|
5023
|
+
const outcome = await factoryPort.rerunSetup(projectId);
|
|
5024
|
+
if (!outcome.ok) return {
|
|
5025
|
+
status: 409,
|
|
5026
|
+
body: {
|
|
5027
|
+
ok: false,
|
|
5028
|
+
error: outcome.reason
|
|
5029
|
+
}
|
|
5030
|
+
};
|
|
5031
|
+
return {
|
|
5032
|
+
status: 200,
|
|
5033
|
+
body: {
|
|
5034
|
+
ok: true,
|
|
5035
|
+
projectId,
|
|
5036
|
+
profile: outcome.profile,
|
|
5037
|
+
text: describeFactorySetupProfile(outcome.profile, projects.some((project) => project.projectId === projectId))
|
|
5038
|
+
}
|
|
5039
|
+
};
|
|
5040
|
+
}
|
|
5041
|
+
async function queueFactoryIntent(session, factoryPort, projects, request) {
|
|
5042
|
+
const projectId = findSessionProjectId(config.projects, session.path);
|
|
5043
|
+
if (!projectId) return {
|
|
5044
|
+
status: 404,
|
|
5045
|
+
body: {
|
|
5046
|
+
ok: false,
|
|
5047
|
+
error: `no configured project has the path ${session.path}, so the operator has to add this repository as a project first`
|
|
5048
|
+
}
|
|
5049
|
+
};
|
|
5050
|
+
if (!projects.some((project) => project.projectId === projectId)) return {
|
|
5051
|
+
status: 409,
|
|
5052
|
+
body: {
|
|
5053
|
+
ok: false,
|
|
5054
|
+
error: `${projectId} is not a factory project yet: commit a coherence.config.json holding {} at the repository root, land it on the integration branch with glimmervoid push, then queue again`
|
|
5055
|
+
}
|
|
5056
|
+
};
|
|
5057
|
+
const outcome = await factoryPort.queueIntent({
|
|
5058
|
+
...request,
|
|
5059
|
+
projectId
|
|
5060
|
+
});
|
|
5061
|
+
if (!outcome.ok) return {
|
|
5062
|
+
status: 409,
|
|
5063
|
+
body: {
|
|
5064
|
+
ok: false,
|
|
5065
|
+
error: outcome.error ?? "the factory refused the intent"
|
|
5066
|
+
}
|
|
5067
|
+
};
|
|
5068
|
+
return {
|
|
5069
|
+
status: 200,
|
|
5070
|
+
body: {
|
|
5071
|
+
ok: true,
|
|
5072
|
+
projectId,
|
|
5073
|
+
workId: outcome.workId,
|
|
5074
|
+
text: `Queued ${outcome.workId ?? "the intent"} on ${projectId}. Follow it with glimmervoid factory status --project ${projectId}`
|
|
5075
|
+
}
|
|
5076
|
+
};
|
|
5077
|
+
}
|
|
5011
5078
|
async function handle(session, verb, payload) {
|
|
5012
5079
|
const parsed = parseAgentVerb(verb, payload);
|
|
5013
5080
|
if (!parsed.ok) return {
|
|
@@ -5017,7 +5084,7 @@ function createAgentApiWiring({ config, agentSessions, listAllSessions, listBoar
|
|
|
5017
5084
|
error: parsed.error
|
|
5018
5085
|
}
|
|
5019
5086
|
};
|
|
5020
|
-
if (parsed.verb === "factory-status" || parsed.verb === "factory-retry") {
|
|
5087
|
+
if (parsed.verb === "factory-status" || parsed.verb === "factory-retry" || parsed.verb === "factory-setup" || parsed.verb === "factory-queue") {
|
|
5021
5088
|
const allowance = decideFactoryControlAllowance(roleFactsOf(session));
|
|
5022
5089
|
if (!allowance.ok) return {
|
|
5023
5090
|
status: allowance.status,
|
|
@@ -5034,6 +5101,8 @@ function createAgentApiWiring({ config, agentSessions, listAllSessions, listBoar
|
|
|
5034
5101
|
error: "Factory is not running"
|
|
5035
5102
|
}
|
|
5036
5103
|
};
|
|
5104
|
+
if (parsed.verb === "factory-setup") return setUpFactoryProject(session, factory, projects);
|
|
5105
|
+
if (parsed.verb === "factory-queue") return queueFactoryIntent(session, factory, projects, parsed.request);
|
|
5037
5106
|
if (parsed.verb === "factory-status") {
|
|
5038
5107
|
const selectedProjects = parsed.request.projectId === void 0 ? projects : projects.filter((project) => project.projectId === parsed.request.projectId);
|
|
5039
5108
|
if (parsed.request.projectId !== void 0 && selectedProjects.length === 0) return {
|
|
@@ -7030,6 +7099,7 @@ function createSessionEventWiring(dependencies) {
|
|
|
7030
7099
|
};
|
|
7031
7100
|
let lastPersistedWasActive = null;
|
|
7032
7101
|
let lastPersistedWasWorking = null;
|
|
7102
|
+
let isTurnWorking = null;
|
|
7033
7103
|
let spawnedAtMs = null;
|
|
7034
7104
|
const persistProjectField = (field, value) => {
|
|
7035
7105
|
Promise.resolve(persistSessionField(dependencies.configStore, dependencies.config, session.id, field, value)).catch((error) => dependencies.logger.warn(`[config] Failed to persist ${field}: ${errorMessage(error)}`));
|
|
@@ -7044,6 +7114,14 @@ function createSessionEventWiring(dependencies) {
|
|
|
7044
7114
|
duration_seconds: durationSeconds
|
|
7045
7115
|
});
|
|
7046
7116
|
};
|
|
7117
|
+
const persistWasWorking = () => {
|
|
7118
|
+
const hasBackgroundWork = session.hasBackgroundWork;
|
|
7119
|
+
if (isTurnWorking === null && !hasBackgroundWork) return;
|
|
7120
|
+
const wasWorking = isTurnWorking === true || hasBackgroundWork;
|
|
7121
|
+
if (wasWorking === lastPersistedWasWorking) return;
|
|
7122
|
+
lastPersistedWasWorking = wasWorking;
|
|
7123
|
+
persistProjectField("wasWorking", wasWorking);
|
|
7124
|
+
};
|
|
7047
7125
|
let liveTranscriptPath = null;
|
|
7048
7126
|
session.on("claude-session-id", ({ id, vendor, isResumeTarget, transcriptPath }) => {
|
|
7049
7127
|
liveTranscriptPath = transcriptPath;
|
|
@@ -7131,11 +7209,9 @@ function createSessionEventWiring(dependencies) {
|
|
|
7131
7209
|
lastPersistedWasActive = nextWasActive;
|
|
7132
7210
|
persistProjectField("wasActive", nextWasActive);
|
|
7133
7211
|
}
|
|
7134
|
-
const
|
|
7135
|
-
if (
|
|
7136
|
-
|
|
7137
|
-
persistProjectField("wasWorking", nextWasWorking);
|
|
7138
|
-
}
|
|
7212
|
+
const nextIsTurnWorking = decideWasWorkingFlip(to, event, detail?.isIdleCompactionActivity === true);
|
|
7213
|
+
if (nextIsTurnWorking !== null) isTurnWorking = nextIsTurnWorking;
|
|
7214
|
+
persistWasWorking();
|
|
7139
7215
|
const acknowledgeDecision = decideAcknowledge(isAcknowledgeDeferredForCompaction, from, event, detail?.isIdleCompactionActivity === true);
|
|
7140
7216
|
isAcknowledgeDeferredForCompaction = acknowledgeDecision.isAcknowledgeDeferred;
|
|
7141
7217
|
clearCompactionConfirm();
|
|
@@ -7192,6 +7268,7 @@ function createSessionEventWiring(dependencies) {
|
|
|
7192
7268
|
timestamp: Date.now()
|
|
7193
7269
|
}));
|
|
7194
7270
|
session.on("agents-change", (payload) => {
|
|
7271
|
+
persistWasWorking();
|
|
7195
7272
|
dependencies.telegramChannel.recheck(session.id);
|
|
7196
7273
|
dependencies.broadcastControl({
|
|
7197
7274
|
type: "session-agents",
|
|
@@ -7203,6 +7280,7 @@ function createSessionEventWiring(dependencies) {
|
|
|
7203
7280
|
});
|
|
7204
7281
|
});
|
|
7205
7282
|
relay("wakeup-change", "session-wakeup");
|
|
7283
|
+
session.on("wakeup-change", persistWasWorking);
|
|
7206
7284
|
relay("prompt-kind-change", "session-prompt");
|
|
7207
7285
|
relay("conversation-change", "session-conversation");
|
|
7208
7286
|
session.on("merge-status", ({ mergeStatus, reason, parked }) => {
|
|
@@ -7432,7 +7510,7 @@ async function listRepoConversations({ repoPath, projectsDir, git, fsMod, limit
|
|
|
7432
7510
|
//#endregion
|
|
7433
7511
|
//#region session/core/auto-resume.ts
|
|
7434
7512
|
var RESUME_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
7435
|
-
var AUTO_CONTINUE_PROMPT = "Glimmervoid restarted while you were
|
|
7513
|
+
var AUTO_CONTINUE_PROMPT = "Glimmervoid restarted while you were working and resumed this conversation. This is not a new request from the user: carry on with the task you were working on. Any tool call, background command, monitor or subagent that was running was stopped and its outcome is unknown, so check the current state, such as files, git status and running processes, before relying on it or repeating it, and start again any background work the task still needs. Do not recap or ask for confirmation. If the task was already finished, say so in one line.";
|
|
7436
7514
|
function pickAutoResume(projects, config) {
|
|
7437
7515
|
if (!Array.isArray(projects)) return [];
|
|
7438
7516
|
if (config && config.autoResume === false) return [];
|
|
@@ -14653,6 +14731,12 @@ function createTaskRegistry({ agentTtlMs = DEFAULT_AGENT_TTL_MS, shellTaskTtlMs
|
|
|
14653
14731
|
reap(at);
|
|
14654
14732
|
return isOnlyBackgroundTasks(declaredEntries, countedAgents, idleTaskIds, (entry) => entryAgeMs(entry, at), shellTaskTtlMs, idleTeammateNames.size, teammateTaskTtlMs, agentTtlMs);
|
|
14655
14733
|
},
|
|
14734
|
+
hasLiveMonitor() {
|
|
14735
|
+
const at = now();
|
|
14736
|
+
reap(at);
|
|
14737
|
+
if (declaredEntries === null) return false;
|
|
14738
|
+
return declaredEntries.some((entry) => entry.type === "monitor" && !(entry.id && idleTaskIds.has(entry.id)) && entryAgeMs(entry, at) < shellTaskTtlMs);
|
|
14739
|
+
},
|
|
14656
14740
|
getBreakdown() {
|
|
14657
14741
|
return breakdown;
|
|
14658
14742
|
},
|
|
@@ -15174,6 +15258,431 @@ function createSessionOutput(options) {
|
|
|
15174
15258
|
};
|
|
15175
15259
|
}
|
|
15176
15260
|
//#endregion
|
|
15261
|
+
//#region server/guardrails/core/guardrails-policy-core.ts
|
|
15262
|
+
var VENDOR_PROFILES = Object.freeze({
|
|
15263
|
+
claude: {
|
|
15264
|
+
homeEntries: [".claude", ".claude.json"],
|
|
15265
|
+
launchWritableFolders: ({ cwd, agentSessionId }) => [path.join("projects", encodeProjectDir(cwd)), ...agentSessionId === null ? [] : [path.join("session-env", agentSessionId)]],
|
|
15266
|
+
launchPrivateFolders: ["shell-snapshots"],
|
|
15267
|
+
launchHomeEnvName: null,
|
|
15268
|
+
loginFiles: [".credentials.json"],
|
|
15269
|
+
configEntries: [
|
|
15270
|
+
"settings.json",
|
|
15271
|
+
"settings.local.json",
|
|
15272
|
+
"hooks",
|
|
15273
|
+
"skills",
|
|
15274
|
+
"plugins",
|
|
15275
|
+
"commands",
|
|
15276
|
+
"agents",
|
|
15277
|
+
"CLAUDE.md",
|
|
15278
|
+
"AGENTS.md"
|
|
15279
|
+
],
|
|
15280
|
+
apiDomains: ["api.anthropic.com", "platform.claude.com"],
|
|
15281
|
+
launchEnv: { DISABLE_AUTOUPDATER: "1" }
|
|
15282
|
+
},
|
|
15283
|
+
codex: {
|
|
15284
|
+
homeEntries: [".codex"],
|
|
15285
|
+
launchWritableFolders: () => [],
|
|
15286
|
+
launchPrivateFolders: [],
|
|
15287
|
+
launchHomeEnvName: "CODEX_HOME",
|
|
15288
|
+
loginFiles: ["auth.json"],
|
|
15289
|
+
configEntries: [
|
|
15290
|
+
"config.toml",
|
|
15291
|
+
"AGENTS.md",
|
|
15292
|
+
"skills",
|
|
15293
|
+
"rules",
|
|
15294
|
+
"prompts",
|
|
15295
|
+
"hooks.json"
|
|
15296
|
+
],
|
|
15297
|
+
apiDomains: [
|
|
15298
|
+
"chatgpt.com",
|
|
15299
|
+
"*.chatgpt.com",
|
|
15300
|
+
"auth.openai.com",
|
|
15301
|
+
"api.openai.com",
|
|
15302
|
+
"*.openai.com"
|
|
15303
|
+
],
|
|
15304
|
+
launchEnv: {}
|
|
15305
|
+
}
|
|
15306
|
+
});
|
|
15307
|
+
var GUARDRAILS_VENDORS = Object.freeze(["claude", "codex"]);
|
|
15308
|
+
var UNWRAPPED_VENDOR_HOME_ENTRIES = Object.freeze([".grok"]);
|
|
15309
|
+
var CREDENTIAL_HOME_ENTRIES = Object.freeze([
|
|
15310
|
+
".ssh",
|
|
15311
|
+
".config/gh",
|
|
15312
|
+
"Library/Keychains",
|
|
15313
|
+
".git-credentials"
|
|
15314
|
+
]);
|
|
15315
|
+
var CLOUD_CREDENTIAL_HOME_ENTRIES = Object.freeze([
|
|
15316
|
+
".aws",
|
|
15317
|
+
".azure",
|
|
15318
|
+
".config/gcloud",
|
|
15319
|
+
".kube",
|
|
15320
|
+
".docker",
|
|
15321
|
+
".gnupg",
|
|
15322
|
+
".netrc",
|
|
15323
|
+
".npmrc"
|
|
15324
|
+
]);
|
|
15325
|
+
var STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES = Object.freeze(["Library/Keychains"]);
|
|
15326
|
+
var XDG_CONFIG_DEFAULT_HOME_PREFIX = ".config/";
|
|
15327
|
+
var SHARED_TEMP_DIRS = Object.freeze(["/tmp/claude", "/private/tmp/claude"]);
|
|
15328
|
+
var SHARED_HOME_WRITE_ENTRIES = Object.freeze([".npm/_logs"]);
|
|
15329
|
+
var GUARDRAILS_PLACEHOLDER_NAMES = Object.freeze([
|
|
15330
|
+
".bash_profile",
|
|
15331
|
+
".bashrc",
|
|
15332
|
+
".claude",
|
|
15333
|
+
".gitconfig",
|
|
15334
|
+
".gitmodules",
|
|
15335
|
+
".idea",
|
|
15336
|
+
".mcp.json",
|
|
15337
|
+
".profile",
|
|
15338
|
+
".ripgreprc",
|
|
15339
|
+
".vscode",
|
|
15340
|
+
".zprofile",
|
|
15341
|
+
".zshrc"
|
|
15342
|
+
]);
|
|
15343
|
+
var WHOLE_FILESYSTEM = "/";
|
|
15344
|
+
var GUARDRAILS_TEMP_FOLDER = "guardrails-temp";
|
|
15345
|
+
var GLIMMERVOID_CONFIG_SIBLING_ENTRIES = Object.freeze([
|
|
15346
|
+
"bin",
|
|
15347
|
+
"pairings.json",
|
|
15348
|
+
"pairings-seen.json",
|
|
15349
|
+
"plans",
|
|
15350
|
+
"telegram-outbox.json",
|
|
15351
|
+
"traces",
|
|
15352
|
+
"uploads",
|
|
15353
|
+
"usage-budget-state.json",
|
|
15354
|
+
"usage-lanes.json",
|
|
15355
|
+
"usage-warehouse.json",
|
|
15356
|
+
"visions-intent.json"
|
|
15357
|
+
]);
|
|
15358
|
+
var GLIMMERVOID_HOME_STATE_ENTRIES = Object.freeze([
|
|
15359
|
+
"benchmark-runs",
|
|
15360
|
+
"benchmarks",
|
|
15361
|
+
"config.json",
|
|
15362
|
+
"factory",
|
|
15363
|
+
"issues-cache.json",
|
|
15364
|
+
"knowledge-graph",
|
|
15365
|
+
"litellm-pricing.json",
|
|
15366
|
+
"my-prs-state.json",
|
|
15367
|
+
"my-prs-work",
|
|
15368
|
+
"posthog-reports",
|
|
15369
|
+
"posthog-state.json",
|
|
15370
|
+
"posthog-work",
|
|
15371
|
+
"recordings",
|
|
15372
|
+
"guardrails-homes",
|
|
15373
|
+
"guardrails-policies",
|
|
15374
|
+
"sane-yolo",
|
|
15375
|
+
"scratch",
|
|
15376
|
+
"sounds",
|
|
15377
|
+
"team-review-repos",
|
|
15378
|
+
"team-review-state.json",
|
|
15379
|
+
"team-review-work",
|
|
15380
|
+
"team-review-worktrees",
|
|
15381
|
+
"telemetry-pending-crash.json",
|
|
15382
|
+
"telemetry.json",
|
|
15383
|
+
"tmp",
|
|
15384
|
+
"update-check.json",
|
|
15385
|
+
"update-journal.json",
|
|
15386
|
+
"workflows-state.json",
|
|
15387
|
+
"workflows-work"
|
|
15388
|
+
]);
|
|
15389
|
+
var RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS = Object.freeze(["commands", "agents"]);
|
|
15390
|
+
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";
|
|
15391
|
+
var HOOK_LOOPBACK_HOST = "127.0.0.1";
|
|
15392
|
+
var AGENT_SESSION_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
15393
|
+
var STANDARD_OPEN_NETWORK = Object.freeze({
|
|
15394
|
+
allowAllUnixSockets: true,
|
|
15395
|
+
allowMachLookup: ["*"]
|
|
15396
|
+
});
|
|
15397
|
+
var STRICT_OPEN_NETWORK = Object.freeze({ allowAllUnixSockets: false });
|
|
15398
|
+
function unique(entries) {
|
|
15399
|
+
return [...new Set(entries)];
|
|
15400
|
+
}
|
|
15401
|
+
function literalEntries(entryPaths) {
|
|
15402
|
+
return unique(entryPaths).map((entryPath) => ({
|
|
15403
|
+
path: entryPath,
|
|
15404
|
+
literal: true
|
|
15405
|
+
}));
|
|
15406
|
+
}
|
|
15407
|
+
function homePaths(host, homeEntries) {
|
|
15408
|
+
return homeEntries.map((entry) => path.join(host.homeDir, entry));
|
|
15409
|
+
}
|
|
15410
|
+
function isInsideAny(parents, child) {
|
|
15411
|
+
return parents.some((parent) => isPathInside(parent, child));
|
|
15412
|
+
}
|
|
15413
|
+
function vendorStatePaths(host, vendor, stateFolderEntries) {
|
|
15414
|
+
return stateFolderEntries.map((entry) => path.join(host.vendorLocations[vendor].stateFolder, entry));
|
|
15415
|
+
}
|
|
15416
|
+
function vendorHeldPaths(host, vendor) {
|
|
15417
|
+
const { stateFolder, configFiles, otherHomes } = host.vendorLocations[vendor];
|
|
15418
|
+
return [
|
|
15419
|
+
stateFolder,
|
|
15420
|
+
...configFiles,
|
|
15421
|
+
...otherHomes
|
|
15422
|
+
];
|
|
15423
|
+
}
|
|
15424
|
+
function launchHomeOf(host, vendor) {
|
|
15425
|
+
return path.join(host.launchHomeDir, vendor);
|
|
15426
|
+
}
|
|
15427
|
+
function vendorsWithLaunchHome(role) {
|
|
15428
|
+
if (role.vendorHome.scope === "state") return [];
|
|
15429
|
+
return role.vendors.filter((vendor) => VENDOR_PROFILES[vendor].launchHomeEnvName !== null);
|
|
15430
|
+
}
|
|
15431
|
+
function vendorWritableFolders(role, host) {
|
|
15432
|
+
const { vendorHome } = role;
|
|
15433
|
+
if (vendorHome.scope === "state") return role.vendors.map((vendor) => host.vendorLocations[vendor].stateFolder);
|
|
15434
|
+
return role.vendors.flatMap((vendor) => {
|
|
15435
|
+
const profile = VENDOR_PROFILES[vendor];
|
|
15436
|
+
if (profile.launchHomeEnvName !== null) return [launchHomeOf(host, vendor)];
|
|
15437
|
+
return vendorStatePaths(host, vendor, profile.launchWritableFolders(vendorHome));
|
|
15438
|
+
});
|
|
15439
|
+
}
|
|
15440
|
+
function launchPrivateFolders(role, host) {
|
|
15441
|
+
if (role.vendorHome.scope === "state") return [];
|
|
15442
|
+
return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].launchPrivateFolders));
|
|
15443
|
+
}
|
|
15444
|
+
function launchHomeLinkCandidates(role, host) {
|
|
15445
|
+
return vendorsWithLaunchHome(role).flatMap((vendor) => {
|
|
15446
|
+
const { configEntries, loginFiles } = VENDOR_PROFILES[vendor];
|
|
15447
|
+
const linkFor = (entry, isLogin) => ({
|
|
15448
|
+
linkPath: path.join(launchHomeOf(host, vendor), entry),
|
|
15449
|
+
targetPath: path.join(host.vendorLocations[vendor].stateFolder, entry),
|
|
15450
|
+
isLogin
|
|
15451
|
+
});
|
|
15452
|
+
return [...configEntries.map((entry) => linkFor(entry, false)), ...loginFiles.map((entry) => linkFor(entry, true))];
|
|
15453
|
+
});
|
|
15454
|
+
}
|
|
15455
|
+
function launchHomeEnv(role, host) {
|
|
15456
|
+
return Object.fromEntries(vendorsWithLaunchHome(role).flatMap((vendor) => {
|
|
15457
|
+
const envName = VENDOR_PROFILES[vendor].launchHomeEnvName;
|
|
15458
|
+
return envName === null ? [] : [[envName, launchHomeOf(host, vendor)]];
|
|
15459
|
+
}));
|
|
15460
|
+
}
|
|
15461
|
+
function vendorLoginFiles(role, host) {
|
|
15462
|
+
return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].loginFiles));
|
|
15463
|
+
}
|
|
15464
|
+
function roleWritableRoots(role) {
|
|
15465
|
+
return [
|
|
15466
|
+
...role.writableRoots,
|
|
15467
|
+
...role.lockedCheckouts,
|
|
15468
|
+
...role.commitCheckouts.flatMap(({ checkout, gitDir }) => [checkout, gitDir])
|
|
15469
|
+
];
|
|
15470
|
+
}
|
|
15471
|
+
function alwaysWritablePaths(role, host) {
|
|
15472
|
+
return [
|
|
15473
|
+
host.tempDir,
|
|
15474
|
+
...roleWritableRoots(role),
|
|
15475
|
+
...vendorWritableFolders(role, host)
|
|
15476
|
+
];
|
|
15477
|
+
}
|
|
15478
|
+
function commitCheckoutWriteDenies({ checkout, gitDir }) {
|
|
15479
|
+
const gitPointer = path.join(checkout, ".git");
|
|
15480
|
+
const gitDirDenies = [path.join(gitDir, "hooks"), path.join(gitDir, "config")];
|
|
15481
|
+
if (path.resolve(gitPointer) === path.resolve(gitDir)) return gitDirDenies;
|
|
15482
|
+
return [gitPointer, ...gitDirDenies];
|
|
15483
|
+
}
|
|
15484
|
+
function writeDeniesWhenPresent(role, host) {
|
|
15485
|
+
const writablePaths = alwaysWritablePaths(role, host);
|
|
15486
|
+
const sharedHomeWrites = homePaths(host, SHARED_HOME_WRITE_ENTRIES).filter((sharedPath) => !isInsideAny(roleWritableRoots(role), sharedPath));
|
|
15487
|
+
const vendorConfig = role.vendors.flatMap((vendor) => [...vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].configEntries), ...host.vendorLocations[vendor].configFiles]).filter((configPath) => isInsideAny(writablePaths, configPath));
|
|
15488
|
+
return [
|
|
15489
|
+
...SHARED_TEMP_DIRS,
|
|
15490
|
+
...sharedHomeWrites,
|
|
15491
|
+
...vendorConfig,
|
|
15492
|
+
...role.commitCheckouts.flatMap(commitCheckoutWriteDenies)
|
|
15493
|
+
];
|
|
15494
|
+
}
|
|
15495
|
+
function lockedCheckoutWriteDenies(role) {
|
|
15496
|
+
return role.lockedCheckouts.flatMap((checkout) => [path.join(checkout, ".git"), path.join(checkout, ".claude")]);
|
|
15497
|
+
}
|
|
15498
|
+
function lockedClaudeMountPoints(role) {
|
|
15499
|
+
return role.lockedCheckouts.flatMap((checkout) => RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS.map((folder) => path.join(checkout, ".claude", folder)));
|
|
15500
|
+
}
|
|
15501
|
+
function guardrailsPlaceholderPaths(role) {
|
|
15502
|
+
return unique([...(role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : []).flatMap((workingFolder) => GUARDRAILS_PLACEHOLDER_NAMES.map((placeholderName) => path.join(workingFolder, placeholderName))), ...lockedCheckoutWriteDenies(role)]);
|
|
15503
|
+
}
|
|
15504
|
+
function homeEntriesNamedLike(host, homeEntries) {
|
|
15505
|
+
return host.homeEntryNames.filter((entryName) => homeEntries.some((homeEntry) => entryName.startsWith(homeEntry)));
|
|
15506
|
+
}
|
|
15507
|
+
function relocatedXdgConfigPaths(host, homeEntries) {
|
|
15508
|
+
const xdgConfigHome = host.relocatedXdgConfigHome;
|
|
15509
|
+
if (xdgConfigHome === null) return [];
|
|
15510
|
+
return homeEntries.filter((entry) => entry.startsWith(XDG_CONFIG_DEFAULT_HOME_PREFIX)).map((entry) => path.join(xdgConfigHome, entry.slice(8)));
|
|
15511
|
+
}
|
|
15512
|
+
function isStandardLevel(role) {
|
|
15513
|
+
return role.guardrailLevel === "standard";
|
|
15514
|
+
}
|
|
15515
|
+
function blockedCredentialHomeEntries(role) {
|
|
15516
|
+
const credentialHomeEntries = [...CREDENTIAL_HOME_ENTRIES, ...CLOUD_CREDENTIAL_HOME_ENTRIES];
|
|
15517
|
+
if (!isStandardLevel(role)) return credentialHomeEntries;
|
|
15518
|
+
return credentialHomeEntries.filter((entry) => !STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES.includes(entry));
|
|
15519
|
+
}
|
|
15520
|
+
function credentialWriteBlocks(role, host) {
|
|
15521
|
+
const credentialHomeEntries = blockedCredentialHomeEntries(role);
|
|
15522
|
+
return [...homePaths(host, credentialHomeEntries), ...relocatedXdgConfigPaths(host, credentialHomeEntries)];
|
|
15523
|
+
}
|
|
15524
|
+
function glimmervoidStateWriteBlocks(role, host) {
|
|
15525
|
+
const keptWritable = alwaysWritablePaths(role, host);
|
|
15526
|
+
const configFolder = path.dirname(host.glimmervoidConfigFile);
|
|
15527
|
+
const homeEntries = [
|
|
15528
|
+
...GLIMMERVOID_HOME_STATE_ENTRIES,
|
|
15529
|
+
...GLIMMERVOID_CONFIG_SIBLING_ENTRIES,
|
|
15530
|
+
...host.glimmervoidHomeEntryNames
|
|
15531
|
+
].map((entryName) => path.join(host.glimmervoidHome, entryName));
|
|
15532
|
+
const configSiblings = GLIMMERVOID_CONFIG_SIBLING_ENTRIES.map((entryName) => path.join(configFolder, entryName));
|
|
15533
|
+
return unique([
|
|
15534
|
+
host.glimmervoidConfigFile,
|
|
15535
|
+
...homeEntries,
|
|
15536
|
+
...configSiblings
|
|
15537
|
+
]).filter((entryPath) => !keptWritable.some((writable) => isPathInside(entryPath, writable)));
|
|
15538
|
+
}
|
|
15539
|
+
function standardWriteBlockCandidates(role, host) {
|
|
15540
|
+
if (!isStandardLevel(role)) return [];
|
|
15541
|
+
return unique([
|
|
15542
|
+
...credentialWriteBlocks(role, host),
|
|
15543
|
+
...glimmervoidStateWriteBlocks(role, host),
|
|
15544
|
+
...role.blockedPaths ?? []
|
|
15545
|
+
]);
|
|
15546
|
+
}
|
|
15547
|
+
function readDeniedPaths(role, host) {
|
|
15548
|
+
const otherVendors = GUARDRAILS_VENDORS.filter((vendor) => !role.vendors.includes(vendor));
|
|
15549
|
+
const otherVendorHomeEntries = [...otherVendors.flatMap((vendor) => VENDOR_PROFILES[vendor].homeEntries), ...UNWRAPPED_VENDOR_HOME_ENTRIES];
|
|
15550
|
+
const credentialHomeEntries = blockedCredentialHomeEntries(role);
|
|
15551
|
+
return [
|
|
15552
|
+
...homePaths(host, [
|
|
15553
|
+
...credentialHomeEntries,
|
|
15554
|
+
...otherVendorHomeEntries,
|
|
15555
|
+
...homeEntriesNamedLike(host, otherVendorHomeEntries)
|
|
15556
|
+
]),
|
|
15557
|
+
...relocatedXdgConfigPaths(host, credentialHomeEntries),
|
|
15558
|
+
...otherVendors.flatMap((vendor) => vendorHeldPaths(host, vendor)),
|
|
15559
|
+
...host.unwrappedVendorHomes,
|
|
15560
|
+
host.glimmervoidHome,
|
|
15561
|
+
...launchPrivateFolders(role, host),
|
|
15562
|
+
...role.readDenied
|
|
15563
|
+
];
|
|
15564
|
+
}
|
|
15565
|
+
function guardrailsPolicyProbePaths(role, host) {
|
|
15566
|
+
return unique([
|
|
15567
|
+
...writeDeniesWhenPresent(role, host),
|
|
15568
|
+
...vendorLoginFiles(role, host),
|
|
15569
|
+
...launchHomeLinkCandidates(role, host).map((link) => link.targetPath)
|
|
15570
|
+
]);
|
|
15571
|
+
}
|
|
15572
|
+
function isValidPort(port) {
|
|
15573
|
+
return Number.isInteger(port) && port >= 1 && port <= 65535;
|
|
15574
|
+
}
|
|
15575
|
+
function hostNamedPaths(host) {
|
|
15576
|
+
const relocatedXdgConfigHomes = host.relocatedXdgConfigHome === null ? [] : [host.relocatedXdgConfigHome];
|
|
15577
|
+
return [
|
|
15578
|
+
host.homeDir,
|
|
15579
|
+
host.glimmervoidHome,
|
|
15580
|
+
host.glimmervoidConfigFile,
|
|
15581
|
+
host.tempDir,
|
|
15582
|
+
host.launchHomeDir,
|
|
15583
|
+
...relocatedXdgConfigHomes,
|
|
15584
|
+
...host.unwrappedVendorHomes,
|
|
15585
|
+
...GUARDRAILS_VENDORS.flatMap((vendor) => vendorHeldPaths(host, vendor))
|
|
15586
|
+
];
|
|
15587
|
+
}
|
|
15588
|
+
function guardrailsRoleRefusal(role, host) {
|
|
15589
|
+
const launchCwds = role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : [];
|
|
15590
|
+
const relativePath = [
|
|
15591
|
+
...hostNamedPaths(host),
|
|
15592
|
+
...roleWritableRoots(role),
|
|
15593
|
+
...role.readDenied,
|
|
15594
|
+
...role.readableWithinDenied,
|
|
15595
|
+
...launchCwds
|
|
15596
|
+
].find((namedPath) => !path.isAbsolute(namedPath));
|
|
15597
|
+
if (relativePath !== void 0) return `guardrails policy path is not absolute: ${relativePath}`;
|
|
15598
|
+
const rootOverProtectedHome = [...roleWritableRoots(role), ...vendorWritableFolders(role, host)].find((root) => isPathInside(root, host.homeDir) || isPathInside(root, host.glimmervoidHome));
|
|
15599
|
+
if (rootOverProtectedHome !== void 0) return `writable root ${rootOverProtectedHome} contains the home folder or the Glimmervoid home`;
|
|
15600
|
+
const writablePaths = alwaysWritablePaths(role, host);
|
|
15601
|
+
const reallowedAncestor = role.readableWithinDenied.find((readable) => writablePaths.some((writable) => isPathInside(readable, writable, { allowEqual: false })));
|
|
15602
|
+
if (reallowedAncestor !== void 0) return `readable path ${reallowedAncestor} is an ancestor of a writable root`;
|
|
15603
|
+
if (role.network.access === "allowlist" && role.network.hookPort !== null && !isValidPort(role.network.hookPort)) return "hook listener port is invalid";
|
|
15604
|
+
const agentSessionId = role.vendorHome.scope === "launch" ? role.vendorHome.agentSessionId : null;
|
|
15605
|
+
if (agentSessionId !== null && !AGENT_SESSION_ID_SHAPE.test(agentSessionId)) return "agent session id is invalid";
|
|
15606
|
+
return null;
|
|
15607
|
+
}
|
|
15608
|
+
function networkPolicy(role) {
|
|
15609
|
+
if (role.network.access === "open") return isStandardLevel(role) ? { ...STANDARD_OPEN_NETWORK } : { ...STRICT_OPEN_NETWORK };
|
|
15610
|
+
if (role.network.access === "none") return {
|
|
15611
|
+
allowedDomains: [],
|
|
15612
|
+
deniedDomains: [],
|
|
15613
|
+
allowLocalBinding: false,
|
|
15614
|
+
allowAllUnixSockets: false
|
|
15615
|
+
};
|
|
15616
|
+
const hookEndpoint = role.network.hookPort === null ? [] : [`${HOOK_LOOPBACK_HOST}:${role.network.hookPort}`];
|
|
15617
|
+
const vendorDomains = role.vendors.flatMap((vendor) => VENDOR_PROFILES[vendor].apiDomains);
|
|
15618
|
+
return {
|
|
15619
|
+
allowedDomains: unique([
|
|
15620
|
+
...hookEndpoint,
|
|
15621
|
+
...vendorDomains,
|
|
15622
|
+
...role.network.domains
|
|
15623
|
+
]),
|
|
15624
|
+
deniedDomains: [],
|
|
15625
|
+
strictAllowlist: true,
|
|
15626
|
+
allowLocalBinding: false,
|
|
15627
|
+
allowAllUnixSockets: false
|
|
15628
|
+
};
|
|
15629
|
+
}
|
|
15630
|
+
function guardedEnvFor(role, host) {
|
|
15631
|
+
if (role.network.access === "allowlist") return {
|
|
15632
|
+
NO_PROXY: GUARDED_PROXY_BYPASS,
|
|
15633
|
+
no_proxy: GUARDED_PROXY_BYPASS,
|
|
15634
|
+
[HOOK_VIA_GUARDRAILS_PROXY_ENV]: "1"
|
|
15635
|
+
};
|
|
15636
|
+
if (role.network.access === "open") return { TMPDIR: host.tempDir };
|
|
15637
|
+
return {};
|
|
15638
|
+
}
|
|
15639
|
+
function filesystemWrites(role, host, writablePaths) {
|
|
15640
|
+
if (isStandardLevel(role)) return {
|
|
15641
|
+
allowWrite: literalEntries([WHOLE_FILESYSTEM, ...writablePaths]),
|
|
15642
|
+
denyWrite: literalEntries(host.writeBlockedPaths)
|
|
15643
|
+
};
|
|
15644
|
+
const isPresent = (candidate) => host.existingPaths.has(candidate);
|
|
15645
|
+
return {
|
|
15646
|
+
allowWrite: literalEntries(writablePaths),
|
|
15647
|
+
denyWrite: literalEntries([...writeDeniesWhenPresent(role, host).filter(isPresent), ...lockedCheckoutWriteDenies(role)])
|
|
15648
|
+
};
|
|
15649
|
+
}
|
|
15650
|
+
function buildGuardrailsLaunchPlan(role, host) {
|
|
15651
|
+
const refusal = guardrailsRoleRefusal(role, host);
|
|
15652
|
+
if (refusal !== null) return {
|
|
15653
|
+
ok: false,
|
|
15654
|
+
reason: refusal
|
|
15655
|
+
};
|
|
15656
|
+
const isPresent = (candidate) => host.existingPaths.has(candidate);
|
|
15657
|
+
const writablePaths = [...alwaysWritablePaths(role, host), ...vendorLoginFiles(role, host).filter(isPresent)];
|
|
15658
|
+
const readDenied = readDeniedPaths(role, host);
|
|
15659
|
+
const writableWithinDenied = writablePaths.filter((writable) => isInsideAny(readDenied, writable));
|
|
15660
|
+
return {
|
|
15661
|
+
ok: true,
|
|
15662
|
+
plan: {
|
|
15663
|
+
launcher: role.network.access === "open" ? "open-network" : "runtime-cli",
|
|
15664
|
+
policy: {
|
|
15665
|
+
network: networkPolicy(role),
|
|
15666
|
+
filesystem: {
|
|
15667
|
+
denyRead: literalEntries(readDenied),
|
|
15668
|
+
allowRead: literalEntries([...writableWithinDenied, ...role.readableWithinDenied]),
|
|
15669
|
+
...filesystemWrites(role, host, writablePaths)
|
|
15670
|
+
},
|
|
15671
|
+
terminalScope: isStandardLevel(role) ? "any" : "own",
|
|
15672
|
+
allowAppleEvents: isStandardLevel(role)
|
|
15673
|
+
},
|
|
15674
|
+
launchEnv: Object.assign({ CLAUDE_CODE_TMPDIR: host.tempDir }, ...role.vendors.map((vendor) => VENDOR_PROFILES[vendor].launchEnv), launchHomeEnv(role, host)),
|
|
15675
|
+
guardedEnv: guardedEnvFor(role, host),
|
|
15676
|
+
requiredDirectories: unique([
|
|
15677
|
+
host.tempDir,
|
|
15678
|
+
...vendorWritableFolders(role, host),
|
|
15679
|
+
...launchPrivateFolders(role, host)
|
|
15680
|
+
]),
|
|
15681
|
+
launchHomeLinks: launchHomeLinkCandidates(role, host).filter((link) => isPresent(link.targetPath))
|
|
15682
|
+
}
|
|
15683
|
+
};
|
|
15684
|
+
}
|
|
15685
|
+
//#endregion
|
|
15177
15686
|
//#region server/ingest/core/ingest-shell-core.ts
|
|
15178
15687
|
var SOURCE$4 = "shellHistory";
|
|
15179
15688
|
var SHELLS = Object.freeze([
|
|
@@ -15526,12 +16035,15 @@ var writtenHomes = /* @__PURE__ */ new Set();
|
|
|
15526
16035
|
var warnedTools = /* @__PURE__ */ new Set();
|
|
15527
16036
|
var ensuredDataDirs = /* @__PURE__ */ new Set();
|
|
15528
16037
|
var RTK_DATA_FOLDER = "rtk";
|
|
16038
|
+
function currentGlimmervoidHome() {
|
|
16039
|
+
return glimmervoidHomeDir(os.homedir(), process.env);
|
|
16040
|
+
}
|
|
15529
16041
|
function saneYoloHomeDir() {
|
|
15530
|
-
return path.join(
|
|
16042
|
+
return path.join(currentGlimmervoidHome(), "sane-yolo");
|
|
15531
16043
|
}
|
|
15532
|
-
function writeSaneYoloPolicy(homeDir) {
|
|
16044
|
+
function writeSaneYoloPolicy(homeDir, glimmervoidHome = currentGlimmervoidHome()) {
|
|
15533
16045
|
if (writtenHomes.has(homeDir)) return;
|
|
15534
|
-
for (const [relativePath, contents] of Object.entries(
|
|
16046
|
+
for (const [relativePath, contents] of Object.entries(saneYoloFiles(path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER)))) {
|
|
15535
16047
|
const filePath = path.join(homeDir, relativePath);
|
|
15536
16048
|
const serialized = `${JSON.stringify(contents, null, 2)}\n`;
|
|
15537
16049
|
fs.mkdirSync(path.dirname(filePath), {
|
|
@@ -16245,430 +16757,6 @@ function proveMergedAcrossTips(probes) {
|
|
|
16245
16757
|
return mostCautiousProof;
|
|
16246
16758
|
}
|
|
16247
16759
|
//#endregion
|
|
16248
|
-
//#region server/guardrails/core/guardrails-policy-core.ts
|
|
16249
|
-
var VENDOR_PROFILES = Object.freeze({
|
|
16250
|
-
claude: {
|
|
16251
|
-
homeEntries: [".claude", ".claude.json"],
|
|
16252
|
-
launchWritableFolders: ({ cwd, agentSessionId }) => [path.join("projects", encodeProjectDir(cwd)), ...agentSessionId === null ? [] : [path.join("session-env", agentSessionId)]],
|
|
16253
|
-
launchPrivateFolders: ["shell-snapshots"],
|
|
16254
|
-
launchHomeEnvName: null,
|
|
16255
|
-
loginFiles: [".credentials.json"],
|
|
16256
|
-
configEntries: [
|
|
16257
|
-
"settings.json",
|
|
16258
|
-
"settings.local.json",
|
|
16259
|
-
"hooks",
|
|
16260
|
-
"skills",
|
|
16261
|
-
"plugins",
|
|
16262
|
-
"commands",
|
|
16263
|
-
"agents",
|
|
16264
|
-
"CLAUDE.md",
|
|
16265
|
-
"AGENTS.md"
|
|
16266
|
-
],
|
|
16267
|
-
apiDomains: ["api.anthropic.com", "platform.claude.com"],
|
|
16268
|
-
launchEnv: { DISABLE_AUTOUPDATER: "1" }
|
|
16269
|
-
},
|
|
16270
|
-
codex: {
|
|
16271
|
-
homeEntries: [".codex"],
|
|
16272
|
-
launchWritableFolders: () => [],
|
|
16273
|
-
launchPrivateFolders: [],
|
|
16274
|
-
launchHomeEnvName: "CODEX_HOME",
|
|
16275
|
-
loginFiles: ["auth.json"],
|
|
16276
|
-
configEntries: [
|
|
16277
|
-
"config.toml",
|
|
16278
|
-
"AGENTS.md",
|
|
16279
|
-
"skills",
|
|
16280
|
-
"rules",
|
|
16281
|
-
"prompts",
|
|
16282
|
-
"hooks.json"
|
|
16283
|
-
],
|
|
16284
|
-
apiDomains: [
|
|
16285
|
-
"chatgpt.com",
|
|
16286
|
-
"*.chatgpt.com",
|
|
16287
|
-
"auth.openai.com",
|
|
16288
|
-
"api.openai.com",
|
|
16289
|
-
"*.openai.com"
|
|
16290
|
-
],
|
|
16291
|
-
launchEnv: {}
|
|
16292
|
-
}
|
|
16293
|
-
});
|
|
16294
|
-
var GUARDRAILS_VENDORS = Object.freeze(["claude", "codex"]);
|
|
16295
|
-
var UNWRAPPED_VENDOR_HOME_ENTRIES = Object.freeze([".grok"]);
|
|
16296
|
-
var CREDENTIAL_HOME_ENTRIES = Object.freeze([
|
|
16297
|
-
".ssh",
|
|
16298
|
-
".config/gh",
|
|
16299
|
-
"Library/Keychains",
|
|
16300
|
-
".git-credentials"
|
|
16301
|
-
]);
|
|
16302
|
-
var CLOUD_CREDENTIAL_HOME_ENTRIES = Object.freeze([
|
|
16303
|
-
".aws",
|
|
16304
|
-
".azure",
|
|
16305
|
-
".config/gcloud",
|
|
16306
|
-
".kube",
|
|
16307
|
-
".docker",
|
|
16308
|
-
".gnupg",
|
|
16309
|
-
".netrc",
|
|
16310
|
-
".npmrc"
|
|
16311
|
-
]);
|
|
16312
|
-
var STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES = Object.freeze(["Library/Keychains"]);
|
|
16313
|
-
var XDG_CONFIG_DEFAULT_HOME_PREFIX = ".config/";
|
|
16314
|
-
var SHARED_TEMP_DIRS = Object.freeze(["/tmp/claude", "/private/tmp/claude"]);
|
|
16315
|
-
var SHARED_HOME_WRITE_ENTRIES = Object.freeze([".npm/_logs"]);
|
|
16316
|
-
var GUARDRAILS_PLACEHOLDER_NAMES = Object.freeze([
|
|
16317
|
-
".bash_profile",
|
|
16318
|
-
".bashrc",
|
|
16319
|
-
".claude",
|
|
16320
|
-
".gitconfig",
|
|
16321
|
-
".gitmodules",
|
|
16322
|
-
".idea",
|
|
16323
|
-
".mcp.json",
|
|
16324
|
-
".profile",
|
|
16325
|
-
".ripgreprc",
|
|
16326
|
-
".vscode",
|
|
16327
|
-
".zprofile",
|
|
16328
|
-
".zshrc"
|
|
16329
|
-
]);
|
|
16330
|
-
var WHOLE_FILESYSTEM = "/";
|
|
16331
|
-
var GLIMMERVOID_CONFIG_SIBLING_ENTRIES = Object.freeze([
|
|
16332
|
-
"bin",
|
|
16333
|
-
"pairings.json",
|
|
16334
|
-
"pairings-seen.json",
|
|
16335
|
-
"plans",
|
|
16336
|
-
"telegram-outbox.json",
|
|
16337
|
-
"traces",
|
|
16338
|
-
"uploads",
|
|
16339
|
-
"usage-budget-state.json",
|
|
16340
|
-
"usage-lanes.json",
|
|
16341
|
-
"usage-warehouse.json",
|
|
16342
|
-
"visions-intent.json"
|
|
16343
|
-
]);
|
|
16344
|
-
var GLIMMERVOID_HOME_STATE_ENTRIES = Object.freeze([
|
|
16345
|
-
"benchmark-runs",
|
|
16346
|
-
"benchmarks",
|
|
16347
|
-
"config.json",
|
|
16348
|
-
"factory",
|
|
16349
|
-
"issues-cache.json",
|
|
16350
|
-
"knowledge-graph",
|
|
16351
|
-
"litellm-pricing.json",
|
|
16352
|
-
"my-prs-state.json",
|
|
16353
|
-
"my-prs-work",
|
|
16354
|
-
"posthog-reports",
|
|
16355
|
-
"posthog-state.json",
|
|
16356
|
-
"posthog-work",
|
|
16357
|
-
"recordings",
|
|
16358
|
-
"guardrails-homes",
|
|
16359
|
-
"guardrails-policies",
|
|
16360
|
-
"sane-yolo",
|
|
16361
|
-
"scratch",
|
|
16362
|
-
"sounds",
|
|
16363
|
-
"team-review-repos",
|
|
16364
|
-
"team-review-state.json",
|
|
16365
|
-
"team-review-work",
|
|
16366
|
-
"team-review-worktrees",
|
|
16367
|
-
"telemetry-pending-crash.json",
|
|
16368
|
-
"telemetry.json",
|
|
16369
|
-
"tmp",
|
|
16370
|
-
"update-check.json",
|
|
16371
|
-
"update-journal.json",
|
|
16372
|
-
"workflows-state.json",
|
|
16373
|
-
"workflows-work"
|
|
16374
|
-
]);
|
|
16375
|
-
var RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS = Object.freeze(["commands", "agents"]);
|
|
16376
|
-
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";
|
|
16377
|
-
var HOOK_LOOPBACK_HOST = "127.0.0.1";
|
|
16378
|
-
var AGENT_SESSION_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
16379
|
-
var STANDARD_OPEN_NETWORK = Object.freeze({
|
|
16380
|
-
allowAllUnixSockets: true,
|
|
16381
|
-
allowMachLookup: ["*"]
|
|
16382
|
-
});
|
|
16383
|
-
var STRICT_OPEN_NETWORK = Object.freeze({ allowAllUnixSockets: false });
|
|
16384
|
-
function unique(entries) {
|
|
16385
|
-
return [...new Set(entries)];
|
|
16386
|
-
}
|
|
16387
|
-
function literalEntries(entryPaths) {
|
|
16388
|
-
return unique(entryPaths).map((entryPath) => ({
|
|
16389
|
-
path: entryPath,
|
|
16390
|
-
literal: true
|
|
16391
|
-
}));
|
|
16392
|
-
}
|
|
16393
|
-
function homePaths(host, homeEntries) {
|
|
16394
|
-
return homeEntries.map((entry) => path.join(host.homeDir, entry));
|
|
16395
|
-
}
|
|
16396
|
-
function isInsideAny(parents, child) {
|
|
16397
|
-
return parents.some((parent) => isPathInside(parent, child));
|
|
16398
|
-
}
|
|
16399
|
-
function vendorStatePaths(host, vendor, stateFolderEntries) {
|
|
16400
|
-
return stateFolderEntries.map((entry) => path.join(host.vendorLocations[vendor].stateFolder, entry));
|
|
16401
|
-
}
|
|
16402
|
-
function vendorHeldPaths(host, vendor) {
|
|
16403
|
-
const { stateFolder, configFiles, otherHomes } = host.vendorLocations[vendor];
|
|
16404
|
-
return [
|
|
16405
|
-
stateFolder,
|
|
16406
|
-
...configFiles,
|
|
16407
|
-
...otherHomes
|
|
16408
|
-
];
|
|
16409
|
-
}
|
|
16410
|
-
function launchHomeOf(host, vendor) {
|
|
16411
|
-
return path.join(host.launchHomeDir, vendor);
|
|
16412
|
-
}
|
|
16413
|
-
function vendorsWithLaunchHome(role) {
|
|
16414
|
-
if (role.vendorHome.scope === "state") return [];
|
|
16415
|
-
return role.vendors.filter((vendor) => VENDOR_PROFILES[vendor].launchHomeEnvName !== null);
|
|
16416
|
-
}
|
|
16417
|
-
function vendorWritableFolders(role, host) {
|
|
16418
|
-
const { vendorHome } = role;
|
|
16419
|
-
if (vendorHome.scope === "state") return role.vendors.map((vendor) => host.vendorLocations[vendor].stateFolder);
|
|
16420
|
-
return role.vendors.flatMap((vendor) => {
|
|
16421
|
-
const profile = VENDOR_PROFILES[vendor];
|
|
16422
|
-
if (profile.launchHomeEnvName !== null) return [launchHomeOf(host, vendor)];
|
|
16423
|
-
return vendorStatePaths(host, vendor, profile.launchWritableFolders(vendorHome));
|
|
16424
|
-
});
|
|
16425
|
-
}
|
|
16426
|
-
function launchPrivateFolders(role, host) {
|
|
16427
|
-
if (role.vendorHome.scope === "state") return [];
|
|
16428
|
-
return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].launchPrivateFolders));
|
|
16429
|
-
}
|
|
16430
|
-
function launchHomeLinkCandidates(role, host) {
|
|
16431
|
-
return vendorsWithLaunchHome(role).flatMap((vendor) => {
|
|
16432
|
-
const { configEntries, loginFiles } = VENDOR_PROFILES[vendor];
|
|
16433
|
-
const linkFor = (entry, isLogin) => ({
|
|
16434
|
-
linkPath: path.join(launchHomeOf(host, vendor), entry),
|
|
16435
|
-
targetPath: path.join(host.vendorLocations[vendor].stateFolder, entry),
|
|
16436
|
-
isLogin
|
|
16437
|
-
});
|
|
16438
|
-
return [...configEntries.map((entry) => linkFor(entry, false)), ...loginFiles.map((entry) => linkFor(entry, true))];
|
|
16439
|
-
});
|
|
16440
|
-
}
|
|
16441
|
-
function launchHomeEnv(role, host) {
|
|
16442
|
-
return Object.fromEntries(vendorsWithLaunchHome(role).flatMap((vendor) => {
|
|
16443
|
-
const envName = VENDOR_PROFILES[vendor].launchHomeEnvName;
|
|
16444
|
-
return envName === null ? [] : [[envName, launchHomeOf(host, vendor)]];
|
|
16445
|
-
}));
|
|
16446
|
-
}
|
|
16447
|
-
function vendorLoginFiles(role, host) {
|
|
16448
|
-
return role.vendors.flatMap((vendor) => vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].loginFiles));
|
|
16449
|
-
}
|
|
16450
|
-
function roleWritableRoots(role) {
|
|
16451
|
-
return [
|
|
16452
|
-
...role.writableRoots,
|
|
16453
|
-
...role.lockedCheckouts,
|
|
16454
|
-
...role.commitCheckouts.flatMap(({ checkout, gitDir }) => [checkout, gitDir])
|
|
16455
|
-
];
|
|
16456
|
-
}
|
|
16457
|
-
function alwaysWritablePaths(role, host) {
|
|
16458
|
-
return [
|
|
16459
|
-
host.tempDir,
|
|
16460
|
-
...roleWritableRoots(role),
|
|
16461
|
-
...vendorWritableFolders(role, host)
|
|
16462
|
-
];
|
|
16463
|
-
}
|
|
16464
|
-
function commitCheckoutWriteDenies({ checkout, gitDir }) {
|
|
16465
|
-
const gitPointer = path.join(checkout, ".git");
|
|
16466
|
-
const gitDirDenies = [path.join(gitDir, "hooks"), path.join(gitDir, "config")];
|
|
16467
|
-
if (path.resolve(gitPointer) === path.resolve(gitDir)) return gitDirDenies;
|
|
16468
|
-
return [gitPointer, ...gitDirDenies];
|
|
16469
|
-
}
|
|
16470
|
-
function writeDeniesWhenPresent(role, host) {
|
|
16471
|
-
const writablePaths = alwaysWritablePaths(role, host);
|
|
16472
|
-
const sharedHomeWrites = homePaths(host, SHARED_HOME_WRITE_ENTRIES).filter((sharedPath) => !isInsideAny(roleWritableRoots(role), sharedPath));
|
|
16473
|
-
const vendorConfig = role.vendors.flatMap((vendor) => [...vendorStatePaths(host, vendor, VENDOR_PROFILES[vendor].configEntries), ...host.vendorLocations[vendor].configFiles]).filter((configPath) => isInsideAny(writablePaths, configPath));
|
|
16474
|
-
return [
|
|
16475
|
-
...SHARED_TEMP_DIRS,
|
|
16476
|
-
...sharedHomeWrites,
|
|
16477
|
-
...vendorConfig,
|
|
16478
|
-
...role.commitCheckouts.flatMap(commitCheckoutWriteDenies)
|
|
16479
|
-
];
|
|
16480
|
-
}
|
|
16481
|
-
function lockedCheckoutWriteDenies(role) {
|
|
16482
|
-
return role.lockedCheckouts.flatMap((checkout) => [path.join(checkout, ".git"), path.join(checkout, ".claude")]);
|
|
16483
|
-
}
|
|
16484
|
-
function lockedClaudeMountPoints(role) {
|
|
16485
|
-
return role.lockedCheckouts.flatMap((checkout) => RUNTIME_MANDATORY_CLAUDE_DENY_FOLDERS.map((folder) => path.join(checkout, ".claude", folder)));
|
|
16486
|
-
}
|
|
16487
|
-
function guardrailsPlaceholderPaths(role) {
|
|
16488
|
-
return unique([...(role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : []).flatMap((workingFolder) => GUARDRAILS_PLACEHOLDER_NAMES.map((placeholderName) => path.join(workingFolder, placeholderName))), ...lockedCheckoutWriteDenies(role)]);
|
|
16489
|
-
}
|
|
16490
|
-
function homeEntriesNamedLike(host, homeEntries) {
|
|
16491
|
-
return host.homeEntryNames.filter((entryName) => homeEntries.some((homeEntry) => entryName.startsWith(homeEntry)));
|
|
16492
|
-
}
|
|
16493
|
-
function relocatedXdgConfigPaths(host, homeEntries) {
|
|
16494
|
-
const xdgConfigHome = host.relocatedXdgConfigHome;
|
|
16495
|
-
if (xdgConfigHome === null) return [];
|
|
16496
|
-
return homeEntries.filter((entry) => entry.startsWith(XDG_CONFIG_DEFAULT_HOME_PREFIX)).map((entry) => path.join(xdgConfigHome, entry.slice(8)));
|
|
16497
|
-
}
|
|
16498
|
-
function isStandardLevel(role) {
|
|
16499
|
-
return role.guardrailLevel === "standard";
|
|
16500
|
-
}
|
|
16501
|
-
function blockedCredentialHomeEntries(role) {
|
|
16502
|
-
const credentialHomeEntries = [...CREDENTIAL_HOME_ENTRIES, ...CLOUD_CREDENTIAL_HOME_ENTRIES];
|
|
16503
|
-
if (!isStandardLevel(role)) return credentialHomeEntries;
|
|
16504
|
-
return credentialHomeEntries.filter((entry) => !STANDARD_LEVEL_USABLE_CREDENTIAL_ENTRIES.includes(entry));
|
|
16505
|
-
}
|
|
16506
|
-
function credentialWriteBlocks(role, host) {
|
|
16507
|
-
const credentialHomeEntries = blockedCredentialHomeEntries(role);
|
|
16508
|
-
return [...homePaths(host, credentialHomeEntries), ...relocatedXdgConfigPaths(host, credentialHomeEntries)];
|
|
16509
|
-
}
|
|
16510
|
-
function glimmervoidStateWriteBlocks(role, host) {
|
|
16511
|
-
const keptWritable = alwaysWritablePaths(role, host);
|
|
16512
|
-
const configFolder = path.dirname(host.glimmervoidConfigFile);
|
|
16513
|
-
const homeEntries = [
|
|
16514
|
-
...GLIMMERVOID_HOME_STATE_ENTRIES,
|
|
16515
|
-
...GLIMMERVOID_CONFIG_SIBLING_ENTRIES,
|
|
16516
|
-
...host.glimmervoidHomeEntryNames
|
|
16517
|
-
].map((entryName) => path.join(host.glimmervoidHome, entryName));
|
|
16518
|
-
const configSiblings = GLIMMERVOID_CONFIG_SIBLING_ENTRIES.map((entryName) => path.join(configFolder, entryName));
|
|
16519
|
-
return unique([
|
|
16520
|
-
host.glimmervoidConfigFile,
|
|
16521
|
-
...homeEntries,
|
|
16522
|
-
...configSiblings
|
|
16523
|
-
]).filter((entryPath) => !keptWritable.some((writable) => isPathInside(entryPath, writable)));
|
|
16524
|
-
}
|
|
16525
|
-
function standardWriteBlockCandidates(role, host) {
|
|
16526
|
-
if (!isStandardLevel(role)) return [];
|
|
16527
|
-
return unique([
|
|
16528
|
-
...credentialWriteBlocks(role, host),
|
|
16529
|
-
...glimmervoidStateWriteBlocks(role, host),
|
|
16530
|
-
...role.blockedPaths ?? []
|
|
16531
|
-
]);
|
|
16532
|
-
}
|
|
16533
|
-
function readDeniedPaths(role, host) {
|
|
16534
|
-
const otherVendors = GUARDRAILS_VENDORS.filter((vendor) => !role.vendors.includes(vendor));
|
|
16535
|
-
const otherVendorHomeEntries = [...otherVendors.flatMap((vendor) => VENDOR_PROFILES[vendor].homeEntries), ...UNWRAPPED_VENDOR_HOME_ENTRIES];
|
|
16536
|
-
const credentialHomeEntries = blockedCredentialHomeEntries(role);
|
|
16537
|
-
return [
|
|
16538
|
-
...homePaths(host, [
|
|
16539
|
-
...credentialHomeEntries,
|
|
16540
|
-
...otherVendorHomeEntries,
|
|
16541
|
-
...homeEntriesNamedLike(host, otherVendorHomeEntries)
|
|
16542
|
-
]),
|
|
16543
|
-
...relocatedXdgConfigPaths(host, credentialHomeEntries),
|
|
16544
|
-
...otherVendors.flatMap((vendor) => vendorHeldPaths(host, vendor)),
|
|
16545
|
-
...host.unwrappedVendorHomes,
|
|
16546
|
-
host.glimmervoidHome,
|
|
16547
|
-
...launchPrivateFolders(role, host),
|
|
16548
|
-
...role.readDenied
|
|
16549
|
-
];
|
|
16550
|
-
}
|
|
16551
|
-
function guardrailsPolicyProbePaths(role, host) {
|
|
16552
|
-
return unique([
|
|
16553
|
-
...writeDeniesWhenPresent(role, host),
|
|
16554
|
-
...vendorLoginFiles(role, host),
|
|
16555
|
-
...launchHomeLinkCandidates(role, host).map((link) => link.targetPath)
|
|
16556
|
-
]);
|
|
16557
|
-
}
|
|
16558
|
-
function isValidPort(port) {
|
|
16559
|
-
return Number.isInteger(port) && port >= 1 && port <= 65535;
|
|
16560
|
-
}
|
|
16561
|
-
function hostNamedPaths(host) {
|
|
16562
|
-
const relocatedXdgConfigHomes = host.relocatedXdgConfigHome === null ? [] : [host.relocatedXdgConfigHome];
|
|
16563
|
-
return [
|
|
16564
|
-
host.homeDir,
|
|
16565
|
-
host.glimmervoidHome,
|
|
16566
|
-
host.glimmervoidConfigFile,
|
|
16567
|
-
host.tempDir,
|
|
16568
|
-
host.launchHomeDir,
|
|
16569
|
-
...relocatedXdgConfigHomes,
|
|
16570
|
-
...host.unwrappedVendorHomes,
|
|
16571
|
-
...GUARDRAILS_VENDORS.flatMap((vendor) => vendorHeldPaths(host, vendor))
|
|
16572
|
-
];
|
|
16573
|
-
}
|
|
16574
|
-
function guardrailsRoleRefusal(role, host) {
|
|
16575
|
-
const launchCwds = role.vendorHome.scope === "launch" ? [role.vendorHome.cwd] : [];
|
|
16576
|
-
const relativePath = [
|
|
16577
|
-
...hostNamedPaths(host),
|
|
16578
|
-
...roleWritableRoots(role),
|
|
16579
|
-
...role.readDenied,
|
|
16580
|
-
...role.readableWithinDenied,
|
|
16581
|
-
...launchCwds
|
|
16582
|
-
].find((namedPath) => !path.isAbsolute(namedPath));
|
|
16583
|
-
if (relativePath !== void 0) return `guardrails policy path is not absolute: ${relativePath}`;
|
|
16584
|
-
const rootOverProtectedHome = [...roleWritableRoots(role), ...vendorWritableFolders(role, host)].find((root) => isPathInside(root, host.homeDir) || isPathInside(root, host.glimmervoidHome));
|
|
16585
|
-
if (rootOverProtectedHome !== void 0) return `writable root ${rootOverProtectedHome} contains the home folder or the Glimmervoid home`;
|
|
16586
|
-
const writablePaths = alwaysWritablePaths(role, host);
|
|
16587
|
-
const reallowedAncestor = role.readableWithinDenied.find((readable) => writablePaths.some((writable) => isPathInside(readable, writable, { allowEqual: false })));
|
|
16588
|
-
if (reallowedAncestor !== void 0) return `readable path ${reallowedAncestor} is an ancestor of a writable root`;
|
|
16589
|
-
if (role.network.access === "allowlist" && role.network.hookPort !== null && !isValidPort(role.network.hookPort)) return "hook listener port is invalid";
|
|
16590
|
-
const agentSessionId = role.vendorHome.scope === "launch" ? role.vendorHome.agentSessionId : null;
|
|
16591
|
-
if (agentSessionId !== null && !AGENT_SESSION_ID_SHAPE.test(agentSessionId)) return "agent session id is invalid";
|
|
16592
|
-
return null;
|
|
16593
|
-
}
|
|
16594
|
-
function networkPolicy(role) {
|
|
16595
|
-
if (role.network.access === "open") return isStandardLevel(role) ? { ...STANDARD_OPEN_NETWORK } : { ...STRICT_OPEN_NETWORK };
|
|
16596
|
-
if (role.network.access === "none") return {
|
|
16597
|
-
allowedDomains: [],
|
|
16598
|
-
deniedDomains: [],
|
|
16599
|
-
allowLocalBinding: false,
|
|
16600
|
-
allowAllUnixSockets: false
|
|
16601
|
-
};
|
|
16602
|
-
const hookEndpoint = role.network.hookPort === null ? [] : [`${HOOK_LOOPBACK_HOST}:${role.network.hookPort}`];
|
|
16603
|
-
const vendorDomains = role.vendors.flatMap((vendor) => VENDOR_PROFILES[vendor].apiDomains);
|
|
16604
|
-
return {
|
|
16605
|
-
allowedDomains: unique([
|
|
16606
|
-
...hookEndpoint,
|
|
16607
|
-
...vendorDomains,
|
|
16608
|
-
...role.network.domains
|
|
16609
|
-
]),
|
|
16610
|
-
deniedDomains: [],
|
|
16611
|
-
strictAllowlist: true,
|
|
16612
|
-
allowLocalBinding: false,
|
|
16613
|
-
allowAllUnixSockets: false
|
|
16614
|
-
};
|
|
16615
|
-
}
|
|
16616
|
-
function guardedEnvFor(role, host) {
|
|
16617
|
-
if (role.network.access === "allowlist") return {
|
|
16618
|
-
NO_PROXY: GUARDED_PROXY_BYPASS,
|
|
16619
|
-
no_proxy: GUARDED_PROXY_BYPASS,
|
|
16620
|
-
[HOOK_VIA_GUARDRAILS_PROXY_ENV]: "1"
|
|
16621
|
-
};
|
|
16622
|
-
if (role.network.access === "open") return { TMPDIR: host.tempDir };
|
|
16623
|
-
return {};
|
|
16624
|
-
}
|
|
16625
|
-
function filesystemWrites(role, host, writablePaths) {
|
|
16626
|
-
if (isStandardLevel(role)) return {
|
|
16627
|
-
allowWrite: literalEntries([WHOLE_FILESYSTEM, ...writablePaths]),
|
|
16628
|
-
denyWrite: literalEntries(host.writeBlockedPaths)
|
|
16629
|
-
};
|
|
16630
|
-
const isPresent = (candidate) => host.existingPaths.has(candidate);
|
|
16631
|
-
return {
|
|
16632
|
-
allowWrite: literalEntries(writablePaths),
|
|
16633
|
-
denyWrite: literalEntries([...writeDeniesWhenPresent(role, host).filter(isPresent), ...lockedCheckoutWriteDenies(role)])
|
|
16634
|
-
};
|
|
16635
|
-
}
|
|
16636
|
-
function buildGuardrailsLaunchPlan(role, host) {
|
|
16637
|
-
const refusal = guardrailsRoleRefusal(role, host);
|
|
16638
|
-
if (refusal !== null) return {
|
|
16639
|
-
ok: false,
|
|
16640
|
-
reason: refusal
|
|
16641
|
-
};
|
|
16642
|
-
const isPresent = (candidate) => host.existingPaths.has(candidate);
|
|
16643
|
-
const writablePaths = [...alwaysWritablePaths(role, host), ...vendorLoginFiles(role, host).filter(isPresent)];
|
|
16644
|
-
const readDenied = readDeniedPaths(role, host);
|
|
16645
|
-
const writableWithinDenied = writablePaths.filter((writable) => isInsideAny(readDenied, writable));
|
|
16646
|
-
return {
|
|
16647
|
-
ok: true,
|
|
16648
|
-
plan: {
|
|
16649
|
-
launcher: role.network.access === "open" ? "open-network" : "runtime-cli",
|
|
16650
|
-
policy: {
|
|
16651
|
-
network: networkPolicy(role),
|
|
16652
|
-
filesystem: {
|
|
16653
|
-
denyRead: literalEntries(readDenied),
|
|
16654
|
-
allowRead: literalEntries([...writableWithinDenied, ...role.readableWithinDenied]),
|
|
16655
|
-
...filesystemWrites(role, host, writablePaths)
|
|
16656
|
-
},
|
|
16657
|
-
terminalScope: isStandardLevel(role) ? "any" : "own",
|
|
16658
|
-
allowAppleEvents: isStandardLevel(role)
|
|
16659
|
-
},
|
|
16660
|
-
launchEnv: Object.assign({ CLAUDE_CODE_TMPDIR: host.tempDir }, ...role.vendors.map((vendor) => VENDOR_PROFILES[vendor].launchEnv), launchHomeEnv(role, host)),
|
|
16661
|
-
guardedEnv: guardedEnvFor(role, host),
|
|
16662
|
-
requiredDirectories: unique([
|
|
16663
|
-
host.tempDir,
|
|
16664
|
-
...vendorWritableFolders(role, host),
|
|
16665
|
-
...launchPrivateFolders(role, host)
|
|
16666
|
-
]),
|
|
16667
|
-
launchHomeLinks: launchHomeLinkCandidates(role, host).filter((link) => isPresent(link.targetPath))
|
|
16668
|
-
}
|
|
16669
|
-
};
|
|
16670
|
-
}
|
|
16671
|
-
//#endregion
|
|
16672
16760
|
//#region shared/repo.ts
|
|
16673
16761
|
var REPO_SLUG = "johncwaters/glimmervoid";
|
|
16674
16762
|
//#endregion
|
|
@@ -21131,6 +21219,7 @@ function createSessionBackgroundTracking({ detectBackgroundAgents, agentTtlMs, s
|
|
|
21131
21219
|
};
|
|
21132
21220
|
let publishedActiveAgents = 0;
|
|
21133
21221
|
let publishedAwaitingBackgroundTasks = false;
|
|
21222
|
+
let publishedHasBackgroundWork = false;
|
|
21134
21223
|
const wakeups = /* @__PURE__ */ new Map();
|
|
21135
21224
|
let wakeupSeq = 0;
|
|
21136
21225
|
let wakeupExpiryTimer = null;
|
|
@@ -21162,12 +21251,20 @@ function createSessionBackgroundTracking({ detectBackgroundAgents, agentTtlMs, s
|
|
|
21162
21251
|
function awaitingBackgroundTasks() {
|
|
21163
21252
|
return detectBackgroundAgents && gateHeldReady !== null && port.state() === "RUNNING" && tasks.isOnlyBackgroundTasks();
|
|
21164
21253
|
}
|
|
21254
|
+
function hasBackgroundWork() {
|
|
21255
|
+
if (activeAgentCount() > 0) return true;
|
|
21256
|
+
if (detectBackgroundAgents && tasks.hasLiveMonitor()) return true;
|
|
21257
|
+
return pendingWakeup() !== null;
|
|
21258
|
+
}
|
|
21165
21259
|
function publishAgentsChange() {
|
|
21260
|
+
if (port.isDestroyed()) return;
|
|
21166
21261
|
const activeAgents = activeAgentCount();
|
|
21167
21262
|
const awaiting = awaitingBackgroundTasks();
|
|
21168
|
-
|
|
21263
|
+
const backgroundWork = hasBackgroundWork();
|
|
21264
|
+
if (activeAgents === publishedActiveAgents && awaiting === publishedAwaitingBackgroundTasks && backgroundWork === publishedHasBackgroundWork) return;
|
|
21169
21265
|
publishedActiveAgents = activeAgents;
|
|
21170
21266
|
publishedAwaitingBackgroundTasks = awaiting;
|
|
21267
|
+
publishedHasBackgroundWork = backgroundWork;
|
|
21171
21268
|
port.emit("agents-change", {
|
|
21172
21269
|
activeAgents,
|
|
21173
21270
|
awaitingBackgroundTasks: awaiting
|
|
@@ -21394,6 +21491,7 @@ function createSessionBackgroundTracking({ detectBackgroundAgents, agentTtlMs, s
|
|
|
21394
21491
|
wakeupExpiryTimer.unref();
|
|
21395
21492
|
}
|
|
21396
21493
|
function emitWakeupChange() {
|
|
21494
|
+
if (port.isDestroyed()) return;
|
|
21397
21495
|
port.emit("wakeup-change", { pendingWakeup: pendingWakeup() });
|
|
21398
21496
|
armWakeupExpiryTimer();
|
|
21399
21497
|
}
|
|
@@ -21418,6 +21516,7 @@ function createSessionBackgroundTracking({ detectBackgroundAgents, agentTtlMs, s
|
|
|
21418
21516
|
trackSubagent,
|
|
21419
21517
|
activeAgentCount,
|
|
21420
21518
|
awaitingBackgroundTasks,
|
|
21519
|
+
hasBackgroundWork,
|
|
21421
21520
|
emitAgentsChange,
|
|
21422
21521
|
clearAgents,
|
|
21423
21522
|
stashGateHeldReady,
|
|
@@ -21776,11 +21875,8 @@ var Session = class extends EventEmitter {
|
|
|
21776
21875
|
this._taskTitleSources.customTitle = this.customTitle;
|
|
21777
21876
|
this._updateTaskTitle();
|
|
21778
21877
|
}
|
|
21779
|
-
get
|
|
21780
|
-
return
|
|
21781
|
-
...this._taskTitleSources,
|
|
21782
|
-
pendingPromptTitle: null
|
|
21783
|
-
}).taskTitle;
|
|
21878
|
+
get refinedTaskTitle() {
|
|
21879
|
+
return this._taskTitleSources.refinedTitle ?? null;
|
|
21784
21880
|
}
|
|
21785
21881
|
get persistedTaskTitle() {
|
|
21786
21882
|
return buildPersistedTaskTitle(this._taskTitleSources);
|
|
@@ -22113,6 +22209,9 @@ var Session = class extends EventEmitter {
|
|
|
22113
22209
|
get hookSeen() {
|
|
22114
22210
|
return this._hookSeen;
|
|
22115
22211
|
}
|
|
22212
|
+
get hasBackgroundWork() {
|
|
22213
|
+
return this.backgroundTracking.hasBackgroundWork();
|
|
22214
|
+
}
|
|
22116
22215
|
get agentToken() {
|
|
22117
22216
|
return this._agentToken;
|
|
22118
22217
|
}
|
|
@@ -23276,6 +23375,7 @@ var GuardrailsLaunchOwner = z.object({
|
|
|
23276
23375
|
ownerHost: z.string(),
|
|
23277
23376
|
ownerPidNamespace: z.string().nullable(),
|
|
23278
23377
|
ownsTempDir: z.boolean(),
|
|
23378
|
+
keptTempFolderName: z.string().min(1).optional(),
|
|
23279
23379
|
logins: z.array(GuardrailsLaunchLogin),
|
|
23280
23380
|
placeholderPaths: z.array(z.string().min(1))
|
|
23281
23381
|
}).strict();
|
|
@@ -23387,11 +23487,45 @@ function bridgeSocketLauncherEnv(inheritedTempDirectory, platform) {
|
|
|
23387
23487
|
return { TMPDIR: SHORT_BRIDGE_SOCKET_FOLDER };
|
|
23388
23488
|
}
|
|
23389
23489
|
//#endregion
|
|
23490
|
+
//#region server/prune-files.ts
|
|
23491
|
+
var MS_PER_DAY = 864e5;
|
|
23492
|
+
function idForEntry(entry, suffixes) {
|
|
23493
|
+
for (const suffix of suffixes) {
|
|
23494
|
+
if (suffix.length === 0) return entry;
|
|
23495
|
+
if (entry.endsWith(suffix)) return entry.slice(0, -suffix.length);
|
|
23496
|
+
}
|
|
23497
|
+
return null;
|
|
23498
|
+
}
|
|
23499
|
+
async function pruneAgedFiles({ directory, suffixes, retainDays, now = Date.now(), isRetainedId = () => false, entryMode = "file", fsPromises = fs.promises }) {
|
|
23500
|
+
let entries;
|
|
23501
|
+
try {
|
|
23502
|
+
entries = await fsPromises.readdir(directory);
|
|
23503
|
+
} catch {
|
|
23504
|
+
return [];
|
|
23505
|
+
}
|
|
23506
|
+
const cutoff = now - retainDays * MS_PER_DAY;
|
|
23507
|
+
const removedIds = [];
|
|
23508
|
+
for (const entry of entries) {
|
|
23509
|
+
const id = idForEntry(entry, suffixes);
|
|
23510
|
+
if (!id || isRetainedId(id)) continue;
|
|
23511
|
+
const filePath = path.join(directory, entry);
|
|
23512
|
+
try {
|
|
23513
|
+
if ((await fsPromises.stat(filePath)).mtimeMs >= cutoff) continue;
|
|
23514
|
+
if (entryMode === "directory") await fsPromises.rm(filePath, {
|
|
23515
|
+
recursive: true,
|
|
23516
|
+
force: true
|
|
23517
|
+
});
|
|
23518
|
+
if (entryMode === "file") await fsPromises.unlink(filePath);
|
|
23519
|
+
removedIds.push(id);
|
|
23520
|
+
} catch {}
|
|
23521
|
+
}
|
|
23522
|
+
return removedIds;
|
|
23523
|
+
}
|
|
23524
|
+
//#endregion
|
|
23390
23525
|
//#region server/guardrails/guardrails-launch.ts
|
|
23391
23526
|
var LAUNCH_ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
23392
23527
|
var GUARDED_ENV_COMMAND = "/usr/bin/env";
|
|
23393
23528
|
var POLICY_FOLDER = "guardrails-policies";
|
|
23394
|
-
var TEMP_FOLDER = "guardrails-temp";
|
|
23395
23529
|
var LAUNCH_HOME_FOLDER = "guardrails-homes";
|
|
23396
23530
|
var START_FOLDER = "start";
|
|
23397
23531
|
var OWNER_FILE_SUFFIX = ".owner.json";
|
|
@@ -23399,6 +23533,7 @@ var ENTER_FOLDER_SCRIPT = "cd \"$1\" && shift && exec \"$@\"";
|
|
|
23399
23533
|
var LOGIN_FILE_MODE = 384;
|
|
23400
23534
|
var ABSENT_PATH_DENY_PLATFORM = "darwin";
|
|
23401
23535
|
var OWN_PID_NAMESPACE_LINK = "/proc/self/ns/pid";
|
|
23536
|
+
var SESSION_TEMP_RETAIN_DAYS = 7;
|
|
23402
23537
|
async function isPresent(candidate) {
|
|
23403
23538
|
try {
|
|
23404
23539
|
await access(candidate);
|
|
@@ -23597,7 +23732,7 @@ async function sweepOrphanedGuardrailsLaunches(log = console) {
|
|
|
23597
23732
|
policyPath: path.join(policyDir, `${launchId}.json`),
|
|
23598
23733
|
ownerPath,
|
|
23599
23734
|
launchHomeDir: path.join(glimmervoidHome, LAUNCH_HOME_FOLDER, launchId),
|
|
23600
|
-
ownedTempDir: owner.ownsTempDir ? path.join(glimmervoidHome,
|
|
23735
|
+
ownedTempDir: owner.ownsTempDir ? path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER, launchId) : null
|
|
23601
23736
|
}, owner, launchId, { onlyNewerLogins: true });
|
|
23602
23737
|
removedLaunchCount += 1;
|
|
23603
23738
|
} catch (error) {
|
|
@@ -23609,6 +23744,24 @@ async function sweepOrphanedGuardrailsLaunches(log = console) {
|
|
|
23609
23744
|
log.warn(`[guardrails] could not sweep leftover launch folders: ${errorMessage(error)}`);
|
|
23610
23745
|
}
|
|
23611
23746
|
}
|
|
23747
|
+
async function pruneLeftoverSessionTempFolders(glimmervoidHome, liveSessionIds, log = console) {
|
|
23748
|
+
const policyEntryNames = await readdir(path.join(glimmervoidHome, POLICY_FOLDER)).catch((error) => {
|
|
23749
|
+
if (isMissingFileError(error)) return [];
|
|
23750
|
+
log.warn(`[guardrails] kept every session temp folder because the launch list could not be read: ${errorMessage(error)}`);
|
|
23751
|
+
return null;
|
|
23752
|
+
});
|
|
23753
|
+
if (policyEntryNames === null) return;
|
|
23754
|
+
const ownerEntryNames = policyEntryNames.filter((entryName) => entryName.endsWith(OWNER_FILE_SUFFIX));
|
|
23755
|
+
const owners = await Promise.all(ownerEntryNames.map((entryName) => readOwnerFile(path.join(glimmervoidHome, POLICY_FOLDER, entryName))));
|
|
23756
|
+
const tempFolderNamesWithOwners = /* @__PURE__ */ new Set([...ownerEntryNames.map((entryName) => entryName.slice(0, -11)), ...owners.flatMap((owner) => owner?.keptTempFolderName === void 0 ? [] : [owner.keptTempFolderName])]);
|
|
23757
|
+
await pruneAgedFiles({
|
|
23758
|
+
directory: path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER),
|
|
23759
|
+
suffixes: [""],
|
|
23760
|
+
retainDays: SESSION_TEMP_RETAIN_DAYS,
|
|
23761
|
+
entryMode: "directory",
|
|
23762
|
+
isRetainedId: (id) => liveSessionIds.has(id) || tempFolderNamesWithOwners.has(id)
|
|
23763
|
+
});
|
|
23764
|
+
}
|
|
23612
23765
|
function launcherCommand(plan, policyPath) {
|
|
23613
23766
|
if (plan.launcher === "open-network") return {
|
|
23614
23767
|
file: process.execPath,
|
|
@@ -23642,11 +23795,19 @@ function enteringFolder(enterDir, file, args) {
|
|
|
23642
23795
|
...args
|
|
23643
23796
|
];
|
|
23644
23797
|
}
|
|
23645
|
-
|
|
23798
|
+
function launchTempDirFor(glimmervoidHome, launchId, tempDir, keptTempFolderName) {
|
|
23799
|
+
if (tempDir !== void 0) return path.resolve(tempDir);
|
|
23800
|
+
return path.join(glimmervoidHome, GUARDRAILS_TEMP_FOLDER, keptTempFolderName ?? launchId);
|
|
23801
|
+
}
|
|
23802
|
+
async function prepareGuardrailsLaunch({ role, launchId, tempDir, keptTempFolderName, enterDir }) {
|
|
23646
23803
|
if (!LAUNCH_ID_SHAPE.test(launchId)) return {
|
|
23647
23804
|
ok: false,
|
|
23648
23805
|
reason: "guardrails launch id is invalid"
|
|
23649
23806
|
};
|
|
23807
|
+
if (keptTempFolderName !== void 0 && !LAUNCH_ID_SHAPE.test(keptTempFolderName)) return {
|
|
23808
|
+
ok: false,
|
|
23809
|
+
reason: "guardrails temp folder name is invalid"
|
|
23810
|
+
};
|
|
23650
23811
|
try {
|
|
23651
23812
|
const policyDir = path.join(glimmervoidHomeDir$1(), POLICY_FOLDER);
|
|
23652
23813
|
await mkdir(policyDir, {
|
|
@@ -23659,8 +23820,8 @@ async function prepareGuardrailsLaunch({ role, launchId, tempDir, enterDir }) {
|
|
|
23659
23820
|
withRealRoots(role),
|
|
23660
23821
|
readOwnPidNamespace()
|
|
23661
23822
|
]);
|
|
23662
|
-
const ownsTempDir = tempDir === void 0;
|
|
23663
|
-
const launchTempDir =
|
|
23823
|
+
const ownsTempDir = tempDir === void 0 && keptTempFolderName === void 0;
|
|
23824
|
+
const launchTempDir = launchTempDirFor(glimmervoidHome, launchId, tempDir, keptTempFolderName);
|
|
23664
23825
|
const launchHomeDir = path.join(glimmervoidHome, LAUNCH_HOME_FOLDER, launchId);
|
|
23665
23826
|
const vendorLocations = await resolveVendorLocations(process.env, homeDir);
|
|
23666
23827
|
if (vendorLocations === null) return {
|
|
@@ -23717,6 +23878,7 @@ async function prepareGuardrailsLaunch({ role, launchId, tempDir, enterDir }) {
|
|
|
23717
23878
|
ownerHost: os.hostname(),
|
|
23718
23879
|
ownerPidNamespace,
|
|
23719
23880
|
ownsTempDir,
|
|
23881
|
+
...keptTempFolderName === void 0 ? {} : { keptTempFolderName },
|
|
23720
23882
|
logins: plan.launchHomeLinks.filter((link) => link.isLogin).map(({ linkPath, targetPath }) => ({
|
|
23721
23883
|
linkPath,
|
|
23722
23884
|
targetPath
|
|
@@ -28743,41 +28905,6 @@ async function commitAndLandFactoryLedger({ projectPath, ledger, targetBranch, m
|
|
|
28743
28905
|
}
|
|
28744
28906
|
}
|
|
28745
28907
|
//#endregion
|
|
28746
|
-
//#region server/prune-files.ts
|
|
28747
|
-
var MS_PER_DAY = 864e5;
|
|
28748
|
-
function idForEntry(entry, suffixes) {
|
|
28749
|
-
for (const suffix of suffixes) {
|
|
28750
|
-
if (suffix.length === 0) return entry;
|
|
28751
|
-
if (entry.endsWith(suffix)) return entry.slice(0, -suffix.length);
|
|
28752
|
-
}
|
|
28753
|
-
return null;
|
|
28754
|
-
}
|
|
28755
|
-
async function pruneAgedFiles({ directory, suffixes, retainDays, now = Date.now(), isRetainedId = () => false, entryMode = "file", fsPromises = fs.promises }) {
|
|
28756
|
-
let entries;
|
|
28757
|
-
try {
|
|
28758
|
-
entries = await fsPromises.readdir(directory);
|
|
28759
|
-
} catch {
|
|
28760
|
-
return [];
|
|
28761
|
-
}
|
|
28762
|
-
const cutoff = now - retainDays * MS_PER_DAY;
|
|
28763
|
-
const removedIds = [];
|
|
28764
|
-
for (const entry of entries) {
|
|
28765
|
-
const id = idForEntry(entry, suffixes);
|
|
28766
|
-
if (!id || isRetainedId(id)) continue;
|
|
28767
|
-
const filePath = path.join(directory, entry);
|
|
28768
|
-
try {
|
|
28769
|
-
if ((await fsPromises.stat(filePath)).mtimeMs >= cutoff) continue;
|
|
28770
|
-
if (entryMode === "directory") await fsPromises.rm(filePath, {
|
|
28771
|
-
recursive: true,
|
|
28772
|
-
force: true
|
|
28773
|
-
});
|
|
28774
|
-
if (entryMode === "file") await fsPromises.unlink(filePath);
|
|
28775
|
-
removedIds.push(id);
|
|
28776
|
-
} catch {}
|
|
28777
|
-
}
|
|
28778
|
-
return removedIds;
|
|
28779
|
-
}
|
|
28780
|
-
//#endregion
|
|
28781
28908
|
//#region server/factory/factory-decision-log.ts
|
|
28782
28909
|
function createFactoryDecisionLog({ homeDir = glimmervoidHomeDir$1(), now = Date.now, log = console, redact = (text) => text, onDecision } = {}) {
|
|
28783
28910
|
const prunedDayByProject = /* @__PURE__ */ new Map();
|
|
@@ -36925,7 +37052,7 @@ function createTaskTitleRefiner({ getConfig, spawnLane, nowFn = () => Date.now()
|
|
|
36925
37052
|
const request = {
|
|
36926
37053
|
session,
|
|
36927
37054
|
revision: session.taskTitlePromptRevision,
|
|
36928
|
-
currentTitle: session.
|
|
37055
|
+
currentTitle: session.refinedTaskTitle,
|
|
36929
37056
|
recentPrompts: session.recentTaskPrompts
|
|
36930
37057
|
};
|
|
36931
37058
|
queuedBySession.set(session, request);
|
|
@@ -47102,6 +47229,7 @@ function createUploadsWiring({ configPath, liveSessionIds, setIntervalFn = DEFAU
|
|
|
47102
47229
|
isRetainedId: (id) => retainedSessionIds.has(id),
|
|
47103
47230
|
fsPromises: fs.promises
|
|
47104
47231
|
});
|
|
47232
|
+
await pruneLeftoverSessionTempFolders(path.dirname(uploadsRoot), retainedSessionIds);
|
|
47105
47233
|
}
|
|
47106
47234
|
async function start() {
|
|
47107
47235
|
if (timer) return;
|
|
@@ -52032,7 +52160,7 @@ function parseSinceParam(url) {
|
|
|
52032
52160
|
return Number.isFinite(n) ? n : null;
|
|
52033
52161
|
}
|
|
52034
52162
|
function registerControlHandlers(controlWss, deps) {
|
|
52035
|
-
const { sessions, agentSessions = /* @__PURE__ */ new Map(), config, configStore, broadcastControl, generateProjectId, applyConfigReload, applySettingsReload, requestShutdown, requestRestart, handleClientFocus, buildHealthSnapshot, getUpdateStatus, getUpdateJournal = null, getPostTurnLeftoversNotice = null, recheckPostTurnLeftovers = null, checkNow = null, applyUpdate = null,
|
|
52163
|
+
const { sessions, agentSessions = /* @__PURE__ */ new Map(), config, configStore, broadcastControl, generateProjectId, applyConfigReload, applySettingsReload, requestShutdown, requestRestart, handleClientFocus, buildHealthSnapshot, getUpdateStatus, getUpdateJournal = null, getPostTurnLeftoversNotice = null, recheckPostTurnLeftovers = null, checkNow = null, applyUpdate = null, noteRestartRequested = null, getRadarStatus, posthogReportsDir = null, posthogSetIssueStatus = null, radarArchiveInvestigation = null, getTeamReviewStatus = null, getMyPrsStatus = null, getIssuesStatus = null, issues = null, teamReview = null, myPrs = null, getBenchmarkStatus = null, getFactoryState = null, benchmarks = null, factory = null, createGithubClient = createPrGh, issueProjectRepos = null, serverBuild = () => null, getUsageSessions = null, getUsageReport = null, requestUsageReport = null, getPlanLimits = null, controlReplayLog = null, getRtkInstallStatus = () => null, resolveRtkPath = () => getRtkPath(), conversationFs = fs, conversationGit = runGitForConversationHistory, conversationProjectsDir = claudeProjectsDir(process.env, os.homedir()), readTracePage = null, readPlanRevision = null, decidePlanReview = null, sessionDocs = null, changeMapNarrator = null } = deps;
|
|
52036
52164
|
const changeMaps = createChangeMapService({
|
|
52037
52165
|
sessions,
|
|
52038
52166
|
narrator: changeMapNarrator,
|
|
@@ -53256,29 +53384,16 @@ function registerControlHandlers(controlWss, deps) {
|
|
|
53256
53384
|
}
|
|
53257
53385
|
await checkNow();
|
|
53258
53386
|
}
|
|
53259
|
-
async function handleUpdateApply(
|
|
53387
|
+
async function handleUpdateApply(_msg, ws) {
|
|
53260
53388
|
if (!applyUpdate) {
|
|
53261
53389
|
sendError(ws, "[update-apply-unavailable] Update application is unavailable.");
|
|
53262
53390
|
return;
|
|
53263
53391
|
}
|
|
53264
53392
|
const outcome = await applyUpdate();
|
|
53265
|
-
if (
|
|
53266
|
-
|
|
53267
|
-
return;
|
|
53268
|
-
}
|
|
53269
|
-
if (msg.restartWhenStaged !== true) return;
|
|
53270
|
-
const confirmedSessionIds = new Set(msg.confirmedSessionIds ?? []);
|
|
53271
|
-
if ([...sessions.keys(), ...agentSessions.keys()].some((liveSessionId) => !confirmedSessionIds.has(liveSessionId))) {
|
|
53272
|
-
sendError(ws, "[update-restart-skipped] The update is staged, but sessions started since you confirmed. Restart when ready.");
|
|
53273
|
-
return;
|
|
53274
|
-
}
|
|
53275
|
-
handleRestart(msg, ws);
|
|
53393
|
+
if (outcome.ok) return;
|
|
53394
|
+
sendError(ws, `[${outcome.reason || "update-refused"}] ${outcome.message}`);
|
|
53276
53395
|
}
|
|
53277
|
-
function handleRestart(_msg
|
|
53278
|
-
if (isStaging?.()) {
|
|
53279
|
-
sendError(ws, "[update-staging] Wait for the update staging run to finish before restarting.");
|
|
53280
|
-
return;
|
|
53281
|
-
}
|
|
53396
|
+
function handleRestart(_msg) {
|
|
53282
53397
|
noteRestartRequested?.();
|
|
53283
53398
|
console.log("[control] Restart requested via UI");
|
|
53284
53399
|
broadcastControl({ type: "restarting" });
|
|
@@ -53739,7 +53854,6 @@ function createBackendControl(dependencies) {
|
|
|
53739
53854
|
recheckPostTurnLeftovers: dependencies.recheckPostTurnLeftovers,
|
|
53740
53855
|
checkNow: dependencies.checkNow,
|
|
53741
53856
|
applyUpdate: dependencies.applyUpdate,
|
|
53742
|
-
isStaging: dependencies.isStaging,
|
|
53743
53857
|
noteRestartRequested: dependencies.noteRestartRequested,
|
|
53744
53858
|
getRadarStatus: () => posthog.getStatus(),
|
|
53745
53859
|
posthogSetIssueStatus: (args) => posthog.setIssueStatus(args),
|
|
@@ -53791,6 +53905,7 @@ var PREVIOUS_DEPENDENCIES_BACKUP_NAME = "prev-node_modules";
|
|
|
53791
53905
|
var QUARANTINED_DIST_NAME = "broken-dist";
|
|
53792
53906
|
var QUARANTINED_DEPENDENCIES_NAME = "broken-node_modules";
|
|
53793
53907
|
var SUPPORTED_UPDATE_REMOTE = "origin";
|
|
53908
|
+
var LOWEST_SCHEDULING_PRIORITY = "19";
|
|
53794
53909
|
var TRANSITIONS_ALLOWED_BY_STATE = Object.freeze({
|
|
53795
53910
|
idle: Object.freeze(["begin-run"]),
|
|
53796
53911
|
running: Object.freeze([
|
|
@@ -53952,6 +54067,21 @@ function planSteps({ lockfileChanged }) {
|
|
|
53952
54067
|
"build"
|
|
53953
54068
|
];
|
|
53954
54069
|
}
|
|
54070
|
+
function lowPriorityCommand({ file, args, platform }) {
|
|
54071
|
+
if (platform === "win32") return {
|
|
54072
|
+
file,
|
|
54073
|
+
args
|
|
54074
|
+
};
|
|
54075
|
+
return {
|
|
54076
|
+
file: "nice",
|
|
54077
|
+
args: [
|
|
54078
|
+
"-n",
|
|
54079
|
+
LOWEST_SCHEDULING_PRIORITY,
|
|
54080
|
+
file,
|
|
54081
|
+
...args
|
|
54082
|
+
]
|
|
54083
|
+
};
|
|
54084
|
+
}
|
|
53955
54085
|
function planHandOffRenames({ root, stagingPath, lockfileChanged }) {
|
|
53956
54086
|
const updatePath = `${root}/.glimmervoid/update`;
|
|
53957
54087
|
const renames = [{
|
|
@@ -54478,6 +54608,7 @@ function createBackendUpdateCheck(dependencies) {
|
|
|
54478
54608
|
let inFlight = null;
|
|
54479
54609
|
let lastChannel = normalizeUpdateChannel(dependencies.config.updateChannel);
|
|
54480
54610
|
let lastSurfacedIdentity = null;
|
|
54611
|
+
let lastDownloadedIdentity = null;
|
|
54481
54612
|
let pendingChannelRefresh = false;
|
|
54482
54613
|
let stopped = false;
|
|
54483
54614
|
const now = dependencies.now || (() => Date.now());
|
|
@@ -54581,6 +54712,26 @@ function createBackendUpdateCheck(dependencies) {
|
|
|
54581
54712
|
const latestRelease = status.latest || shortSha(status.latestSha) || "unknown";
|
|
54582
54713
|
dependencies.logger.log(`[update] A newer glimmervoid is available: ${currentRelease} -> ${latestRelease}. Update: ${status.command}`);
|
|
54583
54714
|
}
|
|
54715
|
+
function downloadInBackground(status) {
|
|
54716
|
+
const downloadUpdate = dependencies.downloadUpdate;
|
|
54717
|
+
if (!downloadUpdate || dependencies.config.checkForUpdates === false) return;
|
|
54718
|
+
if (!status.updateAvailable || status.applyRefusal) return;
|
|
54719
|
+
const identity = status.latestSha || status.latest;
|
|
54720
|
+
if (!identity || identity === lastDownloadedIdentity) return;
|
|
54721
|
+
lastDownloadedIdentity = identity;
|
|
54722
|
+
dependencies.logger.log(`[update] downloading ${status.latest || shortSha(status.latestSha)} in the background`);
|
|
54723
|
+
const allowRetryAtNextCheck = () => {
|
|
54724
|
+
if (lastDownloadedIdentity === identity) lastDownloadedIdentity = null;
|
|
54725
|
+
};
|
|
54726
|
+
downloadUpdate().then((outcome) => {
|
|
54727
|
+
if (outcome.ok) return;
|
|
54728
|
+
allowRetryAtNextCheck();
|
|
54729
|
+
dependencies.logger.log(`[update] background download stopped: ${outcome.message}`);
|
|
54730
|
+
}, (error) => {
|
|
54731
|
+
allowRetryAtNextCheck();
|
|
54732
|
+
dependencies.logger.log(`[update] background download failed: ${String(error)}`);
|
|
54733
|
+
});
|
|
54734
|
+
}
|
|
54584
54735
|
function runCheck(ttlMs) {
|
|
54585
54736
|
if (inFlight) return inFlight;
|
|
54586
54737
|
const channel = normalizeUpdateChannel(dependencies.config.updateChannel);
|
|
@@ -54599,6 +54750,7 @@ function createBackendUpdateCheck(dependencies) {
|
|
|
54599
54750
|
});
|
|
54600
54751
|
const status = recordStatus(updateResult, checkedAt, channel);
|
|
54601
54752
|
surfaceAvailableUpdate(status);
|
|
54753
|
+
downloadInBackground(status);
|
|
54602
54754
|
return status;
|
|
54603
54755
|
}).finally(() => {
|
|
54604
54756
|
inFlight = null;
|
|
@@ -54621,6 +54773,7 @@ function createBackendUpdateCheck(dependencies) {
|
|
|
54621
54773
|
recordedStatus = null;
|
|
54622
54774
|
lastLaneSignature = null;
|
|
54623
54775
|
lastSurfacedIdentity = null;
|
|
54776
|
+
lastDownloadedIdentity = null;
|
|
54624
54777
|
updateAbort?.abort();
|
|
54625
54778
|
return true;
|
|
54626
54779
|
}
|
|
@@ -55054,6 +55207,7 @@ function createSessionGuardrails({ getSettings, uploadsRoot, guardrailsRefusal =
|
|
|
55054
55207
|
const prepared = await prepareGuardrails({
|
|
55055
55208
|
role,
|
|
55056
55209
|
launchId: facts.launchId,
|
|
55210
|
+
keptTempFolderName: request.sessionId,
|
|
55057
55211
|
enterDir: cwd
|
|
55058
55212
|
});
|
|
55059
55213
|
if (!prepared.ok) return {
|
|
@@ -55374,7 +55528,12 @@ function createUpdateApplyLane(dependencies) {
|
|
|
55374
55528
|
stepId,
|
|
55375
55529
|
now: clock()
|
|
55376
55530
|
}));
|
|
55377
|
-
const
|
|
55531
|
+
const throttled = lowPriorityCommand({
|
|
55532
|
+
file,
|
|
55533
|
+
args,
|
|
55534
|
+
platform: dependencies.platform || process.platform
|
|
55535
|
+
});
|
|
55536
|
+
const outcome = await command(throttled.file, throttled.args, cwd, timeout);
|
|
55378
55537
|
journal = appendStepOutput(journal, stepId, outcome.output);
|
|
55379
55538
|
if (!outcome.ok) throw new Error(outcome.reason || `${stepId} failed`);
|
|
55380
55539
|
await publish(finishStep(journal, {
|
|
@@ -55669,9 +55828,6 @@ function createUpdateApplyLane(dependencies) {
|
|
|
55669
55828
|
activeRun = run;
|
|
55670
55829
|
await run;
|
|
55671
55830
|
}
|
|
55672
|
-
function isStaging() {
|
|
55673
|
-
return inFlight;
|
|
55674
|
-
}
|
|
55675
55831
|
function isRestartRequested() {
|
|
55676
55832
|
return restartRequested;
|
|
55677
55833
|
}
|
|
@@ -55778,7 +55934,6 @@ function createUpdateApplyLane(dependencies) {
|
|
|
55778
55934
|
getJournal,
|
|
55779
55935
|
handOffStagedUpdate,
|
|
55780
55936
|
isRestartRequested,
|
|
55781
|
-
isStaging,
|
|
55782
55937
|
noteRestartRequested,
|
|
55783
55938
|
startAfterListening,
|
|
55784
55939
|
stop,
|
|
@@ -56780,6 +56935,12 @@ function createBackend(httpServer, options = {}) {
|
|
|
56780
56935
|
visionsSetup.maybeApply();
|
|
56781
56936
|
laneAssembly.restartDynamicLanes();
|
|
56782
56937
|
}
|
|
56938
|
+
function downloadUpdateOnceListening() {
|
|
56939
|
+
if (httpServer.listening) return updateApply.applyUpdate();
|
|
56940
|
+
return new Promise((resolve) => {
|
|
56941
|
+
httpServer.once("listening", resolve);
|
|
56942
|
+
}).then(() => updateApply.applyUpdate());
|
|
56943
|
+
}
|
|
56783
56944
|
const updateCheck = createBackendUpdateCheck({
|
|
56784
56945
|
config,
|
|
56785
56946
|
currentVersion: packageJson.version,
|
|
@@ -56790,7 +56951,8 @@ function createBackend(httpServer, options = {}) {
|
|
|
56790
56951
|
isRestartRequested: () => updateApply.isRestartRequested(),
|
|
56791
56952
|
getControlClientCount: () => controlWss.clients.size,
|
|
56792
56953
|
broadcastControl,
|
|
56793
|
-
logger: console
|
|
56954
|
+
logger: console,
|
|
56955
|
+
...options.downloadUpdatesInBackground ? { downloadUpdate: downloadUpdateOnceListening } : {}
|
|
56794
56956
|
});
|
|
56795
56957
|
const updateApply = createUpdateApplyLane({
|
|
56796
56958
|
gitWorkspace: assembledGitWorkspace,
|
|
@@ -56913,7 +57075,6 @@ function createBackend(httpServer, options = {}) {
|
|
|
56913
57075
|
recheckPostTurnLeftovers,
|
|
56914
57076
|
checkNow: updateCheck.checkNow,
|
|
56915
57077
|
applyUpdate: updateApply.applyUpdate,
|
|
56916
|
-
isStaging: updateApply.isStaging,
|
|
56917
57078
|
noteRestartRequested: () => {
|
|
56918
57079
|
updateApply.noteRestartRequested();
|
|
56919
57080
|
updateCheck.refreshApplyAvailability();
|
|
@@ -56953,6 +57114,7 @@ function createBackend(httpServer, options = {}) {
|
|
|
56953
57114
|
updateCheck.start();
|
|
56954
57115
|
return {
|
|
56955
57116
|
shutdown,
|
|
57117
|
+
handOffStagedUpdate: updateApply.handOffStagedUpdate,
|
|
56956
57118
|
port,
|
|
56957
57119
|
app,
|
|
56958
57120
|
telemetry,
|
|
@@ -57002,7 +57164,10 @@ function isBootRefusal(error) {
|
|
|
57002
57164
|
}
|
|
57003
57165
|
function createBackendOrExit() {
|
|
57004
57166
|
try {
|
|
57005
|
-
return createBackend(server, {
|
|
57167
|
+
return createBackend(server, {
|
|
57168
|
+
staticDir: "auto",
|
|
57169
|
+
downloadUpdatesInBackground: true
|
|
57170
|
+
});
|
|
57006
57171
|
} catch (err) {
|
|
57007
57172
|
if (!isBootRefusal(err)) throw err;
|
|
57008
57173
|
console.error(err.message);
|
|
@@ -57010,7 +57175,7 @@ function createBackendOrExit() {
|
|
|
57010
57175
|
}
|
|
57011
57176
|
}
|
|
57012
57177
|
var backend = createBackendOrExit();
|
|
57013
|
-
var { shutdown, port, app, telemetry, version } = backend;
|
|
57178
|
+
var { shutdown, handOffStagedUpdate, port, app, telemetry, version } = backend;
|
|
57014
57179
|
server.on("request", app);
|
|
57015
57180
|
function writeTerminalTitle(sequence) {
|
|
57016
57181
|
if (!process.stdout.isTTY) return;
|
|
@@ -57091,7 +57256,8 @@ var { requestShutdown } = createLifecycle({
|
|
|
57091
57256
|
httpServer: server,
|
|
57092
57257
|
extraServers: remoteServers,
|
|
57093
57258
|
spawn,
|
|
57094
|
-
exit: exitWithClearedTerminalTitle
|
|
57259
|
+
exit: exitWithClearedTerminalTitle,
|
|
57260
|
+
beforeHandOff: handOffStagedUpdate
|
|
57095
57261
|
});
|
|
57096
57262
|
function handleShutdownSignal(signal) {
|
|
57097
57263
|
console.log(`\n${signal} received - shutting down...`);
|