@sigil0/looking-glass 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +143 -61
  2. package/dist/agents/coordinator.js +1 -1
  3. package/dist/agents/coordinator.js.map +1 -1
  4. package/dist/cli.js +17 -15
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +5 -3
  8. package/dist/config.js.map +1 -1
  9. package/dist/doctor.d.ts +14 -0
  10. package/dist/doctor.d.ts.map +1 -0
  11. package/dist/doctor.js +26 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/paths.d.ts +8 -4
  14. package/dist/paths.d.ts.map +1 -1
  15. package/dist/paths.js +39 -15
  16. package/dist/paths.js.map +1 -1
  17. package/dist/scheduler/index.d.ts +5 -1
  18. package/dist/scheduler/index.d.ts.map +1 -1
  19. package/dist/scheduler/index.js +3 -1
  20. package/dist/scheduler/index.js.map +1 -1
  21. package/dist/scheduler/runner.d.ts.map +1 -1
  22. package/dist/scheduler/runner.js +35 -3
  23. package/dist/scheduler/runner.js.map +1 -1
  24. package/dist/scheduler/service.d.ts +15 -0
  25. package/dist/scheduler/service.d.ts.map +1 -0
  26. package/dist/scheduler/service.js +20 -0
  27. package/dist/scheduler/service.js.map +1 -0
  28. package/dist/scheduler/windows.d.ts +87 -0
  29. package/dist/scheduler/windows.d.ts.map +1 -0
  30. package/dist/scheduler/windows.js +505 -0
  31. package/dist/scheduler/windows.js.map +1 -0
  32. package/dist/storage/artifact-store.d.ts +2 -1
  33. package/dist/storage/artifact-store.d.ts.map +1 -1
  34. package/dist/storage/artifact-store.js +8 -3
  35. package/dist/storage/artifact-store.js.map +1 -1
  36. package/dist/storage/database.d.ts +1 -1
  37. package/dist/storage/database.d.ts.map +1 -1
  38. package/dist/storage/database.js +10 -6
  39. package/dist/storage/database.js.map +1 -1
  40. package/dist/tools/apply-patch.d.ts +15 -0
  41. package/dist/tools/apply-patch.d.ts.map +1 -1
  42. package/dist/tools/apply-patch.js +81 -12
  43. package/dist/tools/apply-patch.js.map +1 -1
  44. package/dist/tools/bash.d.ts +2 -0
  45. package/dist/tools/bash.d.ts.map +1 -1
  46. package/dist/tools/bash.js +43 -22
  47. package/dist/tools/bash.js.map +1 -1
  48. package/dist/tools/executable.d.ts +13 -0
  49. package/dist/tools/executable.d.ts.map +1 -0
  50. package/dist/tools/executable.js +82 -0
  51. package/dist/tools/executable.js.map +1 -0
  52. package/dist/tools/process.d.ts +8 -0
  53. package/dist/tools/process.d.ts.map +1 -1
  54. package/dist/tools/process.js +105 -35
  55. package/dist/tools/process.js.map +1 -1
  56. package/dist/tools/safety.d.ts +5 -1
  57. package/dist/tools/safety.d.ts.map +1 -1
  58. package/dist/tools/safety.js +125 -7
  59. package/dist/tools/safety.js.map +1 -1
  60. package/dist/tools/schedule.d.ts.map +1 -1
  61. package/dist/tools/schedule.js +4 -3
  62. package/dist/tools/schedule.js.map +1 -1
  63. package/dist/tools/search.d.ts.map +1 -1
  64. package/dist/tools/search.js +9 -4
  65. package/dist/tools/search.js.map +1 -1
  66. package/dist/tools/shell.d.ts +30 -0
  67. package/dist/tools/shell.d.ts.map +1 -0
  68. package/dist/tools/shell.js +51 -0
  69. package/dist/tools/shell.js.map +1 -0
  70. package/dist/ui/tui.d.ts +6 -0
  71. package/dist/ui/tui.d.ts.map +1 -1
  72. package/dist/ui/tui.js +44 -21
  73. package/dist/ui/tui.js.map +1 -1
  74. package/looking-glass-title.svg +69 -0
  75. package/package.json +7 -5
@@ -0,0 +1,505 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { isAbsolute, join, resolve, win32 } from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ import { configDir } from "../paths.js";
7
+ import { powershellExecutable, windowsSystemExecutable } from "../tools/shell.js";
8
+ /** The per-user task used by the scheduler on Windows. */
9
+ export const TASK_NAME = "Looking Glass Scheduler";
10
+ /** Compatibility name shared with the systemd backend's public vocabulary. */
11
+ export const SERVICE_NAME = TASK_NAME;
12
+ export const LAUNCHER_FILE_NAME = "scheduler-launcher.ps1";
13
+ export const TASK_XML_FILE_NAME = "scheduler-task.xml";
14
+ function defaultCommand(command, args) {
15
+ const result = spawnSync(command, args, {
16
+ encoding: "utf8",
17
+ shell: false,
18
+ windowsHide: true,
19
+ });
20
+ const commandResult = {
21
+ status: result.status,
22
+ stdout: result.stdout ?? "",
23
+ stderr: result.stderr ?? "",
24
+ };
25
+ if (result.error) {
26
+ const errorCode = result.error.code;
27
+ if (errorCode !== undefined)
28
+ commandResult.errorCode = errorCode;
29
+ commandResult.errorMessage = result.error.message;
30
+ }
31
+ return commandResult;
32
+ }
33
+ function currentTaskUser() {
34
+ const domain = process.env.USERDOMAIN;
35
+ const user = process.env.USERNAME ?? process.env.USER;
36
+ if (domain && user)
37
+ return `${domain}\\${user}`;
38
+ return user ?? "";
39
+ }
40
+ function resolveOptions(options = {}) {
41
+ const directory = options.configDirectory ?? configDir();
42
+ const resolved = {
43
+ command: options.command ?? options.run ?? options.spawn ?? options.exec ?? defaultCommand,
44
+ configDirectory: directory,
45
+ taskName: options.taskName ?? TASK_NAME,
46
+ launcherPath: options.launcherPath ?? join(directory, LAUNCHER_FILE_NAME),
47
+ taskXmlPath: options.taskXmlPath ?? join(directory, TASK_XML_FILE_NAME),
48
+ nodePath: options.nodePath ?? process.execPath,
49
+ user: options.user ?? currentTaskUser(),
50
+ powershellPath: options.powershellPath ?? powershellExecutable(options.systemRoot),
51
+ schtasksPath: windowsSystemExecutable("schtasks.exe", options.systemRoot),
52
+ };
53
+ requiredText(resolved.configDirectory, "config directory");
54
+ requiredText(resolved.taskName, "task name");
55
+ requiredText(resolved.launcherPath, "launcher path");
56
+ requiredText(resolved.taskXmlPath, "task XML path");
57
+ requiredText(resolved.nodePath, "node path");
58
+ requiredText(resolved.user, "task user");
59
+ requiredText(resolved.powershellPath, "PowerShell path");
60
+ return resolved;
61
+ }
62
+ function validateXmlCharacters(value, label) {
63
+ for (let index = 0; index < value.length;) {
64
+ const codePoint = value.codePointAt(index);
65
+ if (codePoint === undefined)
66
+ break;
67
+ const valid = codePoint === 0x09 || codePoint === 0x0a || codePoint === 0x0d
68
+ || (codePoint >= 0x20 && codePoint <= 0xd7ff)
69
+ || (codePoint >= 0xe000 && codePoint <= 0xfffd)
70
+ || (codePoint >= 0x10000 && codePoint <= 0x10ffff);
71
+ if (!valid)
72
+ throw new TypeError(`${label} contains an invalid XML control character`);
73
+ index += codePoint > 0xffff ? 2 : 1;
74
+ }
75
+ }
76
+ function requiredText(value, label) {
77
+ if (typeof value !== "string" || value.trim().length === 0) {
78
+ throw new TypeError(`${label} must not be empty`);
79
+ }
80
+ validateXmlCharacters(value, label);
81
+ return value;
82
+ }
83
+ /** Escape a value used as a single-quoted PowerShell string literal. */
84
+ export function powerShellLiteral(value) {
85
+ return `'${value.replaceAll("'", "''")}'`;
86
+ }
87
+ /** Escape XML text, rejecting characters that XML 1.0 cannot represent. */
88
+ export function xmlText(value) {
89
+ if (typeof value !== "string")
90
+ throw new TypeError("XML text must be a string");
91
+ validateXmlCharacters(value, "XML text");
92
+ return value
93
+ .replaceAll("&", "&amp;")
94
+ .replaceAll("<", "&lt;")
95
+ .replaceAll(">", "&gt;")
96
+ .replaceAll('"', "&quot;")
97
+ .replaceAll("'", "&apos;");
98
+ }
99
+ /**
100
+ * Quote one argument for the command line passed to an Exec action. The
101
+ * launcher path is a Windows path (and thus cannot contain a double quote),
102
+ * but handling backslashes here also makes this safe for synthetic test
103
+ * paths and future callers.
104
+ */
105
+ export function windowsArgument(value) {
106
+ if (value.length > 0 && !/[\s"]/.test(value))
107
+ return value;
108
+ let result = '"';
109
+ let slashes = 0;
110
+ for (const character of value) {
111
+ if (character === "\\") {
112
+ slashes += 1;
113
+ continue;
114
+ }
115
+ if (character === '"') {
116
+ result += "\\".repeat(slashes * 2 + 1) + '"';
117
+ slashes = 0;
118
+ continue;
119
+ }
120
+ result += "\\".repeat(slashes) + character;
121
+ slashes = 0;
122
+ }
123
+ result += "\\".repeat(slashes * 2) + '"';
124
+ return result;
125
+ }
126
+ /** Render the PowerShell process launcher used by the scheduled task. */
127
+ export function renderLauncher(nodePath, cliPath, dbPath) {
128
+ requiredText(nodePath, "node path");
129
+ requiredText(cliPath, "CLI path");
130
+ requiredText(dbPath, "database path");
131
+ return [
132
+ "$ErrorActionPreference = 'Stop'",
133
+ `$node = ${powerShellLiteral(nodePath)}`,
134
+ `$cli = ${powerShellLiteral(cliPath)}`,
135
+ `$env:LOOKING_GLASS_DB = ${powerShellLiteral(dbPath)}`,
136
+ "& $node $cli 'cron' 'daemon'",
137
+ "exit $LASTEXITCODE",
138
+ "",
139
+ ].join("\r\n");
140
+ }
141
+ /** Descriptive alias for callers that want to make the generated format explicit. */
142
+ export const renderPowerShellLauncher = renderLauncher;
143
+ function taskXmlOptions(userOrOptions, powershellPath, workingDirectory) {
144
+ if (typeof userOrOptions === "object" && userOrOptions !== null) {
145
+ const options = {
146
+ taskName: userOrOptions.taskName ?? TASK_NAME,
147
+ user: userOrOptions.user ?? currentTaskUser(),
148
+ powershellPath: userOrOptions.powershellPath ?? powershellExecutable(userOrOptions.systemRoot),
149
+ workingDirectory: userOrOptions.workingDirectory ?? homedir(),
150
+ };
151
+ requiredText(options.taskName, "task name");
152
+ requiredText(options.user, "task user");
153
+ requiredText(options.powershellPath, "PowerShell path");
154
+ requiredText(options.workingDirectory, "working directory");
155
+ return options;
156
+ }
157
+ const options = {
158
+ taskName: TASK_NAME,
159
+ user: userOrOptions ?? currentTaskUser(),
160
+ powershellPath: powershellPath ?? powershellExecutable(),
161
+ workingDirectory: workingDirectory ?? homedir(),
162
+ };
163
+ requiredText(options.taskName, "task name");
164
+ requiredText(options.user, "task user");
165
+ requiredText(options.powershellPath, "PowerShell path");
166
+ requiredText(options.workingDirectory, "working directory");
167
+ return options;
168
+ }
169
+ export function renderTaskXml(launcherPath, userOrOptions = undefined, powershellPath, workingDirectory) {
170
+ requiredText(launcherPath, "launcher path");
171
+ const options = taskXmlOptions(userOrOptions, powershellPath, workingDirectory);
172
+ const commandArguments = `-NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File ${windowsArgument(launcherPath)}`;
173
+ // The trigger and principal deliberately share UserId: InteractiveToken
174
+ // keeps execution tied to this user's interactive logon, while
175
+ // LeastPrivilege avoids elevating the scheduler daemon.
176
+ return `<?xml version="1.0" encoding="UTF-16"?>
177
+ <Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
178
+ <RegistrationInfo>
179
+ <Description>${xmlText(options.taskName)} persistent scheduler</Description>
180
+ <URI>\\${xmlText(options.taskName)}</URI>
181
+ </RegistrationInfo>
182
+ <Triggers>
183
+ <LogonTrigger>
184
+ <UserId>${xmlText(options.user)}</UserId>
185
+ <Enabled>true</Enabled>
186
+ </LogonTrigger>
187
+ </Triggers>
188
+ <Principals>
189
+ <Principal id="Author">
190
+ <UserId>${xmlText(options.user)}</UserId>
191
+ <LogonType>InteractiveToken</LogonType>
192
+ <RunLevel>LeastPrivilege</RunLevel>
193
+ </Principal>
194
+ </Principals>
195
+ <Settings>
196
+ <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
197
+ <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
198
+ <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
199
+ <AllowHardTerminate>true</AllowHardTerminate>
200
+ <StartWhenAvailable>true</StartWhenAvailable>
201
+ <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
202
+ <RestartOnFailure>
203
+ <Interval>PT1M</Interval>
204
+ <Count>3</Count>
205
+ </RestartOnFailure>
206
+ <Priority>7</Priority>
207
+ </Settings>
208
+ <Actions Context="Author">
209
+ <Exec>
210
+ <Command>${xmlText(options.powershellPath)}</Command>
211
+ <Arguments>${xmlText(commandArguments)}</Arguments>
212
+ <WorkingDirectory>${xmlText(options.workingDirectory)}</WorkingDirectory>
213
+ </Exec>
214
+ </Actions>
215
+ </Task>
216
+ `;
217
+ }
218
+ /** Alias with a shorter name for callers that only need a pure renderer. */
219
+ export const renderTask = renderTaskXml;
220
+ function commandOutput(result) {
221
+ return [
222
+ result.stdout ?? "",
223
+ result.stderr ?? "",
224
+ result.errorMessage ?? result.message ?? "",
225
+ ].filter(Boolean).join("\n").trim();
226
+ }
227
+ function commandFailure(command, args, result) {
228
+ const code = result.errorCode ?? result.code;
229
+ const suffix = code === undefined ? "" : ` (code ${String(code)})`;
230
+ return new Error(commandOutput(result) || `${command} ${args.join(" ")} exited with ${String(result.status)}${suffix}`);
231
+ }
232
+ function runSchtasks(options, args, tolerateFailure = false) {
233
+ const result = options.command(options.schtasksPath, args);
234
+ if (result.status !== 0 && !tolerateFailure) {
235
+ throw commandFailure(options.schtasksPath, args, result);
236
+ }
237
+ return result;
238
+ }
239
+ function resultCode(result) {
240
+ return String(result.errorCode ?? result.code ?? "").toLowerCase().replaceAll("_", "");
241
+ }
242
+ const TASK_NOT_FOUND_SENTINEL = "LOOKING_GLASS_TASK_NOT_FOUND";
243
+ // These are the documented Win32 / Task Scheduler values returned by the
244
+ // schtasks operation itself. Do not add message text (or a generic
245
+ // "*not-found" code) here: a localized or otherwise unrelated failure must
246
+ // never authorize removal of the generated scheduler files.
247
+ const DOCUMENTED_MISSING_TASK_CODES = new Set([
248
+ "2", // ERROR_FILE_NOT_FOUND
249
+ "2147942402", // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
250
+ "0x80070002", // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
251
+ "2147750671", // SCHED_E_TASK_NOT_FOUND
252
+ "0x8004130f", // SCHED_E_TASK_NOT_FOUND
253
+ "errorfilenotfound",
254
+ "schedetasknotfound",
255
+ ]);
256
+ /** Only the internal sentinel or documented invariant codes count as missing. */
257
+ function isMissingTaskFailure(result) {
258
+ if (commandOutput(result).trim() === TASK_NOT_FOUND_SENTINEL)
259
+ return true;
260
+ return DOCUMENTED_MISSING_TASK_CODES.has(resultCode(result));
261
+ }
262
+ function isNotRunningFailure(result) {
263
+ const code = resultCode(result);
264
+ return code === "0x8004131f" || code === "2147750687"
265
+ || /(?:not currently running|is not running|no running instance|cannot be stopped because)/i.test(commandOutput(result));
266
+ }
267
+ function taskStateScript(taskName) {
268
+ return [
269
+ "$ErrorActionPreference = 'Stop'",
270
+ "try {",
271
+ // Enumerate tasks and filter exact root-path/name properties instead of
272
+ // querying an absent path or name. Filtered cmdlet queries throw errors whose
273
+ // FullyQualifiedErrorId has varied between Windows releases, while this
274
+ // successful enumeration is independent of localization and error text.
275
+ ` $tasks = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq ${powerShellLiteral(taskName)} })`,
276
+ ` if ($tasks.Count -eq 0) { [Console]::Error.Write('${TASK_NOT_FOUND_SENTINEL}'); exit 3 }`,
277
+ " [Console]::Out.Write($tasks[0].State.ToString())",
278
+ "} catch {",
279
+ " [Console]::Error.Write('LOOKING_GLASS_TASK_ERROR')",
280
+ " exit 4",
281
+ "}",
282
+ ].join("\r\n");
283
+ }
284
+ /** Query the enum-valued State property; never parse localized schtasks output. */
285
+ function lookupTask(options) {
286
+ const args = ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", taskStateScript(options.taskName)];
287
+ const result = options.command(options.powershellPath, args);
288
+ if (result.status === 0) {
289
+ const state = (result.stdout ?? "").trim();
290
+ if (state.length === 0)
291
+ throw commandFailure(options.powershellPath, args, result);
292
+ return { kind: "present", state };
293
+ }
294
+ if (isMissingTaskFailure(result))
295
+ return { kind: "missing" };
296
+ throw commandFailure(options.powershellPath, args, result);
297
+ }
298
+ function removeFile(path) {
299
+ try {
300
+ unlinkSync(path);
301
+ }
302
+ catch (error) {
303
+ if (error.code !== "ENOENT")
304
+ throw error;
305
+ }
306
+ }
307
+ function restoreFile(path, previous) {
308
+ if (previous === null)
309
+ removeFile(path);
310
+ else
311
+ writeFileSync(path, previous, { mode: 0o600 });
312
+ }
313
+ function isRenameCollision(error) {
314
+ const code = error.code;
315
+ return code === "EEXIST" || code === "EPERM" || code === "ENOTEMPTY";
316
+ }
317
+ /** Replace a completed file atomically where the host permits it. */
318
+ function replaceCompletedFile(temporaryPath, targetPath) {
319
+ try {
320
+ renameSync(temporaryPath, targetPath);
321
+ return;
322
+ }
323
+ catch (error) {
324
+ if (!isRenameCollision(error))
325
+ throw error;
326
+ }
327
+ // Windows rename does not replace an existing file. Move it aside first,
328
+ // then rename the complete temporary file into place; both operations are
329
+ // metadata changes and never expose a partially written generated file.
330
+ const backupPath = `${targetPath}.${randomUUID()}.bak`;
331
+ let backedUp = false;
332
+ try {
333
+ try {
334
+ renameSync(targetPath, backupPath);
335
+ backedUp = true;
336
+ }
337
+ catch (error) {
338
+ if (error.code !== "ENOENT")
339
+ throw error;
340
+ }
341
+ renameSync(temporaryPath, targetPath);
342
+ }
343
+ catch (error) {
344
+ if (backedUp) {
345
+ try {
346
+ renameSync(backupPath, targetPath);
347
+ }
348
+ catch {
349
+ // Preserve the original failure; the caller still rolls back both files.
350
+ }
351
+ }
352
+ throw error;
353
+ }
354
+ if (backedUp)
355
+ removeFile(backupPath);
356
+ }
357
+ /** End a task before replacement/deletion; stopped tasks report a benign error. */
358
+ function endTask(options) {
359
+ const args = ["/End", "/TN", options.taskName];
360
+ const result = runSchtasks(options, args, true);
361
+ if (result.status !== 0 && !isMissingTaskFailure(result) && !isNotRunningFailure(result)) {
362
+ throw commandFailure(options.schtasksPath, args, result);
363
+ }
364
+ }
365
+ /** Best-effort recovery for a task stopped before a replacement/deletion failed. */
366
+ function restartTask(options) {
367
+ try {
368
+ runSchtasks(options, ["/Run", "/TN", options.taskName], true);
369
+ }
370
+ catch {
371
+ // Recovery must never replace the failure that triggered the rollback.
372
+ }
373
+ }
374
+ /** Install or replace the current user's logon task and start it once. */
375
+ export function installService(cliPath, dbPath, serviceOptions = {}) {
376
+ requiredText(cliPath, "CLI path");
377
+ requiredText(dbPath, "database path");
378
+ const options = resolveOptions(serviceOptions);
379
+ mkdirSync(options.configDirectory, { recursive: true, mode: 0o700 });
380
+ const previousLauncher = existsSync(options.launcherPath) ? readFileSync(options.launcherPath) : null;
381
+ const previousXml = existsSync(options.taskXmlPath) ? readFileSync(options.taskXmlPath) : null;
382
+ const existingTask = lookupTask(options);
383
+ const previousTaskWasRunning = existingTask.kind === "present" && /^running$/i.test(existingTask.state ?? "");
384
+ if (previousTaskWasRunning)
385
+ endTask(options);
386
+ // `process.argv[1]` is commonly relative when glass is launched as
387
+ // `node dist/cli.js`; Task Scheduler will not resolve it relative to the
388
+ // terminal that performed the install.
389
+ const resolvedCliPath = isAbsolute(cliPath) || win32.isAbsolute(cliPath) ? cliPath : resolve(cliPath);
390
+ const resolvedDbPath = isAbsolute(dbPath) || win32.isAbsolute(dbPath) ? dbPath : resolve(dbPath);
391
+ const launcher = renderLauncher(options.nodePath, resolvedCliPath, resolvedDbPath);
392
+ const xml = renderTaskXml(options.launcherPath, {
393
+ taskName: options.taskName,
394
+ user: options.user,
395
+ powershellPath: options.powershellPath,
396
+ workingDirectory: homedir(),
397
+ });
398
+ const tempSuffix = randomUUID();
399
+ const temporaryLauncher = `${options.launcherPath}.${tempSuffix}.tmp`;
400
+ const temporaryXml = `${options.taskXmlPath}.${tempSuffix}.tmp`;
401
+ let taskCreated = false;
402
+ try {
403
+ // Windows PowerShell 5.1 reads UTF-8 scripts reliably only when they have
404
+ // a BOM (important for non-ASCII usernames and installation paths).
405
+ writeFileSync(temporaryLauncher, Buffer.from(`\uFEFF${launcher}`, "utf8"), { mode: 0o600, flag: "wx" });
406
+ // Task Scheduler expects UTF-16 XML. Include the BOM as required by its
407
+ // XML importer rather than relying on the host's default encoding.
408
+ writeFileSync(temporaryXml, `\uFEFF${xml}`, { encoding: "utf16le", mode: 0o600, flag: "wx" });
409
+ // Both temporary files are complete before either target is replaced.
410
+ replaceCompletedFile(temporaryLauncher, options.launcherPath);
411
+ replaceCompletedFile(temporaryXml, options.taskXmlPath);
412
+ runSchtasks(options, ["/Create", "/TN", options.taskName, "/XML", options.taskXmlPath, "/F"]);
413
+ taskCreated = true;
414
+ runSchtasks(options, ["/Run", "/TN", options.taskName]);
415
+ }
416
+ catch (error) {
417
+ try {
418
+ removeFile(temporaryLauncher);
419
+ }
420
+ catch {
421
+ // Preserve the replacement failure below.
422
+ }
423
+ try {
424
+ removeFile(temporaryXml);
425
+ }
426
+ catch {
427
+ // Preserve the replacement failure below.
428
+ }
429
+ // Once Create succeeded, retain the matching generated files even if an
430
+ // immediate Run is unavailable. The logon trigger still has a valid
431
+ // task and will start it at the next interactive logon.
432
+ if (!taskCreated) {
433
+ try {
434
+ restoreFile(options.launcherPath, previousLauncher);
435
+ restoreFile(options.taskXmlPath, previousXml);
436
+ }
437
+ catch {
438
+ // Preserve the replacement failure below.
439
+ }
440
+ if (previousTaskWasRunning)
441
+ restartTask(options);
442
+ }
443
+ throw error;
444
+ }
445
+ return options.taskName;
446
+ }
447
+ /**
448
+ * Return a stable ActiveState line in addition to useful Task Scheduler
449
+ * details. A confirmed missing task is inactive; access/operational failures
450
+ * are surfaced instead of being misreported as an absent task.
451
+ */
452
+ export function serviceStatus(serviceOptions = {}) {
453
+ const options = resolveOptions(serviceOptions);
454
+ const task = lookupTask(options);
455
+ if (task.kind === "missing") {
456
+ return `ActiveState=inactive\nTask=${options.taskName} is not installed`;
457
+ }
458
+ const status = task.state ?? "unknown";
459
+ const active = /^running$/i.test(status);
460
+ return [
461
+ `TaskName=${options.taskName}`,
462
+ `TaskStatus=${status.trim() || "unknown"}`,
463
+ `ActiveState=${active ? "active" : "inactive"}`,
464
+ ].join("\n");
465
+ }
466
+ /** Remove the task and only the generated scheduler definition files. */
467
+ export function uninstallService(serviceOptions = {}) {
468
+ const options = resolveOptions(serviceOptions);
469
+ const task = lookupTask(options);
470
+ if (task.kind === "missing") {
471
+ // A confirmed not-found result is sufficient to clean up stale generated
472
+ // definitions; operational failures above intentionally leave them alone.
473
+ removeFile(options.launcherPath);
474
+ removeFile(options.taskXmlPath);
475
+ return false;
476
+ }
477
+ const deleteArgs = ["/Delete", "/TN", options.taskName, "/F"];
478
+ const previousTaskWasRunning = /^running$/i.test(task.state ?? "");
479
+ if (previousTaskWasRunning)
480
+ endTask(options);
481
+ try {
482
+ const deleted = runSchtasks(options, deleteArgs, true);
483
+ if (deleted.status !== 0 && !isMissingTaskFailure(deleted)) {
484
+ throw commandFailure(options.schtasksPath, deleteArgs, deleted);
485
+ }
486
+ }
487
+ catch (error) {
488
+ if (previousTaskWasRunning)
489
+ restartTask(options);
490
+ throw error;
491
+ }
492
+ // Only a successful delete or a confirmed race-to-not-found permits file cleanup.
493
+ removeFile(options.launcherPath);
494
+ removeFile(options.taskXmlPath);
495
+ return true;
496
+ }
497
+ /** Bind injectable options once for the platform dispatcher and tests. */
498
+ export function createWindowsScheduler(options = {}) {
499
+ return {
500
+ installService: (cliPath, dbPath) => installService(cliPath, dbPath, options),
501
+ serviceStatus: () => serviceStatus(options),
502
+ uninstallService: () => uninstallService(options),
503
+ };
504
+ }
505
+ //# sourceMappingURL=windows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.js","sourceRoot":"","sources":["../../src/scheduler/windows.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,8 @@ export interface ArtifactRecord {
11
11
  export declare class ArtifactStore {
12
12
  private readonly db;
13
13
  private readonly directory;
14
- constructor(db: GlassDatabase, directory: string);
14
+ private readonly platform;
15
+ constructor(db: GlassDatabase, directory: string, platform?: NodeJS.Platform);
15
16
  save(sessionId: string | null, kind: string, content: string | Buffer, metadata?: Record<string, unknown>): ArtifactRecord;
16
17
  get(idOrUri: string): ArtifactRecord | null;
17
18
  read(idOrUri: string, offset?: number, limit?: number): Buffer;
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-store.d.ts","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,EAAE,EAAE,aAAa,EACjB,SAAS,EAAE,MAAM;IAGpC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,cAAc;IAc9H,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAe3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,KAAK,SAAY,GAAG,MAAM;CAM7D"}
1
+ {"version":3,"file":"artifact-store.d.ts","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAFR,EAAE,EAAE,aAAa,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAAM,CAAC,QAA2B;IAG/D,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,cAAc;IAe9H,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAe3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,KAAK,SAAY,GAAG,MAAM;CAM7D"}
@@ -1,19 +1,24 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { chmodSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
+ import { shouldEnforcePosixPermissions } from "../paths.js";
4
5
  export class ArtifactStore {
5
6
  db;
6
7
  directory;
7
- constructor(db, directory) {
8
+ platform;
9
+ constructor(db, directory, platform = process.platform) {
8
10
  this.db = db;
9
11
  this.directory = directory;
12
+ this.platform = platform;
10
13
  }
11
14
  save(sessionId, kind, content, metadata = {}) {
12
15
  const id = randomUUID();
13
16
  const path = join(this.directory, id);
14
17
  const data = typeof content === "string" ? Buffer.from(content) : content;
15
- writeFileSync(path, data, { mode: 0o600, flag: "wx" });
16
- chmodSync(path, 0o600);
18
+ const enforcePermissions = shouldEnforcePosixPermissions(this.platform);
19
+ writeFileSync(path, data, { flag: "wx", ...(enforcePermissions ? { mode: 0o600 } : {}) });
20
+ if (enforcePermissions)
21
+ chmodSync(path, 0o600);
17
22
  const createdAt = Date.now();
18
23
  this.db.prepare(`
19
24
  INSERT INTO artifacts(id, session_id, kind, file_path, byte_count, metadata_json, created_at)
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-store.js","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAsBjC,MAAM,OAAO,aAAa;IAEL;IACA;IAFnB,YACmB,EAAiB,EACjB,SAAiB;QADjB,OAAE,GAAF,EAAE,CAAe;QACjB,cAAS,GAAT,SAAS,CAAQ;IACjC,CAAC;IAEJ,IAAI,CAAC,SAAwB,EAAE,IAAY,EAAE,OAAwB,EAAE,WAAoC,EAAE;QAC3G,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC1E,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;KAGf,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;QACxF,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtG,CAAC;IAED,GAAG,CAAC,OAAe;QACjB,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7F,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,CAAC,EAAE,CAA4B,CAAC;QACvG,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,GAAG,EAAE,cAAc,GAAG,CAAC,EAAE,EAAE;YAC3B,IAAI,EAAE,GAAG,CAAC,SAAS;YACnB,SAAS,EAAE,GAAG,CAAC,UAAU;YACzB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAA4B;YAClE,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,GAAG,IAAI;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;CACF"}
1
+ {"version":3,"file":"artifact-store.js","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import Database from "better-sqlite3";
2
2
  export type GlassDatabase = Database.Database;
3
- export declare function openDatabase(path: string): GlassDatabase;
3
+ export declare function openDatabase(path: string, platform?: NodeJS.Platform): GlassDatabase;
4
4
  export declare function checkpointDatabase(db: GlassDatabase): void;
5
5
  //# sourceMappingURL=database.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAiTtC,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC;AAE9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CA+FxD;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI,CAE1D"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAkTtC,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC;AAE9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,aAAa,CAgGtG;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI,CAE1D"}
@@ -1,6 +1,7 @@
1
1
  import Database from "better-sqlite3";
2
2
  import { dirname } from "node:path";
3
3
  import { chmodSync, existsSync, mkdirSync } from "node:fs";
4
+ import { shouldEnforcePosixPermissions } from "../paths.js";
4
5
  import { bashApprovalExecutable } from "../tools/safety.js";
5
6
  const SESSION_SCHEMA = `
6
7
  CREATE TABLE IF NOT EXISTS schema_migrations (
@@ -292,25 +293,28 @@ function migrateBashApprovalScopes(db) {
292
293
  }
293
294
  }
294
295
  }
295
- export function openDatabase(path) {
296
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
297
- const previousUmask = process.umask(0o077);
296
+ export function openDatabase(path, platform = process.platform) {
297
+ const enforcePermissions = shouldEnforcePosixPermissions(platform);
298
+ mkdirSync(dirname(path), { recursive: true, ...(enforcePermissions ? { mode: 0o700 } : {}) });
299
+ const previousUmask = enforcePermissions ? process.umask(0o077) : null;
298
300
  let db;
299
301
  try {
300
302
  db = new Database(path, { timeout: 5_000 });
301
- chmodSync(path, 0o600);
303
+ if (enforcePermissions)
304
+ chmodSync(path, 0o600);
302
305
  db.pragma("journal_mode = WAL");
303
306
  db.pragma("synchronous = FULL");
304
307
  db.pragma("foreign_keys = ON");
305
308
  db.pragma("busy_timeout = 5000");
306
309
  db.pragma("wal_autocheckpoint = 1000");
307
310
  for (const sidecar of [`${path}-wal`, `${path}-shm`]) {
308
- if (existsSync(sidecar))
311
+ if (enforcePermissions && existsSync(sidecar))
309
312
  chmodSync(sidecar, 0o600);
310
313
  }
311
314
  }
312
315
  finally {
313
- process.umask(previousUmask);
316
+ if (previousUmask !== null)
317
+ process.umask(previousUmask);
314
318
  }
315
319
  const migrate = db.transaction(() => {
316
320
  db.exec(SESSION_SCHEMA);