stim 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/{activity-B2-kb7k0.mjs → activity-BxwdD81S.mjs} +29 -16
  2. package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
  3. package/dist/{android-Db2eEMaf.mjs → android-B_NumVyQ.mjs} +21 -20
  4. package/dist/{android-Cu_L4RpL.mjs → android-Ift4kVvt.mjs} +56 -47
  5. package/dist/{android-cas-PnKfAdB2.mjs → android-cas-8U4DPqeR.mjs} +1 -1
  6. package/dist/{android-CYmq0jNi.mjs → android-r2rBL8kV.mjs} +1 -1
  7. package/dist/{app-install-CAAplXAt.mjs → app-install-CKWdbXIX.mjs} +48 -5
  8. package/dist/attempt-Bk2ouQVL.mjs +39 -0
  9. package/dist/{budget-CMiqghig.mjs → budget-DjrURfQn.mjs} +356 -366
  10. package/dist/{build-plan-aeGMFX7e.mjs → build-plan-DjeSb2Xl.mjs} +19 -20
  11. package/dist/{build-slots-Df1ApSuH.mjs → build-slots-rUk77xqh.mjs} +7 -2
  12. package/dist/{cli-0cX5s4NM.mjs → cli-BkYZ_6hy.mjs} +23 -17
  13. package/dist/cli.mjs +1 -1
  14. package/dist/{client-C2IS36Qf.mjs → client-BTY686R6.mjs} +57 -22
  15. package/dist/collector-run.mjs +5 -192
  16. package/dist/{command-output-CliHHn7a.mjs → command-output-DnJMdEY-.mjs} +1 -1
  17. package/dist/{created-devices-BwVb3liH.mjs → created-devices-D5owjN4C.mjs} +1 -1
  18. package/dist/{dependency-state-BmsjKZ2H.mjs → dependency-state-B6cMXZab.mjs} +1 -1
  19. package/dist/{deps-BFlKbOIp.mjs → deps-urbmfXig.mjs} +2 -2
  20. package/dist/{dev-client-CjzLoNs0.mjs → dev-client-CroAIjjj.mjs} +3 -40
  21. package/dist/{device-BZ1IyS5A.mjs → device-DZQjF7H5.mjs} +7 -6
  22. package/dist/{device-capacity-DMuKC7nx.mjs → device-capacity-BHwxNBlu.mjs} +2 -2
  23. package/dist/device-host-worker.mjs +223 -28
  24. package/dist/{device-ios-DMQBUPus.mjs → device-ios-BadmeL2V.mjs} +7 -7
  25. package/dist/{device-lease-W5Pi1q38.mjs → device-lease-D-hLqx1b.mjs} +2 -2
  26. package/dist/{device-pool-B2r38YjS.mjs → device-lease-run-CqjShqWW.mjs} +5 -125
  27. package/dist/device-pool-CUaEWMMm.mjs +125 -0
  28. package/dist/{device-remote-9ulPsdhY.mjs → device-remote-D5WVWqOq.mjs} +12 -12
  29. package/dist/{doctor-BcE5xsBn.mjs → doctor-Cimf-gGB.mjs} +80 -34
  30. package/dist/{error-diagnostics-Cb0P1WLS.mjs → error-diagnostics-B9L4Ae0x.mjs} +11 -15
  31. package/dist/{gc-BuL1Genr.mjs → gc-Bqy4bjEu.mjs} +194 -31
  32. package/dist/{gradle-CmdOBq1d.mjs → gradle-BsO1MdsH.mjs} +4 -4
  33. package/dist/{guide-cCSGRFd3.mjs → guide-B_uyKTxW.mjs} +588 -53
  34. package/dist/{guide-status-CIoWK6mG.mjs → guide-status-CjEZMAD4.mjs} +1 -1
  35. package/dist/hosted-client-a-WmqE2L.mjs +197 -0
  36. package/dist/hosted-ios-CIWelIqf.mjs +220 -0
  37. package/dist/hosted-logs-D5g041Q3.mjs +187 -0
  38. package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
  39. package/dist/{build-progress-C2Jv1AtA.mjs → idle-DYVymG92.mjs} +233 -6
  40. package/dist/{idle-shutdown-B5LPaNyY.mjs → idle-shutdown-CTsDnAde.mjs} +6 -6
  41. package/dist/{in-use-CndPMilN.mjs → in-use-DvBw0Kxo.mjs} +29 -9
  42. package/dist/{ios-3CtCRhwr.mjs → ios-BaInn3sW.mjs} +2 -2
  43. package/dist/ios-Cr1h5gnO.mjs +189 -0
  44. package/dist/{ios-Chob8ny7.mjs → ios-aq3QoGI3.mjs} +729 -452
  45. package/dist/{ios-device-DERmMmk-.mjs → ios-device-FfCN_C8p.mjs} +1 -1
  46. package/dist/ios-state-DS5UpYTH.mjs +48 -0
  47. package/dist/{launch-verify-CLlofxRt.mjs → launch-verify-2DBRizjo.mjs} +3 -3
  48. package/dist/logs-CHEVK8zD.mjs +371 -0
  49. package/dist/{machines-CYtOCqcj.mjs → machines-BIBUdhpj.mjs} +16 -10
  50. package/dist/{macos-BwtbUtTN.mjs → macos-CSYEAFmF.mjs} +22 -17
  51. package/dist/macos-run.mjs +1 -1
  52. package/dist/maintenance-run.d.mts +4 -0
  53. package/dist/maintenance-run.mjs +254 -0
  54. package/dist/{metro-Di8EN2Tb.mjs → metro-BeK1ZPz1.mjs} +1 -1
  55. package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
  56. package/dist/{named-ports-Dj_XBNaL.mjs → named-ports-Bk_YXEmE.mjs} +1 -1
  57. package/dist/{native-run-DFDoIRbY.mjs → native-run-NaBrRFtQ.mjs} +2 -2
  58. package/dist/{native-runtime-i6OkVg-w.mjs → native-runtime-DBzRnEKS.mjs} +6 -6
  59. package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
  60. package/dist/offload-worker.d.mts +1 -0
  61. package/dist/offload-worker.mjs +13 -8
  62. package/dist/{ownership-BkYxUtuj.mjs → ownership-DiA16AsN.mjs} +2 -2
  63. package/dist/{stop-cause-CZ_Mr-v9.mjs → ownership-hCkPzGmr.mjs} +4 -98
  64. package/dist/{ports-DddwttKM.mjs → ports-R2k4Knz3.mjs} +2 -2
  65. package/dist/{prebuild-BvxDlD6C.mjs → prebuild-D2fsca_Z.mjs} +4 -4
  66. package/dist/preview-DhVbvPAZ.mjs +318 -0
  67. package/dist/{project-CV3tDFHl.mjs → project-Du91Ilvc.mjs} +67 -3
  68. package/dist/{recordings-GEXp4iBT.mjs → recordings-BIXOzVnr.mjs} +1 -1
  69. package/dist/{reload-ChPiwvot.mjs → reload-rM9jV1fz.mjs} +49 -12
  70. package/dist/{remote-cache-CO2elm_b.mjs → remote-cache-C8-V13XN.mjs} +4 -4
  71. package/dist/{run-B-xqRrsg.mjs → run-f4vI6EnK.mjs} +2 -2
  72. package/dist/{server-bare-X7PUgizL.mjs → server-bare-CpPGmnmO.mjs} +1 -1
  73. package/dist/server-expo-CVqO2c35.mjs +2 -0
  74. package/dist/{server-expo-DhtX6bom.mjs → server-expo-MC0rHlOC.mjs} +4 -4
  75. package/dist/settings-BBpMcDbD.mjs +25 -0
  76. package/dist/{settings-DbL6uhH8.mjs → settings-ZkDzkzvB.mjs} +10 -4
  77. package/dist/settings-oTSkkNrM.mjs +1439 -0
  78. package/dist/settings.schema.json +432 -39
  79. package/dist/{simslim-Ciluxlq4.mjs → simslim-B8-7AoTI.mjs} +3 -3
  80. package/dist/{slot-launch-BY0BrOLh.mjs → slot-launch-B8VrHxn1.mjs} +10 -7
  81. package/dist/{spawn-entry-DncpJvWL.mjs → spawn-entry-jw19m8Nl.mjs} +1 -0
  82. package/dist/{start-CPO4wRg7.mjs → start-CX8Ig-U2.mjs} +1 -1
  83. package/dist/{start-CUD9nasA.mjs → start-ClDfwXa4.mjs} +21 -17
  84. package/dist/{state-BxCgeTQu.mjs → state-3DwSQIBK.mjs} +2 -2
  85. package/dist/{state-DFm77wRn.mjs → state-C1jB7Q8q.mjs} +5 -5
  86. package/dist/{state-CaeaHbDA.mjs → state-DcW6vOd_.mjs} +1 -1
  87. package/dist/{stats-DBLLFmKd.mjs → stats-CEZ_i5je.mjs} +16 -5
  88. package/dist/{status-l84Gbvp2.mjs → status-BuvBFeII.mjs} +5 -3
  89. package/dist/{status-DYXxNOT0.mjs → status-Cs7VLg9D.mjs} +148 -44
  90. package/dist/status-DlKvVJBE.mjs +49 -0
  91. package/dist/{stop-Bvf1MflS.mjs → stop-B0Yxtmiy.mjs} +3 -3
  92. package/dist/{stop-Bad61z_2.mjs → stop-Bffozsac.mjs} +61 -20
  93. package/dist/{stop-CceYh1yG.mjs → stop-Dt_dM16A.mjs} +2 -2
  94. package/dist/stop-cause-CidxIqup.mjs +97 -0
  95. package/dist/supervisor-run.mjs +148 -17
  96. package/dist/{support-CDQbDkL5.mjs → support-CAP8qDUF.mjs} +4 -3
  97. package/dist/{support-WLOzVKUv.mjs → support-D4aYJniO.mjs} +34 -9
  98. package/dist/{teardown-BYuQafiA.mjs → teardown-CL6vDs2Y.mjs} +56 -47
  99. package/dist/{toolchain-DmeYjXD9.mjs → toolchain-DkUflduf.mjs} +10 -10
  100. package/dist/trigger-Bemu8ytw.mjs +65 -0
  101. package/dist/trigger-CXts6qt1.mjs +2 -0
  102. package/dist/{warm-progress-DVHLN4uC.mjs → warm-progress-CpGv3Wb6.mjs} +274 -5
  103. package/dist/{web-k6w8-HnE.mjs → web-DWUaMp8P.mjs} +15 -16
  104. package/dist/web-run.mjs +5 -5
  105. package/dist/{workspace-state-CL2V2Ons.mjs → workspace-state-B8-aJ1_5.mjs} +33 -33
  106. package/dist/workspaces-BV4pdHFz.mjs +306 -0
  107. package/dist/{worktree-qXKzADSC.mjs → worktree-K-xj9Db0.mjs} +497 -30
  108. package/dist/{worktree-BT_uULFx.mjs → worktree-jnG8Iph5.mjs} +1 -1
  109. package/package.json +5 -5
  110. package/dist/hosted-macos-DwowNU7W.mjs +0 -447
  111. package/dist/logs-h9h6MUvE.mjs +0 -568
  112. package/dist/machine-usage-D_YYMzfR.mjs +0 -283
  113. package/dist/merge-state-BnxLNQiM.mjs +0 -272
  114. package/dist/server-expo-KJeD109I.mjs +0 -2
  115. package/dist/settings-CduVcoxj.mjs +0 -680
  116. package/dist/watchman-Bx0wceoF.mjs +0 -238
  117. package/dist/worktree-C0c5Udwa.mjs +0 -753
@@ -2,31 +2,119 @@ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { A as directorySize, D as withConfigLock$1, F as volumeRootFor, H as projectDeviceSlots, M as isOnMountedVolume, N as listMountedVolumes, S as removeProject, _ as loadConfig$1, j as formatBytes, k as acquireAvdClaim, p as getProject } from "./config-D0DbpZtM.mjs";
3
3
  import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
4
4
  import { n as describePullRequest, o as pullRequestLookups, r as endedPullRequest } from "./pull-request-pxnDCQzn.mjs";
5
- import { C as workspaceLogsDir, E as withDirLock$1, T as workspaceStateFile, b as workspaceDir, s as workspaceLastUsed } from "./workspace-state-CL2V2Ons.mjs";
6
- import { C as sourceCheckoutOf, b as resolveFullRef, d as hasUncommittedWork, l as hasPopulatedSubmodules, m as listWorktrees, o as dirtyPaths, w as unpushedCommits } from "./worktree-C0c5Udwa.mjs";
7
- import { a as findProjectRoot$1, r as detectIsExpo } from "./project-CV3tDFHl.mjs";
8
- import { h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-CliHHn7a.mjs";
9
- import { d as removeExpiredLease, h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-W5Pi1q38.mjs";
10
- import { A as listAvds, H as parseAvdSystemImage, I as ownedAvdDirectory, M as listOrphanedAvdDirectories, V as parseAvdDeviceProfile, _ as avdStorageRoots, at as POOL_SETTING_REMEDY, d as androidToolPath, dt as parkedMaxSetting, ft as readParked, it as isStimOwnedSim, j as listInstalledSystemImages, m as avdNameAbsent, o as androidHome, p as avdIniPaths, rt as isStimOwnedAvd, z as ownedAvdSerialResolver } from "./android-Db2eEMaf.mjs";
11
- import { n as readCreatedDevices$1, t as forgetCreatedDevice } from "./created-devices-BwVb3liH.mjs";
12
- import { u as listAllIosSims } from "./ios-3CtCRhwr.mjs";
13
- import { d as parseIdleDuration, f as shutDownIdleDevices, h as takeGcResults, l as idleDeviceLines, m as recordGcResult, s as collectIdleDevices } from "./watchman-Bx0wceoF.mjs";
14
- import { i as canonicalPath, n as withIdleWorkspace, r as workspaceInUse } from "./in-use-CndPMilN.mjs";
15
- import { n as listBuildSlots } from "./build-slots-Df1ApSuH.mjs";
16
- import { r as readCollectors } from "./ownership-BkYxUtuj.mjs";
17
- import { f as resolveEasCliBin } from "./remote-cache-CO2elm_b.mjs";
18
- import { C as listOwnedSessionsArgs, D as verifyStoppedSession, E as stopSessionArgs, S as isDefinitiveMissingSessionError, T as parseSessionListPage, b as getSessionArgs, d as withRemoteSessionLock, f as withEasProjectLock, h as removeEasSessionClaim, m as readEasSessionLedger$1, p as easMachineStateRoot$1, x as inspectSessionForTeardown, y as findOrphanedOwnedSessions } from "./device-remote-9ulPsdhY.mjs";
19
- import { $ as discoverCaches, A as withAndroidAvdSizes, B as trimCaches, C as describeUnverifiableDevices, D as findStaleDeviceRecords, E as findOrphanedDevices, F as isWorkspacesScope, G as memoryCacheKind, I as planCacheEmptying, J as memorySweepIsScoped, K as memoryLines, L as previewScopedEmptying, M as includesParkedDevices, N as includesRecordings, O as findStaleProjectDevices, P as includesWorkspaceOutputs, Q as phase, R as selectCaches, S as describeParkedSims, T as eraseParkedDevices, U as collectMemoryReport, X as reclaimMemory, Y as memoryWorkPending, Z as scopedMemoryReport, _ as collectParkedAvds, a as REBUILD_COST, b as deleteParkedSims, c as collectOrphanedWorkspaces, d as isInsideWorkspaces, et as sizeCaches, f as listWorkspaceDirs, g as collectDeviceLeases, h as DEVICE_LIST_TIMEOUT_MS, i as machineNumber, j as emptyCaches, k as unverifiedDeviceCommand, l as collectWorkspaceOutputs, m as sizeText, o as WORKSPACE_OUTPUT_DIRS, p as rootPresence, q as memoryScope, s as clearWorkspaceOutputs, u as deleteOrphanedWorkspaces, v as collectParkedSims, w as deviceSweepIsScoped, x as deleteProjectDevices, y as deleteParkedAvds, z as selectsBeyondCaches } from "./budget-CMiqghig.mjs";
20
- import { f as removeWorktreeTarget, g as reclaimProject, h as describeDereferenced, i as matchWorktreeEntry, n as excludePodChurn, o as reclaimKeys, r as excludeWatchmanCookies } from "./worktree-qXKzADSC.mjs";
21
- import { n as mergeState, t as fetchDefaultBranch } from "./merge-state-BnxLNQiM.mjs";
5
+ import { h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-DnJMdEY-.mjs";
6
+ import { _t as resolveFullRef, bt as sourceCheckoutOf, ct as hasUncommittedWork, dt as listWorktrees, ot as hasPopulatedSubmodules, rt as dirtyPaths, xt as unpushedCommits } from "./settings-oTSkkNrM.mjs";
7
+ import { o as findProjectRoot$1, r as detectIsExpo } from "./project-Du91Ilvc.mjs";
8
+ import { C as workspaceStateFile, s as workspaceLastUsed, v as workspaceDir, w as withDirLock$1, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
9
+ import { A as isWorkspacesScope, B as memoryCacheKind, C as unverifiedDeviceCommand, D as includesParkedDevices, E as includesArchives, F as trimCaches, G as reclaimMemory, H as memoryScope, K as scopedMemoryReport, M as previewScopedEmptying, N as selectCaches, O as includesRecordings, P as selectsBeyondCaches, R as collectMemoryReport, S as findStaleProjectDevices, T as emptyCaches, U as memorySweepIsScoped, V as memoryLines, W as memoryWorkPending, X as discoverCaches, Z as sizeCaches, _ as describeUnverifiableDevices, a as machineNumber, b as findOrphanedDevices, d as collectParkedAvds, f as collectParkedSims, g as describeParkedSims, h as deleteProjectDevices, j as planCacheEmptying, k as includesWorkspaceOutputs, l as DEVICE_LIST_TIMEOUT_MS, m as deleteParkedSims, p as deleteParkedAvds, q as phase, u as collectDeviceLeases, v as deviceSweepIsScoped, w as withAndroidAvdSizes, x as findStaleDeviceRecords, y as eraseParkedDevices } from "./budget-DjrURfQn.mjs";
10
+ import { a as takeGcResults, i as recordGcResult, n as withIdleWorkspace, o as canonicalPath, r as workspaceInUse } from "./in-use-DvBw0Kxo.mjs";
11
+ import { d as removeExpiredLease, h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-D-hLqx1b.mjs";
12
+ import { n as listBuildSlots } from "./build-slots-rUk77xqh.mjs";
13
+ import { a as parseIdleDuration, o as shutDownIdleDevices, r as idleDeviceLines, t as collectIdleDevices } from "./idle-DYVymG92.mjs";
14
+ import { n as readCreatedDevices$1, t as forgetCreatedDevice } from "./created-devices-D5owjN4C.mjs";
15
+ import { A as listAvds, H as parseAvdSystemImage, I as ownedAvdDirectory, M as listOrphanedAvdDirectories, V as parseAvdDeviceProfile, _ as avdStorageRoots, at as isStimOwnedSim, d as androidToolPath, ft as parkedMaxSetting, it as isStimOwnedAvd, j as listInstalledSystemImages, m as avdNameAbsent, o as androidHome, ot as POOL_SETTING_REMEDY, p as avdIniPaths, pt as readParked, z as ownedAvdSerialResolver } from "./android-B_NumVyQ.mjs";
16
+ import { u as listAllIosSims } from "./ios-BaInn3sW.mjs";
17
+ import { a as collectWorkspaceOutputs, c as listWorkspaceDirs, i as collectOrphanedWorkspaces, l as rootPresence, n as WORKSPACE_OUTPUT_DIRS, o as deleteOrphanedWorkspaces, r as clearWorkspaceOutputs, s as isInsideWorkspaces, t as REBUILD_COST, u as sizeText } from "./workspaces-BV4pdHFz.mjs";
18
+ import { n as previewMaintenance } from "./preview-DhVbvPAZ.mjs";
19
+ import { r as readCollectors } from "./ownership-DiA16AsN.mjs";
20
+ import { f as resolveEasCliBin } from "./remote-cache-C8-V13XN.mjs";
21
+ import { C as listOwnedSessionsArgs, D as verifyStoppedSession, E as stopSessionArgs, S as isDefinitiveMissingSessionError, T as parseSessionListPage, b as getSessionArgs, d as withRemoteSessionLock, f as withEasProjectLock, h as removeEasSessionClaim, m as readEasSessionLedger$1, p as easMachineStateRoot$1, x as inspectSessionForTeardown, y as findOrphanedOwnedSessions } from "./device-remote-D5WVWqOq.mjs";
22
+ import { o as fetchDefaultBranch, s as mergeState } from "./warm-progress-CpGv3Wb6.mjs";
23
+ import { _ as deleteSelectedArchives, f as removeWorktreeTarget, g as reclaimProject, h as describeDereferenced, i as matchWorktreeEntry, n as excludePodChurn, o as reclaimKeys, r as excludeWatchmanCookies, v as sweepArchiveStaging } from "./worktree-K-xj9Db0.mjs";
24
+ import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-Dpih1Tfa.mjs";
22
25
  import { existsSync, lstatSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
23
26
  import { basename, dirname, join } from "node:path";
24
- import { closeSync as closeSync$1, existsSync as existsSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readSync as readSync$1, readdirSync as readdirSync$1, renameSync as renameSync$1, rmSync as rmSync$1, statSync as statSync$1, utimesSync, writeFileSync as writeFileSync$1 } from "fs";
27
+ import { closeSync as closeSync$1, existsSync as existsSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readSync as readSync$1, readdirSync as readdirSync$1, renameSync as renameSync$1, rmSync as rmSync$1, statSync as statSync$1, utimesSync as utimesSync$1, writeFileSync as writeFileSync$1 } from "fs";
25
28
  import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1 } from "path";
26
29
  import { LOG_ROTATE_BYTES, rotatedLogPath } from "@stim-cli/core";
27
30
  import { InvalidArgumentError } from "commander";
28
- import { listRecordedDevices, listStatusCacheEntries, recordedBytes, settingDefinition } from "@stim-cli/core/state";
31
+ import { listRecordedDevices, listStatusCacheEntries, maintenanceRunClaims, readArchives, recordedBytes, settingDefinition } from "@stim-cli/core/state";
29
32
  import chalk from "chalk";
33
+ //#region src/commands/gc/archives.ts
34
+ function stagingOrNone() {
35
+ try {
36
+ return sweepArchiveStaging(false, 5e3);
37
+ } catch {
38
+ return [];
39
+ }
40
+ }
41
+ function collectArchives(scope, olderThan, now) {
42
+ const wanted = scope.trim().toLowerCase();
43
+ const records = readArchives();
44
+ const id = wanted.startsWith("archived:") ? scope.trim().slice(9) : null;
45
+ const kind = wanted === "archived-logs" ? "logs" : wanted === "archived-recordings" ? "recordings" : wanted === "archived-agent" ? "agentActions" : null;
46
+ const match = id !== null ? records.find((record) => record.id.toLowerCase() === id.toLowerCase()) : null;
47
+ return {
48
+ records: records.filter((record) => id === null || record.id === match?.id).map((record) => ({
49
+ id: record.id,
50
+ kinds: kind ? [kind] : [
51
+ "logs",
52
+ "recordings",
53
+ "agentActions",
54
+ "record"
55
+ ].filter((key) => record.bytes[key] > 0),
56
+ bytes: kind ? record.bytes[kind] : record.bytes.total,
57
+ expires: record.expires,
58
+ willDelete: (id === null && olderThan !== null ? now - Date.parse(record.removedAt) >= olderThan * 864e5 : true) && (!kind || record.bytes[kind] > 0)
59
+ })),
60
+ staging: stagingOrNone(),
61
+ unknownId: id !== null && !match ? id : null,
62
+ knownIds: records.map((record) => record.id),
63
+ kind
64
+ };
65
+ }
66
+ function archiveLines(selection) {
67
+ if (!selection) return [];
68
+ return [
69
+ `Archived workspaces (${selection.records.length}):`,
70
+ ...selection.records.map((record) => ` ${record.id}: ${record.kinds.join(", ")}, ${formatBytes(record.bytes)}, expires ${JSON.stringify(record.expires)}${record.willDelete ? "" : " (kept)"}`),
71
+ ...selection.staging.map((entry) => ` ${entry.path}: ${entry.kept ? `kept: ${entry.reason}` : "abandoned staging"}${entry.removeCommand ? `; ${entry.removeCommand}` : ""}`)
72
+ ];
73
+ }
74
+ function deleteArchives(selection) {
75
+ if (!selection) return 0;
76
+ let failures = 0;
77
+ for (const record of selection.records.filter((entry) => entry.willDelete)) try {
78
+ deleteSelectedArchives([record.id], selection.kind);
79
+ recordGcResult("archive", "done", record.id, {
80
+ id: record.id,
81
+ bytes: record.bytes
82
+ });
83
+ } catch (error) {
84
+ failures++;
85
+ recordGcResult("archive", "failed", record.id, {
86
+ id: record.id,
87
+ detail: error.message
88
+ });
89
+ console.error(`Could not delete ${record.id}: ${error.message}`);
90
+ }
91
+ try {
92
+ const remaining = new Set(sweepArchiveStaging(true, 5e3).map((entry) => entry.path));
93
+ for (const entry of selection.staging) if (!entry.kept && !remaining.has(entry.path)) recordGcResult("archive", "done", "archive staging", { id: entry.path });
94
+ } catch (error) {
95
+ failures++;
96
+ console.error(`Could not clear archive staging: ${error.message}`);
97
+ }
98
+ return failures;
99
+ }
100
+ function archiveRefusal(selection) {
101
+ if (selection?.unknownId === void 0 || selection.unknownId === null) return null;
102
+ process.exitCode = 1;
103
+ const message = `Unknown archive "${selection.unknownId}".`;
104
+ const remedy = `Known archive ids: ${selection.knownIds.join(", ") || "(none)"}`;
105
+ console.error(chalk.red(message));
106
+ console.error(chalk.dim(remedy));
107
+ console.error(chalk.red("failed: STIM_BAD_ARG"));
108
+ return {
109
+ code: "STIM_BAD_ARG",
110
+ message,
111
+ remedy
112
+ };
113
+ }
114
+ function archiveWorkPending(selection, otherWork) {
115
+ return otherWork || Boolean(selection?.records.some((record) => record.willDelete) || selection?.staging.some((entry) => !entry.kept));
116
+ }
117
+ //#endregion
30
118
  //#region src/commands/gc/eas-sessions.ts
31
119
  const EAS_OPERATION_TIMEOUT_MS = 3e4;
32
120
  const EAS_COLLECTION_TIMEOUT_MS = 6e4;
@@ -608,7 +696,7 @@ function newestMtime(paths) {
608
696
  return newest;
609
697
  }
610
698
  function logFiles$1(key) {
611
- const dir = workspaceLogsDir(key);
699
+ const dir = workspaceLogsDir$1(key);
612
700
  try {
613
701
  return readdirSync$1(dir).map((name) => ({
614
702
  path: join$1(dir, name),
@@ -1142,7 +1230,19 @@ function scopeLine(cacheScope) {
1142
1230
  if (memoryCacheKind(cacheScope)) return `Cache scope: "${cacheScope}". Only these helper processes were inspected.`;
1143
1231
  return includesParkedDevices(cacheScope) ? `Cache scope: "${cacheScope}". Unparked devices, project entries and locks were not inspected.` : `Cache scope: "${cacheScope}". Devices, project entries and locks were not inspected.`;
1144
1232
  }
1145
- function formatGcReport({ skipped = [], deadProjects = [], orphanedPorts, invalidProjects = [], orphanedWorkspaces = [], parkedSims = [], parkedAvds = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1233
+ function maintenanceReportLines(maintenance) {
1234
+ const lines = [];
1235
+ if (maintenance) {
1236
+ lines.push(`Automatic maintenance (${maintenance.mode === "report" ? "report only" : "off"}):`);
1237
+ if (maintenance.note) lines.push(` ${maintenance.note}`);
1238
+ for (const action of maintenance.actions) lines.push(` ${action.kind}: ${action.target} (${formatBytes(action.bytes)}): ${action.reason}`);
1239
+ for (const skip of maintenance.skips) lines.push(` kept ${skip.target}: ${skip.reason}`);
1240
+ for (const reason of maintenance.blocked) lines.push(` blocked: ${reason}`);
1241
+ if (!maintenance.actions.length && !maintenance.blocked.length) lines.push(" no actions planned");
1242
+ }
1243
+ return lines;
1244
+ }
1245
+ function formatGcReport({ maintenance, archives, skipped = [], deadProjects = [], orphanedPorts, invalidProjects = [], orphanedWorkspaces = [], parkedSims = [], parkedAvds = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1146
1246
  stale: [],
1147
1247
  live: [],
1148
1248
  unresolved: []
@@ -1158,8 +1258,8 @@ function formatGcReport({ skipped = [], deadProjects = [], orphanedPorts, invali
1158
1258
  orphaned: [],
1159
1259
  notices: [],
1160
1260
  deletionSafe: true
1161
- }, caches = [], workspaceOutputs = null, workspaceLogs = [], recordings = [], worktreeSweep = null, memory, cacheScope = null, olderThan = null }, { now = Date.now() } = {}) {
1162
- const lines = [];
1261
+ }, agentDeviceUsage = null, swiftpmCacheUsage, caches = [], workspaceOutputs = null, workspaceLogs = [], recordings = [], worktreeSweep = null, memory, cacheScope = null, olderThan = null }, { now = Date.now() } = {}) {
1262
+ const lines = archiveLines(archives);
1163
1263
  const staleLocks = buildLocks?.stale ?? [];
1164
1264
  const liveLocks = buildLocks?.live ?? [];
1165
1265
  const staleSlots = buildSlots?.stale ?? [];
@@ -1279,7 +1379,10 @@ function formatGcReport({ skipped = [], deadProjects = [], orphanedPorts, invali
1279
1379
  lines.push(...workspaceLogLines(workspaceLogs));
1280
1380
  lines.push(...recordingLines(recordings));
1281
1381
  lines.push(...cacheLines(caches, workspaceOutputs));
1382
+ lines.push(...agentDeviceLines(agentDeviceUsage, true, now));
1383
+ lines.push(...swiftpmCacheLines(swiftpmCacheUsage, now));
1282
1384
  lines.push(...memoryLines(memory, memoryCacheKind(cacheScope), now));
1385
+ lines.push(...maintenanceReportLines(maintenance));
1283
1386
  return lines;
1284
1387
  }
1285
1388
  function workspaceLogLines(workspaceLogs) {
@@ -1410,7 +1513,7 @@ function jsonPullRequest(lookup) {
1410
1513
  containsHead: pr.containsHead
1411
1514
  } : null;
1412
1515
  }
1413
- function gcReportSections({ skipped = [], deadProjects = [], orphanedPorts = [], invalidProjects = [], orphanedWorkspaces = [], worktreeSweep = null, parkedSims = [], parkedAvds = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1516
+ function gcReportSections({ archives, skipped = [], deadProjects = [], orphanedPorts = [], invalidProjects = [], orphanedWorkspaces = [], worktreeSweep = null, parkedSims = [], parkedAvds = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1414
1517
  stale: [],
1415
1518
  live: [],
1416
1519
  unresolved: []
@@ -1426,8 +1529,12 @@ function gcReportSections({ skipped = [], deadProjects = [], orphanedPorts = [],
1426
1529
  orphaned: [],
1427
1530
  notices: [],
1428
1531
  deletionSafe: true
1429
- }, workspaceOutputs = null, workspaceLogs = [], recordings = [], caches = [], memory = null }) {
1532
+ }, workspaceOutputs = null, workspaceLogs = [], recordings = [], agentDeviceUsage = null, swiftpmCacheUsage = null, caches = [], memory = null }) {
1430
1533
  return {
1534
+ ...archives ? {
1535
+ archived: archives.records,
1536
+ archiveStaging: archives.staging
1537
+ } : {},
1431
1538
  deadProjects: deadProjects.map((path) => ({ path })),
1432
1539
  invalidProjects: invalidProjects.map((path) => ({ path })),
1433
1540
  orphanedPorts: orphanedPorts.map(({ project, label, port }) => ({
@@ -1597,6 +1704,8 @@ function gcReportSections({ skipped = [], deadProjects = [], orphanedPorts = [],
1597
1704
  emptySkipped: c.emptySkipped ?? null,
1598
1705
  scopedEmpty: c.scopedEmpty ?? null
1599
1706
  })),
1707
+ agentDevice: agentDeviceUsage,
1708
+ swiftpmCache: swiftpmCacheUsage,
1600
1709
  memory: memory?.processes ?? [],
1601
1710
  watchmanRoots: memory?.watchmanRoots ?? [],
1602
1711
  memoryNotices: (memory?.notices ?? []).map((message) => ({ message }))
@@ -1788,7 +1897,7 @@ function trimToNewest({ file, log }, maxBytes) {
1788
1897
  const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
1789
1898
  try {
1790
1899
  writeFileSync$1(tmp, kept);
1791
- utimesSync(tmp, atime, mtime);
1900
+ utimesSync$1(tmp, atime, mtime);
1792
1901
  renameSync$1(tmp, file);
1793
1902
  } catch (error) {
1794
1903
  rmSync$1(tmp, { force: true });
@@ -2153,6 +2262,7 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2153
2262
  const sized = sizeCaches(selected);
2154
2263
  const caches = scope === null ? previewScopedEmptying(sized) : planCacheEmptying(sized, all);
2155
2264
  if (scope) return {
2265
+ archives: includesArchives(scope) ? collectArchives(scope, olderThan, now) : void 0,
2156
2266
  skipped: [],
2157
2267
  deadProjects: [],
2158
2268
  invalidProjects: [],
@@ -2207,10 +2317,16 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2207
2317
  }) : [],
2208
2318
  worktreeSweep: null,
2209
2319
  memory: memoryCacheKind(scope) ? await collectGcMemory(memoryScope(scope)) : null,
2320
+ agentDeviceUsage: null,
2321
+ swiftpmCacheUsage: null,
2210
2322
  cacheScope: scope,
2211
2323
  olderThan,
2212
2324
  all
2213
2325
  };
2326
+ phase("agent-device", "measuring report-only state");
2327
+ const agentDeviceUsage = await getAgentDeviceUsage();
2328
+ phase("SwiftPM cache", "measuring report-only state");
2329
+ const swiftpmCacheUsage = await getSwiftpmCacheUsage();
2214
2330
  const mountedVolumes = listMountedVolumes();
2215
2331
  const cfg = loadConfig$1();
2216
2332
  let easSessionSweep = deps.precollectedEasSessionSweep;
@@ -2387,6 +2503,8 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2387
2503
  watchman: true,
2388
2504
  gradle: true
2389
2505
  }),
2506
+ agentDeviceUsage,
2507
+ swiftpmCacheUsage,
2390
2508
  cacheScope: null,
2391
2509
  olderThan,
2392
2510
  all
@@ -2394,19 +2512,53 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2394
2512
  }
2395
2513
  async function runGc(opts = {}, deps = {}) {
2396
2514
  if (!opts.json) {
2397
- await sweep(opts, deps);
2515
+ await maintenanceGuardedSweep(opts, deps);
2398
2516
  return;
2399
2517
  }
2400
2518
  const log = console.log;
2401
2519
  console.log = console.error;
2402
2520
  let payload;
2403
2521
  try {
2404
- payload = await sweep(opts, deps);
2522
+ payload = await maintenanceGuardedSweep(opts, deps);
2405
2523
  } finally {
2406
2524
  console.log = log;
2407
2525
  }
2408
2526
  console.log(JSON.stringify(payload));
2409
2527
  }
2528
+ async function maintenanceGuardedSweep(opts, deps) {
2529
+ if (!opts.delete) return sweep(opts, deps);
2530
+ let claim;
2531
+ try {
2532
+ const root = maintenanceRunClaims();
2533
+ const attempt = (0, ownership_claim_exports.tryAcquireClaim)({
2534
+ root,
2535
+ mode: "exclusive",
2536
+ label: "maintenance",
2537
+ details: { trigger: "gc --delete" }
2538
+ });
2539
+ if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
2540
+ claim = attempt.acquired;
2541
+ if (!claim) {
2542
+ const holder = attempt.held ?? attempt.waitingFor?.[0];
2543
+ throw new ownership_claim_exports.ClaimRefusedError({
2544
+ root,
2545
+ claimPath: holder?.path ?? root,
2546
+ label: "maintenance",
2547
+ reason: `held by pid ${holder?.owner.pid ?? "?"} since ${holder?.startedAt ?? "?"} (${String(holder?.details.trigger ?? "maintenance")})`
2548
+ });
2549
+ }
2550
+ return await sweep(opts, deps);
2551
+ } catch (error) {
2552
+ const failure = (0, ownership_claim_exports.claimFailure)(error, "stim gc --delete");
2553
+ if (!failure) throw error;
2554
+ console.error(`${failure.code}: ${failure.message}`);
2555
+ console.error(failure.remedy);
2556
+ process.exitCode = 1;
2557
+ return failure;
2558
+ } finally {
2559
+ if (claim) (0, ownership_claim_exports.releaseClaim)(claim);
2560
+ }
2561
+ }
2410
2562
  async function sweep(opts, deps) {
2411
2563
  if (opts.cache && (opts.worktrees || opts.idle !== void 0)) {
2412
2564
  const flag = opts.worktrees ? "--worktrees" : "--idle";
@@ -2512,7 +2664,10 @@ async function pruneDeadProjects(deadProjects) {
2512
2664
  recordGcResult("project", "kept", path, { detail: "its absence can no longer be confirmed" });
2513
2665
  continue;
2514
2666
  }
2515
- const result = await reclaimProject(path, { stopRequester: { by: "stim gc --delete" } }).catch((error) => {
2667
+ const result = await reclaimProject(path, {
2668
+ archive: { removedBy: "gc" },
2669
+ stopRequester: { by: "stim gc --delete" }
2670
+ }).catch((error) => {
2516
2671
  deleteFailures++;
2517
2672
  console.log(chalk.red(`Could not prune ${path}; its registry entry was kept: ${error.message}`));
2518
2673
  recordGcResult("project", "failed", path, { detail: `its registry entry was kept: ${error.message}` });
@@ -2547,6 +2702,9 @@ async function pruneDeadProjects(deadProjects) {
2547
2702
  }
2548
2703
  return deleteFailures;
2549
2704
  }
2705
+ async function attachMaintenancePreview(report, deleting, cache) {
2706
+ if (!deleting) report.maintenance = await previewMaintenance({ devices: !cache });
2707
+ }
2550
2708
  function scopedDryRunAction(cache) {
2551
2709
  const memory = memoryCacheKind(cache);
2552
2710
  if (memory === "watchman") return "remove the stale roots and shut down the unused watchman";
@@ -2587,10 +2745,13 @@ async function runGcCore(opts, deps) {
2587
2745
  remedy: names.length ? `Pass --cache all or a name from: ${names.join(", ")}.` : "No shared cache was found on this machine."
2588
2746
  };
2589
2747
  }
2748
+ await attachMaintenancePreview(report, opts.delete === true, cache);
2749
+ const refusal = archiveRefusal(report.archives);
2750
+ if (refusal !== null) return refusal;
2590
2751
  const all = report.all;
2591
2752
  for (const line of formatGcReport(report)) console.log(line);
2592
2753
  const { deadProjects, invalidProjects, orphanedDevices, staleDevices, staleDeviceRecords, buildLocks, buildSlots, deviceLeases, easSessionSweep, caches } = report;
2593
- const actionable = deadProjects.length + invalidProjects.length > 0 || report.orphanedWorkspaces.length > 0 || Boolean(report.workspaceOutputs?.workspaces.some((entry) => entry.willClear)) || report.workspaceLogs.some((entry) => entry.willTrim) || report.recordings.some((entry) => entry.willDelete && !entry.withWorkspace) || Boolean(report.worktreeSweep?.worktrees.some((entry) => !entry.skipped)) || report.parkedSims.length > 0 || report.parkedAvds.length > 0 || orphanedDevices.length > 0 || staleDevices.length > 0 || staleDeviceRecords.length > 0 || report.staleLedgerEntries.length > 0 || report.staleStatusCaches.length > 0 || buildLocks.stale.length > 0 || buildSlots.stale.length > 0 || deviceLeases.expired.length > 0 || easSessionSweep.orphaned.length > 0 || (olderThan !== null || all) && caches.length > 0 || memoryWorkPending(cache, report.memory);
2754
+ const actionable = archiveWorkPending(report.archives, deadProjects.length + invalidProjects.length > 0 || report.orphanedWorkspaces.length > 0 || Boolean(report.workspaceOutputs?.workspaces.some((entry) => entry.willClear)) || report.workspaceLogs.some((entry) => entry.willTrim) || report.recordings.some((entry) => entry.willDelete && !entry.withWorkspace) || Boolean(report.worktreeSweep?.worktrees.some((entry) => !entry.skipped)) || report.parkedSims.length > 0 || report.parkedAvds.length > 0 || orphanedDevices.length > 0 || staleDevices.length > 0 || staleDeviceRecords.length > 0 || report.staleLedgerEntries.length > 0 || report.staleStatusCaches.length > 0 || buildLocks.stale.length > 0 || buildSlots.stale.length > 0 || deviceLeases.expired.length > 0 || easSessionSweep.orphaned.length > 0 || (olderThan !== null || all) && caches.length > 0 || memoryWorkPending(cache, report.memory));
2594
2755
  const idle = opts.idle ?? null;
2595
2756
  const idleFailures = idle === null ? 0 : shutDownIdleDevices(report.idleDevices, idle, () => collectIdleDevices(loadConfig$1(), listAllIosSims({ timeoutMs: DEVICE_LIST_TIMEOUT_MS }), report.deadProjects)).failures;
2596
2757
  if (idleFailures) process.exitCode = 1;
@@ -2604,6 +2765,7 @@ async function runGcCore(opts, deps) {
2604
2765
  actionable,
2605
2766
  failures,
2606
2767
  sections: gcReportSections(report),
2768
+ ...report.maintenance ? { maintenance: report.maintenance } : {},
2607
2769
  results: takeGcResults(),
2608
2770
  inventory
2609
2771
  });
@@ -2613,6 +2775,7 @@ async function runGcCore(opts, deps) {
2613
2775
  return payload(idle === null ? null : idleFailures);
2614
2776
  }
2615
2777
  let deleteFailures = idleFailures;
2778
+ deleteFailures += deleteArchives(report.archives);
2616
2779
  deleteFailures += report.workspaceOutputs ? (await clearWorkspaceOutputs(report.workspaceOutputs, { olderThan })).failures : 0;
2617
2780
  deleteFailures += await trimWorkspaceLogs(report.workspaceLogs);
2618
2781
  deleteFailures += deleteRecordings(report.recordings, {
@@ -2710,7 +2873,7 @@ function gcCommand(program) {
2710
2873
  const n = parseInt(v, 10);
2711
2874
  if (!Number.isFinite(n) || String(n) !== String(v).trim()) throw new InvalidArgumentError("must be a whole number of days, e.g. --older-than 30");
2712
2875
  return n;
2713
- }).option("--cache <name>", "act on the shared caches whose name or directory contains <name>, every cache, the workspace build outputs and the device recordings with --cache all, only the workspace build outputs with --cache workspaces, only the device recordings with --cache recordings, only the parked simulators and emulators with --cache parked, the watchman daemon and its stale roots with --cache watchman, or the Gradle and Kotlin compile daemons with --cache gradle-daemons; all, workspaces, recordings, parked, watchman and gradle-daemons are reserved names that never select a single cache, and --cache all never includes watchman or gradle-daemons. With --delete they are emptied whole (a parked device is erased and stays parked, watchman loses its stale roots and shuts down only when no client uses it, and only daemons proven idle stop), which is the only way to clear an index-backed cache; add --older-than <days> to trim them by age instead. Only those caches are reported; other devices and project entries are not inspected. Caches outside the config dir are refused while STIM_HOME is set.", (v) => {
2876
+ }).option("--cache <name>", "act on the shared caches whose name or directory contains <name>, every cache, the workspace build outputs and the device recordings with --cache all, only the workspace build outputs with --cache workspaces, only the device recordings with --cache recordings, only the parked simulators and emulators with --cache parked, the watchman daemon and its stale roots with --cache watchman, or the Gradle and Kotlin compile daemons with --cache gradle-daemons; archived, archived:<id>, archived-logs, archived-recordings and archived-agent select archived history explicitly; --cache all excludes archives. all, workspaces, recordings, parked, archived, archived:<id>, archived-logs, archived-recordings, archived-agent, watchman and gradle-daemons are reserved names that never select a single cache, and --cache all never includes watchman or gradle-daemons. With --delete they are emptied whole (a parked device is erased and stays parked, watchman loses its stale roots and shuts down only when no client uses it, and only daemons proven idle stop), which is the only way to clear an index-backed cache; add --older-than <days> to trim them by age instead. Archive ids ignore --older-than; archived and per-kind archive selectors filter by removal age. Only those caches are reported; other devices and project entries are not inspected. Caches outside the config dir are refused while STIM_HOME is set.", (v) => {
2714
2877
  if (!v.trim()) throw new InvalidArgumentError("must name a cache, e.g. --cache \"compilation cache\"");
2715
2878
  return v;
2716
2879
  }).option("--idle <duration>", "shut down (never delete) owned simulators and emulators that have had no driver, claim, or activity for at least <duration>, such as 30m, 2h, or 1d; acts without --delete", (v) => {
@@ -1,9 +1,9 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { a as spawnDeclared } from "./spawn-claims-D0XfSe8u.mjs";
3
2
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { l as phaseLine } from "./command-output-CliHHn7a.mjs";
5
- import { o as androidHome } from "./android-Db2eEMaf.mjs";
6
- import { O as readCcacheActivity, T as CCACHE_UNAVAILABLE, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-DmeYjXD9.mjs";
3
+ import { l as phaseLine } from "./command-output-DnJMdEY-.mjs";
4
+ import { a as spawnDeclared } from "./spawn-claims-D0XfSe8u.mjs";
5
+ import { o as androidHome } from "./android-B_NumVyQ.mjs";
6
+ import { O as readCcacheActivity, T as CCACHE_UNAVAILABLE, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-DkUflduf.mjs";
7
7
  import { createHash } from "node:crypto";
8
8
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
9
9
  import { dirname, isAbsolute, join, relative, sep } from "node:path";