@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.
- package/README.md +1 -0
- package/THIRD_PARTY_NOTICES.md +26 -0
- package/node_modules/@herbertgao/pi-bark/package.json +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -2
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +427 -120
- package/node_modules/@herbertgao/pi-subagents/docs/rpc.md +184 -0
- package/node_modules/@herbertgao/pi-subagents/docs/workflows.md +466 -0
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +6 -6
- package/node_modules/@herbertgao/pi-subagents/examples/workflows/compose.js +52 -0
- package/node_modules/@herbertgao/pi-subagents/examples/workflows/fan-out-audit.js +56 -0
- package/node_modules/@herbertgao/pi-subagents/examples/workflows/gated-fix.js +60 -0
- package/node_modules/@herbertgao/pi-subagents/examples/workflows/lib/count-child.js +30 -0
- package/node_modules/@herbertgao/pi-subagents/examples/workflows/review-panel.js +68 -0
- package/node_modules/@herbertgao/pi-subagents/examples/workflows/structured-findings.js +81 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +12 -10
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +52 -12
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +837 -146
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +213 -39
- package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +73 -14
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +101 -47
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +2249 -914
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +13 -0
- package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +215 -0
- package/node_modules/@herbertgao/pi-subagents/src/mention.ts +147 -0
- package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +9 -1
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +40 -26
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +18 -8
- package/node_modules/@herbertgao/pi-subagents/src/prompts.ts +46 -9
- package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +21 -16
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +137 -7
- package/node_modules/@herbertgao/pi-subagents/src/structured-output.ts +136 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +126 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-mention.ts +274 -0
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +20 -5
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +10 -4
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +167 -22
- package/node_modules/@herbertgao/pi-subagents/src/ui/workflow-card.ts +555 -0
- package/node_modules/@herbertgao/pi-subagents/src/ui/workflow-dialog.ts +1304 -0
- package/node_modules/@herbertgao/pi-subagents/src/ui/workflow-menu.ts +226 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/collisions.ts +122 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/entry.ts +47 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/host.ts +463 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/journal.ts +164 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/json-schema.ts +142 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/meta.ts +401 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/progress.ts +622 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/runtime.ts +1399 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/saved.ts +230 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/task.ts +333 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/tool-description.ts +200 -0
- package/node_modules/@herbertgao/pi-subagents/src/workflow/worker-source.ts +781 -0
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +97 -95
- package/node_modules/@herbertgao/pi-subagents/src/xml.ts +13 -0
- package/node_modules/@herbertgao/resume-from/package.json +1 -1
- package/node_modules/@herbertgao/sol-pi/README.md +3 -3
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +4 -4
- package/node_modules/@herbertgao/sol-pi/agents-install.md +4 -4
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +6 -6
- package/node_modules/@herbertgao/sol-pi/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/dist/index.ts +39 -89
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
- package/node_modules/@narumitw/pi-btw/package.json +4 -4
- package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -87
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +8 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +40 -37
- package/node_modules/@narumitw/pi-caffeinate/README.md +21 -66
- package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +10 -41
- package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +2 -2
- package/node_modules/@narumitw/pi-caffeinate/package.json +50 -51
- package/node_modules/@narumitw/pi-caffeinate/src/caffeinate.ts +637 -663
- package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +114 -120
- package/node_modules/@narumitw/pi-caffeinate/src/inhibitor-process.ts +29 -29
- package/node_modules/@narumitw/pi-caffeinate/src/inhibitors.ts +108 -126
- package/node_modules/@narumitw/pi-caffeinate/src/settings.ts +124 -128
- package/node_modules/pi-multi-account/CHANGELOG.md +1209 -0
- package/node_modules/pi-multi-account/CONTRIBUTING.md +61 -0
- package/node_modules/pi-multi-account/LICENSE +21 -0
- package/node_modules/pi-multi-account/README.md +197 -0
- package/node_modules/pi-multi-account/SECURITY.md +27 -0
- package/node_modules/pi-multi-account/auth-file-transaction.ts +56 -0
- package/node_modules/pi-multi-account/child-usability.ts +233 -0
- package/node_modules/pi-multi-account/compaction-summary.ts +32 -0
- package/node_modules/pi-multi-account/completion-route-planner.ts +224 -0
- package/node_modules/pi-multi-account/context-guard.ts +420 -0
- package/node_modules/pi-multi-account/cursor/LICENSE +21 -0
- package/node_modules/pi-multi-account/cursor/NOTICE +2 -0
- package/node_modules/pi-multi-account/cursor/auth.ts +165 -0
- package/node_modules/pi-multi-account/cursor/bridge-handle.ts +155 -0
- package/node_modules/pi-multi-account/cursor/conversation-registry.ts +104 -0
- package/node_modules/pi-multi-account/cursor/cursor-models-raw.json +611 -0
- package/node_modules/pi-multi-account/cursor/cursor-shared.ts +192 -0
- package/node_modules/pi-multi-account/cursor/h2-bridge.mjs +175 -0
- package/node_modules/pi-multi-account/cursor/index.ts +572 -0
- package/node_modules/pi-multi-account/cursor/message-parsing.ts +323 -0
- package/node_modules/pi-multi-account/cursor/prompt-usage.ts +53 -0
- package/node_modules/pi-multi-account/cursor/proto/agent_pb.ts +15294 -0
- package/node_modules/pi-multi-account/cursor/proxy.ts +2510 -0
- package/node_modules/pi-multi-account/cursor/session-lifecycle.ts +40 -0
- package/node_modules/pi-multi-account/cursor/sse-keepalive.ts +24 -0
- package/node_modules/pi-multi-account/cursor/stream-lifecycle.ts +193 -0
- package/node_modules/pi-multi-account/cursor/upstream-watchdog.ts +88 -0
- package/node_modules/pi-multi-account/cursor-bridge.ts +240 -0
- package/node_modules/pi-multi-account/cursor-model-name.ts +12 -0
- package/node_modules/pi-multi-account/index.ts +11825 -0
- package/node_modules/pi-multi-account/model-catalog.ts +354 -0
- package/node_modules/pi-multi-account/package.json +101 -0
- package/node_modules/pi-multi-account/pi-contract.ts +281 -0
- package/node_modules/pi-multi-account/provider-payload-stream.ts +44 -0
- package/node_modules/pi-multi-account/provider-priority.ts +189 -0
- package/node_modules/pi-multi-account/slot-proxy-auth.ts +167 -0
- package/node_modules/pi-multi-account/slot-proxy.ts +344 -0
- package/node_modules/pi-multi-account/state-file-transaction.ts +67 -0
- package/node_modules/pi-multi-account/usage.ts +1099 -0
- package/node_modules/pi-typesafe/README.md +6 -2
- package/node_modules/pi-typesafe/dist/client.d.ts +11 -0
- package/node_modules/pi-typesafe/dist/client.js +45 -10
- package/node_modules/pi-typesafe/dist/index.d.ts +2 -2
- package/node_modules/pi-typesafe/dist/index.js +1 -1
- package/node_modules/pi-typesafe/package.json +2 -2
- package/node_modules/pi-web-access/CHANGELOG.md +36 -0
- package/node_modules/pi-web-access/README.md +75 -18
- package/node_modules/pi-web-access/anysearch.ts +4 -15
- package/node_modules/pi-web-access/bocha.ts +3 -22
- package/node_modules/pi-web-access/brave.ts +3 -21
- package/node_modules/pi-web-access/brightdata.ts +5 -32
- package/node_modules/pi-web-access/content-find.ts +168 -53
- package/node_modules/pi-web-access/curator-page.ts +4 -1
- package/node_modules/pi-web-access/curator-run.ts +2 -1
- package/node_modules/pi-web-access/curator-server.ts +1 -0
- package/node_modules/pi-web-access/dist/index.js +24620 -0
- package/node_modules/pi-web-access/domain-filter-normalization.ts +14 -0
- package/node_modules/pi-web-access/duckduckgo.ts +3 -21
- package/node_modules/pi-web-access/extract.ts +3 -1
- package/node_modules/pi-web-access/firecrawl.ts +5 -29
- package/node_modules/pi-web-access/gemini-search.ts +81 -32
- package/node_modules/pi-web-access/index.ts +149 -148
- package/node_modules/pi-web-access/jina-search.ts +4 -15
- package/node_modules/pi-web-access/kagi.ts +4 -13
- package/node_modules/pi-web-access/kimi-search.ts +5 -30
- package/node_modules/pi-web-access/mistral-search.ts +1 -15
- package/node_modules/pi-web-access/ollama.ts +2 -7
- package/node_modules/pi-web-access/openai-search.ts +174 -36
- package/node_modules/pi-web-access/opencode-session-headers.ts +24 -0
- package/node_modules/pi-web-access/package.json +10 -4
- package/node_modules/pi-web-access/page-query.ts +10 -2
- package/node_modules/pi-web-access/parallel.ts +1 -15
- package/node_modules/pi-web-access/pdf-extract.ts +3 -0
- package/node_modules/pi-web-access/querit.ts +5 -29
- package/node_modules/pi-web-access/search-answer-formatting.ts +11 -0
- package/node_modules/pi-web-access/search-result-count-normalization.ts +4 -0
- package/node_modules/pi-web-access/search1api.ts +5 -29
- package/node_modules/pi-web-access/searchinfinity.ts +5 -29
- package/node_modules/pi-web-access/searxng.ts +3 -21
- package/node_modules/pi-web-access/serpapi.ts +5 -28
- package/node_modules/pi-web-access/serpbase.ts +3 -22
- package/node_modules/pi-web-access/serpdive.ts +3 -21
- package/node_modules/pi-web-access/serper.ts +5 -28
- package/node_modules/pi-web-access/serply.ts +197 -0
- package/node_modules/pi-web-access/source-check.ts +11 -47
- package/node_modules/pi-web-access/summary-review.ts +7 -3
- package/node_modules/pi-web-access/tavily.ts +3 -21
- package/node_modules/pi-web-access/tinyfish.ts +5 -29
- package/node_modules/pi-web-access/utils.ts +9 -1
- package/node_modules/pi-web-access/valyu.ts +5 -28
- package/node_modules/pi-web-access/xai-search.ts +1 -15
- package/node_modules/pi-web-access/xcrawl.ts +5 -32
- package/package.json +17 -11
|
@@ -1,811 +1,785 @@
|
|
|
1
1
|
import type { ChildProcess } from "node:child_process";
|
|
2
2
|
import process from "node:process";
|
|
3
|
-
import type {
|
|
4
|
-
ExtensionAPI,
|
|
5
|
-
ExtensionCommandContext,
|
|
6
|
-
ExtensionContext,
|
|
7
|
-
} from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
4
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
type DbusScreenSaverClient,
|
|
6
|
+
type DbusScreenSaverFactory,
|
|
7
|
+
defaultDbusScreenSaverFactory,
|
|
8
|
+
INHIBIT_REASON,
|
|
9
|
+
SCREENSAVER_BUS_NAME,
|
|
14
10
|
} from "./dbus-inhibit.js";
|
|
15
11
|
import { startInhibitorProcess, stopInhibitorProcess } from "./inhibitor-process.js";
|
|
16
12
|
import { formatMode, getInhibitorCommand, type InhibitorCommand } from "./inhibitors.js";
|
|
17
13
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
type CaffeinateMode,
|
|
15
|
+
type CaffeinateSettings,
|
|
16
|
+
loadSettings,
|
|
17
|
+
saveSettings,
|
|
18
|
+
settingsFilePath,
|
|
23
19
|
} from "./settings.js";
|
|
24
20
|
|
|
25
21
|
const STATUS_KEY = "caffeinate";
|
|
26
22
|
const DISABLED_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
27
23
|
const DEFAULT_MODE = "display" satisfies CaffeinateMode;
|
|
28
24
|
const COMMAND_COMPLETIONS = [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
{ value: "display", label: "display", description: "Keep system and display awake" },
|
|
26
|
+
{ value: "sleep", label: "sleep", description: "Keep system awake; allow display sleep" },
|
|
27
|
+
{ value: "status", label: "status", description: "Show current status" },
|
|
28
|
+
{ value: "mode", label: "mode", description: "Choose keep-awake mode" },
|
|
29
|
+
{ value: "stop", label: "stop", description: "Release inhibitor for now" },
|
|
30
|
+
{ value: "help", label: "help", description: "Show command help" },
|
|
35
31
|
];
|
|
36
32
|
const MENU_OPTIONS = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
display: "Keep system and display awake",
|
|
34
|
+
sleep: "Keep system awake; allow display sleep",
|
|
35
|
+
status: "Show current status",
|
|
36
|
+
stop: "Release inhibitor for now",
|
|
37
|
+
help: "Show command help",
|
|
42
38
|
} as const;
|
|
43
39
|
const MODE_OPTIONS = {
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
display: "Keep system and display awake",
|
|
41
|
+
sleep: "Keep system awake; allow display sleep",
|
|
46
42
|
} as const;
|
|
47
43
|
|
|
48
44
|
type CommandAction = "menu" | "help" | "status" | "mode" | "sleep" | "display" | "stop";
|
|
49
45
|
type CommandContext = ExtensionCommandContext;
|
|
50
46
|
|
|
51
47
|
interface CaffeinateOptions {
|
|
52
|
-
|
|
48
|
+
dbusFactory?: DbusScreenSaverFactory;
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
interface PendingDbusStart {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
token: number;
|
|
53
|
+
controller: AbortController;
|
|
54
|
+
client?: DbusScreenSaverClient;
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
interface CaffeinateState {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
58
|
+
process?: ChildProcess;
|
|
59
|
+
dbus?: DbusScreenSaverClient;
|
|
60
|
+
currentSession?: { generation: number; ctx: ExtensionContext };
|
|
61
|
+
dbusCleanup?: Promise<void>;
|
|
62
|
+
pendingDbus?: PendingDbusStart;
|
|
63
|
+
startedAt?: number;
|
|
64
|
+
command?: InhibitorCommand;
|
|
65
|
+
lastError?: string;
|
|
66
|
+
inhibitWarning?: string;
|
|
67
|
+
inhibitorStarting: boolean;
|
|
68
|
+
activeTurns: number;
|
|
69
|
+
available: boolean;
|
|
70
|
+
disabled: boolean;
|
|
71
|
+
mode: CaffeinateMode;
|
|
72
|
+
quiet: boolean;
|
|
73
|
+
settingsLoaded: boolean;
|
|
74
|
+
settingsError?: string;
|
|
75
|
+
settingsNotice?: string;
|
|
76
|
+
iconWarningShown: boolean;
|
|
77
|
+
sessionGeneration: number;
|
|
78
|
+
menuController: AbortController;
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
const state: CaffeinateState = {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
activeTurns: 0,
|
|
83
|
+
available: true,
|
|
84
|
+
inhibitorStarting: false,
|
|
85
|
+
disabled: isDisabled(),
|
|
86
|
+
mode: DEFAULT_MODE,
|
|
87
|
+
quiet: false,
|
|
88
|
+
settingsLoaded: false,
|
|
89
|
+
iconWarningShown: false,
|
|
90
|
+
sessionGeneration: 0,
|
|
91
|
+
menuController: new AbortController(),
|
|
96
92
|
};
|
|
97
93
|
|
|
98
94
|
let dbusFactory = defaultDbusScreenSaverFactory;
|
|
99
95
|
let inhibitSequence = 0;
|
|
100
96
|
|
|
101
97
|
export default function caffeinate(pi: ExtensionAPI, options: CaffeinateOptions = {}) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
98
|
+
dbusFactory = options.dbusFactory ?? defaultDbusScreenSaverFactory;
|
|
99
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
100
|
+
const generation = ++state.sessionGeneration;
|
|
101
|
+
state.currentSession = { generation, ctx };
|
|
102
|
+
replaceMenuController("Caffeinate session replaced");
|
|
103
|
+
state.iconWarningShown = false;
|
|
104
|
+
state.settingsNotice = undefined;
|
|
105
|
+
warnDeprecatedIcon(ctx);
|
|
106
|
+
await loadSettingsIntoState(ctx, generation);
|
|
107
|
+
if (generation !== state.sessionGeneration) return;
|
|
108
|
+
updateStatus(ctx);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
pi.on("agent_start", async (_event, ctx) => {
|
|
112
|
+
const generation = state.sessionGeneration;
|
|
113
|
+
await ensureSettingsLoaded(ctx, generation);
|
|
114
|
+
if (generation !== state.sessionGeneration) return;
|
|
115
|
+
state.activeTurns += 1;
|
|
116
|
+
await startInhibitor(ctx, generation, { notify: !state.quiet });
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
120
|
+
const generation = state.sessionGeneration;
|
|
121
|
+
state.activeTurns = Math.max(0, state.activeTurns - 1);
|
|
122
|
+
if (state.activeTurns === 0) {
|
|
123
|
+
await stopInhibitor(ctx, "agent finished", { notify: !state.quiet });
|
|
124
|
+
}
|
|
125
|
+
if (generation !== state.sessionGeneration) return;
|
|
126
|
+
updateStatus(ctx);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
130
|
+
const generation = ++state.sessionGeneration;
|
|
131
|
+
state.currentSession = undefined;
|
|
132
|
+
state.menuController.abort(new DOMException("Caffeinate session shut down", "AbortError"));
|
|
133
|
+
state.activeTurns = 0;
|
|
134
|
+
await stopInhibitor(ctx, "session shutdown", { notify: false });
|
|
135
|
+
await modeOperationQueue;
|
|
136
|
+
if (generation !== state.sessionGeneration) return;
|
|
137
|
+
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
pi.registerCommand("caffeinate", {
|
|
141
|
+
description: "Open pi-caffeinate keep-awake controls",
|
|
142
|
+
getArgumentCompletions: (prefix) => commandCompletions(prefix),
|
|
143
|
+
handler: async (args, ctx) => {
|
|
144
|
+
const generation = state.sessionGeneration;
|
|
145
|
+
const command = parseCommand(args);
|
|
146
|
+
if (command === "sleep" || command === "display") {
|
|
147
|
+
await setModeAfterSettingsLoad(ctx, command, generation);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
await ensureSettingsLoaded(ctx, generation);
|
|
151
|
+
if (generation !== state.sessionGeneration) return;
|
|
152
|
+
await handleCaffeinateCommand(args, ctx, generation);
|
|
153
|
+
},
|
|
154
|
+
});
|
|
159
155
|
}
|
|
160
156
|
|
|
161
157
|
async function handleCaffeinateCommand(args: string, ctx: CommandContext, generation: number) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
158
|
+
const command = parseCommand(args);
|
|
159
|
+
switch (command) {
|
|
160
|
+
case "menu":
|
|
161
|
+
await showMenu(ctx, generation);
|
|
162
|
+
return;
|
|
163
|
+
case "help":
|
|
164
|
+
ctx.ui.notify(buildCommandGuide(), "info");
|
|
165
|
+
return;
|
|
166
|
+
case "status":
|
|
167
|
+
showStatus(ctx);
|
|
168
|
+
return;
|
|
169
|
+
case "mode":
|
|
170
|
+
await showModeSelector(ctx, generation);
|
|
171
|
+
return;
|
|
172
|
+
case "sleep":
|
|
173
|
+
await setMode(ctx, "sleep", generation);
|
|
174
|
+
return;
|
|
175
|
+
case "display":
|
|
176
|
+
await setMode(ctx, "display", generation);
|
|
177
|
+
return;
|
|
178
|
+
case "stop":
|
|
179
|
+
await stopCaffeinate(ctx, "manual stop", generation);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
ctx.ui.notify(`Unknown /caffeinate command: ${args.trim()}\n\n${buildCommandGuide()}`, "warning");
|
|
188
184
|
}
|
|
189
185
|
|
|
190
186
|
async function showMenu(ctx: CommandContext, generation: number) {
|
|
191
|
-
|
|
187
|
+
await runCaffeinateMenu(ctx, generation, "main");
|
|
192
188
|
}
|
|
193
189
|
|
|
194
190
|
async function showModeSelector(ctx: CommandContext, generation: number) {
|
|
195
|
-
|
|
191
|
+
await runCaffeinateMenu(ctx, generation, "mode");
|
|
196
192
|
}
|
|
197
193
|
|
|
198
194
|
async function runCaffeinateMenu(ctx: CommandContext, generation: number, start: "main" | "mode") {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
195
|
+
if (!ctx.hasUI) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
start === "mode"
|
|
198
|
+
? "Mode selection requires TUI or RPC mode. Use /caffeinate sleep or /caffeinate display."
|
|
199
|
+
: `The pi-caffeinate menu requires TUI or RPC mode.\n\n${buildCommandGuide()}\n\n${describeState()}`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
const menuSignal = state.menuController.signal;
|
|
203
|
+
const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;
|
|
204
|
+
const { defineMenu, runMenu } = await import("@narumitw/pi-tui-kit");
|
|
205
|
+
if (!isCurrent()) return;
|
|
206
|
+
type Screen = "main" | "mode";
|
|
207
|
+
type Action = "display" | "sleep" | "status" | "stop" | "help";
|
|
208
|
+
const menu = defineMenu<undefined, Screen, Action>({
|
|
209
|
+
start,
|
|
210
|
+
screens: {
|
|
211
|
+
main: () => ({
|
|
212
|
+
kind: "actions",
|
|
213
|
+
title: "pi-caffeinate controls",
|
|
214
|
+
lines: describeState().split("\n"),
|
|
215
|
+
items: Object.entries(MENU_OPTIONS).map(([id, label]) => ({
|
|
216
|
+
id,
|
|
217
|
+
label,
|
|
218
|
+
action: id as Action,
|
|
219
|
+
})),
|
|
220
|
+
hint: "close",
|
|
221
|
+
}),
|
|
222
|
+
mode: () => ({
|
|
223
|
+
kind: "actions",
|
|
224
|
+
title: `pi-caffeinate mode (current: ${formatMode(state.mode)})`,
|
|
225
|
+
items: Object.entries(MODE_OPTIONS).map(([id, label]) => ({
|
|
226
|
+
id,
|
|
227
|
+
label,
|
|
228
|
+
action: id as Action,
|
|
229
|
+
})),
|
|
230
|
+
hint: "close",
|
|
231
|
+
}),
|
|
232
|
+
},
|
|
233
|
+
actions: {
|
|
234
|
+
display: async () => {
|
|
235
|
+
await setMode(ctx, "display", generation);
|
|
236
|
+
return { kind: "close" };
|
|
237
|
+
},
|
|
238
|
+
sleep: async () => {
|
|
239
|
+
await setMode(ctx, "sleep", generation);
|
|
240
|
+
return { kind: "close" };
|
|
241
|
+
},
|
|
242
|
+
status: async () => {
|
|
243
|
+
showStatus(ctx);
|
|
244
|
+
return { kind: "close" };
|
|
245
|
+
},
|
|
246
|
+
stop: async () => {
|
|
247
|
+
await stopCaffeinate(ctx, "manual stop", generation);
|
|
248
|
+
return { kind: "close" };
|
|
249
|
+
},
|
|
250
|
+
help: async () => {
|
|
251
|
+
ctx.ui.notify(buildCommandGuide(), "info");
|
|
252
|
+
return { kind: "close" };
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
await runMenu(ctx, menu, {
|
|
257
|
+
getState: () => undefined,
|
|
258
|
+
signal: menuSignal,
|
|
259
|
+
isCurrent,
|
|
260
|
+
});
|
|
265
261
|
}
|
|
266
262
|
|
|
267
263
|
function replaceMenuController(reason: string) {
|
|
268
|
-
|
|
269
|
-
|
|
264
|
+
state.menuController.abort(new DOMException(reason, "AbortError"));
|
|
265
|
+
state.menuController = new AbortController();
|
|
270
266
|
}
|
|
271
267
|
|
|
272
268
|
let modeOperationQueue = Promise.resolve();
|
|
273
269
|
|
|
274
|
-
function setModeAfterSettingsLoad(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
await ensureSettingsLoaded(ctx, generation);
|
|
281
|
-
if (generation !== state.sessionGeneration) return;
|
|
282
|
-
await setModeNow(ctx, mode, generation);
|
|
283
|
-
});
|
|
270
|
+
function setModeAfterSettingsLoad(ctx: ExtensionContext, mode: CaffeinateMode, generation: number): Promise<void> {
|
|
271
|
+
return enqueueModeOperation(async () => {
|
|
272
|
+
await ensureSettingsLoaded(ctx, generation);
|
|
273
|
+
if (generation !== state.sessionGeneration) return;
|
|
274
|
+
await setModeNow(ctx, mode, generation);
|
|
275
|
+
});
|
|
284
276
|
}
|
|
285
277
|
|
|
286
278
|
function setMode(ctx: ExtensionContext, mode: CaffeinateMode, generation: number): Promise<void> {
|
|
287
|
-
|
|
279
|
+
return enqueueModeOperation(() => setModeNow(ctx, mode, generation));
|
|
288
280
|
}
|
|
289
281
|
|
|
290
282
|
function enqueueModeOperation(operation: () => Promise<void>): Promise<void> {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
283
|
+
const queued = modeOperationQueue.then(operation);
|
|
284
|
+
modeOperationQueue = queued.catch(() => undefined);
|
|
285
|
+
return queued;
|
|
294
286
|
}
|
|
295
287
|
|
|
296
288
|
async function setModeNow(ctx: ExtensionContext, mode: CaffeinateMode, generation: number) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
ctx.ui.notify(`pi-caffeinate mode set to ${formatMode(mode)} and saved.`, "info");
|
|
360
|
-
updateStatus(ctx);
|
|
289
|
+
if (generation !== state.sessionGeneration) return;
|
|
290
|
+
const previousMode = state.mode;
|
|
291
|
+
const previousQuiet = state.quiet;
|
|
292
|
+
const restartRequired = Boolean(hasActiveInhibitor() && previousMode !== mode && !state.command?.custom);
|
|
293
|
+
state.settingsError = undefined;
|
|
294
|
+
|
|
295
|
+
if (restartRequired) {
|
|
296
|
+
state.mode = mode;
|
|
297
|
+
await stopInhibitor(ctx, "mode changed", { notify: false });
|
|
298
|
+
if (generation !== state.sessionGeneration) return;
|
|
299
|
+
await startInhibitor(ctx, generation, { notify: false });
|
|
300
|
+
if (generation !== state.sessionGeneration) return;
|
|
301
|
+
if (!hasActiveInhibitor()) {
|
|
302
|
+
const applicationError = state.lastError ?? "the inhibitor could not be restarted";
|
|
303
|
+
state.mode = previousMode;
|
|
304
|
+
await startInhibitor(ctx, generation, { notify: false });
|
|
305
|
+
if (generation !== state.sessionGeneration) return;
|
|
306
|
+
const rollbackError = hasActiveInhibitor()
|
|
307
|
+
? undefined
|
|
308
|
+
: (state.lastError ?? "the previous inhibitor could not be restored");
|
|
309
|
+
state.settingsError = rollbackError
|
|
310
|
+
? `mode application failed (${applicationError}); runtime rollback failed: ${rollbackError}`
|
|
311
|
+
: `mode application failed and was rolled back: ${applicationError}`;
|
|
312
|
+
ctx.ui.notify(`pi-caffeinate ${state.settingsError}`, "warning");
|
|
313
|
+
updateStatus(ctx);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let savedSettings: CaffeinateSettings;
|
|
319
|
+
try {
|
|
320
|
+
savedSettings = await saveSettings({ mode, updatedAt: Date.now() });
|
|
321
|
+
} catch (error) {
|
|
322
|
+
if (generation !== state.sessionGeneration) return;
|
|
323
|
+
let rollbackError: string | undefined;
|
|
324
|
+
if (restartRequired) {
|
|
325
|
+
state.mode = previousMode;
|
|
326
|
+
state.quiet = previousQuiet;
|
|
327
|
+
await stopInhibitor(ctx, "settings save failed", { notify: false });
|
|
328
|
+
if (generation !== state.sessionGeneration) return;
|
|
329
|
+
await startInhibitor(ctx, generation, { notify: false });
|
|
330
|
+
if (generation !== state.sessionGeneration) return;
|
|
331
|
+
if (!hasActiveInhibitor()) {
|
|
332
|
+
rollbackError = state.lastError ?? "the prior inhibitor was not restored";
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
state.settingsError = rollbackError
|
|
336
|
+
? `settings save failed (${formatError(error)}); runtime rollback failed: ${rollbackError}`
|
|
337
|
+
: `settings save failed: ${formatError(error)}`;
|
|
338
|
+
ctx.ui.notify(
|
|
339
|
+
`pi-caffeinate mode remains ${formatMode(previousMode)}; settings were not saved: ${state.settingsError}`,
|
|
340
|
+
"warning",
|
|
341
|
+
);
|
|
342
|
+
updateStatus(ctx);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (generation !== state.sessionGeneration) return;
|
|
347
|
+
state.mode = mode;
|
|
348
|
+
state.quiet = savedSettings.quiet;
|
|
349
|
+
ctx.ui.notify(`pi-caffeinate mode set to ${formatMode(mode)} and saved.`, "info");
|
|
350
|
+
updateStatus(ctx);
|
|
361
351
|
}
|
|
362
352
|
|
|
363
353
|
function showStatus(ctx: ExtensionContext) {
|
|
364
|
-
|
|
365
|
-
|
|
354
|
+
ctx.ui.notify(describeState(), statusLevel());
|
|
355
|
+
updateStatus(ctx);
|
|
366
356
|
}
|
|
367
357
|
|
|
368
358
|
async function stopCaffeinate(ctx: ExtensionContext, reason: string, sessionGeneration: number) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
359
|
+
state.activeTurns = 0;
|
|
360
|
+
await stopInhibitor(ctx, reason);
|
|
361
|
+
if (sessionGeneration !== state.sessionGeneration) return;
|
|
362
|
+
updateStatus(ctx);
|
|
373
363
|
}
|
|
374
364
|
|
|
375
365
|
export function parseCommand(args: string): CommandAction | "unknown" {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
366
|
+
const command = args.trim().toLowerCase();
|
|
367
|
+
if (!command) return "menu";
|
|
368
|
+
if (command === "help") return "help";
|
|
369
|
+
if (command === "status") return "status";
|
|
370
|
+
if (command === "mode" || command === "config" || command === "settings") return "mode";
|
|
371
|
+
if (command === "sleep" || command === "system") return "sleep";
|
|
372
|
+
if (command === "display" || command === "screen") return "display";
|
|
373
|
+
if (command === "stop" || command === "off") return "stop";
|
|
374
|
+
return "unknown";
|
|
385
375
|
}
|
|
386
376
|
|
|
387
377
|
export function commandCompletions(prefix: string) {
|
|
388
|
-
|
|
389
|
-
|
|
378
|
+
const normalized = prefix.trimStart().toLowerCase();
|
|
379
|
+
if (/\s/.test(normalized)) return null;
|
|
390
380
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
);
|
|
394
|
-
return matches.length > 0 ? matches : null;
|
|
381
|
+
const matches = COMMAND_COMPLETIONS.filter((completion) => completion.value.startsWith(normalized));
|
|
382
|
+
return matches.length > 0 ? matches : null;
|
|
395
383
|
}
|
|
396
384
|
|
|
397
385
|
function buildCommandGuide() {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
async function startInhibitor(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
if (options.notify !== false) ctx.ui.notify(`Released pi-caffeinate (${reason}).`, "info");
|
|
568
|
-
await Promise.all([dbusCleanup, pendingClient?.close().catch(() => undefined)]);
|
|
569
|
-
if (!dbus) return;
|
|
570
|
-
try {
|
|
571
|
-
await dbus.uninhibit();
|
|
572
|
-
} catch {
|
|
573
|
-
// Closing the session-bus connection also releases its inhibition cookie.
|
|
574
|
-
}
|
|
575
|
-
await dbus.close().catch(() => undefined);
|
|
386
|
+
return [
|
|
387
|
+
"pi-caffeinate commands:",
|
|
388
|
+
"/caffeinate — open keep-awake controls",
|
|
389
|
+
"/caffeinate display — keep the system and display awake",
|
|
390
|
+
"/caffeinate sleep — keep the system awake while allowing display sleep",
|
|
391
|
+
"/caffeinate status — show current mode, settings, and inhibitor state",
|
|
392
|
+
"/caffeinate mode — choose a keep-awake mode",
|
|
393
|
+
"/caffeinate stop — release the active inhibitor until the next agent run",
|
|
394
|
+
].join("\n");
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async function startInhibitor(ctx: ExtensionContext, sessionGeneration: number, options: { notify?: boolean } = {}) {
|
|
398
|
+
if (state.disabled || hasActiveInhibitor() || state.inhibitorStarting) {
|
|
399
|
+
updateStatus(ctx);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const token = ++inhibitSequence;
|
|
404
|
+
const command = getInhibitorCommand(state.mode);
|
|
405
|
+
const wantsDbus =
|
|
406
|
+
!command?.custom &&
|
|
407
|
+
state.mode === "display" &&
|
|
408
|
+
process.platform === "linux" &&
|
|
409
|
+
(command === undefined || command.addDbusIdleInhibit === true);
|
|
410
|
+
if (!command && !wantsDbus) {
|
|
411
|
+
state.available = false;
|
|
412
|
+
state.lastError = `No supported sleep inhibitor found for ${process.platform}.`;
|
|
413
|
+
ctx.ui.notify(state.lastError, "warning");
|
|
414
|
+
updateStatus(ctx);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
state.inhibitorStarting = true;
|
|
419
|
+
state.inhibitWarning = undefined;
|
|
420
|
+
let child: ChildProcess | undefined;
|
|
421
|
+
let childError =
|
|
422
|
+
!command && wantsDbus
|
|
423
|
+
? "No supported system sleep inhibitor is available; direct system suspend may remain possible."
|
|
424
|
+
: undefined;
|
|
425
|
+
let assembling = true;
|
|
426
|
+
const handleChildFailure = (message: string) => {
|
|
427
|
+
if (!child || token !== inhibitSequence || state.process !== child) return;
|
|
428
|
+
state.process = undefined;
|
|
429
|
+
state.command = undefined;
|
|
430
|
+
if (assembling) {
|
|
431
|
+
childError = message;
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
applyChildFailure(message);
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
if (command) {
|
|
438
|
+
try {
|
|
439
|
+
child = startInhibitorProcess(
|
|
440
|
+
command,
|
|
441
|
+
(error) => handleChildFailure(`${command.description} failed: ${error.message}`),
|
|
442
|
+
(exit) => handleChildFailure(`${command.description} exited unexpectedly (${exit}).`),
|
|
443
|
+
);
|
|
444
|
+
state.process = child;
|
|
445
|
+
state.command = command;
|
|
446
|
+
state.startedAt = Date.now();
|
|
447
|
+
} catch (error) {
|
|
448
|
+
childError = `${command.description}: ${formatError(error)}`;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
let dbus: DbusScreenSaverClient | undefined;
|
|
453
|
+
let dbusError: string | undefined;
|
|
454
|
+
if (wantsDbus) {
|
|
455
|
+
const pending: PendingDbusStart = { token, controller: new AbortController() };
|
|
456
|
+
state.pendingDbus = pending;
|
|
457
|
+
try {
|
|
458
|
+
const client = await dbusFactory();
|
|
459
|
+
if (!pendingStartIsCurrent(pending, sessionGeneration)) {
|
|
460
|
+
await client.close().catch(() => undefined);
|
|
461
|
+
await cancelPendingStart(token, child, command);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
pending.client = client;
|
|
465
|
+
await client.inhibit(INHIBIT_REASON, pending.controller.signal);
|
|
466
|
+
if (!pendingStartIsCurrent(pending, sessionGeneration)) {
|
|
467
|
+
await cancelPendingStart(token, child, command);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
pending.client = undefined;
|
|
471
|
+
state.pendingDbus = undefined;
|
|
472
|
+
dbus = client;
|
|
473
|
+
} catch (error) {
|
|
474
|
+
const stale = !pendingStartIsCurrent(pending, sessionGeneration) || pending.controller.signal.aborted;
|
|
475
|
+
const pendingClient = takePendingDbusClient(pending);
|
|
476
|
+
await pendingClient?.close().catch(() => undefined);
|
|
477
|
+
if (stale) {
|
|
478
|
+
await cancelPendingStart(token, child, command);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
dbusError = `D-Bus idle inhibit (${SCREENSAVER_BUS_NAME}): ${formatError(error)}`;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
assembling = false;
|
|
486
|
+
if (startIsStale(token, sessionGeneration)) {
|
|
487
|
+
await cancelPendingStart(token, child, command);
|
|
488
|
+
await dbus?.close().catch(() => undefined);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
state.inhibitorStarting = false;
|
|
493
|
+
state.dbus = dbus;
|
|
494
|
+
if (dbus) {
|
|
495
|
+
dbus.setFailureHandler((error) => applyDbusFailure(token, dbus, error));
|
|
496
|
+
if (state.dbus !== dbus) return;
|
|
497
|
+
}
|
|
498
|
+
const failures = [childError, dbusError].filter((failure): failure is string => Boolean(failure));
|
|
499
|
+
if (!hasActiveInhibitor()) {
|
|
500
|
+
state.startedAt = undefined;
|
|
501
|
+
state.command = undefined;
|
|
502
|
+
state.available = false;
|
|
503
|
+
state.lastError = failures.join("; ") || `No supported sleep inhibitor found for ${process.platform}.`;
|
|
504
|
+
ctx.ui.notify(state.lastError, "warning");
|
|
505
|
+
updateStatus(ctx);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
state.startedAt ??= Date.now();
|
|
510
|
+
state.available = true;
|
|
511
|
+
state.lastError = undefined;
|
|
512
|
+
state.inhibitWarning = failures.length > 0 ? failures.join("; ") : undefined;
|
|
513
|
+
if (state.inhibitWarning) {
|
|
514
|
+
ctx.ui.notify(`pi-caffeinate is partially active: ${state.inhibitWarning}`, "warning");
|
|
515
|
+
} else if (options.notify !== false) {
|
|
516
|
+
ctx.ui.notify(`Keeping computer awake (${statusModeLabel()}).`, "info");
|
|
517
|
+
}
|
|
518
|
+
updateStatus(ctx);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async function stopInhibitor(ctx: ExtensionContext, reason: string, options: { notify?: boolean } = {}) {
|
|
522
|
+
inhibitSequence += 1;
|
|
523
|
+
const child = state.process;
|
|
524
|
+
const dbus = state.dbus;
|
|
525
|
+
const dbusCleanup = state.dbusCleanup;
|
|
526
|
+
const pending = state.pendingDbus;
|
|
527
|
+
const command = state.command;
|
|
528
|
+
const wasStarting = state.inhibitorStarting;
|
|
529
|
+
state.process = undefined;
|
|
530
|
+
state.dbus = undefined;
|
|
531
|
+
state.dbusCleanup = undefined;
|
|
532
|
+
state.pendingDbus = undefined;
|
|
533
|
+
state.command = undefined;
|
|
534
|
+
state.startedAt = undefined;
|
|
535
|
+
state.inhibitWarning = undefined;
|
|
536
|
+
state.inhibitorStarting = false;
|
|
537
|
+
dbus?.setFailureHandler(undefined);
|
|
538
|
+
pending?.controller.abort(new DOMException(`Caffeinate stopped: ${reason}`, "AbortError"));
|
|
539
|
+
const pendingClient = pending ? takePendingDbusClient(pending) : undefined;
|
|
540
|
+
if (child) stopInhibitorProcess(child, command);
|
|
541
|
+
if (!child && !dbus && !pendingClient && !wasStarting) {
|
|
542
|
+
await dbusCleanup;
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (options.notify !== false) ctx.ui.notify(`Released pi-caffeinate (${reason}).`, "info");
|
|
546
|
+
await Promise.all([dbusCleanup, pendingClient?.close().catch(() => undefined)]);
|
|
547
|
+
if (!dbus) return;
|
|
548
|
+
try {
|
|
549
|
+
await dbus.uninhibit();
|
|
550
|
+
} catch {
|
|
551
|
+
// Closing the session-bus connection also releases its inhibition cookie.
|
|
552
|
+
}
|
|
553
|
+
await dbus.close().catch(() => undefined);
|
|
576
554
|
}
|
|
577
555
|
|
|
578
556
|
function applyChildFailure(message: string) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
557
|
+
if (state.dbus) {
|
|
558
|
+
state.available = true;
|
|
559
|
+
state.lastError = undefined;
|
|
560
|
+
state.inhibitWarning = message;
|
|
561
|
+
} else {
|
|
562
|
+
state.startedAt = undefined;
|
|
563
|
+
state.available = false;
|
|
564
|
+
state.lastError = message;
|
|
565
|
+
state.inhibitWarning = undefined;
|
|
566
|
+
}
|
|
567
|
+
const ctx = currentSessionContext();
|
|
568
|
+
if (!ctx) return;
|
|
569
|
+
ctx.ui.notify(message, "warning");
|
|
570
|
+
updateStatus(ctx);
|
|
593
571
|
}
|
|
594
572
|
|
|
595
573
|
function applyDbusFailure(token: number, client: DbusScreenSaverClient, error: Error) {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
574
|
+
if (token !== inhibitSequence || state.dbus !== client) return;
|
|
575
|
+
client.setFailureHandler(undefined);
|
|
576
|
+
state.dbus = undefined;
|
|
577
|
+
const message = `D-Bus idle inhibit (${SCREENSAVER_BUS_NAME}) failed: ${formatError(error)}`;
|
|
578
|
+
const notification = state.process ? `pi-caffeinate is partially active: ${message}` : message;
|
|
579
|
+
if (state.process) {
|
|
580
|
+
state.available = true;
|
|
581
|
+
state.lastError = undefined;
|
|
582
|
+
state.inhibitWarning = message;
|
|
583
|
+
} else {
|
|
584
|
+
state.startedAt = undefined;
|
|
585
|
+
state.command = undefined;
|
|
586
|
+
state.available = false;
|
|
587
|
+
state.lastError = [state.inhibitWarning, message].filter(Boolean).join("; ");
|
|
588
|
+
state.inhibitWarning = undefined;
|
|
589
|
+
}
|
|
590
|
+
const cleanup = client.close().catch(() => undefined);
|
|
591
|
+
state.dbusCleanup = cleanup;
|
|
592
|
+
void cleanup.then(() => {
|
|
593
|
+
if (state.dbusCleanup === cleanup) state.dbusCleanup = undefined;
|
|
594
|
+
});
|
|
595
|
+
const ctx = currentSessionContext();
|
|
596
|
+
if (!ctx) return;
|
|
597
|
+
ctx.ui.notify(notification, "warning");
|
|
598
|
+
updateStatus(ctx);
|
|
621
599
|
}
|
|
622
600
|
|
|
623
601
|
function currentSessionContext() {
|
|
624
|
-
|
|
625
|
-
|
|
602
|
+
const session = state.currentSession;
|
|
603
|
+
return session?.generation === state.sessionGeneration ? session.ctx : undefined;
|
|
626
604
|
}
|
|
627
605
|
|
|
628
606
|
function hasActiveInhibitor() {
|
|
629
|
-
|
|
607
|
+
return Boolean(state.process || state.dbus);
|
|
630
608
|
}
|
|
631
609
|
|
|
632
610
|
function startIsStale(token: number, sessionGeneration: number) {
|
|
633
|
-
|
|
611
|
+
return token !== inhibitSequence || sessionGeneration !== state.sessionGeneration;
|
|
634
612
|
}
|
|
635
613
|
|
|
636
614
|
function pendingStartIsCurrent(pending: PendingDbusStart, sessionGeneration: number) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
615
|
+
return (
|
|
616
|
+
state.pendingDbus === pending &&
|
|
617
|
+
!pending.controller.signal.aborted &&
|
|
618
|
+
!startIsStale(pending.token, sessionGeneration)
|
|
619
|
+
);
|
|
642
620
|
}
|
|
643
621
|
|
|
644
622
|
function takePendingDbusClient(pending: PendingDbusStart) {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
623
|
+
if (state.pendingDbus === pending) state.pendingDbus = undefined;
|
|
624
|
+
const client = pending.client;
|
|
625
|
+
pending.client = undefined;
|
|
626
|
+
return client;
|
|
649
627
|
}
|
|
650
628
|
|
|
651
629
|
async function cancelPendingStart(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
630
|
+
token: number,
|
|
631
|
+
child: ChildProcess | undefined,
|
|
632
|
+
command: InhibitorCommand | undefined,
|
|
655
633
|
) {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
634
|
+
if (token !== inhibitSequence) return;
|
|
635
|
+
inhibitSequence += 1;
|
|
636
|
+
state.inhibitorStarting = false;
|
|
637
|
+
const pending = state.pendingDbus?.token === token ? state.pendingDbus : undefined;
|
|
638
|
+
state.pendingDbus = undefined;
|
|
639
|
+
pending?.controller.abort(new DOMException("Caffeinate start cancelled", "AbortError"));
|
|
640
|
+
const pendingClient = pending ? takePendingDbusClient(pending) : undefined;
|
|
641
|
+
if (child && state.process === child) {
|
|
642
|
+
state.process = undefined;
|
|
643
|
+
state.command = undefined;
|
|
644
|
+
state.startedAt = undefined;
|
|
645
|
+
stopInhibitorProcess(child, command);
|
|
646
|
+
}
|
|
647
|
+
await pendingClient?.close().catch(() => undefined);
|
|
670
648
|
}
|
|
671
649
|
|
|
672
650
|
function updateStatus(ctx: ExtensionContext) {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
651
|
+
if (state.disabled || state.quiet) {
|
|
652
|
+
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
677
655
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
656
|
+
if (hasActiveInhibitor()) {
|
|
657
|
+
ctx.ui.setStatus(STATUS_KEY, withDeprecatedIcon(statusModeLabel()));
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
682
660
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
661
|
+
if (!state.available) {
|
|
662
|
+
ctx.ui.setStatus(STATUS_KEY, withDeprecatedIcon("unavailable"));
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
687
665
|
|
|
688
|
-
|
|
666
|
+
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
689
667
|
}
|
|
690
668
|
|
|
691
669
|
function describeState() {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
lines.unshift(
|
|
725
|
-
"pi-caffeinate is idle and will keep the computer awake during the next agent run.",
|
|
726
|
-
);
|
|
727
|
-
return lines.join("\n");
|
|
670
|
+
const customCommand = hasCustomCommand();
|
|
671
|
+
const lines = [
|
|
672
|
+
`Mode: ${formatMode(state.mode)}${customCommand ? " (overridden by custom command)" : ""}`,
|
|
673
|
+
`Quiet mode: ${state.quiet ? "enabled" : "disabled"}`,
|
|
674
|
+
`Settings: ${settingsFilePath()}`,
|
|
675
|
+
];
|
|
676
|
+
|
|
677
|
+
if (customCommand) lines.push("Custom command: PI_CAFFEINATE_COMMAND overrides the saved mode.");
|
|
678
|
+
if (state.settingsNotice) lines.push(`Settings note: ${state.settingsNotice}`);
|
|
679
|
+
if (state.settingsError) lines.push(`Settings warning: ${state.settingsError}`);
|
|
680
|
+
if (state.disabled) {
|
|
681
|
+
lines.unshift("pi-caffeinate is disabled by PI_CAFFEINATE_DISABLED.");
|
|
682
|
+
return lines.join("\n");
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if (hasActiveInhibitor()) {
|
|
686
|
+
const seconds = state.startedAt ? Math.round((Date.now() - state.startedAt) / 1000) : 0;
|
|
687
|
+
const activeParts: string[] = [];
|
|
688
|
+
if (state.dbus) activeParts.push(`D-Bus idle inhibit (${SCREENSAVER_BUS_NAME})`);
|
|
689
|
+
if (state.process && state.command) activeParts.push(state.command.description);
|
|
690
|
+
lines.unshift(`pi-caffeinate is active using ${activeParts.join(" + ") || "an inhibitor"} for ${seconds}s.`);
|
|
691
|
+
if (state.inhibitWarning) lines.push(`Inhibitor warning: ${state.inhibitWarning}`);
|
|
692
|
+
return lines.join("\n");
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (!state.available) {
|
|
696
|
+
lines.unshift(`pi-caffeinate is unavailable: ${state.lastError ?? "unknown reason"}`);
|
|
697
|
+
return lines.join("\n");
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
lines.unshift("pi-caffeinate is idle and will keep the computer awake during the next agent run.");
|
|
701
|
+
return lines.join("\n");
|
|
728
702
|
}
|
|
729
703
|
|
|
730
704
|
function statusLevel() {
|
|
731
|
-
|
|
705
|
+
return state.available && !state.settingsError && !state.inhibitWarning ? "info" : "warning";
|
|
732
706
|
}
|
|
733
707
|
|
|
734
708
|
function statusModeLabel() {
|
|
735
|
-
|
|
736
|
-
|
|
709
|
+
if (state.command?.custom) return "custom";
|
|
710
|
+
return formatMode(state.mode);
|
|
737
711
|
}
|
|
738
712
|
|
|
739
713
|
async function ensureSettingsLoaded(ctx: ExtensionContext, generation: number) {
|
|
740
|
-
|
|
741
|
-
|
|
714
|
+
if (state.disabled || state.settingsLoaded) return;
|
|
715
|
+
await loadSettingsIntoState(ctx, generation);
|
|
742
716
|
}
|
|
743
717
|
|
|
744
718
|
async function loadSettingsIntoState(ctx: ExtensionContext, generation: number) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
719
|
+
if (state.disabled) {
|
|
720
|
+
state.settingsLoaded = true;
|
|
721
|
+
state.settingsError = undefined;
|
|
722
|
+
state.quiet = false;
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const settings = await loadSettings();
|
|
727
|
+
if (generation !== state.sessionGeneration) return;
|
|
728
|
+
state.settingsLoaded = true;
|
|
729
|
+
state.settingsError = undefined;
|
|
730
|
+
if (settings.notice) {
|
|
731
|
+
state.settingsNotice = settings.notice;
|
|
732
|
+
ctx.ui.notify(settings.notice, "warning");
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (settings.kind === "loaded") {
|
|
736
|
+
state.mode = settings.settings.mode;
|
|
737
|
+
state.quiet = settings.settings.quiet;
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
state.mode = DEFAULT_MODE;
|
|
742
|
+
state.quiet = false;
|
|
743
|
+
if (settings.kind === "invalid") {
|
|
744
|
+
state.settingsError = settings.reason;
|
|
745
|
+
ctx.ui.notify(
|
|
746
|
+
`pi-caffeinate settings ignored: ${settings.reason}; using ${formatMode(DEFAULT_MODE)} mode.`,
|
|
747
|
+
"warning",
|
|
748
|
+
);
|
|
749
|
+
}
|
|
776
750
|
}
|
|
777
751
|
|
|
778
752
|
function formatError(error: unknown) {
|
|
779
|
-
|
|
753
|
+
return error instanceof Error ? error.message : String(error);
|
|
780
754
|
}
|
|
781
755
|
|
|
782
756
|
function isDisabled() {
|
|
783
|
-
|
|
784
|
-
|
|
757
|
+
const value = process.env.PI_CAFFEINATE_DISABLED?.trim().toLowerCase();
|
|
758
|
+
return value ? DISABLED_VALUES.has(value) : false;
|
|
785
759
|
}
|
|
786
760
|
|
|
787
761
|
function hasCustomCommand() {
|
|
788
|
-
|
|
762
|
+
return Boolean(process.env.PI_CAFFEINATE_COMMAND?.trim());
|
|
789
763
|
}
|
|
790
764
|
|
|
791
765
|
function withDeprecatedIcon(text: string) {
|
|
792
|
-
|
|
793
|
-
|
|
766
|
+
const icon = process.env.PI_CAFFEINATE_ICON?.trim();
|
|
767
|
+
return icon ? `${icon} ${text}` : text;
|
|
794
768
|
}
|
|
795
769
|
|
|
796
770
|
function warnDeprecatedIcon(ctx: ExtensionContext) {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
771
|
+
if (state.iconWarningShown || !process.env.PI_CAFFEINATE_ICON?.trim()) return;
|
|
772
|
+
state.iconWarningShown = true;
|
|
773
|
+
ctx.ui.notify(
|
|
774
|
+
"PI_CAFFEINATE_ICON is deprecated but still works for now. If you use @narumitw/pi-statusline, move it to pi-statusline.json (extensionStatusIcons.caffeinate).",
|
|
775
|
+
"warning",
|
|
776
|
+
);
|
|
803
777
|
}
|
|
804
778
|
|
|
805
779
|
export {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
780
|
+
formatMode,
|
|
781
|
+
getInhibitorCommand,
|
|
782
|
+
splitCommand,
|
|
783
|
+
windowsInhibitorScript,
|
|
810
784
|
} from "./inhibitors.js";
|
|
811
785
|
export { normalizeCaffeinateSettings } from "./settings.js";
|