@agimon-ai/doompi-loop 0.0.1-alpha.84 → 0.0.1-alpha.86
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/dist/extensions/pi.cjs +188 -147
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.mts.map +1 -1
- package/dist/extensions/pi.mjs +179 -138
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +233 -227
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +234 -228
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +114 -11
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/{loopLaunchers-CPUUrDzQ.d.mts → loopLaunchers-Bciapxt0.d.mts} +9 -1
- package/dist/loopLaunchers-Bciapxt0.d.mts.map +1 -0
- package/dist/loopLaunchers-BtcLH_xN.cjs.map +1 -1
- package/dist/loopLaunchers-cCniFbVA.mjs.map +1 -1
- package/dist/loopLaunchers.d.mts +1 -1
- package/dist/{loopView-CmuIEbUa.mjs → loopView-BK4X_1UI.mjs} +153 -5
- package/dist/loopView-BK4X_1UI.mjs.map +1 -0
- package/dist/{loopView-CLIBhqYC.cjs → loopView-C_OPuy8L.cjs} +218 -4
- package/dist/loopView-C_OPuy8L.cjs.map +1 -0
- package/package.json +9 -7
- package/src/prompts/doompi-use-loop/SKILL.md +33 -13
- package/src/types/loopView.ts +2 -2
- package/dist/loopLaunchers-CPUUrDzQ.d.mts.map +0 -1
- package/dist/loopView-CLIBhqYC.cjs.map +0 -1
- package/dist/loopView-CmuIEbUa.mjs.map +0 -1
package/dist/extensions/pi.mjs
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import { t as DOOM_LOOP_LAUNCHERS_SERVICE } from "../loopLaunchers-cCniFbVA.mjs";
|
|
2
|
-
import { a as
|
|
3
|
-
import { definePiExtension } from "@agimon-ai/doompi-core/piExtension";
|
|
4
|
-
import { composeRootHooks, defineCliCommand, defineCliHook, defineResource, defineRoot } from "@agimon-ai/doompi-core/extensionFile";
|
|
2
|
+
import { _ as PACKAGE_SOURCE, a as CronLoopSchema, c as parseIntervalLoop, d as START_COMMAND_DESCRIPTION, f as START_COMMAND_NAME, g as NOTIFY_WARNING_LEVEL, h as NOTIFY_INFO_LEVEL, i as createDoomLoopLaunchersService, l as LIST_COMMAND_DESCRIPTION, m as MODE_STATUS_ID, n as formatLoopStatusView, o as IntervalLoopSchema, p as ACTIVE_MODE_COLOR, r as createLoopTools, s as parseCronLoop, t as LOOP_VIEW_STATUS_KEY, u as LIST_COMMAND_NAME, v as STATUS_KEY } from "../loopView-BK4X_1UI.mjs";
|
|
3
|
+
import { definePiExtension, piToolContributions } from "@agimon-ai/doompi-core/piExtension";
|
|
4
|
+
import { composeRootHooks, defineCliCommand, defineCliHook, defineResource, defineRoot, defineTool as defineTool$1, defineToolRestriction } from "@agimon-ai/doompi-core/extensionFile";
|
|
5
5
|
import { defineMinorMode, piMinorModes } from "@agimon-ai/doompi-minor-mode";
|
|
6
6
|
import { DOOM_CORDIS_SESSION_SERVICE } from "@agimon-ai/doompi-core/cordisHost";
|
|
7
7
|
import { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from "@agimon-ai/doompi-core/uiHub";
|
|
8
|
+
import { Cron } from "croner";
|
|
8
9
|
import { DOOM_FULLSCREEN_UI_OPTIONS, DOOM_NAVIGATION_KEYS, DOOM_OVERLAY_ACCENT, DoomOverlay } from "@agimon-ai/doompi-ui/doomOverlay";
|
|
9
10
|
import { matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
|
|
10
|
-
//#region src/constants/piLoop.ts
|
|
11
|
-
const PACKAGE_SOURCE = "@agimon-ai/doompi-loop";
|
|
12
|
-
const STATUS_KEY = "doom-loop";
|
|
13
|
-
const MODE_STATUS_ID = "loop.active";
|
|
14
|
-
const ACTIVE_MODE_COLOR = "warning";
|
|
15
|
-
const NOTIFY_INFO_LEVEL = "info";
|
|
16
|
-
const NOTIFY_WARNING_LEVEL = "warning";
|
|
17
|
-
//#endregion
|
|
18
11
|
//#region src/services/loopCommand/index.ts
|
|
19
12
|
function createLoopCommands(handlers) {
|
|
20
13
|
return [[START_COMMAND_NAME, {
|
|
@@ -22,37 +15,43 @@ function createLoopCommands(handlers) {
|
|
|
22
15
|
handler: async (args, ctx) => handlers.start(ctx, args)
|
|
23
16
|
}], [LIST_COMMAND_NAME, {
|
|
24
17
|
description: LIST_COMMAND_DESCRIPTION,
|
|
25
|
-
handler: async (
|
|
18
|
+
handler: async (args, ctx) => handlers.list(ctx, args)
|
|
26
19
|
}]];
|
|
27
20
|
}
|
|
28
21
|
//#endregion
|
|
29
22
|
//#region src/services/defaultLoopLauncher/index.ts
|
|
30
|
-
const DEFAULT_LAUNCHER_ID = "doompi.default";
|
|
31
23
|
const DEFAULT_INTERVAL_SECONDS = 300;
|
|
32
24
|
const MIN_INTERVAL_SECONDS = 30;
|
|
33
25
|
const MAX_INTERVAL_SECONDS = 3600;
|
|
34
26
|
const MILLISECONDS_PER_SECOND = 1e3;
|
|
35
27
|
const PROMPT_PREVIEW_LENGTH = 80;
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
if (seconds < MIN_INTERVAL_SECONDS || seconds > MAX_INTERVAL_SECONDS) return `Interval must be between ${MIN_INTERVAL_SECONDS} and ${MAX_INTERVAL_SECONDS} seconds.`;
|
|
40
|
-
}
|
|
41
|
-
async function prepareDefaultLoop(ui, signal) {
|
|
28
|
+
async function prepareLoop(ui, request, cron) {
|
|
29
|
+
if (request.input !== void 0) return cron ? parseCronLoop(request.input) : parseIntervalLoop(request.input);
|
|
30
|
+
if (request.interactive === false) throw new Error("Loop configuration is required for agent launches.");
|
|
42
31
|
const prompt = (await ui.editor("Loop prompt", ""))?.trim();
|
|
43
|
-
if (!prompt || signal.aborted) return void 0;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
if (!prompt || request.signal.aborted) return void 0;
|
|
33
|
+
if (cron) {
|
|
34
|
+
const expression = await ui.input("Cron expression (five fields)", "0 * * * *");
|
|
35
|
+
if (expression === void 0 || request.signal.aborted) return void 0;
|
|
36
|
+
const timezone = await ui.input("Loop timezone", "UTC");
|
|
37
|
+
if (timezone === void 0 || request.signal.aborted) return void 0;
|
|
38
|
+
return parseCronLoop({
|
|
39
|
+
prompt,
|
|
40
|
+
cron: expression,
|
|
41
|
+
timezone: timezone.trim() || "UTC"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const raw = await ui.input("Loop interval in seconds", `Default: ${DEFAULT_INTERVAL_SECONDS}s`);
|
|
45
|
+
if (raw === void 0 || request.signal.aborted) return void 0;
|
|
46
|
+
const intervalSeconds = Number(raw.trim() || DEFAULT_INTERVAL_SECONDS);
|
|
47
|
+
if (!Number.isInteger(intervalSeconds) || intervalSeconds < MIN_INTERVAL_SECONDS || intervalSeconds > MAX_INTERVAL_SECONDS) {
|
|
48
|
+
ui.notify(`Interval must be between ${MIN_INTERVAL_SECONDS} and ${MAX_INTERVAL_SECONDS} seconds.`, NOTIFY_WARNING_LEVEL);
|
|
50
49
|
return;
|
|
51
50
|
}
|
|
52
|
-
return {
|
|
51
|
+
return parseIntervalLoop({
|
|
53
52
|
prompt,
|
|
54
|
-
intervalSeconds
|
|
55
|
-
};
|
|
53
|
+
intervalSeconds
|
|
54
|
+
});
|
|
56
55
|
}
|
|
57
56
|
function promptPreview(prompt) {
|
|
58
57
|
const oneLine = prompt.replaceAll(/\s+/gu, " ").trim();
|
|
@@ -73,44 +72,62 @@ function createDefaultLoopLauncher(pi) {
|
|
|
73
72
|
loop.context.ui.notify(`Default loop pass could not start: ${error instanceof Error ? error.message : String(error)}`, NOTIFY_WARNING_LEVEL);
|
|
74
73
|
}
|
|
75
74
|
};
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
instanceId,
|
|
101
|
-
label: "Default loop",
|
|
102
|
-
detail: `every ${loop.intervalSeconds}s · ${promptPreview(loop.prompt)}`,
|
|
103
|
-
stop() {
|
|
104
|
-
if (loop.stopped) return;
|
|
105
|
-
loop.stopped = true;
|
|
106
|
-
if (loop.timer) clearInterval(loop.timer);
|
|
107
|
-
loop.timer = void 0;
|
|
108
|
-
pending.delete(loop);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
75
|
+
const register = (ctx, launchers, cron) => launchers.register({
|
|
76
|
+
id: cron ? "doompi.cron" : "doompi.default",
|
|
77
|
+
source: PACKAGE_SOURCE,
|
|
78
|
+
label: cron ? "Cron loop" : "Default loop",
|
|
79
|
+
description: cron ? "Run a prompt on a five-field cron schedule." : "Run your own prompt in this session on an interval",
|
|
80
|
+
inputSchema: { ...cron ? CronLoopSchema : IntervalLoopSchema },
|
|
81
|
+
async launch(request) {
|
|
82
|
+
const prepared = await prepareLoop(ctx.ui, request, cron);
|
|
83
|
+
if (!prepared || request.signal.aborted) return void 0;
|
|
84
|
+
const loop = {
|
|
85
|
+
prompt: prepared.prompt,
|
|
86
|
+
context: ctx,
|
|
87
|
+
stopped: false
|
|
88
|
+
};
|
|
89
|
+
let stopTimer;
|
|
90
|
+
let schedule;
|
|
91
|
+
if ("cron" in prepared) {
|
|
92
|
+
const job = new Cron(prepared.cron, {
|
|
93
|
+
timezone: prepared.timezone,
|
|
94
|
+
unref: true
|
|
95
|
+
}, () => requestPass(loop));
|
|
96
|
+
if (job.nextRun() === null) {
|
|
97
|
+
job.stop();
|
|
98
|
+
throw new Error("Cron expression has no future run.");
|
|
111
99
|
}
|
|
112
|
-
|
|
100
|
+
stopTimer = () => {
|
|
101
|
+
job.stop();
|
|
102
|
+
};
|
|
103
|
+
schedule = `${prepared.cron} (${prepared.timezone})`;
|
|
104
|
+
} else {
|
|
105
|
+
const timer = setInterval(() => requestPass(loop), prepared.intervalSeconds * MILLISECONDS_PER_SECOND);
|
|
106
|
+
timer.unref?.();
|
|
107
|
+
stopTimer = () => clearInterval(timer);
|
|
108
|
+
schedule = `every ${prepared.intervalSeconds}s`;
|
|
109
|
+
requestPass(loop);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
instanceId: request.instanceId,
|
|
113
|
+
label: cron ? "Cron loop" : "Default loop",
|
|
114
|
+
detail: `${schedule} · ${promptPreview(loop.prompt)}`,
|
|
115
|
+
stop() {
|
|
116
|
+
if (loop.stopped) return;
|
|
117
|
+
loop.stopped = true;
|
|
118
|
+
stopTimer();
|
|
119
|
+
pending.delete(loop);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
113
122
|
}
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
onAgentSettled() {
|
|
126
|
+
const next = pending.values().next().value;
|
|
127
|
+
if (next) requestPass(next);
|
|
128
|
+
},
|
|
129
|
+
register: (ctx, launchers) => register(ctx, launchers, false),
|
|
130
|
+
registerCron: (ctx, launchers) => register(ctx, launchers, true)
|
|
114
131
|
};
|
|
115
132
|
}
|
|
116
133
|
//#endregion
|
|
@@ -306,34 +323,27 @@ async function openStartLoopOverlay(ctx, launchers) {
|
|
|
306
323
|
}
|
|
307
324
|
//#endregion
|
|
308
325
|
//#region src/tui/loopRuntime.ts
|
|
309
|
-
const
|
|
310
|
-
const
|
|
326
|
+
const MODE_ACTION_ACTIVATE = "activate";
|
|
327
|
+
const MODE_ACTION_DEACTIVATE = "deactivate";
|
|
311
328
|
const SESSION_REPLACED_REASON = "Pi session replaced.";
|
|
312
329
|
const SESSION_SHUTDOWN_REASON = "Pi session shut down.";
|
|
313
|
-
function loopModeState(
|
|
314
|
-
const active = instances.length > 0;
|
|
330
|
+
function loopModeState(enabled, instances) {
|
|
315
331
|
return {
|
|
316
|
-
activation:
|
|
317
|
-
condition:
|
|
318
|
-
...
|
|
319
|
-
detail: `${instances.length}
|
|
332
|
+
activation: enabled ? "active" : "inactive",
|
|
333
|
+
condition: "ready",
|
|
334
|
+
...enabled ? {
|
|
335
|
+
detail: `${instances.length} loops`,
|
|
320
336
|
color: ACTIVE_MODE_COLOR
|
|
321
337
|
} : {},
|
|
322
|
-
actions: [
|
|
323
|
-
id:
|
|
324
|
-
enabled:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
enabled: true
|
|
332
|
-
}] : [{
|
|
333
|
-
id: MODE_ACTION_STOP,
|
|
334
|
-
enabled: false,
|
|
335
|
-
disabledReason: "No loops are active."
|
|
336
|
-
}]]
|
|
338
|
+
actions: [{
|
|
339
|
+
id: MODE_ACTION_ACTIVATE,
|
|
340
|
+
enabled: !enabled,
|
|
341
|
+
...enabled ? { disabledReason: "Loop mode is already active." } : {}
|
|
342
|
+
}, {
|
|
343
|
+
id: MODE_ACTION_DEACTIVATE,
|
|
344
|
+
enabled,
|
|
345
|
+
...enabled ? {} : { disabledReason: "Loop mode is not active." }
|
|
346
|
+
}]
|
|
337
347
|
};
|
|
338
348
|
}
|
|
339
349
|
/** Install Loop state and external resources into its host-owned Cordis plugin fiber. */
|
|
@@ -343,6 +353,15 @@ function createLoopPiRuntime(pi) {
|
|
|
343
353
|
let mode;
|
|
344
354
|
let disposeLeader;
|
|
345
355
|
const launchesInProgress = /* @__PURE__ */ new WeakSet();
|
|
356
|
+
let modeEnabled = false;
|
|
357
|
+
const toolListeners = /* @__PURE__ */ new Set();
|
|
358
|
+
const loopTools = createLoopTools(() => {
|
|
359
|
+
if (!activeSession) throw new Error("Loop launchers are unavailable for the active session.");
|
|
360
|
+
return activeSession.launchers;
|
|
361
|
+
}, () => {
|
|
362
|
+
if (!active || !modeEnabled) throw new Error("Enable Loop minor mode before using agent loop tools.");
|
|
363
|
+
});
|
|
364
|
+
const toolNames = new Set(loopTools.map((tool) => tool.name));
|
|
346
365
|
const currentSession = (context) => {
|
|
347
366
|
const binding = activeSession;
|
|
348
367
|
if (!active || !binding || binding.context.sessionManager !== context.sessionManager || binding.hostSession.sessionId !== context.sessionManager.getSessionId()) return;
|
|
@@ -365,66 +384,47 @@ function createLoopPiRuntime(pi) {
|
|
|
365
384
|
source: PACKAGE_SOURCE,
|
|
366
385
|
id: MODE_STATUS_ID,
|
|
367
386
|
label: "Loop",
|
|
368
|
-
description: "
|
|
387
|
+
description: "Give the agent tools to create, inspect, and stop session loops.",
|
|
369
388
|
order: 60,
|
|
370
389
|
actions: [{
|
|
371
|
-
id:
|
|
372
|
-
label: "
|
|
373
|
-
description: "
|
|
390
|
+
id: MODE_ACTION_ACTIVATE,
|
|
391
|
+
label: "Activate",
|
|
392
|
+
description: "Expose loop tools to the agent.",
|
|
374
393
|
contexts: ["tui", "headless"],
|
|
375
|
-
parameters: [
|
|
376
|
-
name: "launcherId",
|
|
377
|
-
label: "Launcher",
|
|
378
|
-
kind: "string",
|
|
379
|
-
required: true,
|
|
380
|
-
minLength: 1
|
|
381
|
-
}, {
|
|
382
|
-
name: "instanceId",
|
|
383
|
-
label: "Instance ID",
|
|
384
|
-
kind: "string",
|
|
385
|
-
required: false,
|
|
386
|
-
minLength: 1
|
|
387
|
-
}]
|
|
394
|
+
parameters: []
|
|
388
395
|
}, {
|
|
389
|
-
id:
|
|
390
|
-
label: "
|
|
391
|
-
description: "
|
|
396
|
+
id: MODE_ACTION_DEACTIVATE,
|
|
397
|
+
label: "Deactivate",
|
|
398
|
+
description: "Hide agent loop tools. Existing loops and manual controls remain available.",
|
|
392
399
|
contexts: ["tui", "headless"],
|
|
393
|
-
parameters: [
|
|
394
|
-
name: "instanceId",
|
|
395
|
-
label: "Instance ID",
|
|
396
|
-
kind: "string",
|
|
397
|
-
required: true,
|
|
398
|
-
minLength: 1
|
|
399
|
-
}, {
|
|
400
|
-
name: "reason",
|
|
401
|
-
label: "Reason",
|
|
402
|
-
kind: "string",
|
|
403
|
-
required: false,
|
|
404
|
-
minLength: 1
|
|
405
|
-
}]
|
|
400
|
+
parameters: []
|
|
406
401
|
}]
|
|
407
402
|
},
|
|
408
|
-
state: () =>
|
|
409
|
-
async handleAction(_runtime, actionId,
|
|
403
|
+
state: () => loopModeState(modeEnabled, activeSession?.launchers.listInstances() ?? []),
|
|
404
|
+
async handleAction(_runtime, actionId, _arguments, { signal }) {
|
|
410
405
|
signal.throwIfAborted();
|
|
411
406
|
const binding = activeSession ? currentSession(activeSession.context) : void 0;
|
|
412
407
|
if (!binding) throw new Error("Loop launchers are unavailable for the active session.");
|
|
413
|
-
if (actionId
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
if (actionId === MODE_ACTION_STOP) {
|
|
419
|
-
const stopped = await binding.launchers.stop(argumentsValue.instanceId, argumentsValue.reason ?? "Stopped through minor_mode.");
|
|
420
|
-
if (activeSession !== binding) throw new Error("Loop action became stale.");
|
|
421
|
-
return { message: stopped ? "Loop stopped." : "Loop instance was not active." };
|
|
422
|
-
}
|
|
423
|
-
throw new Error(`Unknown loop mode action: ${actionId}`);
|
|
408
|
+
if (actionId !== MODE_ACTION_ACTIVATE && actionId !== MODE_ACTION_DEACTIVATE) throw new Error(`Unknown loop mode action: ${actionId}`);
|
|
409
|
+
modeEnabled = actionId === MODE_ACTION_ACTIVATE;
|
|
410
|
+
for (const listener of toolListeners) listener();
|
|
411
|
+
publishStatus(binding);
|
|
412
|
+
return { message: modeEnabled ? "Loop tools activated." : "Loop tools deactivated. Existing loops are unchanged." };
|
|
424
413
|
}
|
|
425
414
|
}).createOwner(void 0);
|
|
426
415
|
return {
|
|
427
416
|
onAgentSettled: defaultLauncher.onAgentSettled,
|
|
417
|
+
loopTools,
|
|
418
|
+
toolRestrictions: [{
|
|
419
|
+
source: PACKAGE_SOURCE,
|
|
420
|
+
restrict: (incoming) => modeEnabled ? incoming : incoming.filter((name) => !toolNames.has(name)),
|
|
421
|
+
subscribe(listener) {
|
|
422
|
+
toolListeners.add(listener);
|
|
423
|
+
return () => {
|
|
424
|
+
toolListeners.delete(listener);
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}],
|
|
428
428
|
services: [(cordis) => {
|
|
429
429
|
cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {
|
|
430
430
|
const dispose = registerLeaderContribution(requireDoomUiHub(uiContext));
|
|
@@ -447,13 +447,17 @@ function createLoopPiRuntime(pi) {
|
|
|
447
447
|
launchers
|
|
448
448
|
};
|
|
449
449
|
activeSession = binding;
|
|
450
|
+
modeEnabled = false;
|
|
451
|
+
for (const listener of toolListeners) listener();
|
|
450
452
|
const provider = cordis.plugin((providerContext) => {
|
|
451
453
|
providerContext.provide(DOOM_LOOP_LAUNCHERS_SERVICE, launchers);
|
|
452
454
|
});
|
|
453
455
|
let defaultRegistration;
|
|
456
|
+
let cronRegistration;
|
|
454
457
|
let unsubscribe;
|
|
455
458
|
try {
|
|
456
459
|
defaultRegistration = defaultLauncher.register(hostSession.context, launchers);
|
|
460
|
+
cronRegistration = defaultLauncher.registerCron(hostSession.context, launchers);
|
|
457
461
|
unsubscribe = launchers.subscribe(() => publishStatus(binding));
|
|
458
462
|
publishStatus(binding);
|
|
459
463
|
} catch (error) {
|
|
@@ -464,12 +468,14 @@ function createLoopPiRuntime(pi) {
|
|
|
464
468
|
}
|
|
465
469
|
return async () => {
|
|
466
470
|
if (activeSession === binding) activeSession = void 0;
|
|
471
|
+
modeEnabled = false;
|
|
472
|
+
for (const listener of toolListeners) listener();
|
|
467
473
|
unsubscribe();
|
|
468
474
|
clearStatuses(binding);
|
|
469
475
|
mode?.publish();
|
|
470
476
|
const cleanupErrors = [];
|
|
471
477
|
try {
|
|
472
|
-
await defaultRegistration.dispose(SESSION_REPLACED_REASON);
|
|
478
|
+
await Promise.all([defaultRegistration.dispose(SESSION_REPLACED_REASON), cronRegistration.dispose(SESSION_REPLACED_REASON)]);
|
|
473
479
|
} catch (error) {
|
|
474
480
|
cleanupErrors.push(error);
|
|
475
481
|
}
|
|
@@ -528,9 +534,15 @@ function createLoopPiRuntime(pi) {
|
|
|
528
534
|
launchesInProgress.delete(binding);
|
|
529
535
|
}
|
|
530
536
|
},
|
|
531
|
-
async list(ctx) {
|
|
537
|
+
async list(ctx, args = "") {
|
|
532
538
|
const binding = currentSession(ctx);
|
|
533
539
|
if (!binding) return;
|
|
540
|
+
if (args.trim().startsWith("stop ")) {
|
|
541
|
+
const stopped = await binding.launchers.stop(args.trim().slice(5).trim(), "Stopped manually.");
|
|
542
|
+
ctx.ui.notify(stopped ? "Loop stopped." : "Loop instance was not active.", NOTIFY_INFO_LEVEL);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (args.trim()) throw new Error("Usage: /loops [stop instanceId]");
|
|
534
546
|
await openLoopListOverlay(ctx, binding.launchers);
|
|
535
547
|
}
|
|
536
548
|
},
|
|
@@ -539,6 +551,9 @@ function createLoopPiRuntime(pi) {
|
|
|
539
551
|
active = false;
|
|
540
552
|
const binding = activeSession;
|
|
541
553
|
activeSession = void 0;
|
|
554
|
+
modeEnabled = false;
|
|
555
|
+
for (const listener of toolListeners) listener();
|
|
556
|
+
toolListeners.clear();
|
|
542
557
|
if (binding) clearStatuses(binding);
|
|
543
558
|
mode?.publish();
|
|
544
559
|
disposeLeader?.();
|
|
@@ -552,6 +567,8 @@ var runtime_cli_default = (({ pi }) => {
|
|
|
552
567
|
const runtime = createLoopPiRuntime(pi);
|
|
553
568
|
return {
|
|
554
569
|
services: [...runtime.services ?? [], piMinorModes(runtime.minorModes)],
|
|
570
|
+
loopTools: runtime.loopTools,
|
|
571
|
+
toolRestrictions: runtime.toolRestrictions,
|
|
555
572
|
events: { agent_settled: runtime.onAgentSettled },
|
|
556
573
|
commands: createLoopCommands(runtime.handlers),
|
|
557
574
|
onDispose: () => runtime.onDispose(),
|
|
@@ -577,7 +594,7 @@ var root_cli_default = defineRoot((context) => {
|
|
|
577
594
|
});
|
|
578
595
|
//#endregion
|
|
579
596
|
//#region src/extensions/workspaces/sessions/(backend)/command/loop.cli.ts
|
|
580
|
-
var loop_cli_default = defineCliCommand((context) => context.root.commands[0]);
|
|
597
|
+
var loop_cli_default$1 = defineCliCommand((context) => context.root.commands[0]);
|
|
581
598
|
//#endregion
|
|
582
599
|
//#region src/extensions/workspaces/sessions/(backend)/command/loops.cli.ts
|
|
583
600
|
var loops_cli_default = defineCliCommand((context) => context.root.commands[1]);
|
|
@@ -588,8 +605,24 @@ var agent_settled_cli_default = defineCliHook((context) => context.root.events["
|
|
|
588
605
|
//#region src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.ts
|
|
589
606
|
var doompi_use_loop_cli_default = defineResource((context) => context.root.resources[0]);
|
|
590
607
|
//#endregion
|
|
608
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool-restriction/loop.cli.ts
|
|
609
|
+
var loop_cli_default = defineToolRestriction((context) => context.root.toolRestrictions[0]);
|
|
610
|
+
//#endregion
|
|
611
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/loop-list.cli.ts
|
|
612
|
+
var loop_list_cli_default = defineTool$1((context) => context.root.loopTools[0]);
|
|
613
|
+
//#endregion
|
|
614
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/loop-start.cli.ts
|
|
615
|
+
var loop_start_cli_default = defineTool$1((context) => context.root.loopTools[1]);
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/loop-stop.cli.ts
|
|
618
|
+
var loop_stop_cli_default = defineTool$1((context) => context.root.loopTools[2]);
|
|
619
|
+
//#endregion
|
|
591
620
|
//#region generated/pi.ts
|
|
592
621
|
const at = (value, context) => typeof value === "function" ? value(context) : value;
|
|
622
|
+
const via = (identity, value) => value === void 0 ? void 0 : {
|
|
623
|
+
...identity,
|
|
624
|
+
...value
|
|
625
|
+
};
|
|
593
626
|
const extension = definePiExtension("@agimon-ai/doompi-loop", async (context) => {
|
|
594
627
|
const scopeSession = await root_cli_default(context);
|
|
595
628
|
const contextSession = {
|
|
@@ -599,12 +632,20 @@ const extension = definePiExtension("@agimon-ai/doompi-loop", async (context) =>
|
|
|
599
632
|
return {
|
|
600
633
|
...composeRootHooks(scopeSession),
|
|
601
634
|
get commands() {
|
|
602
|
-
return [at(loop_cli_default, contextSession), at(loops_cli_default, contextSession)];
|
|
635
|
+
return [at(loop_cli_default$1, contextSession), at(loops_cli_default, contextSession)];
|
|
603
636
|
},
|
|
604
637
|
events: { agent_settled: at(agent_settled_cli_default, contextSession) },
|
|
605
638
|
get resources() {
|
|
606
639
|
return [at(doompi_use_loop_cli_default, contextSession)];
|
|
607
640
|
},
|
|
641
|
+
get toolRestrictions() {
|
|
642
|
+
return [at(loop_cli_default, contextSession)];
|
|
643
|
+
},
|
|
644
|
+
...piToolContributions("@agimon-ai/doompi-loop", [
|
|
645
|
+
via({ name: "loop_list" }, at(loop_list_cli_default, contextSession)),
|
|
646
|
+
via({ name: "loop_start" }, at(loop_start_cli_default, contextSession)),
|
|
647
|
+
via({ name: "loop_stop" }, at(loop_stop_cli_default, contextSession))
|
|
648
|
+
]),
|
|
608
649
|
services: [...scopeSession.services ?? []]
|
|
609
650
|
};
|
|
610
651
|
});
|