@herbertgao/pi-extensions 2026.9.9 → 2026.9.11

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 (170) hide show
  1. package/README.md +1 -0
  2. package/THIRD_PARTY_NOTICES.md +26 -0
  3. package/node_modules/@herbertgao/pi-bark/package.json +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  5. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  6. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -2
  7. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +12 -0
  8. package/node_modules/@herbertgao/pi-subagents/README.md +427 -120
  9. package/node_modules/@herbertgao/pi-subagents/docs/rpc.md +184 -0
  10. package/node_modules/@herbertgao/pi-subagents/docs/workflows.md +466 -0
  11. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +6 -6
  12. package/node_modules/@herbertgao/pi-subagents/examples/workflows/compose.js +52 -0
  13. package/node_modules/@herbertgao/pi-subagents/examples/workflows/fan-out-audit.js +56 -0
  14. package/node_modules/@herbertgao/pi-subagents/examples/workflows/gated-fix.js +60 -0
  15. package/node_modules/@herbertgao/pi-subagents/examples/workflows/lib/count-child.js +30 -0
  16. package/node_modules/@herbertgao/pi-subagents/examples/workflows/review-panel.js +68 -0
  17. package/node_modules/@herbertgao/pi-subagents/examples/workflows/structured-findings.js +81 -0
  18. package/node_modules/@herbertgao/pi-subagents/package.json +12 -10
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +52 -12
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +837 -146
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +213 -39
  22. package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +73 -14
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +101 -47
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +2249 -914
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +13 -0
  26. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +215 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/mention.ts +147 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +9 -1
  29. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +40 -26
  30. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +18 -8
  31. package/node_modules/@herbertgao/pi-subagents/src/prompts.ts +46 -9
  32. package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +21 -16
  33. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +137 -7
  34. package/node_modules/@herbertgao/pi-subagents/src/structured-output.ts +136 -0
  35. package/node_modules/@herbertgao/pi-subagents/src/types.ts +126 -8
  36. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-mention.ts +274 -0
  37. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +20 -5
  38. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +10 -4
  39. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +167 -22
  40. package/node_modules/@herbertgao/pi-subagents/src/ui/workflow-card.ts +555 -0
  41. package/node_modules/@herbertgao/pi-subagents/src/ui/workflow-dialog.ts +1304 -0
  42. package/node_modules/@herbertgao/pi-subagents/src/ui/workflow-menu.ts +226 -0
  43. package/node_modules/@herbertgao/pi-subagents/src/workflow/collisions.ts +122 -0
  44. package/node_modules/@herbertgao/pi-subagents/src/workflow/entry.ts +47 -0
  45. package/node_modules/@herbertgao/pi-subagents/src/workflow/host.ts +463 -0
  46. package/node_modules/@herbertgao/pi-subagents/src/workflow/journal.ts +164 -0
  47. package/node_modules/@herbertgao/pi-subagents/src/workflow/json-schema.ts +142 -0
  48. package/node_modules/@herbertgao/pi-subagents/src/workflow/meta.ts +401 -0
  49. package/node_modules/@herbertgao/pi-subagents/src/workflow/progress.ts +622 -0
  50. package/node_modules/@herbertgao/pi-subagents/src/workflow/runtime.ts +1399 -0
  51. package/node_modules/@herbertgao/pi-subagents/src/workflow/saved.ts +230 -0
  52. package/node_modules/@herbertgao/pi-subagents/src/workflow/task.ts +333 -0
  53. package/node_modules/@herbertgao/pi-subagents/src/workflow/tool-description.ts +200 -0
  54. package/node_modules/@herbertgao/pi-subagents/src/workflow/worker-source.ts +781 -0
  55. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +97 -95
  56. package/node_modules/@herbertgao/pi-subagents/src/xml.ts +13 -0
  57. package/node_modules/@herbertgao/resume-from/package.json +1 -1
  58. package/node_modules/@herbertgao/sol-pi/README.md +3 -3
  59. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +4 -4
  60. package/node_modules/@herbertgao/sol-pi/agents-install.md +4 -4
  61. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +6 -6
  62. package/node_modules/@herbertgao/sol-pi/package.json +2 -2
  63. package/node_modules/@narumitw/pi-btw/dist/index.ts +39 -89
  64. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  65. package/node_modules/@narumitw/pi-btw/package.json +4 -4
  66. package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -87
  67. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +8 -0
  68. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +40 -37
  69. package/node_modules/@narumitw/pi-caffeinate/README.md +21 -66
  70. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +10 -41
  71. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +2 -2
  72. package/node_modules/@narumitw/pi-caffeinate/package.json +50 -51
  73. package/node_modules/@narumitw/pi-caffeinate/src/caffeinate.ts +637 -663
  74. package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +114 -120
  75. package/node_modules/@narumitw/pi-caffeinate/src/inhibitor-process.ts +29 -29
  76. package/node_modules/@narumitw/pi-caffeinate/src/inhibitors.ts +108 -126
  77. package/node_modules/@narumitw/pi-caffeinate/src/settings.ts +124 -128
  78. package/node_modules/pi-multi-account/CHANGELOG.md +1209 -0
  79. package/node_modules/pi-multi-account/CONTRIBUTING.md +61 -0
  80. package/node_modules/pi-multi-account/LICENSE +21 -0
  81. package/node_modules/pi-multi-account/README.md +197 -0
  82. package/node_modules/pi-multi-account/SECURITY.md +27 -0
  83. package/node_modules/pi-multi-account/auth-file-transaction.ts +56 -0
  84. package/node_modules/pi-multi-account/child-usability.ts +233 -0
  85. package/node_modules/pi-multi-account/compaction-summary.ts +32 -0
  86. package/node_modules/pi-multi-account/completion-route-planner.ts +224 -0
  87. package/node_modules/pi-multi-account/context-guard.ts +420 -0
  88. package/node_modules/pi-multi-account/cursor/LICENSE +21 -0
  89. package/node_modules/pi-multi-account/cursor/NOTICE +2 -0
  90. package/node_modules/pi-multi-account/cursor/auth.ts +165 -0
  91. package/node_modules/pi-multi-account/cursor/bridge-handle.ts +155 -0
  92. package/node_modules/pi-multi-account/cursor/conversation-registry.ts +104 -0
  93. package/node_modules/pi-multi-account/cursor/cursor-models-raw.json +611 -0
  94. package/node_modules/pi-multi-account/cursor/cursor-shared.ts +192 -0
  95. package/node_modules/pi-multi-account/cursor/h2-bridge.mjs +175 -0
  96. package/node_modules/pi-multi-account/cursor/index.ts +572 -0
  97. package/node_modules/pi-multi-account/cursor/message-parsing.ts +323 -0
  98. package/node_modules/pi-multi-account/cursor/prompt-usage.ts +53 -0
  99. package/node_modules/pi-multi-account/cursor/proto/agent_pb.ts +15294 -0
  100. package/node_modules/pi-multi-account/cursor/proxy.ts +2510 -0
  101. package/node_modules/pi-multi-account/cursor/session-lifecycle.ts +40 -0
  102. package/node_modules/pi-multi-account/cursor/sse-keepalive.ts +24 -0
  103. package/node_modules/pi-multi-account/cursor/stream-lifecycle.ts +193 -0
  104. package/node_modules/pi-multi-account/cursor/upstream-watchdog.ts +88 -0
  105. package/node_modules/pi-multi-account/cursor-bridge.ts +240 -0
  106. package/node_modules/pi-multi-account/cursor-model-name.ts +12 -0
  107. package/node_modules/pi-multi-account/index.ts +11825 -0
  108. package/node_modules/pi-multi-account/model-catalog.ts +354 -0
  109. package/node_modules/pi-multi-account/package.json +101 -0
  110. package/node_modules/pi-multi-account/pi-contract.ts +281 -0
  111. package/node_modules/pi-multi-account/provider-payload-stream.ts +44 -0
  112. package/node_modules/pi-multi-account/provider-priority.ts +189 -0
  113. package/node_modules/pi-multi-account/slot-proxy-auth.ts +167 -0
  114. package/node_modules/pi-multi-account/slot-proxy.ts +344 -0
  115. package/node_modules/pi-multi-account/state-file-transaction.ts +67 -0
  116. package/node_modules/pi-multi-account/usage.ts +1099 -0
  117. package/node_modules/pi-typesafe/README.md +6 -2
  118. package/node_modules/pi-typesafe/dist/client.d.ts +11 -0
  119. package/node_modules/pi-typesafe/dist/client.js +45 -10
  120. package/node_modules/pi-typesafe/dist/index.d.ts +2 -2
  121. package/node_modules/pi-typesafe/dist/index.js +1 -1
  122. package/node_modules/pi-typesafe/package.json +2 -2
  123. package/node_modules/pi-web-access/CHANGELOG.md +36 -0
  124. package/node_modules/pi-web-access/README.md +75 -18
  125. package/node_modules/pi-web-access/anysearch.ts +4 -15
  126. package/node_modules/pi-web-access/bocha.ts +3 -22
  127. package/node_modules/pi-web-access/brave.ts +3 -21
  128. package/node_modules/pi-web-access/brightdata.ts +5 -32
  129. package/node_modules/pi-web-access/content-find.ts +168 -53
  130. package/node_modules/pi-web-access/curator-page.ts +4 -1
  131. package/node_modules/pi-web-access/curator-run.ts +2 -1
  132. package/node_modules/pi-web-access/curator-server.ts +1 -0
  133. package/node_modules/pi-web-access/dist/index.js +24620 -0
  134. package/node_modules/pi-web-access/domain-filter-normalization.ts +14 -0
  135. package/node_modules/pi-web-access/duckduckgo.ts +3 -21
  136. package/node_modules/pi-web-access/extract.ts +3 -1
  137. package/node_modules/pi-web-access/firecrawl.ts +5 -29
  138. package/node_modules/pi-web-access/gemini-search.ts +81 -32
  139. package/node_modules/pi-web-access/index.ts +149 -148
  140. package/node_modules/pi-web-access/jina-search.ts +4 -15
  141. package/node_modules/pi-web-access/kagi.ts +4 -13
  142. package/node_modules/pi-web-access/kimi-search.ts +5 -30
  143. package/node_modules/pi-web-access/mistral-search.ts +1 -15
  144. package/node_modules/pi-web-access/ollama.ts +2 -7
  145. package/node_modules/pi-web-access/openai-search.ts +174 -36
  146. package/node_modules/pi-web-access/opencode-session-headers.ts +24 -0
  147. package/node_modules/pi-web-access/package.json +10 -4
  148. package/node_modules/pi-web-access/page-query.ts +10 -2
  149. package/node_modules/pi-web-access/parallel.ts +1 -15
  150. package/node_modules/pi-web-access/pdf-extract.ts +3 -0
  151. package/node_modules/pi-web-access/querit.ts +5 -29
  152. package/node_modules/pi-web-access/search-answer-formatting.ts +11 -0
  153. package/node_modules/pi-web-access/search-result-count-normalization.ts +4 -0
  154. package/node_modules/pi-web-access/search1api.ts +5 -29
  155. package/node_modules/pi-web-access/searchinfinity.ts +5 -29
  156. package/node_modules/pi-web-access/searxng.ts +3 -21
  157. package/node_modules/pi-web-access/serpapi.ts +5 -28
  158. package/node_modules/pi-web-access/serpbase.ts +3 -22
  159. package/node_modules/pi-web-access/serpdive.ts +3 -21
  160. package/node_modules/pi-web-access/serper.ts +5 -28
  161. package/node_modules/pi-web-access/serply.ts +197 -0
  162. package/node_modules/pi-web-access/source-check.ts +11 -47
  163. package/node_modules/pi-web-access/summary-review.ts +7 -3
  164. package/node_modules/pi-web-access/tavily.ts +3 -21
  165. package/node_modules/pi-web-access/tinyfish.ts +5 -29
  166. package/node_modules/pi-web-access/utils.ts +9 -1
  167. package/node_modules/pi-web-access/valyu.ts +5 -28
  168. package/node_modules/pi-web-access/xai-search.ts +1 -15
  169. package/node_modules/pi-web-access/xcrawl.ts +5 -32
  170. package/package.json +17 -11
@@ -11,192 +11,188 @@ const LEGACY_SETTINGS_FILE = "pi-caffeinate-settings.json";
11
11
  export type CaffeinateMode = "sleep" | "display";
12
12
 
13
13
  export interface CaffeinateSettings {
14
- mode: CaffeinateMode;
15
- quiet: boolean;
16
- updatedAt: number;
14
+ mode: CaffeinateMode;
15
+ quiet: boolean;
16
+ updatedAt: number;
17
17
  }
18
18
 
19
19
  export interface SettingsFileOperations {
20
- write(path: string, data: string): Promise<void>;
21
- rename(source: string, destination: string): Promise<void>;
20
+ write(path: string, data: string): Promise<void>;
21
+ rename(source: string, destination: string): Promise<void>;
22
22
  }
23
23
 
24
24
  const DEFAULT_FILE_OPERATIONS: SettingsFileOperations = {
25
- write: (path, data) => writeFile(path, data, "utf8").then(() => undefined),
26
- rename,
25
+ write: (path, data) => writeFile(path, data, "utf8").then(() => undefined),
26
+ rename,
27
27
  };
28
28
 
29
29
  export type SettingsLoadResult =
30
- | { kind: "missing"; notice?: string }
31
- | { kind: "invalid"; reason: string; notice?: string }
32
- | { kind: "loaded"; settings: CaffeinateSettings; notice?: string };
30
+ | { kind: "missing"; notice?: string }
31
+ | { kind: "invalid"; reason: string; notice?: string }
32
+ | { kind: "loaded"; settings: CaffeinateSettings; notice?: string };
33
33
 
34
34
  export async function loadSettings(): Promise<SettingsLoadResult> {
35
- await settingsSaveQueue;
36
- const newPath = settingsFilePath();
37
- const newSettings = await readSettingsFile(newPath);
38
- if (newSettings.kind !== "missing") return withLegacyIgnoredNotice(newSettings);
39
-
40
- const legacyPath = legacySettingsFilePath();
41
- const legacySettings = await readSettingsFile(legacyPath);
42
- const concurrentlyCreatedSettings = await readSettingsFile(newPath);
43
- if (concurrentlyCreatedSettings.kind !== "missing") {
44
- return withLegacyIgnoredNotice(concurrentlyCreatedSettings);
45
- }
46
- if (legacySettings.kind === "missing") return { kind: "missing" };
47
- if (legacySettings.kind === "invalid") return legacySettings;
48
-
49
- return {
50
- ...legacySettings,
51
- notice: `Using legacy ${LEGACY_SETTINGS_FILE}; rename it to ${NEW_SETTINGS_FILE}. Future saves write ${NEW_SETTINGS_FILE} without modifying the legacy file.`,
52
- };
35
+ await settingsSaveQueue;
36
+ const newPath = settingsFilePath();
37
+ const newSettings = await readSettingsFile(newPath);
38
+ if (newSettings.kind !== "missing") return withLegacyIgnoredNotice(newSettings);
39
+
40
+ const legacyPath = legacySettingsFilePath();
41
+ const legacySettings = await readSettingsFile(legacyPath);
42
+ const concurrentlyCreatedSettings = await readSettingsFile(newPath);
43
+ if (concurrentlyCreatedSettings.kind !== "missing") {
44
+ return withLegacyIgnoredNotice(concurrentlyCreatedSettings);
45
+ }
46
+ if (legacySettings.kind === "missing") return { kind: "missing" };
47
+ if (legacySettings.kind === "invalid") return legacySettings;
48
+
49
+ return {
50
+ ...legacySettings,
51
+ notice: `Using legacy ${LEGACY_SETTINGS_FILE}; rename it to ${NEW_SETTINGS_FILE}. Future saves write ${NEW_SETTINGS_FILE} without modifying the legacy file.`,
52
+ };
53
53
  }
54
54
 
55
55
  interface SettingsDocumentResult {
56
- result: SettingsLoadResult;
57
- document?: Record<string, unknown>;
56
+ result: SettingsLoadResult;
57
+ document?: Record<string, unknown>;
58
58
  }
59
59
 
60
60
  async function readSettingsDocument(filePath: string): Promise<SettingsDocumentResult> {
61
- let text: string;
62
- try {
63
- text = await readFile(filePath, "utf8");
64
- } catch (error) {
65
- if (isNodeError(error) && error.code === "ENOENT") return { result: { kind: "missing" } };
66
- return { result: { kind: "invalid", reason: `${filePath}: ${formatError(error)}` } };
67
- }
68
- try {
69
- const document = JSON.parse(text) as unknown;
70
- const settings = normalizeCaffeinateSettings(document);
71
- if (settings) {
72
- return {
73
- result: { kind: "loaded", settings },
74
- document: { ...(document as Record<string, unknown>) },
75
- };
76
- }
77
- return {
78
- result: {
79
- kind: "invalid",
80
- reason: `${filePath}: expected { "mode": "sleep" | "display", optional "quiet": boolean }`,
81
- },
82
- };
83
- } catch (error) {
84
- return { result: { kind: "invalid", reason: `${filePath}: ${formatError(error)}` } };
85
- }
61
+ let text: string;
62
+ try {
63
+ text = await readFile(filePath, "utf8");
64
+ } catch (error) {
65
+ if (isNodeError(error) && error.code === "ENOENT") return { result: { kind: "missing" } };
66
+ return { result: { kind: "invalid", reason: `${filePath}: ${formatError(error)}` } };
67
+ }
68
+ try {
69
+ const document = JSON.parse(text) as unknown;
70
+ const settings = normalizeCaffeinateSettings(document);
71
+ if (settings) {
72
+ return {
73
+ result: { kind: "loaded", settings },
74
+ document: { ...(document as Record<string, unknown>) },
75
+ };
76
+ }
77
+ return {
78
+ result: {
79
+ kind: "invalid",
80
+ reason: `${filePath}: expected { "mode": "sleep" | "display", optional "quiet": boolean }`,
81
+ },
82
+ };
83
+ } catch (error) {
84
+ return { result: { kind: "invalid", reason: `${filePath}: ${formatError(error)}` } };
85
+ }
86
86
  }
87
87
 
88
88
  async function readSettingsFile(filePath: string): Promise<SettingsLoadResult> {
89
- return (await readSettingsDocument(filePath)).result;
89
+ return (await readSettingsDocument(filePath)).result;
90
90
  }
91
91
 
92
92
  async function withLegacyIgnoredNotice(settings: SettingsLoadResult): Promise<SettingsLoadResult> {
93
- if (!(await fileExists(legacySettingsFilePath()))) return settings;
94
- return {
95
- ...settings,
96
- notice: `pi-caffeinate legacy settings ignored: ${legacySettingsFilePath()} exists, but ${settingsFilePath()} takes precedence. Delete ${LEGACY_SETTINGS_FILE} after confirming your settings.`,
97
- };
93
+ if (!(await fileExists(legacySettingsFilePath()))) return settings;
94
+ return {
95
+ ...settings,
96
+ notice: `pi-caffeinate legacy settings ignored: ${legacySettingsFilePath()} exists, but ${settingsFilePath()} takes precedence. Delete ${LEGACY_SETTINGS_FILE} after confirming your settings.`,
97
+ };
98
98
  }
99
99
 
100
100
  async function fileExists(filePath: string) {
101
- try {
102
- await access(filePath, constants.F_OK);
103
- return true;
104
- } catch {
105
- return false;
106
- }
101
+ try {
102
+ await access(filePath, constants.F_OK);
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
107
  }
108
108
 
109
109
  async function pathEntryExists(filePath: string) {
110
- try {
111
- await lstat(filePath);
112
- return true;
113
- } catch (error) {
114
- if (isNodeError(error) && error.code === "ENOENT") return false;
115
- throw error;
116
- }
110
+ try {
111
+ await lstat(filePath);
112
+ return true;
113
+ } catch (error) {
114
+ if (isNodeError(error) && error.code === "ENOENT") return false;
115
+ throw error;
116
+ }
117
117
  }
118
118
 
119
119
  export function normalizeCaffeinateSettings(value: unknown): CaffeinateSettings | undefined {
120
- if (!value || typeof value !== "object") return undefined;
121
- const settings = value as { mode?: unknown; quiet?: unknown; updatedAt?: unknown };
122
- if (!isCaffeinateMode(settings.mode)) return undefined;
123
- if (settings.quiet !== undefined && typeof settings.quiet !== "boolean") return undefined;
124
- if (settings.updatedAt !== undefined && typeof settings.updatedAt !== "number") return undefined;
125
- return {
126
- mode: settings.mode,
127
- quiet: settings.quiet ?? false,
128
- updatedAt: settings.updatedAt ?? 0,
129
- };
120
+ if (!value || typeof value !== "object") return undefined;
121
+ const settings = value as { mode?: unknown; quiet?: unknown; updatedAt?: unknown };
122
+ if (!isCaffeinateMode(settings.mode)) return undefined;
123
+ if (settings.quiet !== undefined && typeof settings.quiet !== "boolean") return undefined;
124
+ if (settings.updatedAt !== undefined && typeof settings.updatedAt !== "number") return undefined;
125
+ return {
126
+ mode: settings.mode,
127
+ quiet: settings.quiet ?? false,
128
+ updatedAt: settings.updatedAt ?? 0,
129
+ };
130
130
  }
131
131
 
132
132
  function isCaffeinateMode(value: unknown): value is CaffeinateMode {
133
- return value === "sleep" || value === "display";
133
+ return value === "sleep" || value === "display";
134
134
  }
135
135
 
136
136
  let settingsSaveQueue: Promise<unknown> = Promise.resolve();
137
137
 
138
138
  export function saveSettings(
139
- settings: Omit<CaffeinateSettings, "quiet"> & { quiet?: boolean },
140
- operations: Partial<SettingsFileOperations> = {},
139
+ settings: Omit<CaffeinateSettings, "quiet"> & { quiet?: boolean },
140
+ operations: Partial<SettingsFileOperations> = {},
141
141
  ): Promise<CaffeinateSettings> {
142
- const operation = settingsSaveQueue.then(() => saveSettingsNow(settings, operations));
143
- settingsSaveQueue = operation.catch(() => undefined);
144
- return operation;
142
+ const operation = settingsSaveQueue.then(() => saveSettingsNow(settings, operations));
143
+ settingsSaveQueue = operation.catch(() => undefined);
144
+ return operation;
145
145
  }
146
146
 
147
147
  async function saveSettingsNow(
148
- settings: Omit<CaffeinateSettings, "quiet"> & { quiet?: boolean },
149
- operations: Partial<SettingsFileOperations>,
148
+ settings: Omit<CaffeinateSettings, "quiet"> & { quiet?: boolean },
149
+ operations: Partial<SettingsFileOperations>,
150
150
  ): Promise<CaffeinateSettings> {
151
- const filePath = settingsFilePath();
152
- let current = await readSettingsDocument(filePath);
153
- const replaceCanonical = current.result.kind !== "missing";
154
- if (!replaceCanonical) current = await readSettingsDocument(legacySettingsFilePath());
155
- if (current.result.kind === "invalid") {
156
- throw new Error(`Cannot save pi-caffeinate settings until you repair ${current.result.reason}`);
157
- }
158
- const document = current.document ?? {};
159
- const quiet =
160
- settings.quiet ?? (current.result.kind === "loaded" ? current.result.settings.quiet : false);
161
- const nextSettings = { mode: settings.mode, quiet, updatedAt: settings.updatedAt };
162
- const nextDocument = {
163
- ...document,
164
- ...nextSettings,
165
- };
166
- await mkdir(dirname(filePath), { recursive: true });
167
- const tempFile = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
168
- try {
169
- await (operations.write ?? DEFAULT_FILE_OPERATIONS.write)(
170
- tempFile,
171
- `${JSON.stringify(nextDocument, null, 2)}\n`,
172
- );
173
- if (!replaceCanonical && (await pathEntryExists(filePath))) {
174
- throw new Error(`${NEW_SETTINGS_FILE} was created concurrently; reopen settings and retry.`);
175
- }
176
- await (operations.rename ?? DEFAULT_FILE_OPERATIONS.rename)(tempFile, filePath);
177
- return nextSettings;
178
- } catch (error) {
179
- await rm(tempFile, { force: true }).catch(() => undefined);
180
- throw error;
181
- }
151
+ const filePath = settingsFilePath();
152
+ let current = await readSettingsDocument(filePath);
153
+ const replaceCanonical = current.result.kind !== "missing";
154
+ if (!replaceCanonical) current = await readSettingsDocument(legacySettingsFilePath());
155
+ if (current.result.kind === "invalid") {
156
+ throw new Error(`Cannot save pi-caffeinate settings until you repair ${current.result.reason}`);
157
+ }
158
+ const document = current.document ?? {};
159
+ const quiet = settings.quiet ?? (current.result.kind === "loaded" ? current.result.settings.quiet : false);
160
+ const nextSettings = { mode: settings.mode, quiet, updatedAt: settings.updatedAt };
161
+ const nextDocument = {
162
+ ...document,
163
+ ...nextSettings,
164
+ };
165
+ await mkdir(dirname(filePath), { recursive: true });
166
+ const tempFile = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
167
+ try {
168
+ await (operations.write ?? DEFAULT_FILE_OPERATIONS.write)(tempFile, `${JSON.stringify(nextDocument, null, 2)}\n`);
169
+ if (!replaceCanonical && (await pathEntryExists(filePath))) {
170
+ throw new Error(`${NEW_SETTINGS_FILE} was created concurrently; reopen settings and retry.`);
171
+ }
172
+ await (operations.rename ?? DEFAULT_FILE_OPERATIONS.rename)(tempFile, filePath);
173
+ return nextSettings;
174
+ } catch (error) {
175
+ await rm(tempFile, { force: true }).catch(() => undefined);
176
+ throw error;
177
+ }
182
178
  }
183
179
 
184
180
  export function settingsFilePath() {
185
- return join(agentDir(), NEW_SETTINGS_FILE);
181
+ return join(agentDir(), NEW_SETTINGS_FILE);
186
182
  }
187
183
 
188
184
  function legacySettingsFilePath() {
189
- return join(agentDir(), LEGACY_SETTINGS_FILE);
185
+ return join(agentDir(), LEGACY_SETTINGS_FILE);
190
186
  }
191
187
 
192
188
  function agentDir() {
193
- return getAgentDir();
189
+ return getAgentDir();
194
190
  }
195
191
 
196
192
  function isNodeError(error: unknown): error is NodeJS.ErrnoException {
197
- return error instanceof Error && "code" in error;
193
+ return error instanceof Error && "code" in error;
198
194
  }
199
195
 
200
196
  function formatError(error: unknown) {
201
- return error instanceof Error ? error.message : String(error);
197
+ return error instanceof Error ? error.message : String(error);
202
198
  }