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