@parall/daemon 1.42.1 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -122,63 +122,6 @@ var init_lane_key = __esm({
122
122
  }
123
123
  });
124
124
 
125
- // ts/agent-core/dist/session-state.js
126
- var init_session_state = __esm({
127
- "ts/agent-core/dist/session-state.js"() {
128
- "use strict";
129
- }
130
- });
131
-
132
- // ts/agent-core/dist/routing.js
133
- var init_routing = __esm({
134
- "ts/agent-core/dist/routing.js"() {
135
- "use strict";
136
- }
137
- });
138
-
139
- // ts/agent-core/dist/event-format.js
140
- var init_event_format = __esm({
141
- "ts/agent-core/dist/event-format.js"() {
142
- "use strict";
143
- }
144
- });
145
-
146
- // ts/agent-core/dist/prompt-fragments.js
147
- var init_prompt_fragments = __esm({
148
- "ts/agent-core/dist/prompt-fragments.js"() {
149
- "use strict";
150
- }
151
- });
152
-
153
- // ts/agent-core/dist/bridge-workspace.js
154
- var init_bridge_workspace = __esm({
155
- "ts/agent-core/dist/bridge-workspace.js"() {
156
- "use strict";
157
- }
158
- });
159
-
160
- // ts/agent-core/dist/dispatch-adapter.js
161
- var init_dispatch_adapter = __esm({
162
- "ts/agent-core/dist/dispatch-adapter.js"() {
163
- "use strict";
164
- }
165
- });
166
-
167
- // ts/agent-core/dist/logger.js
168
- function createLogger(prefix) {
169
- return {
170
- info: (msg) => console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
171
- warn: (msg) => console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
172
- error: (msg) => console.error(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
173
- child: (sub) => createLogger(`${prefix}:${sub}`)
174
- };
175
- }
176
- var init_logger = __esm({
177
- "ts/agent-core/dist/logger.js"() {
178
- "use strict";
179
- }
180
- });
181
-
182
125
  // ts/sdk/dist/types.js
183
126
  var init_types2 = __esm({
184
127
  "ts/sdk/dist/types.js"() {
@@ -672,6 +615,7 @@ var init_client = __esm({
672
615
  setTokens;
673
616
  refreshPromise = null;
674
617
  swimlaneName;
618
+ getFeatureFlagOverrides;
675
619
  /** Auth endpoints excluded from automatic 401 refresh to prevent recursion. */
676
620
  static AUTH_PATHS = /* @__PURE__ */ new Set([
677
621
  "/auth/login",
@@ -702,7 +646,7 @@ var init_client = __esm({
702
646
  return apiError;
703
647
  }
704
648
  /** Build headers common to all requests (auth, swimlane). */
705
- buildHeaders(extra) {
649
+ buildHeaders(path19, extra) {
706
650
  const headers = {
707
651
  "Content-Type": "application/json",
708
652
  ...extra
@@ -713,6 +657,11 @@ var init_client = __esm({
713
657
  if (this.swimlaneName) {
714
658
  headers["X-Prll-Swimlane"] = this.swimlaneName;
715
659
  }
660
+ if (path19.startsWith(API_BASE)) {
661
+ const overrides = this.getFeatureFlagOverrides?.();
662
+ if (overrides)
663
+ headers["X-Prll-FF-Override"] = overrides;
664
+ }
716
665
  return headers;
717
666
  }
718
667
  constructor(options = {}) {
@@ -723,6 +672,7 @@ var init_client = __esm({
723
672
  this.getRefreshToken = options.getRefreshToken;
724
673
  this.setTokens = options.setTokens;
725
674
  this.swimlaneName = options.swimlaneName;
675
+ this.getFeatureFlagOverrides = options.getFeatureFlagOverrides;
726
676
  }
727
677
  /**
728
678
  * Pick the origin for a request path: wiki-service base for `/wiki/v1`
@@ -730,8 +680,8 @@ var init_client = __esm({
730
680
  * is authoritative, so wiki vs api routing can't drift from how a caller
731
681
  * happens to invoke the client.
732
682
  */
733
- baseUrlFor(path18) {
734
- return path18.startsWith(WIKI_BASE) ? this.wikiBaseUrl : this.baseUrl;
683
+ baseUrlFor(path19) {
684
+ return path19.startsWith(WIKI_BASE) ? this.wikiBaseUrl : this.baseUrl;
735
685
  }
736
686
  setToken(token) {
737
687
  this.token = token;
@@ -758,10 +708,10 @@ var init_client = __esm({
758
708
  * REFRESH_THRESHOLD_S, refresh it **before** sending the request.
759
709
  * No-op when the token is still fresh, missing, or un-parseable.
760
710
  */
761
- async ensureFreshToken(path18) {
711
+ async ensureFreshToken(path19) {
762
712
  if (!this.token || !this.getRefreshToken)
763
713
  return;
764
- const pathSuffix = path18.replace(/^\/api\/v1/, "");
714
+ const pathSuffix = path19.replace(/^\/api\/v1/, "");
765
715
  if (_ParallClient.AUTH_PATHS.has(pathSuffix))
766
716
  return;
767
717
  const exp = _ParallClient.decodeJwtExp(this.token);
@@ -793,11 +743,11 @@ var init_client = __esm({
793
743
  this.refreshPromise = null;
794
744
  }
795
745
  }
796
- async request(method, path18, body, query, retried = false, opts) {
746
+ async request(method, path19, body, query, retried = false, opts) {
797
747
  if (!retried) {
798
- await this.ensureFreshToken(path18);
748
+ await this.ensureFreshToken(path19);
799
749
  }
800
- let url = `${this.baseUrlFor(path18)}${path18}`;
750
+ let url = `${this.baseUrlFor(path19)}${path19}`;
801
751
  if (query) {
802
752
  const params = new URLSearchParams();
803
753
  for (const [key, value] of Object.entries(query)) {
@@ -809,7 +759,7 @@ var init_client = __esm({
809
759
  if (qs)
810
760
  url += `?${qs}`;
811
761
  }
812
- const headers = this.buildHeaders();
762
+ const headers = this.buildHeaders(path19);
813
763
  const timeoutSignal = AbortSignal.timeout(opts?.timeoutMs ?? 15e3);
814
764
  const signal = opts?.signal ? AbortSignal.any([opts.signal, timeoutSignal]) : timeoutSignal;
815
765
  let res;
@@ -827,12 +777,12 @@ var init_client = __esm({
827
777
  throw _ParallClient.normalizeFetchError(err);
828
778
  }
829
779
  if (res.status === 401) {
830
- const pathSuffix = path18.replace(/^\/api\/v1/, "");
780
+ const pathSuffix = path19.replace(/^\/api\/v1/, "");
831
781
  const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
832
782
  if (!retried && !isAuthPath && this.getRefreshToken) {
833
783
  const refreshed = await this.tryRefresh();
834
784
  if (refreshed) {
835
- return this.request(method, path18, body, query, true, opts);
785
+ return this.request(method, path19, body, query, true, opts);
836
786
  }
837
787
  }
838
788
  if (this.onTokenExpired && !isAuthPath) {
@@ -862,15 +812,15 @@ var init_client = __esm({
862
812
  * hit the 100 MiB cap, so a longer 5-minute timeout is used so a
863
813
  * 50 MiB blob on a slow connection doesn't get chopped at 15 s.
864
814
  */
865
- async multipartRequest(method, path18, body, retried = false) {
815
+ async multipartRequest(method, path19, body, retried = false) {
866
816
  if (!retried) {
867
- await this.ensureFreshToken(path18);
817
+ await this.ensureFreshToken(path19);
868
818
  }
869
- const { "Content-Type": _drop, ...headers } = this.buildHeaders();
819
+ const { "Content-Type": _drop, ...headers } = this.buildHeaders(path19);
870
820
  void _drop;
871
821
  let res;
872
822
  try {
873
- res = await fetch(`${this.baseUrlFor(path18)}${path18}`, {
823
+ res = await fetch(`${this.baseUrlFor(path19)}${path19}`, {
874
824
  method,
875
825
  headers,
876
826
  body,
@@ -880,12 +830,12 @@ var init_client = __esm({
880
830
  throw _ParallClient.normalizeFetchError(err);
881
831
  }
882
832
  if (res.status === 401) {
883
- const pathSuffix = path18.replace(/^\/api\/v1/, "");
833
+ const pathSuffix = path19.replace(/^\/api\/v1/, "");
884
834
  const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
885
835
  if (!retried && !isAuthPath && this.getRefreshToken) {
886
836
  const refreshed = await this.tryRefresh();
887
837
  if (refreshed) {
888
- return this.multipartRequest(method, path18, body, true);
838
+ return this.multipartRequest(method, path19, body, true);
889
839
  }
890
840
  }
891
841
  if (this.onTokenExpired && !isAuthPath) {
@@ -1589,8 +1539,8 @@ var init_client = __esm({
1589
1539
  async requestMachineUpdate(orgId, machineId, mandatory = false) {
1590
1540
  await this.request("POST", ENDPOINTS.MACHINE_REQUEST_UPDATE(orgId, machineId), { mandatory });
1591
1541
  }
1592
- async browseMachineFilesystem(orgId, machineId, path18) {
1593
- return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path18 }, void 0, false, { timeoutMs: 15e3 });
1542
+ async browseMachineFilesystem(orgId, machineId, path19) {
1543
+ return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path19 }, void 0, false, { timeoutMs: 15e3 });
1594
1544
  }
1595
1545
  /** Create a new machine key. Returns the raw key string (shown once) + metadata. */
1596
1546
  async createMachineKey(orgId, machineId, name) {
@@ -1711,7 +1661,7 @@ var init_client = __esm({
1711
1661
  if (currentVersion !== void 0) {
1712
1662
  extra["If-None-Match"] = currentVersion;
1713
1663
  }
1714
- const headers = this.buildHeaders(extra);
1664
+ const headers = this.buildHeaders(ENDPOINTS.PLATFORM_CONFIG, extra);
1715
1665
  let res;
1716
1666
  try {
1717
1667
  res = await fetch(url, {
@@ -2159,8 +2109,8 @@ var init_client = __esm({
2159
2109
  async deleteWikiRestriction(orgId, wikiId, restrictionId) {
2160
2110
  await this.request("DELETE", ENDPOINTS.WIKI_RESTRICTION(orgId, wikiId, restrictionId));
2161
2111
  }
2162
- async getWikiAccessStatus(orgId, wikiId, path18) {
2163
- return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path18 ? { path: path18 } : void 0);
2112
+ async getWikiAccessStatus(orgId, wikiId, path19) {
2113
+ return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path19 ? { path: path19 } : void 0);
2164
2114
  }
2165
2115
  async createWikiAccessRequest(orgId, wikiId, data) {
2166
2116
  await this.request("POST", ENDPOINTS.WIKI_ACCESS_REQUESTS(orgId, wikiId), data);
@@ -2169,14 +2119,14 @@ var init_client = __esm({
2169
2119
  async getWikiCommits(orgId, wikiId, params) {
2170
2120
  return this.request("GET", ENDPOINTS.WIKI_COMMITS(orgId, wikiId), void 0, params);
2171
2121
  }
2172
- async getWikiFileCommits(orgId, wikiId, path18, params) {
2122
+ async getWikiFileCommits(orgId, wikiId, path19, params) {
2173
2123
  return this.request("GET", ENDPOINTS.WIKI_FILE_COMMITS(orgId, wikiId), void 0, {
2174
- path: path18,
2124
+ path: path19,
2175
2125
  ...params
2176
2126
  });
2177
2127
  }
2178
- async getWikiBlame(orgId, wikiId, path18, ref) {
2179
- return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path18, ref });
2128
+ async getWikiBlame(orgId, wikiId, path19, ref) {
2129
+ return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path19, ref });
2180
2130
  }
2181
2131
  // ---- Wiki Operations (audit log) ----
2182
2132
  async getWikiOperations(orgId, wikiId, params) {
@@ -2824,10 +2774,69 @@ var init_lane_ledger = __esm({
2824
2774
  });
2825
2775
 
2826
2776
  // ts/agent-core/dist/gateway-lane-flow.js
2777
+ var TYPED_BACKOFF_CAP_MS;
2827
2778
  var init_gateway_lane_flow = __esm({
2828
2779
  "ts/agent-core/dist/gateway-lane-flow.js"() {
2829
2780
  "use strict";
2830
2781
  init_lane_ledger();
2782
+ TYPED_BACKOFF_CAP_MS = 5 * 6e4;
2783
+ }
2784
+ });
2785
+
2786
+ // ts/agent-core/dist/session-state.js
2787
+ var init_session_state = __esm({
2788
+ "ts/agent-core/dist/session-state.js"() {
2789
+ "use strict";
2790
+ }
2791
+ });
2792
+
2793
+ // ts/agent-core/dist/routing.js
2794
+ var init_routing = __esm({
2795
+ "ts/agent-core/dist/routing.js"() {
2796
+ "use strict";
2797
+ }
2798
+ });
2799
+
2800
+ // ts/agent-core/dist/event-format.js
2801
+ var init_event_format = __esm({
2802
+ "ts/agent-core/dist/event-format.js"() {
2803
+ "use strict";
2804
+ }
2805
+ });
2806
+
2807
+ // ts/agent-core/dist/prompt-fragments.js
2808
+ var init_prompt_fragments = __esm({
2809
+ "ts/agent-core/dist/prompt-fragments.js"() {
2810
+ "use strict";
2811
+ }
2812
+ });
2813
+
2814
+ // ts/agent-core/dist/bridge-workspace.js
2815
+ var init_bridge_workspace = __esm({
2816
+ "ts/agent-core/dist/bridge-workspace.js"() {
2817
+ "use strict";
2818
+ }
2819
+ });
2820
+
2821
+ // ts/agent-core/dist/dispatch-adapter.js
2822
+ var init_dispatch_adapter = __esm({
2823
+ "ts/agent-core/dist/dispatch-adapter.js"() {
2824
+ "use strict";
2825
+ }
2826
+ });
2827
+
2828
+ // ts/agent-core/dist/logger.js
2829
+ function createLogger(prefix) {
2830
+ return {
2831
+ info: (msg) => console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
2832
+ warn: (msg) => console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
2833
+ error: (msg) => console.error(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
2834
+ child: (sub) => createLogger(`${prefix}:${sub}`)
2835
+ };
2836
+ }
2837
+ var init_logger = __esm({
2838
+ "ts/agent-core/dist/logger.js"() {
2839
+ "use strict";
2831
2840
  }
2832
2841
  });
2833
2842
 
@@ -20510,9 +20519,9 @@ var require_getMachineId_linux = __commonJS({
20510
20519
  var api_1 = (init_esm(), __toCommonJS(esm_exports));
20511
20520
  async function getMachineId() {
20512
20521
  const paths = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
20513
- for (const path18 of paths) {
20522
+ for (const path19 of paths) {
20514
20523
  try {
20515
- const result = await fs_1.promises.readFile(path18, { encoding: "utf8" });
20524
+ const result = await fs_1.promises.readFile(path19, { encoding: "utf8" });
20516
20525
  return result.trim();
20517
20526
  } catch (e) {
20518
20527
  api_1.diag.debug(`error reading machine id: ${e}`);
@@ -20722,7 +20731,7 @@ var require_ProcessDetectorSync = __commonJS({
20722
20731
  var api_1 = (init_esm(), __toCommonJS(esm_exports));
20723
20732
  var semantic_conventions_1 = (init_esm2(), __toCommonJS(esm_exports2));
20724
20733
  var Resource_1 = require_Resource();
20725
- var os6 = __require("os");
20734
+ var os8 = __require("os");
20726
20735
  var ProcessDetectorSync = class {
20727
20736
  detect(_config) {
20728
20737
  const attributes = {
@@ -20742,7 +20751,7 @@ var require_ProcessDetectorSync = __commonJS({
20742
20751
  attributes[semantic_conventions_1.SEMRESATTRS_PROCESS_COMMAND] = process.argv[1];
20743
20752
  }
20744
20753
  try {
20745
- const userInfo = os6.userInfo();
20754
+ const userInfo = os8.userInfo();
20746
20755
  attributes[semantic_conventions_1.SEMRESATTRS_PROCESS_OWNER] = userInfo.username;
20747
20756
  } catch (e) {
20748
20757
  api_1.diag.debug(`error obtaining process owner: ${e}`);
@@ -23915,7 +23924,7 @@ function appendRootPathToUrlIfNeeded(url) {
23915
23924
  return void 0;
23916
23925
  }
23917
23926
  }
23918
- function appendResourcePathToUrl(url, path18) {
23927
+ function appendResourcePathToUrl(url, path19) {
23919
23928
  try {
23920
23929
  new URL(url);
23921
23930
  } catch (_a) {
@@ -23925,11 +23934,11 @@ function appendResourcePathToUrl(url, path18) {
23925
23934
  if (!url.endsWith("/")) {
23926
23935
  url = url + "/";
23927
23936
  }
23928
- url += path18;
23937
+ url += path19;
23929
23938
  try {
23930
23939
  new URL(url);
23931
23940
  } catch (_b) {
23932
- diag2.warn("Configuration: Provided URL appended with '" + path18 + "' is not a valid URL, using 'undefined' instead of '" + url + "'");
23941
+ diag2.warn("Configuration: Provided URL appended with '" + path19 + "' is not a valid URL, using 'undefined' instead of '" + url + "'");
23933
23942
  return void 0;
23934
23943
  }
23935
23944
  return url;
@@ -29390,6 +29399,20 @@ var init_platform_config = __esm({
29390
29399
  }
29391
29400
  });
29392
29401
 
29402
+ // ts/agent-core/dist/channel-capability.js
29403
+ var init_channel_capability = __esm({
29404
+ "ts/agent-core/dist/channel-capability.js"() {
29405
+ "use strict";
29406
+ }
29407
+ });
29408
+
29409
+ // ts/agent-core/dist/channel-token.js
29410
+ var init_channel_token = __esm({
29411
+ "ts/agent-core/dist/channel-token.js"() {
29412
+ "use strict";
29413
+ }
29414
+ });
29415
+
29393
29416
  // ts/agent-core/dist/skills/parall-platform.js
29394
29417
  var init_parall_platform = __esm({
29395
29418
  "ts/agent-core/dist/skills/parall-platform.js"() {
@@ -29458,6 +29481,7 @@ var init_dist2 = __esm({
29458
29481
  init_provider_config();
29459
29482
  init_types();
29460
29483
  init_lane_key();
29484
+ init_gateway_lane_flow();
29461
29485
  init_session_state();
29462
29486
  init_routing();
29463
29487
  init_event_format();
@@ -29467,6 +29491,8 @@ var init_dist2 = __esm({
29467
29491
  init_logger();
29468
29492
  init_gateway_base();
29469
29493
  init_platform_config();
29494
+ init_channel_capability();
29495
+ init_channel_token();
29470
29496
  init_skills();
29471
29497
  init_telemetry();
29472
29498
  }
@@ -29477,6 +29503,7 @@ var config_exports = {};
29477
29503
  __export(config_exports, {
29478
29504
  agentClaudeCredentialsFileFor: () => agentClaudeCredentialsFileFor,
29479
29505
  agentClaudeHomeFor: () => agentClaudeHomeFor,
29506
+ agentHomeDirFor: () => agentHomeDirFor,
29480
29507
  agentStateDirFor: () => agentStateDirFor,
29481
29508
  agentWorkspaceDirFor: () => agentWorkspaceDirFor,
29482
29509
  daemonConfigDir: () => daemonConfigDir,
@@ -29563,7 +29590,8 @@ function resolveClaudeDaemonConfig(env = process.env) {
29563
29590
  updateCdnUrl: env.PRLL_DAEMON_UPDATE_CDN_URL?.trim() || ((env.PRLL_DAEMON_UPDATE_CHANNEL?.trim() ?? "production") === "staging" ? "https://releases.staging.prll.sh/daemon/staging" : "https://releases.parall.com/daemon/production"),
29564
29591
  updateIntervalMs: parseMsAllowZero(env.PRLL_DAEMON_UPDATE_INTERVAL_MS, 6 * 60 * 6e4),
29565
29592
  updateDisabled: env.PRLL_DAEMON_UPDATE_DISABLED === "true" || !!env.KUBERNETES_SERVICE_HOST,
29566
- updateConfirmDelayMs: parseMsAllowZero(env.PRLL_DAEMON_UPDATE_CONFIRM_DELAY_MS?.trim() || void 0, 6e4)
29593
+ updateConfirmDelayMs: parseMsAllowZero(env.PRLL_DAEMON_UPDATE_CONFIRM_DELAY_MS?.trim() || void 0, 6e4),
29594
+ homeIsolationDisabled: env.PRLL_DAEMON_HOME_ISOLATION?.trim() === "0"
29567
29595
  };
29568
29596
  }
29569
29597
  function assertSafeAgentId(agentId) {
@@ -29587,6 +29615,9 @@ function agentClaudeCredentialsFileFor(agentClaudeHome) {
29587
29615
  function agentWorkspaceDirFor(rootStateDir, agentId) {
29588
29616
  return path3.join(rootStateDir, "agents", assertSafeAgentId(agentId), "workspace");
29589
29617
  }
29618
+ function agentHomeDirFor(rootStateDir, agentId) {
29619
+ return path3.join(rootStateDir, "agents", assertSafeAgentId(agentId), "home");
29620
+ }
29590
29621
  function resolveUpdateSigningEnabled(env = process.env) {
29591
29622
  return env.PRLL_DAEMON_SIGNING_DISABLED !== "1";
29592
29623
  }
@@ -31101,6 +31132,7 @@ var init_manifest = __esm({
31101
31132
 
31102
31133
  // ts/daemon/dist/runtimes.js
31103
31134
  import * as fs7 from "node:fs";
31135
+ import * as os4 from "node:os";
31104
31136
  import * as path9 from "node:path";
31105
31137
  function buildStandardEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
31106
31138
  const env = { ...baseEnv };
@@ -31113,6 +31145,8 @@ function buildStandardEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
31113
31145
  env.PRLL_WORKSPACE_DIR = dirs.workspaceDir;
31114
31146
  if (pc)
31115
31147
  env.PRLL_PROVIDER_CONFIG = JSON.stringify(pc);
31148
+ if (dirs.homeDir)
31149
+ env.HOME = dirs.homeDir;
31116
31150
  delete env.PRLL_DAEMON_MODE;
31117
31151
  return env;
31118
31152
  }
@@ -31158,6 +31192,8 @@ var init_runtimes = __esm({
31158
31192
  const env = buildStandardEnv(baseEnv, agentId, orgId, apiKey, dirs, pc);
31159
31193
  if (baseEnv.KUBERNETES_SERVICE_HOST || llmSource(pc) !== "runtime_auth") {
31160
31194
  env.PRLL_CODEX_HOME = path9.join(dirs.stateDir, ".codex");
31195
+ } else if (dirs.homeDir && !env.CODEX_HOME) {
31196
+ env.CODEX_HOME = path9.join(baseEnv.HOME || os4.homedir(), ".codex");
31161
31197
  }
31162
31198
  return env;
31163
31199
  }
@@ -32408,7 +32444,7 @@ var init_process_manager = __esm({
32408
32444
  * (GetBindings), then forward the invoke through the hub (Invoke) to the bound
32409
32445
  * BrowserProfile's host. No local shortcut, no fallback — unbound is rejected.
32410
32446
  * The execution daemon never verifies clip_token; the hub does.
32411
- * See docs/engineering-design/browser-profile-clip-integration.md §11.3.
32447
+ * See docs/archive/engineering-design/browser-profile-clip-integration.md §11.3.
32412
32448
  */
32413
32449
  async invokeDependency(clipName, command, input, context2) {
32414
32450
  if (!isBrowserDependencyName(clipName)) {
@@ -32441,7 +32477,7 @@ var init_process_manager = __esm({
32441
32477
  * synthetic "browser" clip). The hub forwards clip_token as the PLAINTEXT
32442
32478
  * browser_profile_id, which the host daemon uses directly as the bb-browser
32443
32479
  * account. Only daemons that host BrowserProfiles register this capability.
32444
- * See docs/engineering-design/browser-profile-clip-integration.md §11.2.
32480
+ * See docs/archive/engineering-design/browser-profile-clip-integration.md §11.2.
32445
32481
  */
32446
32482
  async invokeBrowserCapability(clipToken, command, input) {
32447
32483
  if (!this.browserProfileManager) {
@@ -34796,7 +34832,7 @@ var init_clip_runtime = __esm({
34796
34832
  // ts/daemon/dist/filesystem.js
34797
34833
  import * as fs9 from "fs";
34798
34834
  import * as path13 from "path";
34799
- import * as os4 from "os";
34835
+ import * as os5 from "os";
34800
34836
  function browseDenyReason(value) {
34801
34837
  const normalized = path13.resolve(value).split(path13.sep).join("/");
34802
34838
  if (normalized === "/")
@@ -34816,8 +34852,8 @@ function browseDenyReason(value) {
34816
34852
  }
34817
34853
  function syntheticRoots() {
34818
34854
  const roots = [];
34819
- const platform2 = os4.platform();
34820
- const candidates = platform2 === "darwin" ? ["/Users", os4.homedir()] : ["/home", os4.homedir()];
34855
+ const platform2 = os5.platform();
34856
+ const candidates = platform2 === "darwin" ? ["/Users", os5.homedir()] : ["/home", os5.homedir()];
34821
34857
  for (const dir of [...new Set(candidates)]) {
34822
34858
  try {
34823
34859
  fs9.accessSync(dir, fs9.constants.R_OK);
@@ -34913,11 +34949,108 @@ var init_filesystem = __esm({
34913
34949
  }
34914
34950
  });
34915
34951
 
34916
- // ts/daemon/dist/runtime-bin-resolver.js
34917
- import { execFileSync as execFileSync3 } from "node:child_process";
34952
+ // ts/daemon/dist/home-isolation.js
34918
34953
  import * as fs10 from "node:fs";
34919
- import * as os5 from "node:os";
34920
34954
  import * as path14 from "node:path";
34955
+ function ensureIsolatedHome(spec, agentId, log2, platform2 = process.platform) {
34956
+ fs10.mkdirSync(spec.homeDir, { recursive: true });
34957
+ const failures = [];
34958
+ const attempt = (label, fn) => {
34959
+ try {
34960
+ fn();
34961
+ } catch (err) {
34962
+ failures.push(`${label}: ${String(err)}`);
34963
+ }
34964
+ };
34965
+ attempt(".claude link", () => {
34966
+ fs10.mkdirSync(path14.join(spec.claudeStateRoot, ".claude"), { recursive: true });
34967
+ ensureLink(path14.join(spec.homeDir, ".claude"), path14.join(spec.claudeStateRoot, ".claude"), agentId, log2);
34968
+ });
34969
+ attempt(".claude.json link", () => ensureLink(path14.join(spec.homeDir, ".claude.json"), path14.join(spec.claudeStateRoot, ".claude.json"), agentId, log2));
34970
+ if (platform2 === "darwin") {
34971
+ attempt("Library/Keychains link", () => {
34972
+ fs10.mkdirSync(path14.join(spec.homeDir, "Library"), { recursive: true });
34973
+ ensureLink(path14.join(spec.homeDir, "Library", "Keychains"), path14.join(spec.systemHome, "Library", "Keychains"), agentId, log2);
34974
+ });
34975
+ }
34976
+ attempt(".gitconfig", () => {
34977
+ const gitconfig = path14.join(spec.homeDir, ".gitconfig");
34978
+ if (!fs10.existsSync(gitconfig)) {
34979
+ fs10.writeFileSync(gitconfig, `[user]
34980
+ name = ${gitConfigValue(spec.gitUserName)}
34981
+ email = ${gitConfigValue(spec.gitUserEmail)}
34982
+ `, { mode: 420 });
34983
+ log2.info(`agent ${agentId}: wrote per-agent .gitconfig (${spec.gitUserName})`);
34984
+ }
34985
+ });
34986
+ return failures;
34987
+ }
34988
+ function gitConfigValue(value) {
34989
+ const flat = value.replace(/[\r\n\t]+/g, " ").trim();
34990
+ return `"${flat.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
34991
+ }
34992
+ function ensureLink(linkPath, target, agentId, log2) {
34993
+ let existing;
34994
+ try {
34995
+ existing = fs10.lstatSync(linkPath);
34996
+ } catch (err) {
34997
+ if (err.code !== "ENOENT")
34998
+ throw err;
34999
+ }
35000
+ if (existing) {
35001
+ if (existing.isSymbolicLink()) {
35002
+ const current = fs10.readlinkSync(linkPath);
35003
+ if (path14.resolve(path14.dirname(linkPath), current) === path14.resolve(target))
35004
+ return;
35005
+ fs10.unlinkSync(linkPath);
35006
+ log2.info(`agent ${agentId}: relinking ${linkPath} \u2192 ${target}`);
35007
+ } else {
35008
+ const preserved = `${linkPath}.pre-isolation.${Date.now()}`;
35009
+ fs10.renameSync(linkPath, preserved);
35010
+ log2.warn(`agent ${agentId}: ${linkPath} was a real ${existing.isDirectory() ? "directory" : "file"}, not the expected passthrough symlink \u2014 preserved at ${preserved} and relinked`);
35011
+ }
35012
+ }
35013
+ fs10.symlinkSync(target, linkPath);
35014
+ }
35015
+ function ensureSharedCredentialLink(rootClaudeHome, agentClaudeHome, agentId, log2) {
35016
+ const sharedCredentials = path14.resolve(sharedClaudeCredentialsFileFor(rootClaudeHome));
35017
+ const agentCredentials = agentClaudeCredentialsFileFor(agentClaudeHome);
35018
+ const agentCredentialsDir = path14.dirname(agentCredentials);
35019
+ fs10.mkdirSync(path14.dirname(sharedCredentials), { recursive: true });
35020
+ fs10.mkdirSync(agentCredentialsDir, { recursive: true });
35021
+ try {
35022
+ const existing = fs10.lstatSync(agentCredentials);
35023
+ if (existing.isSymbolicLink()) {
35024
+ const currentTarget = fs10.readlinkSync(agentCredentials);
35025
+ if (path14.resolve(agentCredentialsDir, currentTarget) === sharedCredentials) {
35026
+ return;
35027
+ }
35028
+ fs10.unlinkSync(agentCredentials);
35029
+ } else if (existing.isDirectory()) {
35030
+ log2.warn(`agent ${agentId}: credential path is a directory, cannot link ${agentCredentials}`);
35031
+ return;
35032
+ } else {
35033
+ fs10.unlinkSync(agentCredentials);
35034
+ }
35035
+ } catch (err) {
35036
+ if (err.code !== "ENOENT") {
35037
+ throw err;
35038
+ }
35039
+ }
35040
+ fs10.symlinkSync(sharedCredentials, agentCredentials);
35041
+ }
35042
+ var init_home_isolation = __esm({
35043
+ "ts/daemon/dist/home-isolation.js"() {
35044
+ "use strict";
35045
+ init_config();
35046
+ }
35047
+ });
35048
+
35049
+ // ts/daemon/dist/runtime-bin-resolver.js
35050
+ import { execFileSync as execFileSync3 } from "node:child_process";
35051
+ import * as fs11 from "node:fs";
35052
+ import * as os6 from "node:os";
35053
+ import * as path15 from "node:path";
34921
35054
  function runtimeBinaryEnvVar(runtimeType) {
34922
35055
  return RUNTIME_BINARIES[runtimeType]?.envVar;
34923
35056
  }
@@ -34994,16 +35127,16 @@ function resolveRuntimeCommand(command, env, inheritedPath, primaryPath, fallbac
34994
35127
  function resolveDirectPath(command) {
34995
35128
  if (!command.includes("/") && !command.includes("\\"))
34996
35129
  return null;
34997
- const abs = path14.isAbsolute(command) ? command : path14.resolve(process.cwd(), command);
35130
+ const abs = path15.isAbsolute(command) ? command : path15.resolve(process.cwd(), command);
34998
35131
  return isExecutable(abs) ? abs : null;
34999
35132
  }
35000
35133
  function resolveFromPath(command, pathValue, env) {
35001
35134
  if (!pathValue || command.includes("/") || command.includes("\\"))
35002
35135
  return null;
35003
- const dirs = pathValue.split(path14.delimiter).filter(Boolean);
35136
+ const dirs = pathValue.split(path15.delimiter).filter(Boolean);
35004
35137
  for (const dir of dirs) {
35005
35138
  for (const file of commandCandidates(command, env)) {
35006
- const candidate = path14.join(dir, file);
35139
+ const candidate = path15.join(dir, file);
35007
35140
  if (isExecutable(candidate))
35008
35141
  return { binaryPath: candidate, pathValue };
35009
35142
  }
@@ -35042,7 +35175,7 @@ __PRLL_PATH__%s
35042
35175
  if (line.startsWith("__PRLL_PATH__"))
35043
35176
  pathValue = line.slice("__PRLL_PATH__".length);
35044
35177
  }
35045
- if (path14.isAbsolute(binaryPath) && isExecutable(binaryPath)) {
35178
+ if (path15.isAbsolute(binaryPath) && isExecutable(binaryPath)) {
35046
35179
  return { binaryPath, pathValue: pathValue || void 0 };
35047
35180
  }
35048
35181
  } catch {
@@ -35060,25 +35193,25 @@ function cachedCandidatePathPlan(env) {
35060
35193
  return value;
35061
35194
  }
35062
35195
  function candidatePathPlan(env) {
35063
- const home = env.HOME || os5.homedir();
35196
+ const home = env.HOME || os6.homedir();
35064
35197
  const primaryDirs = [
35065
35198
  ...splitPath(env.PRLL_DAEMON_RUNTIME_PATH),
35066
35199
  ...splitPath(env.PRLL_DAEMON_EXTRA_PATH),
35067
- path14.dirname(process.execPath),
35068
- path14.join(path14.dirname(process.execPath), "bin"),
35069
- path14.resolve(path14.dirname(process.execPath), "..", "Resources", "bin"),
35070
- path14.join(home, ".local", "bin"),
35071
- path14.join(home, "bin"),
35072
- path14.join(home, ".npm-global", "bin"),
35073
- path14.join(home, "Library", "pnpm"),
35074
- path14.join(home, ".local", "share", "pnpm"),
35075
- path14.join(home, ".volta", "bin"),
35076
- path14.join(home, ".bun", "bin"),
35077
- path14.join(home, ".asdf", "shims"),
35078
- path14.join(home, ".local", "share", "mise", "shims"),
35079
- path14.join(home, ".mise", "shims"),
35080
- path14.join(home, ".fnm", "aliases", "default", "bin"),
35081
- path14.join(home, "Library", "Application Support", "fnm", "aliases", "default", "bin"),
35200
+ path15.dirname(process.execPath),
35201
+ path15.join(path15.dirname(process.execPath), "bin"),
35202
+ path15.resolve(path15.dirname(process.execPath), "..", "Resources", "bin"),
35203
+ path15.join(home, ".local", "bin"),
35204
+ path15.join(home, "bin"),
35205
+ path15.join(home, ".npm-global", "bin"),
35206
+ path15.join(home, "Library", "pnpm"),
35207
+ path15.join(home, ".local", "share", "pnpm"),
35208
+ path15.join(home, ".volta", "bin"),
35209
+ path15.join(home, ".bun", "bin"),
35210
+ path15.join(home, ".asdf", "shims"),
35211
+ path15.join(home, ".local", "share", "mise", "shims"),
35212
+ path15.join(home, ".mise", "shims"),
35213
+ path15.join(home, ".fnm", "aliases", "default", "bin"),
35214
+ path15.join(home, "Library", "Application Support", "fnm", "aliases", "default", "bin"),
35082
35215
  "/opt/homebrew/bin",
35083
35216
  "/usr/local/bin",
35084
35217
  "/usr/bin",
@@ -35097,29 +35230,29 @@ function candidatePathPlan(env) {
35097
35230
  };
35098
35231
  }
35099
35232
  function nvmVersionBinDirs(home) {
35100
- const root = path14.join(home, ".nvm", "versions", "node");
35233
+ const root = path15.join(home, ".nvm", "versions", "node");
35101
35234
  let versions;
35102
35235
  try {
35103
- versions = fs10.readdirSync(root);
35236
+ versions = fs11.readdirSync(root);
35104
35237
  } catch {
35105
35238
  return [];
35106
35239
  }
35107
- return sortVersionNamesDesc(versions).map((version) => path14.join(root, version, "bin"));
35240
+ return sortVersionNamesDesc(versions).map((version) => path15.join(root, version, "bin"));
35108
35241
  }
35109
35242
  function fnmVersionBinDirs(home) {
35110
35243
  const roots = [
35111
- path14.join(home, ".fnm", "node-versions"),
35112
- path14.join(home, "Library", "Application Support", "fnm", "node-versions")
35244
+ path15.join(home, ".fnm", "node-versions"),
35245
+ path15.join(home, "Library", "Application Support", "fnm", "node-versions")
35113
35246
  ];
35114
35247
  const dirs = [];
35115
35248
  for (const root of roots) {
35116
35249
  let versions;
35117
35250
  try {
35118
- versions = fs10.readdirSync(root);
35251
+ versions = fs11.readdirSync(root);
35119
35252
  } catch {
35120
35253
  continue;
35121
35254
  }
35122
- dirs.push(...sortVersionNamesDesc(versions).map((version) => path14.join(root, version, "installation", "bin")));
35255
+ dirs.push(...sortVersionNamesDesc(versions).map((version) => path15.join(root, version, "installation", "bin")));
35123
35256
  }
35124
35257
  return dirs;
35125
35258
  }
@@ -35141,13 +35274,13 @@ function parseVersionName(value) {
35141
35274
  return value.replace(/^v/i, "").split(".").map((part) => Number.parseInt(part, 10)).filter((part) => Number.isFinite(part));
35142
35275
  }
35143
35276
  function splitPath(value) {
35144
- return value?.split(path14.delimiter).filter(Boolean) ?? [];
35277
+ return value?.split(path15.delimiter).filter(Boolean) ?? [];
35145
35278
  }
35146
35279
  function mergePath(prependDirs, existing) {
35147
- return unique([...prependDirs, ...splitPath(existing)]).join(path14.delimiter);
35280
+ return unique([...prependDirs, ...splitPath(existing)]).join(path15.delimiter);
35148
35281
  }
35149
35282
  function anchorResolvedPath(pathValue, resolution) {
35150
- return mergePath([path14.dirname(resolution.binaryPath), ...splitPath(resolution.pathValue)], pathValue);
35283
+ return mergePath([path15.dirname(resolution.binaryPath), ...splitPath(resolution.pathValue)], pathValue);
35151
35284
  }
35152
35285
  function commandCandidates(command, env) {
35153
35286
  if (process.platform !== "win32")
@@ -35173,10 +35306,10 @@ function setCachedResolution(cacheKey, value) {
35173
35306
  }
35174
35307
  function isExecutable(file) {
35175
35308
  try {
35176
- const stat = fs10.statSync(file);
35309
+ const stat = fs11.statSync(file);
35177
35310
  if (!stat.isFile())
35178
35311
  return false;
35179
- fs10.accessSync(file, fs10.constants.X_OK);
35312
+ fs11.accessSync(file, fs11.constants.X_OK);
35180
35313
  return true;
35181
35314
  } catch {
35182
35315
  return false;
@@ -35184,7 +35317,7 @@ function isExecutable(file) {
35184
35317
  }
35185
35318
  function isDirectory(dir) {
35186
35319
  try {
35187
- return fs10.statSync(dir).isDirectory();
35320
+ return fs11.statSync(dir).isDirectory();
35188
35321
  } catch {
35189
35322
  return false;
35190
35323
  }
@@ -35301,8 +35434,8 @@ var init_runtime_detector = __esm({
35301
35434
  // ts/daemon/dist/workspace.js
35302
35435
  import { spawn as spawn5 } from "node:child_process";
35303
35436
  import { createHash as createHash3 } from "node:crypto";
35304
- import * as fs11 from "node:fs";
35305
- import * as path15 from "node:path";
35437
+ import * as fs12 from "node:fs";
35438
+ import * as path16 from "node:path";
35306
35439
  async function prepareWorkspace(opts) {
35307
35440
  const prior = opts.attached.workspace_state;
35308
35441
  const plan = buildWorkspacePlan(opts.attached.daemon_config, opts.defaultWorkspaceDir, prior?.config_hash);
@@ -35417,7 +35550,7 @@ function resolveWorkspaceDir(workspace, defaultWorkspaceDir) {
35417
35550
  async function ensureWorkspace(plan, log2) {
35418
35551
  const ws = plan.workspace;
35419
35552
  if (ws.mode === "default") {
35420
- fs11.mkdirSync(plan.workspaceDir, { recursive: true });
35553
+ fs12.mkdirSync(plan.workspaceDir, { recursive: true });
35421
35554
  assertWritableWorkspaceDir(plan.workspaceDir);
35422
35555
  return;
35423
35556
  }
@@ -35425,7 +35558,7 @@ async function ensureWorkspace(plan, log2) {
35425
35558
  assertSafeCustomWorkspacePath(plan);
35426
35559
  let st;
35427
35560
  try {
35428
- st = fs11.statSync(plan.workspaceDir);
35561
+ st = fs12.statSync(plan.workspaceDir);
35429
35562
  } catch (err) {
35430
35563
  if (isNodeError(err) && err.code === "ENOENT") {
35431
35564
  throw new Error(`workspace path does not exist: ${plan.workspaceDir}`);
@@ -35435,7 +35568,7 @@ async function ensureWorkspace(plan, log2) {
35435
35568
  if (!st.isDirectory()) {
35436
35569
  throw new Error(`workspace path is not a directory: ${plan.workspaceDir}`);
35437
35570
  }
35438
- assertSafeCustomWorkspacePath(plan, fs11.realpathSync(plan.workspaceDir));
35571
+ assertSafeCustomWorkspacePath(plan, fs12.realpathSync(plan.workspaceDir));
35439
35572
  assertWritableWorkspaceDir(plan.workspaceDir);
35440
35573
  return;
35441
35574
  }
@@ -35446,17 +35579,17 @@ async function ensureWorkspace(plan, log2) {
35446
35579
  if (plan.customWorkspaceField) {
35447
35580
  assertSafeCustomWorkspacePath(plan);
35448
35581
  }
35449
- if (!fs11.existsSync(plan.workspaceDir)) {
35450
- fs11.mkdirSync(path15.dirname(plan.workspaceDir), { recursive: true });
35451
- assertWritableWorkspaceDir(path15.dirname(plan.workspaceDir));
35582
+ if (!fs12.existsSync(plan.workspaceDir)) {
35583
+ fs12.mkdirSync(path16.dirname(plan.workspaceDir), { recursive: true });
35584
+ assertWritableWorkspaceDir(path16.dirname(plan.workspaceDir));
35452
35585
  await runCommand("git", ["clone", remote, plan.workspaceDir], process.cwd());
35453
35586
  } else {
35454
- const st = fs11.statSync(plan.workspaceDir);
35587
+ const st = fs12.statSync(plan.workspaceDir);
35455
35588
  if (!st.isDirectory()) {
35456
35589
  throw new Error(`workspace path is not a directory: ${plan.workspaceDir}`);
35457
35590
  }
35458
35591
  if (plan.customWorkspaceField) {
35459
- assertSafeCustomWorkspacePath(plan, fs11.realpathSync(plan.workspaceDir));
35592
+ assertSafeCustomWorkspacePath(plan, fs12.realpathSync(plan.workspaceDir));
35460
35593
  }
35461
35594
  assertWritableWorkspaceDir(plan.workspaceDir);
35462
35595
  await ensureGitWorktree(plan.workspaceDir);
@@ -35480,13 +35613,13 @@ async function verifyExistingWorkspace(plan, log2) {
35480
35613
  if (plan.customWorkspaceField) {
35481
35614
  assertSafeCustomWorkspacePath(plan);
35482
35615
  }
35483
- const st = fs11.statSync(plan.workspaceDir);
35616
+ const st = fs12.statSync(plan.workspaceDir);
35484
35617
  if (!st.isDirectory()) {
35485
35618
  log2.warn(`workspace ready state ignored: path is not a directory: ${plan.workspaceDir}`);
35486
35619
  return false;
35487
35620
  }
35488
35621
  if (plan.customWorkspaceField) {
35489
- assertSafeCustomWorkspacePath(plan, fs11.realpathSync(plan.workspaceDir));
35622
+ assertSafeCustomWorkspacePath(plan, fs12.realpathSync(plan.workspaceDir));
35490
35623
  }
35491
35624
  assertWritableWorkspaceDir(plan.workspaceDir);
35492
35625
  if (plan.workspace.mode === "git") {
@@ -35630,10 +35763,10 @@ ${tail}`)));
35630
35763
  });
35631
35764
  }
35632
35765
  function requireAbsolute(value, field) {
35633
- if (!value || !path15.isAbsolute(value)) {
35766
+ if (!value || !path16.isAbsolute(value)) {
35634
35767
  throw new Error(`${field} must be an absolute path`);
35635
35768
  }
35636
- return path15.resolve(value);
35769
+ return path16.resolve(value);
35637
35770
  }
35638
35771
  function assertSafeCustomWorkspacePath(plan, candidate = plan.workspaceDir) {
35639
35772
  if (!plan.customWorkspaceField)
@@ -35643,17 +35776,17 @@ function assertSafeCustomWorkspacePath(plan, candidate = plan.workspaceDir) {
35643
35776
  if (reason) {
35644
35777
  throw new Error(`${plan.customWorkspaceField} must point to a project folder, not ${reason}: ${normalized}`);
35645
35778
  }
35646
- const defaultWorkspace = path15.resolve(plan.defaultWorkspaceDir);
35779
+ const defaultWorkspace = path16.resolve(plan.defaultWorkspaceDir);
35647
35780
  if (isAncestorPath(normalized, defaultWorkspace) || normalized === defaultWorkspace) {
35648
35781
  throw new Error(`${plan.customWorkspaceField} must not point at daemon state directories: ${normalized}`);
35649
35782
  }
35650
35783
  }
35651
35784
  function assertWritableWorkspaceDir(dir) {
35652
- fs11.accessSync(dir, fs11.constants.R_OK | fs11.constants.W_OK | fs11.constants.X_OK);
35653
- const probe = path15.join(dir, `.parall-workspace-check-${process.pid}-${Date.now()}`);
35654
- const fd = fs11.openSync(probe, "wx", 384);
35655
- fs11.closeSync(fd);
35656
- fs11.unlinkSync(probe);
35785
+ fs12.accessSync(dir, fs12.constants.R_OK | fs12.constants.W_OK | fs12.constants.X_OK);
35786
+ const probe = path16.join(dir, `.parall-workspace-check-${process.pid}-${Date.now()}`);
35787
+ const fd = fs12.openSync(probe, "wx", 384);
35788
+ fs12.closeSync(fd);
35789
+ fs12.unlinkSync(probe);
35657
35790
  }
35658
35791
  function workspacePathDenyReason(value) {
35659
35792
  if (value === "/")
@@ -35714,11 +35847,11 @@ function workspacePathDenyReason(value) {
35714
35847
  return "";
35715
35848
  }
35716
35849
  function isAncestorPath(parent, child) {
35717
- const relative2 = path15.relative(parent, child);
35718
- return relative2 !== "" && !relative2.startsWith("..") && !path15.isAbsolute(relative2);
35850
+ const relative2 = path16.relative(parent, child);
35851
+ return relative2 !== "" && !relative2.startsWith("..") && !path16.isAbsolute(relative2);
35719
35852
  }
35720
35853
  function toPolicyPath(value) {
35721
- return path15.resolve(value).split(path15.sep).join("/");
35854
+ return path16.resolve(value).split(path16.sep).join("/");
35722
35855
  }
35723
35856
  function isNodeError(err) {
35724
35857
  return err instanceof Error && "code" in err;
@@ -35735,8 +35868,9 @@ var init_workspace = __esm({
35735
35868
 
35736
35869
  // ts/daemon/dist/supervisor.js
35737
35870
  import { spawn as spawn6 } from "node:child_process";
35738
- import * as fs12 from "node:fs";
35739
- import * as path16 from "node:path";
35871
+ import * as fs13 from "node:fs";
35872
+ import * as os7 from "node:os";
35873
+ import * as path17 from "node:path";
35740
35874
  function sleepCancellable(ms, signal) {
35741
35875
  if (signal.aborted)
35742
35876
  return Promise.resolve(false);
@@ -35763,6 +35897,7 @@ var init_supervisor = __esm({
35763
35897
  init_clip_runtime();
35764
35898
  init_config();
35765
35899
  init_filesystem();
35900
+ init_home_isolation();
35766
35901
  init_runtimes();
35767
35902
  init_runtime_bin_resolver();
35768
35903
  init_runtime_detector();
@@ -35886,7 +36021,7 @@ var init_supervisor = __esm({
35886
36021
  this.migrateFlatLayout();
35887
36022
  if (process.env.PRLL_CLIP_RUNTIME_ENABLED === "true") {
35888
36023
  this.browserProfilePool = new BrowserProfilePool({
35889
- baseHomeDir: path16.join(this.config.rootStateDir, "bb-browser"),
36024
+ baseHomeDir: path17.join(this.config.rootStateDir, "bb-browser"),
35890
36025
  log: this.log,
35891
36026
  reportStatus: (profileId, status, errorMsg, generation) => {
35892
36027
  this.client.reportBrowserProfileStatus(profileId, status, errorMsg, generation).catch((err) => this.log.warn(`browser profile status report failed: ${String(err)}`));
@@ -35894,8 +36029,8 @@ var init_supervisor = __esm({
35894
36029
  resolveProxy: (profileId) => this.resolveBrowserProfileProxy(profileId)
35895
36030
  });
35896
36031
  this.clipManager = new ClipProcessManager({
35897
- clipsDir: path16.join(this.config.rootStateDir, "clips"),
35898
- dataDir: path16.join(this.config.rootStateDir, "clip-data"),
36032
+ clipsDir: path17.join(this.config.rootStateDir, "clips"),
36033
+ dataDir: path17.join(this.config.rootStateDir, "clip-data"),
35899
36034
  browserProfileManager: this.browserProfilePool,
35900
36035
  // Execution side: nested browser dependency invokes resolve their
35901
36036
  // binding and route through the hub (no local shortcut).
@@ -36124,6 +36259,22 @@ var init_supervisor = __esm({
36124
36259
  }
36125
36260
  await this.spawnAgent(userId, orgId, a);
36126
36261
  } else {
36262
+ const isolationChanged = !existing.shuttingDown && !!existing.homeIsolation !== !!this.buildHomeIsolationSpec(a, userId);
36263
+ if (isolationChanged) {
36264
+ this.log.info(`agent ${userId}: home isolation changed while disconnected \u2014 rebuilding child`);
36265
+ existing.shuttingDown = true;
36266
+ if (existing.restartTimer) {
36267
+ clearTimeout(existing.restartTimer);
36268
+ existing.restartTimer = null;
36269
+ }
36270
+ await this.terminateChild(existing);
36271
+ this.children.delete(userId);
36272
+ const orgId = this.machineOrgId;
36273
+ if (orgId) {
36274
+ await this.spawnAgent(userId, orgId, a);
36275
+ }
36276
+ continue;
36277
+ }
36127
36278
  const configChanged = JSON.stringify(existing.providerConfig ?? null) !== JSON.stringify(a.provider_config ?? null);
36128
36279
  existing.providerConfig = a.provider_config;
36129
36280
  if (!existing.child && !existing.restartTimer && !existing.shuttingDown) {
@@ -36284,15 +36435,15 @@ var init_supervisor = __esm({
36284
36435
  */
36285
36436
  migrateFlatLayout() {
36286
36437
  const root = this.config.rootStateDir;
36287
- const agentsDir = path16.join(root, "agents");
36288
- const flatWorkspace = path16.join(root, "workspace");
36289
- if (!fs12.existsSync(flatWorkspace) || fs12.existsSync(agentsDir))
36438
+ const agentsDir = path17.join(root, "agents");
36439
+ const flatWorkspace = path17.join(root, "workspace");
36440
+ if (!fs13.existsSync(flatWorkspace) || fs13.existsSync(agentsDir))
36290
36441
  return;
36291
36442
  let ownerAgentId;
36292
- const sessionsDir = path16.join(root, "sessions");
36293
- if (fs12.existsSync(sessionsDir)) {
36443
+ const sessionsDir = path17.join(root, "sessions");
36444
+ if (fs13.existsSync(sessionsDir)) {
36294
36445
  try {
36295
- for (const file of fs12.readdirSync(sessionsDir)) {
36446
+ for (const file of fs13.readdirSync(sessionsDir)) {
36296
36447
  if (!file.endsWith(".json"))
36297
36448
  continue;
36298
36449
  const decoded = Buffer.from(file.replace(".json", ""), "base64url").toString();
@@ -36306,13 +36457,13 @@ var init_supervisor = __esm({
36306
36457
  }
36307
36458
  }
36308
36459
  const targetId = ownerAgentId ?? "_orphan";
36309
- const targetDir = path16.join(agentsDir, targetId);
36460
+ const targetDir = path17.join(agentsDir, targetId);
36310
36461
  try {
36311
- fs12.mkdirSync(targetDir, { recursive: true });
36462
+ fs13.mkdirSync(targetDir, { recursive: true });
36312
36463
  for (const sub of ["workspace", "sessions", "dispatch-context"]) {
36313
- const src = path16.join(root, sub);
36314
- if (fs12.existsSync(src)) {
36315
- fs12.renameSync(src, path16.join(targetDir, sub));
36464
+ const src = path17.join(root, sub);
36465
+ if (fs13.existsSync(src)) {
36466
+ fs13.renameSync(src, path17.join(targetDir, sub));
36316
36467
  }
36317
36468
  }
36318
36469
  this.log.info(`migrated legacy flat state \u2192 agents/${targetId}/`);
@@ -36603,7 +36754,7 @@ var init_supervisor = __esm({
36603
36754
  return this.runtimeDetectInFlight;
36604
36755
  }
36605
36756
  machineClipToConfig(clip) {
36606
- const clipPath = path16.join(this.config.rootStateDir, "clips", clip.alias);
36757
+ const clipPath = path17.join(this.config.rootStateDir, "clips", clip.alias);
36607
36758
  return {
36608
36759
  clipId: clip.clip_id,
36609
36760
  name: clip.alias,
@@ -36669,7 +36820,7 @@ var init_supervisor = __esm({
36669
36820
  if (!sourceRef) {
36670
36821
  throw new Error(`registry clip "${config.name}" is missing source_ref`);
36671
36822
  }
36672
- const expectedPath = path16.join(this.config.rootStateDir, "clips", config.name);
36823
+ const expectedPath = path17.join(this.config.rootStateDir, "clips", config.name);
36673
36824
  const localVersion = this.readInstalledClipVersion(expectedPath);
36674
36825
  if (localVersion && (!config.version || localVersion === config.version)) {
36675
36826
  return { ...config, path: expectedPath, source: expectedPath };
@@ -36687,7 +36838,7 @@ var init_supervisor = __esm({
36687
36838
  const result = await installClip({
36688
36839
  source,
36689
36840
  alias: config.name,
36690
- clipsDir: path16.join(this.config.rootStateDir, "clips"),
36841
+ clipsDir: path17.join(this.config.rootStateDir, "clips"),
36691
36842
  registryUrl: process.env.PRLL_PINIX_REGISTRY_URL?.trim() || void 0
36692
36843
  });
36693
36844
  this.log.info(`clip ensured: ${result.alias} v${result.version} at ${result.path}`);
@@ -36702,7 +36853,7 @@ var init_supervisor = __esm({
36702
36853
  readInstalledClipVersion(dir) {
36703
36854
  for (const file of ["clip.json", "package.json"]) {
36704
36855
  try {
36705
- const raw = fs12.readFileSync(path16.join(dir, file), "utf-8");
36856
+ const raw = fs13.readFileSync(path17.join(dir, file), "utf-8");
36706
36857
  const parsed = JSON.parse(raw);
36707
36858
  if (typeof parsed.version === "string" && parsed.version.trim()) {
36708
36859
  return parsed.version.trim();
@@ -37012,6 +37163,28 @@ var init_supervisor = __esm({
37012
37163
  });
37013
37164
  }
37014
37165
  }
37166
+ /**
37167
+ * Local credential isolation (home-isolation.ts): per-agent opt-in via
37168
+ * daemon_config.home_isolation (unset = legacy shared HOME for existing
37169
+ * agents), machine-level kill switch PRLL_DAEMON_HOME_ISOLATION=0. K8s
37170
+ * pods never take this path — they keep the isolated claude-home +
37171
+ * shared-credential-link branch in spawnAgentOnce.
37172
+ */
37173
+ buildHomeIsolationSpec(attached, agentId) {
37174
+ if (process.env.KUBERNETES_SERVICE_HOST)
37175
+ return void 0;
37176
+ if (this.config.homeIsolationDisabled)
37177
+ return void 0;
37178
+ if (attached.daemon_config?.home_isolation !== true)
37179
+ return void 0;
37180
+ return {
37181
+ homeDir: agentHomeDirFor(this.config.rootStateDir, agentId),
37182
+ claudeStateRoot: this.config.rootClaudeHome,
37183
+ systemHome: os7.homedir(),
37184
+ gitUserName: attached.user?.display_name?.trim() || agentId,
37185
+ gitUserEmail: `${agentId}@noreply.parall.com`
37186
+ };
37187
+ }
37015
37188
  async spawnAgentOnce(agentId, orgId, attached) {
37016
37189
  let credential;
37017
37190
  try {
@@ -37023,12 +37196,13 @@ var init_supervisor = __esm({
37023
37196
  const stateDir = agentStateDirFor(this.config.rootStateDir, agentId);
37024
37197
  const defaultWorkspaceDir = agentWorkspaceDirFor(this.config.rootStateDir, agentId);
37025
37198
  const isK8s = !!process.env.KUBERNETES_SERVICE_HOST;
37026
- const claudeHome = isK8s ? agentClaudeHomeFor(this.config.rootClaudeHome, agentId) : this.config.rootClaudeHome;
37199
+ const homeIsolation = this.buildHomeIsolationSpec(attached, agentId);
37200
+ const claudeHome = isK8s ? agentClaudeHomeFor(this.config.rootClaudeHome, agentId) : homeIsolation?.homeDir ?? this.config.rootClaudeHome;
37027
37201
  try {
37028
- fs12.mkdirSync(stateDir, { recursive: true });
37202
+ fs13.mkdirSync(stateDir, { recursive: true });
37029
37203
  if (isK8s) {
37030
- fs12.mkdirSync(claudeHome, { recursive: true });
37031
- this.ensureSharedCredentialLink(claudeHome, agentId);
37204
+ fs13.mkdirSync(claudeHome, { recursive: true });
37205
+ ensureSharedCredentialLink(this.config.rootClaudeHome, claudeHome, agentId, this.log);
37032
37206
  }
37033
37207
  } catch (err) {
37034
37208
  this.log.warn(`mkdir agent dirs (${agentId}) failed: ${String(err)}`);
@@ -37061,6 +37235,7 @@ var init_supervisor = __esm({
37061
37235
  // resolved at startChild time (see resolveProviderConfig) so a respawn
37062
37236
  // after a machine llm_source change picks up the new source.
37063
37237
  providerConfig: attached.provider_config,
37238
+ homeIsolation,
37064
37239
  child: null,
37065
37240
  credential,
37066
37241
  restartAttempts: 0,
@@ -37080,17 +37255,38 @@ var init_supervisor = __esm({
37080
37255
  return;
37081
37256
  }
37082
37257
  assertAgentKey(state.credential.api_key);
37258
+ const effectiveProviderConfig = effectiveLLMSourceExplicit(state.providerConfig) ? state.providerConfig : { llm_source: this.machineLlmSource };
37259
+ let isolation = state.homeIsolation;
37260
+ if (isolation) {
37261
+ try {
37262
+ const failures = ensureIsolatedHome(isolation, state.agentId, this.log);
37263
+ if (failures.length > 0) {
37264
+ const needsPassthrough = state.runtimeType === "claude-code" && llmSource(effectiveProviderConfig) === "runtime_auth";
37265
+ if (needsPassthrough) {
37266
+ this.log.warn(`agent ${state.agentId}: home isolation passthrough failed (${failures.join("; ")}) \u2014 falling back to the shared HOME for this spawn so the runtime keeps its login`);
37267
+ isolation = void 0;
37268
+ } else {
37269
+ this.log.warn(`agent ${state.agentId}: home isolation passthrough incomplete (${failures.join("; ")}) \u2014 keeping the fake HOME (this runtime/source does not need the shared-login links)`);
37270
+ }
37271
+ }
37272
+ } catch (err) {
37273
+ this.log.warn(`agent ${state.agentId}: home isolation setup failed \u2014 falling back to the shared HOME for this spawn: ${String(err)}`);
37274
+ isolation = void 0;
37275
+ }
37276
+ }
37083
37277
  const adapter = getRuntimeAdapter(state.runtimeType);
37084
37278
  const dirs = {
37085
37279
  stateDir: agentStateDirFor(this.config.rootStateDir, state.agentId),
37086
37280
  workspaceDir: state.workspacePath,
37087
- claudeHome: state.claudeHome
37281
+ // Only the isolation-fallback case replaces claudeHome: K8s (isolation
37282
+ // never set) and legacy-shared children keep their state.claudeHome.
37283
+ claudeHome: state.homeIsolation && !isolation ? this.config.rootClaudeHome : state.claudeHome,
37284
+ homeDir: isolation?.homeDir
37088
37285
  };
37089
37286
  let baseEnv = { ...process.env, PRLL_API_URL: this.config.apiUrl };
37090
37287
  if (this.machineId)
37091
37288
  baseEnv.PRLL_MACHINE_ID = this.machineId;
37092
37289
  baseEnv = applyRuntimeBinaryEnv(state.runtimeType, baseEnv, this.log);
37093
- const effectiveProviderConfig = effectiveLLMSourceExplicit(state.providerConfig) ? state.providerConfig : { llm_source: this.machineLlmSource };
37094
37290
  const env = adapter.buildEnv(baseEnv, state.agentId, state.orgId, state.credential.api_key, dirs, effectiveProviderConfig);
37095
37291
  const spawnCmd = adapter.args.length > 0 ? `${adapter.bin} ${adapter.args.join(" ")}` : adapter.bin;
37096
37292
  this.log.info(`spawning agent ${state.agentId} runtime=${state.runtimeType} cmd=${spawnCmd} (attempt ${state.restartAttempts + 1})`);
@@ -37173,33 +37369,6 @@ var init_supervisor = __esm({
37173
37369
  child.once("exit", () => clearTimeout(hardKill));
37174
37370
  });
37175
37371
  }
37176
- ensureSharedCredentialLink(agentClaudeHome, agentId) {
37177
- const sharedCredentials = path16.resolve(sharedClaudeCredentialsFileFor(this.config.rootClaudeHome));
37178
- const agentCredentials = agentClaudeCredentialsFileFor(agentClaudeHome);
37179
- const agentCredentialsDir = path16.dirname(agentCredentials);
37180
- fs12.mkdirSync(path16.dirname(sharedCredentials), { recursive: true });
37181
- fs12.mkdirSync(agentCredentialsDir, { recursive: true });
37182
- try {
37183
- const existing = fs12.lstatSync(agentCredentials);
37184
- if (existing.isSymbolicLink()) {
37185
- const currentTarget = fs12.readlinkSync(agentCredentials);
37186
- if (path16.resolve(agentCredentialsDir, currentTarget) === sharedCredentials) {
37187
- return;
37188
- }
37189
- fs12.unlinkSync(agentCredentials);
37190
- } else if (existing.isDirectory()) {
37191
- this.log.warn(`agent ${agentId}: credential path is a directory, cannot link ${agentCredentials}`);
37192
- return;
37193
- } else {
37194
- fs12.unlinkSync(agentCredentials);
37195
- }
37196
- } catch (err) {
37197
- if (err.code !== "ENOENT") {
37198
- throw err;
37199
- }
37200
- }
37201
- fs12.symlinkSync(sharedCredentials, agentCredentials);
37202
- }
37203
37372
  };
37204
37373
  }
37205
37374
  });
@@ -37405,8 +37574,8 @@ var init_daemon_main = __esm({
37405
37574
  // ts/daemon/dist/index.js
37406
37575
  init_daemon_paths();
37407
37576
  init_daemon_update_mode();
37408
- import * as fs13 from "node:fs";
37409
- import * as path17 from "node:path";
37577
+ import * as fs14 from "node:fs";
37578
+ import * as path18 from "node:path";
37410
37579
  var UPDATE_EXIT_CODE2 = 42;
37411
37580
  function formatError2(reason) {
37412
37581
  if (reason instanceof Error) {
@@ -37422,7 +37591,7 @@ function errnoCode(err) {
37422
37591
  }
37423
37592
  function clearRunningMarker(markerPath) {
37424
37593
  try {
37425
- fs13.unlinkSync(markerPath);
37594
+ fs14.unlinkSync(markerPath);
37426
37595
  } catch (err) {
37427
37596
  if (errnoCode(err) === "ENOENT")
37428
37597
  return;
@@ -37431,15 +37600,15 @@ function clearRunningMarker(markerPath) {
37431
37600
  }
37432
37601
  function prepareDaemonBootstrap(env = process.env, args = process.argv.slice(2)) {
37433
37602
  const bundleDir = resolveBundleDir(env);
37434
- const runningMarker = path17.join(bundleDir, "daemon-running");
37603
+ const runningMarker = path18.join(bundleDir, "daemon-running");
37435
37604
  const lifecycleMarkerEnabled = args.length === 0 && !isSelfUpdateDisabledByEnv(env) && isSelfUpdateManaged(bundleDir, env);
37436
37605
  if (!lifecycleMarkerEnabled) {
37437
37606
  return { lifecycleMarkerEnabled: false, runningMarker, uncleanPrevExit: false };
37438
37607
  }
37439
- const uncleanPrevExit = fs13.existsSync(runningMarker);
37608
+ const uncleanPrevExit = fs14.existsSync(runningMarker);
37440
37609
  try {
37441
- fs13.mkdirSync(bundleDir, { recursive: true });
37442
- fs13.writeFileSync(runningMarker, String(process.pid));
37610
+ fs14.mkdirSync(bundleDir, { recursive: true });
37611
+ fs14.writeFileSync(runningMarker, String(process.pid));
37443
37612
  } catch (err) {
37444
37613
  console.warn(`failed to write daemon running marker: ${formatError2(err)}`);
37445
37614
  }