looply-cli 0.5.7 → 0.5.9

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 (84) hide show
  1. package/dist/.src-hash +1 -1
  2. package/dist/bin.d.ts.map +1 -1
  3. package/dist/bin.js +9 -1
  4. package/dist/bin.js.map +1 -1
  5. package/dist/branch-delivery-wiring.d.ts +41 -0
  6. package/dist/branch-delivery-wiring.d.ts.map +1 -0
  7. package/dist/branch-delivery-wiring.js +85 -0
  8. package/dist/branch-delivery-wiring.js.map +1 -0
  9. package/dist/branch-delivery.d.ts +275 -0
  10. package/dist/branch-delivery.d.ts.map +1 -0
  11. package/dist/branch-delivery.js +659 -0
  12. package/dist/branch-delivery.js.map +1 -0
  13. package/dist/config.d.ts +20 -1
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/config.js +24 -0
  16. package/dist/config.js.map +1 -1
  17. package/dist/coordinator-state.d.ts.map +1 -1
  18. package/dist/coordinator-state.js +28 -18
  19. package/dist/coordinator-state.js.map +1 -1
  20. package/dist/daemon-cmd.d.ts.map +1 -1
  21. package/dist/daemon-cmd.js +64 -5
  22. package/dist/daemon-cmd.js.map +1 -1
  23. package/dist/daemon-lock.d.ts +65 -2
  24. package/dist/daemon-lock.d.ts.map +1 -1
  25. package/dist/daemon-lock.js +149 -5
  26. package/dist/daemon-lock.js.map +1 -1
  27. package/dist/daemon.d.ts +12 -1
  28. package/dist/daemon.d.ts.map +1 -1
  29. package/dist/daemon.js +23 -3
  30. package/dist/daemon.js.map +1 -1
  31. package/dist/deliver-cmd.d.ts +41 -0
  32. package/dist/deliver-cmd.d.ts.map +1 -0
  33. package/dist/deliver-cmd.js +189 -0
  34. package/dist/deliver-cmd.js.map +1 -0
  35. package/dist/delivery-rules.d.ts +71 -0
  36. package/dist/delivery-rules.d.ts.map +1 -0
  37. package/dist/delivery-rules.js +186 -0
  38. package/dist/delivery-rules.js.map +1 -0
  39. package/dist/delivery-settings-cache.d.ts +35 -0
  40. package/dist/delivery-settings-cache.d.ts.map +1 -0
  41. package/dist/delivery-settings-cache.js +119 -0
  42. package/dist/delivery-settings-cache.js.map +1 -0
  43. package/dist/github-api.d.ts +99 -0
  44. package/dist/github-api.d.ts.map +1 -0
  45. package/dist/github-api.js +226 -0
  46. package/dist/github-api.js.map +1 -0
  47. package/dist/goal-runs.d.ts +2 -2
  48. package/dist/goal-runs.d.ts.map +1 -1
  49. package/dist/goal-runs.js +13 -11
  50. package/dist/goal-runs.js.map +1 -1
  51. package/dist/machine-settings.d.ts +188 -0
  52. package/dist/machine-settings.d.ts.map +1 -0
  53. package/dist/machine-settings.js +658 -0
  54. package/dist/machine-settings.js.map +1 -0
  55. package/dist/project-terminal.d.ts +6 -0
  56. package/dist/project-terminal.d.ts.map +1 -1
  57. package/dist/project-terminal.js +3 -0
  58. package/dist/project-terminal.js.map +1 -1
  59. package/dist/run-ending-locator.d.ts.map +1 -1
  60. package/dist/run-ending-locator.js +5 -3
  61. package/dist/run-ending-locator.js.map +1 -1
  62. package/dist/serve-cmd.d.ts +8 -0
  63. package/dist/serve-cmd.d.ts.map +1 -1
  64. package/dist/serve-cmd.js +12 -0
  65. package/dist/serve-cmd.js.map +1 -1
  66. package/dist/server-client.d.ts +29 -2
  67. package/dist/server-client.d.ts.map +1 -1
  68. package/dist/server-client.js +39 -2
  69. package/dist/server-client.js.map +1 -1
  70. package/dist/stale-run-sweep.js +11 -10
  71. package/dist/stale-run-sweep.js.map +1 -1
  72. package/dist/untrusted-exec.d.ts +11 -0
  73. package/dist/untrusted-exec.d.ts.map +1 -1
  74. package/dist/untrusted-exec.js +1 -0
  75. package/dist/untrusted-exec.js.map +1 -1
  76. package/dist/workspace-provisioner.d.ts +8 -0
  77. package/dist/workspace-provisioner.d.ts.map +1 -1
  78. package/dist/workspace-provisioner.js +18 -0
  79. package/dist/workspace-provisioner.js.map +1 -1
  80. package/dist/workspace.d.ts +47 -13
  81. package/dist/workspace.d.ts.map +1 -1
  82. package/dist/workspace.js +121 -94
  83. package/dist/workspace.js.map +1 -1
  84. package/package.json +2 -2
@@ -0,0 +1,188 @@
1
+ import { DEFAULT_MIN_FREE_GB, type MachineSettings, type WorkspacesReport, type WorkspacesSource } from '@looply/core';
2
+ /**
3
+ * WHERE THIS MACHINE'S CHECKOUTS GO, AND HOW MUCH DISK THEY MAY TAKE.
4
+ *
5
+ * ─────────────────────────────────────────────────────────────────────────────
6
+ * 🔴 ON 2026-10-16 CHECKOUTS FILLED THE OWNER'S C: (about 100 GB). 0.5.7 gave
7
+ * the machine a local file for it; this lets the machine's OWNER choose the same
8
+ * thing remotely — from the Looply console or AutoRyn — per machine.
9
+ *
10
+ * PRECEDENCE, per field:
11
+ * 1. the machine's own say: `LOOPLY_WORKSPACES_ROOT`, then
12
+ * `~/.looply/machine-settings.json` (`workspacesRoot`, `checkoutsCapGb`,
13
+ * `minFreeGb`);
14
+ * 2. the remote setting, as this machine last heard it (cached here, so an
15
+ * offline machine keeps what it was last told);
16
+ * 3. the default: `~/.looply/workspaces`, no cap, 20 GB free.
17
+ *
18
+ * 🔴 A REMOTE FOLDER IS CHECKED ON THIS MACHINE BEFORE IT IS USED. The server
19
+ * can only check a path's shape; whether it is on a local fixed drive, outside
20
+ * every served repository and outside `~/.looply`, not a system folder, and
21
+ * creatable and writable is a fact about this machine. A folder that fails is
22
+ * REFUSED IN WORDS and the previous folder stays in effect — the refusal travels
23
+ * on the heartbeat so the console and AutoRyn can show it.
24
+ *
25
+ * ⚠️ A CHANGE APPLIES TO NEW CHECKOUTS ONLY. Every folder checkouts were ever
26
+ * made in is remembered (`knownWorkspacesBases`), so a run already going
27
+ * finishes where it is and its checkout is reaped where it is.
28
+ *
29
+ * Files, all under `~/.looply` (machine-level, never inside a repository):
30
+ * machine-settings.json the machine's own say (a person writes it)
31
+ * machine-settings-remote.json the remote setting and the verdict on its folder
32
+ * workspaces-bases.json every folder checkouts were made in
33
+ * checkouts-usage.json GB used by checkouts, measured now and then
34
+ */
35
+ export { DEFAULT_MIN_FREE_GB };
36
+ export declare const MACHINE_SETTINGS_FILE = "machine-settings.json";
37
+ export declare const REMOTE_MACHINE_SETTINGS_FILE = "machine-settings-remote.json";
38
+ export declare const WORKSPACES_BASES_FILE = "workspaces-bases.json";
39
+ export declare const CHECKOUTS_USAGE_FILE = "checkouts-usage.json";
40
+ export declare const WORKSPACES_DIR = "workspaces";
41
+ /** How long a usage measurement is trusted before it is taken again. */
42
+ export declare const USAGE_MAX_AGE_MS: number;
43
+ export declare const defaultWorkspacesBase: (home?: string) => string;
44
+ export interface LocalMachineSettings {
45
+ workspacesRoot?: string;
46
+ checkoutsCapGb?: number;
47
+ minFreeGb?: number;
48
+ }
49
+ /**
50
+ * `~/.looply/machine-settings.json`, checked. Absent is `{}`.
51
+ *
52
+ * ⚠️ AN UNUSABLE LOCAL SETTING THROWS, as it did in 0.5.7: falling back to the
53
+ * home drive silently is the exact outcome the setting exists to prevent, and a
54
+ * person wrote this file on this machine and can fix it.
55
+ */
56
+ export declare function readLocalMachineSettings(home?: string): LocalMachineSettings;
57
+ /** The verdict on the remote folder, as this machine reached it. */
58
+ export interface FolderVerdict {
59
+ /** The remote value judged. */
60
+ value: string;
61
+ ok: boolean;
62
+ /** Why not, in words a person can act on. */
63
+ because: string | null;
64
+ checkedAt: string;
65
+ }
66
+ export interface RemoteMachineSettingsCache {
67
+ settings: MachineSettings;
68
+ updatedAt: string | null;
69
+ fetchedAt: string;
70
+ /** The remote folder actually in use: the last one that passed. Null: the default. */
71
+ inEffect: string | null;
72
+ /** The last verdict on `settings.workspacesRoot`, when there is one. */
73
+ verdict: FolderVerdict | null;
74
+ }
75
+ export declare function readRemoteMachineSettings(home?: string): RemoteMachineSettingsCache | null;
76
+ export declare function writeRemoteMachineSettings(home: string, value: RemoteMachineSettingsCache): void;
77
+ export type DriveKind = 'fixed' | 'removable' | 'network' | 'cdrom' | 'ram' | 'unknown' | 'missing';
78
+ /**
79
+ * What kind of drive `path` is on. Windows only asks; elsewhere every local
80
+ * path is answered `fixed` (a POSIX machine has no drive letters to judge).
81
+ */
82
+ export declare function nodeDriveKind(path: string, platform?: NodeJS.Platform): DriveKind;
83
+ export interface FolderCheckDeps {
84
+ home: string;
85
+ platform?: NodeJS.Platform;
86
+ env?: NodeJS.ProcessEnv;
87
+ /** Every repository this machine serves, and every folder it scans for them. */
88
+ servedPaths: readonly string[];
89
+ driveKind?: (path: string) => DriveKind;
90
+ /** Create the folder and prove a file can be written in it; throws with the reason. */
91
+ probeWritable?: (path: string) => void;
92
+ }
93
+ export declare function nodeProbeWritable(path: string): void;
94
+ /**
95
+ * Why `folder` may not hold this machine's checkouts, or null when it may.
96
+ * The answer is the sentence the console and the ticket show.
97
+ */
98
+ export declare function checkoutFolderProblem(folder: string, deps: FolderCheckDeps): string | null;
99
+ export interface EffectiveWorkspaces {
100
+ /** Where new checkouts go. */
101
+ base: string;
102
+ source: WorkspacesSource;
103
+ /** Why the remote folder is not the one in use, or null. */
104
+ refused: string | null;
105
+ minFreeGb: number;
106
+ /** Null: no cap. */
107
+ capGb: number | null;
108
+ }
109
+ /**
110
+ * What applies right now, from the three sources in order. Reads two small
111
+ * files; never asks the server and never checks a folder (the pull did that).
112
+ */
113
+ export declare function effectiveWorkspaces(home?: string, env?: NodeJS.ProcessEnv): EffectiveWorkspaces;
114
+ /**
115
+ * Remember that checkouts are being made under `base`, so a later change of
116
+ * folder does not hide them from the reaper. Idempotent; never throws.
117
+ */
118
+ export declare function rememberWorkspacesBase(base: string, home?: string): void;
119
+ /**
120
+ * Every folder checkouts may sit in: the current one first, then every one
121
+ * remembered, then the default. Only folders that exist are returned unless
122
+ * `existingOnly` is false.
123
+ */
124
+ export declare function knownWorkspacesBases(home?: string, includeCurrent?: boolean): string[];
125
+ export interface CheckoutsUsage {
126
+ usedGb: number;
127
+ /** How many checkouts that is, so a new one can be estimated. */
128
+ checkouts: number;
129
+ measuredAt: string;
130
+ }
131
+ /** Free GB on the drive that holds `dir` (or its nearest existing parent). */
132
+ export declare function freeGbAt(dir: string): number | null;
133
+ /**
134
+ * Bytes under `dir`, walking without following links (a carried
135
+ * `node_modules` link must not count its target, and a junction must not walk
136
+ * the user's repository). Yields to the event loop as it goes, so a daemon's
137
+ * heartbeat is never held by a big tree.
138
+ */
139
+ export declare function bytesUnder(dir: string): Promise<number>;
140
+ /**
141
+ * Measure every checkout under every known folder: `<base>/<project key>/<checkout>`.
142
+ * Junction/symlink entries are not followed (see `bytesUnder`).
143
+ */
144
+ export declare function measureCheckouts(bases: readonly string[], now?: Date): Promise<CheckoutsUsage>;
145
+ export declare function readCheckoutsUsage(home?: string): CheckoutsUsage | null;
146
+ /**
147
+ * Measure again when the last measurement is older than `maxAgeMs`. Many
148
+ * daemons share this machine, so one claims the measurement and the others
149
+ * use what is there. Never throws.
150
+ */
151
+ export declare function refreshCheckoutsUsage(home?: string, opts?: {
152
+ maxAgeMs?: number;
153
+ now?: () => number;
154
+ measure?: (bases: readonly string[]) => Promise<CheckoutsUsage>;
155
+ }): Promise<CheckoutsUsage | null>;
156
+ export interface RoomDeps {
157
+ freeGb?: (dir: string) => number | null;
158
+ /** Used GB right now; the cached measurement unless a caller measured. */
159
+ usage?: CheckoutsUsage | null;
160
+ }
161
+ /**
162
+ * Why no new checkout may be made under `root` right now, or null when one may.
163
+ * Minimum free space first (the drive), then the cap (Looply's share of it).
164
+ * The answer is a sentence a person can act on, because it is what the run and
165
+ * the ticket say.
166
+ */
167
+ export declare function checkoutRoomProblem(root: string, eff: Pick<EffectiveWorkspaces, 'minFreeGb' | 'capGb'>, deps?: RoomDeps): string | null;
168
+ /** What the heartbeat says about checkouts. Never throws: presence is worth more. */
169
+ export declare function workspacesReport(home?: string, deps?: RoomDeps): WorkspacesReport | undefined;
170
+ export interface MachineSettingsPullDeps {
171
+ /** `GET /v1/machine/settings`. */
172
+ fetch(): Promise<unknown>;
173
+ home?: string;
174
+ /** Served repositories and scanned folders, for the folder check. */
175
+ servedPaths(): readonly string[];
176
+ log(line: string): void;
177
+ now?(): number;
178
+ checkFolder?: (folder: string, deps: FolderCheckDeps) => string | null;
179
+ /** Measure checkout usage when it is stale; tests pass a no-op. */
180
+ refreshUsage?: () => Promise<unknown>;
181
+ }
182
+ export type MachineSettingsPullResult = 'updated' | 'unchanged' | 'failed';
183
+ /**
184
+ * One pull: ask the server for this machine's settings, check a new folder on
185
+ * this machine, and write the cache. A failure keeps what the cache holds.
186
+ */
187
+ export declare function makeMachineSettingsPull(deps: MachineSettingsPullDeps): () => Promise<MachineSettingsPullResult>;
188
+ //# sourceMappingURL=machine-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machine-settings.d.ts","sourceRoot":"","sources":["../src/machine-settings.ts"],"names":[],"mappings":"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"}