@aliou/pi-processes 0.9.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +40 -42
- package/README.md +54 -84
- package/extensions/process-tabs.ts +26 -0
- package/extensions/processes/client.ts +194 -0
- package/extensions/processes/commands/clear.ts +29 -0
- package/extensions/processes/commands/kill.ts +152 -0
- package/extensions/processes/commands/overview.ts +102 -0
- package/extensions/processes/components/overview-component.ts +729 -0
- package/extensions/processes/components/overview-panel.ts +177 -0
- package/extensions/processes/config/defaults.ts +28 -0
- package/extensions/processes/config/index.ts +13 -0
- package/extensions/processes/config/loader.ts +62 -0
- package/extensions/processes/config/migrations/000-import-legacy-process-config.ts +113 -0
- package/extensions/processes/config/migrations/001-v0-9-4-to-v0-10-0-config.ts +184 -0
- package/extensions/processes/config/migrations/002-stamp-v0-10-0-config-version.ts +21 -0
- package/extensions/processes/config/migrations/index.ts +25 -0
- package/extensions/processes/config/schema.ts +9 -0
- package/extensions/processes/config/types.ts +72 -0
- package/extensions/processes/constants.ts +1 -0
- package/extensions/processes/handlers/commands.ts +113 -0
- package/extensions/processes/handlers/kill-process.ts +31 -0
- package/extensions/processes/handlers/notifications.ts +147 -0
- package/extensions/processes/handlers/requests.ts +114 -0
- package/extensions/processes/handlers/subscriptions.ts +144 -0
- package/extensions/processes/hooks/background-blocker.ts +201 -0
- package/extensions/processes/hooks/cleanup.ts +43 -0
- package/extensions/processes/hooks/event-bridge.ts +32 -0
- package/extensions/processes/i18n/index.ts +3 -0
- package/extensions/processes/i18n/messages.ts +27 -0
- package/extensions/processes/i18n/translator.ts +49 -0
- package/extensions/processes/index.ts +109 -0
- package/extensions/processes/message-renderer.ts +117 -0
- package/extensions/processes/notification-sender.ts +43 -0
- package/extensions/processes/notifications/classify.ts +27 -0
- package/extensions/processes/notifications/log-matchers.ts +146 -0
- package/extensions/processes/notifications/registry.ts +225 -0
- package/extensions/processes/notifications/render-content.ts +122 -0
- package/extensions/processes/notifications/service.ts +336 -0
- package/extensions/processes/notifications/types.ts +11 -0
- package/extensions/processes/settings/apply-setting-change.ts +30 -0
- package/extensions/processes/settings/build-sections.ts +420 -0
- package/extensions/processes/settings/index.ts +42 -0
- package/extensions/processes/tools/clear/index.ts +21 -0
- package/extensions/processes/tools/clear/render.ts +40 -0
- package/extensions/processes/tools/components/index.ts +4 -0
- package/extensions/processes/tools/components/process-action-header.ts +31 -0
- package/extensions/processes/tools/components/process-action-title.ts +17 -0
- package/extensions/processes/tools/components/tool-layout.ts +70 -0
- package/extensions/processes/tools/components/watch.ts +53 -0
- package/extensions/processes/tools/index.ts +265 -0
- package/extensions/processes/tools/list/index.ts +157 -0
- package/extensions/processes/tools/list/render.ts +211 -0
- package/extensions/processes/tools/notify.ts +191 -0
- package/extensions/processes/tools/output/index.ts +307 -0
- package/extensions/processes/tools/output/render.ts +229 -0
- package/extensions/processes/tools/schema.ts +263 -0
- package/extensions/processes/tools/start/index.ts +64 -0
- package/extensions/processes/tools/start/render.ts +67 -0
- package/extensions/processes/tools/stop/index.ts +35 -0
- package/extensions/processes/tools/stop/render.ts +43 -0
- package/extensions/processes/tools/update/index.ts +320 -0
- package/extensions/processes/tools/update/render.ts +251 -0
- package/extensions/processes/tools/utils.ts +112 -0
- package/extensions/processes/tools/watch-format.ts +14 -0
- package/extensions/processes/tools/write/index.ts +75 -0
- package/extensions/processes/tools/write/render.ts +68 -0
- package/extensions/processes/utils/truncate.ts +285 -0
- package/extensions/processes-dock/client.ts +60 -0
- package/extensions/processes-dock/commands/dock.ts +70 -0
- package/extensions/processes-dock/commands/pin.ts +166 -0
- package/extensions/processes-dock/components/log-dock-component.ts +375 -0
- package/extensions/processes-dock/dock-state.ts +33 -0
- package/extensions/processes-dock/index.ts +28 -0
- package/extensions/processes-dock/logs-client.ts +5 -0
- package/extensions/processes-dock/widget/setup.ts +520 -0
- package/extensions/processes-dock/widget/status.ts +149 -0
- package/extensions/processes-dock/widget/types.ts +16 -0
- package/extensions/processes-logs/client.ts +51 -0
- package/extensions/processes-logs/commands/logs.ts +108 -0
- package/extensions/processes-logs/completions.ts +31 -0
- package/extensions/processes-logs/components/log-file-viewer.ts +274 -0
- package/extensions/processes-logs/components/log-overlay-component.ts +685 -0
- package/extensions/processes-logs/index.ts +27 -0
- package/extensions/processes-logs/logs-client.ts +101 -0
- package/extensions/shared/line-buffer.ts +35 -0
- package/extensions/shared/output-payload.ts +28 -0
- package/extensions/shared/ui.ts +146 -0
- package/package.json +47 -20
- package/schema.json +134 -0
- package/skills/pi-processes/SKILL.md +496 -25
- package/src/get-manager.ts +15 -0
- package/src/manager/index.ts +182 -0
- package/src/manager/internal-types.ts +130 -0
- package/src/manager/limits.ts +15 -0
- package/src/manager/process-log-store.ts +422 -0
- package/src/manager/process-output.ts +345 -0
- package/src/manager/process-registry.ts +78 -0
- package/src/manager/process-runtime-controller.ts +499 -0
- package/src/protocol/broadcasts.ts +14 -0
- package/src/protocol/channels.ts +30 -0
- package/src/protocol/commands.ts +24 -0
- package/src/protocol/index.ts +34 -0
- package/src/protocol/logs.ts +23 -0
- package/src/protocol/notifications.ts +48 -0
- package/src/protocol/requests.ts +76 -0
- package/src/types.ts +66 -0
- package/src/utils/ansi.ts +2 -4
- package/src/utils/format.ts +24 -32
- package/src/utils/index.ts +5 -1
- package/src/utils/is-record.ts +3 -0
- package/src/utils/match-line.ts +32 -0
- package/src/utils/platform.ts +13 -0
- package/src/utils/shorten-path.ts +11 -0
- package/src/utils/signals.ts +22 -0
- package/src/commands/clear/command.ts +0 -14
- package/src/commands/clear/index.ts +0 -1
- package/src/commands/completions.ts +0 -38
- package/src/commands/dock/command.ts +0 -29
- package/src/commands/dock/index.ts +0 -1
- package/src/commands/index.ts +0 -33
- package/src/commands/kill/command.ts +0 -69
- package/src/commands/kill/index.ts +0 -1
- package/src/commands/logs/command.ts +0 -47
- package/src/commands/logs/index.ts +0 -1
- package/src/commands/pick-process.ts +0 -34
- package/src/commands/pin/command.ts +0 -34
- package/src/commands/pin/index.ts +0 -1
- package/src/commands/processes/command.ts +0 -39
- package/src/commands/processes/index.ts +0 -1
- package/src/commands/settings/apply-setting-change.ts +0 -72
- package/src/commands/settings/build-sections.ts +0 -160
- package/src/commands/settings/command.ts +0 -20
- package/src/commands/settings/index.ts +0 -1
- package/src/components/log-dock-component.test.ts +0 -29
- package/src/components/log-dock-component.ts +0 -236
- package/src/components/log-file-viewer.ts +0 -317
- package/src/components/log-overlay-component.ts +0 -546
- package/src/components/panel-helpers.ts +0 -37
- package/src/components/process-picker-component.ts +0 -166
- package/src/components/processes-component.ts +0 -485
- package/src/components/status-format.ts +0 -38
- package/src/config.ts +0 -107
- package/src/constants/index.ts +0 -16
- package/src/constants/types.ts +0 -106
- package/src/hooks/background-blocker.ts +0 -66
- package/src/hooks/cleanup.ts +0 -10
- package/src/hooks/index.ts +0 -32
- package/src/hooks/message-renderer.ts +0 -115
- package/src/hooks/process-end.ts +0 -69
- package/src/hooks/process-watch.ts +0 -85
- package/src/hooks/utils.ts +0 -23
- package/src/hooks/widget/index.ts +0 -2
- package/src/hooks/widget/setup.ts +0 -167
- package/src/hooks/widget/status-widget.ts +0 -105
- package/src/hooks/widget/types.ts +0 -20
- package/src/index.ts +0 -35
- package/src/manager.test.ts +0 -331
- package/src/manager.ts +0 -758
- package/src/tools/actions/clear.ts +0 -20
- package/src/tools/actions/debug.ts +0 -148
- package/src/tools/actions/index.ts +0 -171
- package/src/tools/actions/kill.ts +0 -89
- package/src/tools/actions/list.ts +0 -188
- package/src/tools/actions/logs.ts +0 -117
- package/src/tools/actions/output.ts +0 -269
- package/src/tools/actions/start.ts +0 -245
- package/src/tools/actions/write.ts +0 -113
- package/src/tools/index.ts +0 -207
- package/src/utils/ansi.test.ts +0 -22
- package/src/utils/command-executor.test.ts +0 -48
- package/src/utils/keybindings.ts +0 -71
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import type { EventBus } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
import type { ProcessManager } from "../../../src/manager";
|
|
4
|
+
import { CHANNELS } from "../../../src/protocol";
|
|
5
|
+
import type { ManagerEvent, ProcessInfo } from "../../../src/types";
|
|
6
|
+
import { classifyProcessEnd } from "./classify";
|
|
7
|
+
import {
|
|
8
|
+
type CompiledLogMatcher,
|
|
9
|
+
compileLogMatchers,
|
|
10
|
+
evaluateLogMatchers,
|
|
11
|
+
type LogMatchResult,
|
|
12
|
+
} from "./log-matchers";
|
|
13
|
+
import type { NotifyConfig, WatchState } from "./registry";
|
|
14
|
+
import {
|
|
15
|
+
createNotificationRegistry,
|
|
16
|
+
type NotificationRegistry,
|
|
17
|
+
} from "./registry";
|
|
18
|
+
import type {
|
|
19
|
+
Attention,
|
|
20
|
+
ProcessNotificationDetails,
|
|
21
|
+
ProcessNotificationKind,
|
|
22
|
+
} from "./types";
|
|
23
|
+
|
|
24
|
+
const DEFAULT_ATTENTION: Record<
|
|
25
|
+
"onSuccess" | "onFailure" | "onKilled",
|
|
26
|
+
Attention
|
|
27
|
+
> = {
|
|
28
|
+
onSuccess: "context",
|
|
29
|
+
onFailure: "turn",
|
|
30
|
+
// External kills surface as context by default (see DEFAULT_NOTIFY_CONFIG
|
|
31
|
+
// in tools/notify.ts for rationale). Intentional stops are classified
|
|
32
|
+
// separately and never reach this branch.
|
|
33
|
+
onKilled: "context",
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export interface NotificationServiceDeps {
|
|
37
|
+
/**
|
|
38
|
+
* Event bus used to fan out notification events on CHANNELS.NOTIFICATION.
|
|
39
|
+
* The service never calls pi.sendMessage directly; a core delivery listener
|
|
40
|
+
* converts the emitted payload into a persisted custom message. This keeps
|
|
41
|
+
* notification flow event-driven and lets UI extensions observe the same
|
|
42
|
+
* events (e.g. for log-match highlighting).
|
|
43
|
+
*/
|
|
44
|
+
events: EventBus;
|
|
45
|
+
manager: ProcessManager;
|
|
46
|
+
registry: NotificationRegistry;
|
|
47
|
+
getProcess: (id: string) => ProcessInfo | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface ProcessMatcherState {
|
|
51
|
+
matchers: CompiledLogMatcher[];
|
|
52
|
+
revision: number;
|
|
53
|
+
generation: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createNotificationService(deps: NotificationServiceDeps): {
|
|
57
|
+
dispose: () => void;
|
|
58
|
+
} {
|
|
59
|
+
const { events, manager, registry, getProcess } = deps;
|
|
60
|
+
let disposed = false;
|
|
61
|
+
const matcherStates = new Map<string, ProcessMatcherState>();
|
|
62
|
+
|
|
63
|
+
const unsubscribe = manager.onEvent(handleEvent);
|
|
64
|
+
|
|
65
|
+
function handleEvent(event: ManagerEvent): void {
|
|
66
|
+
if (disposed) return;
|
|
67
|
+
|
|
68
|
+
if (event.type === "process_ended") {
|
|
69
|
+
// Defer to a microtask so that tool code (e.g. executeStart) can
|
|
70
|
+
// register the notify config in the registry before we read it.
|
|
71
|
+
// manager.start() may synchronously emit process_ended for missing_pid.
|
|
72
|
+
queueMicrotask(() => {
|
|
73
|
+
if (disposed) return;
|
|
74
|
+
handleProcessEnded(event.info);
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (event.type === "process_output_changed") {
|
|
80
|
+
handleOutputChanged(event);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function handleProcessEnded(info: ProcessInfo): void {
|
|
86
|
+
const isIntentionalStop = registry.consumeIntentionalStop(info.id);
|
|
87
|
+
const kind = classifyProcessEnd(info);
|
|
88
|
+
|
|
89
|
+
if (isIntentionalStop) {
|
|
90
|
+
cleanupMatcherState(info.id);
|
|
91
|
+
registry.unregister(info.id);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const config = registry.get(info.id);
|
|
96
|
+
const attention = resolveAttention(kind, config);
|
|
97
|
+
|
|
98
|
+
const shouldForceDisplay = kind === "crash" || kind === "failure";
|
|
99
|
+
|
|
100
|
+
if (attention === "ignore" && !shouldForceDisplay) {
|
|
101
|
+
cleanupMatcherState(info.id);
|
|
102
|
+
registry.unregister(info.id);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const effectiveAttention: Attention =
|
|
107
|
+
attention === "ignore" && shouldForceDisplay ? "context" : attention;
|
|
108
|
+
|
|
109
|
+
const details = buildLifecycleDetails(info, kind, effectiveAttention);
|
|
110
|
+
events.emit(CHANNELS.NOTIFICATION, details);
|
|
111
|
+
|
|
112
|
+
cleanupMatcherState(info.id);
|
|
113
|
+
registry.unregister(info.id);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function handleOutputChanged(
|
|
117
|
+
event: ManagerEvent & { type: "process_output_changed" },
|
|
118
|
+
): void {
|
|
119
|
+
if (!event.appendedText || event.appendedText.length === 0) return;
|
|
120
|
+
|
|
121
|
+
const watchState = registry.getWatchState(event.id);
|
|
122
|
+
if (!watchState) return;
|
|
123
|
+
|
|
124
|
+
const state = syncMatcherState(event.id, watchState);
|
|
125
|
+
if (!state) return;
|
|
126
|
+
|
|
127
|
+
const matchTime = performance.now();
|
|
128
|
+
const matches = evaluateLogMatchers(
|
|
129
|
+
state.matchers,
|
|
130
|
+
event.appendedText,
|
|
131
|
+
matchTime,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const processInfo = getProcess(event.id);
|
|
135
|
+
const timestamp = Date.now();
|
|
136
|
+
|
|
137
|
+
for (const match of matches) {
|
|
138
|
+
const attention = match.on;
|
|
139
|
+
const details = buildLogMatchDetails(
|
|
140
|
+
event.id,
|
|
141
|
+
processInfo,
|
|
142
|
+
match,
|
|
143
|
+
attention,
|
|
144
|
+
timestamp,
|
|
145
|
+
);
|
|
146
|
+
events.emit(CHANNELS.NOTIFICATION, details);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function resolveAttention(
|
|
151
|
+
kind: ProcessNotificationKind,
|
|
152
|
+
config: NotifyConfig | null,
|
|
153
|
+
): Attention {
|
|
154
|
+
switch (kind) {
|
|
155
|
+
case "success":
|
|
156
|
+
return config?.onSuccess ?? DEFAULT_ATTENTION.onSuccess;
|
|
157
|
+
case "failure":
|
|
158
|
+
case "crash":
|
|
159
|
+
return config?.onFailure ?? DEFAULT_ATTENTION.onFailure;
|
|
160
|
+
case "killed":
|
|
161
|
+
return config?.onKilled ?? DEFAULT_ATTENTION.onKilled;
|
|
162
|
+
case "log_match":
|
|
163
|
+
return "turn";
|
|
164
|
+
case "log_match_suppressed":
|
|
165
|
+
return "context";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function buildLifecycleDetails(
|
|
170
|
+
info: ProcessInfo,
|
|
171
|
+
kind: ProcessNotificationKind,
|
|
172
|
+
attention: Attention,
|
|
173
|
+
): ProcessNotificationDetails {
|
|
174
|
+
const elapsed =
|
|
175
|
+
info.endTime !== null && info.startTime > 0
|
|
176
|
+
? Math.round((info.endTime - info.startTime) / 1000)
|
|
177
|
+
: null;
|
|
178
|
+
|
|
179
|
+
let summary: string;
|
|
180
|
+
if (kind === "success") {
|
|
181
|
+
summary =
|
|
182
|
+
elapsed !== null
|
|
183
|
+
? `Process "${info.name}" succeeded after ${elapsed}s.`
|
|
184
|
+
: `Process "${info.name}" succeeded.`;
|
|
185
|
+
} else if (kind === "killed" && info.signal) {
|
|
186
|
+
const number =
|
|
187
|
+
info.signal.number === null
|
|
188
|
+
? ""
|
|
189
|
+
: ` (${info.signal.number}, ${info.signal.description})`;
|
|
190
|
+
summary = `Process "${info.name}" ended after receiving ${info.signal.name}${number}.`;
|
|
191
|
+
} else if (info.exitCode !== null && info.exitCode !== 0) {
|
|
192
|
+
summary =
|
|
193
|
+
elapsed !== null
|
|
194
|
+
? `Process "${info.name}" failed with exit code ${info.exitCode} after ${elapsed}s.`
|
|
195
|
+
: `Process "${info.name}" failed with exit code ${info.exitCode}.`;
|
|
196
|
+
} else {
|
|
197
|
+
summary = `Process "${info.name}" failed.`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
kind,
|
|
202
|
+
processId: info.id,
|
|
203
|
+
processName: info.name,
|
|
204
|
+
command: info.command,
|
|
205
|
+
timestamp: info.endTime ?? Date.now(),
|
|
206
|
+
summary,
|
|
207
|
+
status: info.status,
|
|
208
|
+
exitCode: info.exitCode,
|
|
209
|
+
endReason: info.endReason,
|
|
210
|
+
signal: info.signal,
|
|
211
|
+
attention,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function buildLogMatchDetails(
|
|
216
|
+
processId: string,
|
|
217
|
+
processInfo: ProcessInfo | null,
|
|
218
|
+
match: LogMatchResult,
|
|
219
|
+
attention: Attention,
|
|
220
|
+
timestamp: number,
|
|
221
|
+
): ProcessNotificationDetails {
|
|
222
|
+
const name = processInfo?.name ?? processId;
|
|
223
|
+
const command = processInfo?.command ?? "";
|
|
224
|
+
const truncatedLine =
|
|
225
|
+
match.line.length > 160 ? `${match.line.slice(0, 157)}...` : match.line;
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
kind: "log_match",
|
|
229
|
+
processId,
|
|
230
|
+
processName: name,
|
|
231
|
+
command,
|
|
232
|
+
timestamp,
|
|
233
|
+
summary: `Process "${name}" matched log pattern "${match.pattern}" on ${match.stream}.`,
|
|
234
|
+
logMatch: {
|
|
235
|
+
pattern: match.pattern,
|
|
236
|
+
mode: match.mode,
|
|
237
|
+
stream: match.stream,
|
|
238
|
+
line: truncatedLine,
|
|
239
|
+
matcherIndex: match.matcherIndex,
|
|
240
|
+
},
|
|
241
|
+
attention,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function syncMatcherState(
|
|
246
|
+
processId: string,
|
|
247
|
+
watchState: WatchState,
|
|
248
|
+
): ProcessMatcherState | null {
|
|
249
|
+
const existing = matcherStates.get(processId);
|
|
250
|
+
|
|
251
|
+
if (!existing) {
|
|
252
|
+
const matchers = compileLogMatchers({
|
|
253
|
+
logMatches: watchState.logMatches,
|
|
254
|
+
});
|
|
255
|
+
if (matchers.length === 0) return null;
|
|
256
|
+
const state: ProcessMatcherState = {
|
|
257
|
+
matchers,
|
|
258
|
+
revision: watchState.revision,
|
|
259
|
+
generation: watchState.generation,
|
|
260
|
+
};
|
|
261
|
+
matcherStates.set(processId, state);
|
|
262
|
+
return state;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (existing.revision === watchState.revision) return existing;
|
|
266
|
+
|
|
267
|
+
const next = compileLogMatchers({ logMatches: watchState.logMatches });
|
|
268
|
+
|
|
269
|
+
if (existing.generation === watchState.generation) {
|
|
270
|
+
preserveMatcherRuntimeState(existing.matchers, next);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (next.length === 0) {
|
|
274
|
+
matcherStates.delete(processId);
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const state: ProcessMatcherState = {
|
|
279
|
+
matchers: next,
|
|
280
|
+
revision: watchState.revision,
|
|
281
|
+
generation: watchState.generation,
|
|
282
|
+
};
|
|
283
|
+
matcherStates.set(processId, state);
|
|
284
|
+
return state;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function preserveMatcherRuntimeState(
|
|
288
|
+
prev: CompiledLogMatcher[],
|
|
289
|
+
next: CompiledLogMatcher[],
|
|
290
|
+
): void {
|
|
291
|
+
const byKey = new Map<string, CompiledLogMatcher[]>();
|
|
292
|
+
for (const m of prev) {
|
|
293
|
+
const key = matcherIdentityKey(m);
|
|
294
|
+
const bucket = byKey.get(key);
|
|
295
|
+
if (bucket) {
|
|
296
|
+
bucket.push(m);
|
|
297
|
+
} else {
|
|
298
|
+
byKey.set(key, [m]);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (const m of next) {
|
|
303
|
+
const key = matcherIdentityKey(m);
|
|
304
|
+
const bucket = byKey.get(key);
|
|
305
|
+
if (!bucket || bucket.length === 0) continue;
|
|
306
|
+
const donor = bucket.shift();
|
|
307
|
+
if (!donor) continue;
|
|
308
|
+
m.fired = donor.fired;
|
|
309
|
+
m.lastMatchTime = donor.lastMatchTime;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function matcherIdentityKey(m: {
|
|
314
|
+
pattern: string;
|
|
315
|
+
mode: string;
|
|
316
|
+
stream: string;
|
|
317
|
+
repeat: boolean;
|
|
318
|
+
on: string;
|
|
319
|
+
}): string {
|
|
320
|
+
return JSON.stringify([m.pattern, m.mode, m.stream, m.repeat, m.on]);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function cleanupMatcherState(processId: string): void {
|
|
324
|
+
matcherStates.delete(processId);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
dispose() {
|
|
329
|
+
disposed = true;
|
|
330
|
+
unsubscribe();
|
|
331
|
+
matcherStates.clear();
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export { createNotificationRegistry };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Re-export the protocol-safe notification types so the core extension and the
|
|
2
|
+
// protocol layer cannot drift apart. The canonical shape lives in
|
|
3
|
+
// `src/protocol/notifications.ts`; these names keep existing import sites
|
|
4
|
+
// stable while guaranteeing structural compatibility with the events emitted on
|
|
5
|
+
// CHANNELS.NOTIFICATION.
|
|
6
|
+
export type {
|
|
7
|
+
ProcessProtocolAttention as Attention,
|
|
8
|
+
ProcessProtocolNotificationKind as ProcessNotificationKind,
|
|
9
|
+
ProcessProtocolNotificationLogMatch as ProcessNotificationLogMatchDetails,
|
|
10
|
+
ProcessProtocolNotificationPayload as ProcessNotificationDetails,
|
|
11
|
+
} from "../../../src/protocol";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply a setting change to the core processes config.
|
|
3
|
+
*
|
|
4
|
+
* Logs/overview/dock settings are handled by their owning extensions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { setNestedValue } from "@aliou/pi-utils-settings";
|
|
8
|
+
|
|
9
|
+
import type { ProcessConfig } from "../config";
|
|
10
|
+
|
|
11
|
+
const BOOLEAN_FIELDS = new Set([
|
|
12
|
+
"interception.blockBackgroundCommands",
|
|
13
|
+
"widget.showStatusWidget",
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
export function applySettingChange(
|
|
17
|
+
id: string,
|
|
18
|
+
newValue: string,
|
|
19
|
+
config: ProcessConfig,
|
|
20
|
+
): ProcessConfig | null {
|
|
21
|
+
const updated = structuredClone(config);
|
|
22
|
+
|
|
23
|
+
if (BOOLEAN_FIELDS.has(id)) {
|
|
24
|
+
setNestedValue(updated, id, newValue === "on");
|
|
25
|
+
return updated;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Unknown field: fall through to default string storage
|
|
29
|
+
return null;
|
|
30
|
+
}
|