@agimon-ai/doompi-loop 0.0.1-alpha.9 → 0.0.1-alpha.91
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 +83 -21
- package/dist/apiContracts.cjs +17 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +13 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/extensions/pi.cjs +659 -1
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.mts +5 -2
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +654 -1
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +369 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +364 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +331 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +0 -1
- package/dist/index.d.mts +2 -4
- package/dist/index.mjs +1 -1
- package/dist/loopLaunchers-Bciapxt0.d.mts +69 -0
- package/dist/loopLaunchers-Bciapxt0.d.mts.map +1 -0
- package/dist/loopLaunchers-BtcLH_xN.cjs +32 -0
- package/dist/loopLaunchers-BtcLH_xN.cjs.map +1 -0
- package/dist/loopLaunchers-cCniFbVA.mjs +15 -0
- package/dist/loopLaunchers-cCniFbVA.mjs.map +1 -0
- package/dist/loopLaunchers.cjs +5 -0
- package/dist/loopLaunchers.d.mts +2 -0
- package/dist/loopLaunchers.mjs +2 -0
- package/dist/loopView-BK4X_1UI.mjs +349 -0
- package/dist/loopView-BK4X_1UI.mjs.map +1 -0
- package/dist/loopView-C_OPuy8L.cjs +456 -0
- package/dist/loopView-C_OPuy8L.cjs.map +1 -0
- package/llms.txt +9 -0
- package/package.json +82 -14
- package/src/prompts/doompi-use-loop/SKILL.md +44 -0
- package/src/types/loopView.ts +73 -0
- package/dist/commands/loopCommand.cjs +0 -2
- package/dist/commands/loopCommand.cjs.map +0 -1
- package/dist/commands/loopCommand.mjs +0 -2
- package/dist/commands/loopCommand.mjs.map +0 -1
- package/dist/constants.cjs +0 -2
- package/dist/constants.cjs.map +0 -1
- package/dist/constants.mjs +0 -2
- package/dist/constants.mjs.map +0 -1
- package/dist/defaultLauncher.cjs +0 -2
- package/dist/defaultLauncher.cjs.map +0 -1
- package/dist/defaultLauncher.d.cts +0 -10
- package/dist/defaultLauncher.d.cts.map +0 -1
- package/dist/defaultLauncher.d.mts +0 -10
- package/dist/defaultLauncher.d.mts.map +0 -1
- package/dist/defaultLauncher.mjs +0 -2
- package/dist/defaultLauncher.mjs.map +0 -1
- package/dist/extension.cjs +0 -2
- package/dist/extension.cjs.map +0 -1
- package/dist/extension.d.cts +0 -6
- package/dist/extension.d.cts.map +0 -1
- package/dist/extension.d.mts +0 -6
- package/dist/extension.d.mts.map +0 -1
- package/dist/extension.mjs +0 -2
- package/dist/extension.mjs.map +0 -1
- package/dist/extensions/pi.d.cts +0 -2
- package/dist/index.d.cts +0 -4
- package/dist/launcher.cjs +0 -2
- package/dist/launcher.cjs.map +0 -1
- package/dist/launcher.d.cts +0 -47
- package/dist/launcher.d.cts.map +0 -1
- package/dist/launcher.d.mts +0 -47
- package/dist/launcher.d.mts.map +0 -1
- package/dist/launcher.mjs +0 -2
- package/dist/launcher.mjs.map +0 -1
- package/dist/leader.cjs +0 -2
- package/dist/leader.cjs.map +0 -1
- package/dist/leader.mjs +0 -2
- package/dist/leader.mjs.map +0 -1
- package/dist/tui/loopListOverlay.cjs +0 -2
- package/dist/tui/loopListOverlay.cjs.map +0 -1
- package/dist/tui/loopListOverlay.mjs +0 -2
- package/dist/tui/loopListOverlay.mjs.map +0 -1
- package/dist/tui/startLoopOverlay.cjs +0 -2
- package/dist/tui/startLoopOverlay.cjs.map +0 -1
- package/dist/tui/startLoopOverlay.mjs +0 -2
- package/dist/tui/startLoopOverlay.mjs.map +0 -1
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
let _agimon_ai_doompi_core_piExtension = require("@agimon-ai/doompi-core/piExtension");
|
|
2
|
+
let typebox = require("typebox");
|
|
3
|
+
let typebox_value = require("typebox/value");
|
|
4
|
+
//#region src/constants/piLoop.ts
|
|
5
|
+
const PACKAGE_SOURCE = "@agimon-ai/doompi-loop";
|
|
6
|
+
const STATUS_KEY = "doom-loop";
|
|
7
|
+
const MODE_STATUS_ID = "loop.active";
|
|
8
|
+
const ACTIVE_MODE_COLOR = "warning";
|
|
9
|
+
const NOTIFY_INFO_LEVEL = "info";
|
|
10
|
+
const NOTIFY_WARNING_LEVEL = "warning";
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/constants/loop.ts
|
|
13
|
+
const START_COMMAND_DESCRIPTION = "Start a registered loop";
|
|
14
|
+
const LIST_COMMAND_DESCRIPTION = "List and stop active loops";
|
|
15
|
+
const START_COMMAND_NAME = "loop";
|
|
16
|
+
const LIST_COMMAND_NAME = "loops";
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/schemas/loopTools.ts
|
|
19
|
+
const LoopListSchema = typebox.Type.Object({}, { additionalProperties: false });
|
|
20
|
+
const LoopStartSchema = typebox.Type.Object({
|
|
21
|
+
launcherId: typebox.Type.String({
|
|
22
|
+
minLength: 1,
|
|
23
|
+
maxLength: 256
|
|
24
|
+
}),
|
|
25
|
+
instanceId: typebox.Type.Optional(typebox.Type.String({
|
|
26
|
+
minLength: 1,
|
|
27
|
+
maxLength: 256
|
|
28
|
+
})),
|
|
29
|
+
input: typebox.Type.Record(typebox.Type.String(), typebox.Type.Unknown())
|
|
30
|
+
}, { additionalProperties: false });
|
|
31
|
+
const LoopStopSchema = typebox.Type.Object({
|
|
32
|
+
instanceId: typebox.Type.String({
|
|
33
|
+
minLength: 1,
|
|
34
|
+
maxLength: 256
|
|
35
|
+
}),
|
|
36
|
+
reason: typebox.Type.Optional(typebox.Type.String({
|
|
37
|
+
minLength: 1,
|
|
38
|
+
maxLength: 512
|
|
39
|
+
}))
|
|
40
|
+
}, { additionalProperties: false });
|
|
41
|
+
const IntervalLoopSchema = typebox.Type.Object({
|
|
42
|
+
prompt: typebox.Type.String({
|
|
43
|
+
minLength: 1,
|
|
44
|
+
maxLength: 32768
|
|
45
|
+
}),
|
|
46
|
+
intervalSeconds: typebox.Type.Integer({
|
|
47
|
+
minimum: 30,
|
|
48
|
+
maximum: 3600
|
|
49
|
+
})
|
|
50
|
+
}, { additionalProperties: false });
|
|
51
|
+
const CronLoopSchema = typebox.Type.Object({
|
|
52
|
+
prompt: typebox.Type.String({
|
|
53
|
+
minLength: 1,
|
|
54
|
+
maxLength: 32768
|
|
55
|
+
}),
|
|
56
|
+
cron: typebox.Type.String({
|
|
57
|
+
minLength: 1,
|
|
58
|
+
maxLength: 256
|
|
59
|
+
}),
|
|
60
|
+
timezone: typebox.Type.Optional(typebox.Type.String({
|
|
61
|
+
minLength: 1,
|
|
62
|
+
maxLength: 128
|
|
63
|
+
}))
|
|
64
|
+
}, { additionalProperties: false });
|
|
65
|
+
function parseIntervalLoop(input) {
|
|
66
|
+
if (!(0, typebox_value.Check)(IntervalLoopSchema, input) || !input.prompt.trim()) throw new Error("Provide a non-empty prompt and an integer intervalSeconds between 30 and 3600.");
|
|
67
|
+
return {
|
|
68
|
+
...input,
|
|
69
|
+
prompt: input.prompt.trim()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function parseCronLoop(input) {
|
|
73
|
+
if (!(0, typebox_value.Check)(CronLoopSchema, input) || !input.prompt.trim() || input.cron.trim().split(/\s+/u).length !== 5) throw new Error("Provide a non-empty prompt and a five-field cron expression, with an optional IANA timezone.");
|
|
74
|
+
const timezone = input.timezone ?? "UTC";
|
|
75
|
+
new Intl.DateTimeFormat("en", { timeZone: timezone }).format();
|
|
76
|
+
return {
|
|
77
|
+
...input,
|
|
78
|
+
prompt: input.prompt.trim(),
|
|
79
|
+
cron: input.cron.trim(),
|
|
80
|
+
timezone
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/services/loopLaunchers/index.ts
|
|
85
|
+
const MAX_ID_LENGTH = 256;
|
|
86
|
+
const MAX_GENERATION_LENGTH = 256;
|
|
87
|
+
const LAUNCHER_ID_LABEL = "loop launcher id";
|
|
88
|
+
const INSTANCE_ID_LABEL = "loop instance id";
|
|
89
|
+
function validId(value, label) {
|
|
90
|
+
if (typeof value !== "string") throw new TypeError(`Invalid ${label}.`);
|
|
91
|
+
const normalized = value.trim();
|
|
92
|
+
let hasControl = false;
|
|
93
|
+
for (const character of normalized) {
|
|
94
|
+
const code = character.codePointAt(0);
|
|
95
|
+
if (code !== void 0 && (code <= 31 || code === 127)) {
|
|
96
|
+
hasControl = true;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!normalized || normalized.length > MAX_ID_LENGTH || hasControl) throw new Error(`Invalid ${label}.`);
|
|
101
|
+
return normalized;
|
|
102
|
+
}
|
|
103
|
+
function snapshot(entry) {
|
|
104
|
+
return {
|
|
105
|
+
instanceId: entry.instanceId,
|
|
106
|
+
launcherId: entry.launcher.definition.id,
|
|
107
|
+
launcherLabel: entry.launcher.definition.label,
|
|
108
|
+
...entry.handle?.label ? { label: entry.handle.label } : {},
|
|
109
|
+
...entry.handle?.detail ? { detail: entry.handle.detail } : {},
|
|
110
|
+
state: entry.state,
|
|
111
|
+
...entry.startedAt ? { startedAt: entry.startedAt } : {}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** Creates the provider-owned launcher registry for one active Doom session. */
|
|
115
|
+
function createDoomLoopLaunchersService({ generation, createInstanceId, timestamp }) {
|
|
116
|
+
if (!generation || generation.length > MAX_GENERATION_LENGTH) throw new TypeError("Doom loop launchers require a valid generation.");
|
|
117
|
+
const launchers = /* @__PURE__ */ new Map();
|
|
118
|
+
const instances = /* @__PURE__ */ new Map();
|
|
119
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
120
|
+
let registrationSequence = 0;
|
|
121
|
+
let disposed = false;
|
|
122
|
+
const ensureActive = () => {
|
|
123
|
+
if (disposed) throw new Error("The Doom loop-launchers service is disposed.");
|
|
124
|
+
};
|
|
125
|
+
const notify = () => {
|
|
126
|
+
for (const listener of listeners) listener();
|
|
127
|
+
};
|
|
128
|
+
const stopEntry = async (entry, reason) => {
|
|
129
|
+
if (instances.get(entry.instanceId) !== entry) return;
|
|
130
|
+
entry.state = "stopping";
|
|
131
|
+
entry.abortController.abort(reason);
|
|
132
|
+
notify();
|
|
133
|
+
try {
|
|
134
|
+
await entry.handle?.stop(reason);
|
|
135
|
+
} finally {
|
|
136
|
+
if (instances.get(entry.instanceId) === entry) instances.delete(entry.instanceId);
|
|
137
|
+
notify();
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
generation,
|
|
142
|
+
register(definition) {
|
|
143
|
+
ensureActive();
|
|
144
|
+
const id = validId(definition.id, LAUNCHER_ID_LABEL);
|
|
145
|
+
if (launchers.has(id)) throw new Error(`Loop launcher '${id}' is already registered.`);
|
|
146
|
+
const token = Symbol(id);
|
|
147
|
+
const entry = {
|
|
148
|
+
token,
|
|
149
|
+
definition: {
|
|
150
|
+
...definition,
|
|
151
|
+
id
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
launchers.set(id, entry);
|
|
155
|
+
registrationSequence += 1;
|
|
156
|
+
notify();
|
|
157
|
+
let registrationDisposed = false;
|
|
158
|
+
return Object.freeze({
|
|
159
|
+
id,
|
|
160
|
+
generation: `${generation}:launcher:${registrationSequence}`,
|
|
161
|
+
async dispose(reason = "Loop launcher disposed.") {
|
|
162
|
+
if (registrationDisposed) return;
|
|
163
|
+
registrationDisposed = true;
|
|
164
|
+
if (launchers.get(id)?.token !== token) return;
|
|
165
|
+
launchers.delete(id);
|
|
166
|
+
const owned = [...instances.values()].filter((instance) => instance.launcher.token === token);
|
|
167
|
+
await Promise.allSettled(owned.map((instance) => stopEntry(instance, reason)));
|
|
168
|
+
notify();
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
listLaunchers() {
|
|
173
|
+
ensureActive();
|
|
174
|
+
return [...launchers.values()].map(({ definition }) => ({
|
|
175
|
+
id: definition.id,
|
|
176
|
+
source: definition.source,
|
|
177
|
+
label: definition.label,
|
|
178
|
+
...definition.description ? { description: definition.description } : {},
|
|
179
|
+
...definition.inputSchema ? { inputSchema: definition.inputSchema } : {}
|
|
180
|
+
})).sort((left, right) => left.label.localeCompare(right.label) || left.id.localeCompare(right.id));
|
|
181
|
+
},
|
|
182
|
+
listInstances() {
|
|
183
|
+
ensureActive();
|
|
184
|
+
return [...instances.values()].map(snapshot).sort((left, right) => left.instanceId.localeCompare(right.instanceId));
|
|
185
|
+
},
|
|
186
|
+
subscribe(listener) {
|
|
187
|
+
ensureActive();
|
|
188
|
+
listeners.add(listener);
|
|
189
|
+
let subscribed = true;
|
|
190
|
+
return () => {
|
|
191
|
+
if (!subscribed) return;
|
|
192
|
+
subscribed = false;
|
|
193
|
+
listeners.delete(listener);
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
async launch(launcherId, options) {
|
|
197
|
+
ensureActive();
|
|
198
|
+
options?.signal?.throwIfAborted();
|
|
199
|
+
const normalizedLauncherId = validId(launcherId, LAUNCHER_ID_LABEL);
|
|
200
|
+
const launcher = launchers.get(normalizedLauncherId);
|
|
201
|
+
if (!launcher) throw new Error(`Loop launcher '${normalizedLauncherId}' is unavailable.`);
|
|
202
|
+
const instanceId = validId(options?.instanceId ?? createInstanceId(), INSTANCE_ID_LABEL);
|
|
203
|
+
if (instances.has(instanceId)) throw new Error(`Loop instance '${instanceId}' already exists.`);
|
|
204
|
+
const entry = {
|
|
205
|
+
instanceId,
|
|
206
|
+
launcher,
|
|
207
|
+
abortController: new AbortController(),
|
|
208
|
+
state: "starting"
|
|
209
|
+
};
|
|
210
|
+
const abortSetup = () => entry.abortController.abort(options?.signal?.reason);
|
|
211
|
+
options?.signal?.addEventListener("abort", abortSetup, { once: true });
|
|
212
|
+
instances.set(instanceId, entry);
|
|
213
|
+
notify();
|
|
214
|
+
try {
|
|
215
|
+
if (options?.interactive === false && !launcher.definition.inputSchema) throw new Error(`Loop launcher '${normalizedLauncherId}' requires manual setup in Activity.`);
|
|
216
|
+
const handle = await launcher.definition.launch({
|
|
217
|
+
instanceId,
|
|
218
|
+
signal: entry.abortController.signal,
|
|
219
|
+
...options?.input === void 0 ? {} : { input: options.input },
|
|
220
|
+
...options?.interactive === void 0 ? {} : { interactive: options.interactive }
|
|
221
|
+
});
|
|
222
|
+
const active = !disposed && instances.get(instanceId) === entry && !entry.abortController.signal.aborted;
|
|
223
|
+
if (!handle) {
|
|
224
|
+
if (instances.get(instanceId) === entry) instances.delete(instanceId);
|
|
225
|
+
notify();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (!active || handle.instanceId !== instanceId) {
|
|
229
|
+
await handle.stop(active ? "Loop launcher returned a mismatched instance id." : "Loop launch was cancelled.");
|
|
230
|
+
if (instances.get(instanceId) === entry) instances.delete(instanceId);
|
|
231
|
+
notify();
|
|
232
|
+
if (active) throw new Error(`Loop launcher '${normalizedLauncherId}' returned a mismatched instance id.`);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
entry.handle = handle;
|
|
236
|
+
entry.state = "running";
|
|
237
|
+
entry.startedAt = timestamp();
|
|
238
|
+
notify();
|
|
239
|
+
return snapshot(entry);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const cancelled = entry.abortController.signal.aborted || disposed;
|
|
242
|
+
if (instances.get(instanceId) === entry) instances.delete(instanceId);
|
|
243
|
+
notify();
|
|
244
|
+
if (cancelled) return void 0;
|
|
245
|
+
throw error;
|
|
246
|
+
} finally {
|
|
247
|
+
options?.signal?.removeEventListener("abort", abortSetup);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
async stop(instanceId, reason) {
|
|
251
|
+
ensureActive();
|
|
252
|
+
const entry = instances.get(validId(instanceId, INSTANCE_ID_LABEL));
|
|
253
|
+
if (!entry) return false;
|
|
254
|
+
await stopEntry(entry, reason);
|
|
255
|
+
return true;
|
|
256
|
+
},
|
|
257
|
+
async stopAll(reason) {
|
|
258
|
+
if (disposed && instances.size === 0) return;
|
|
259
|
+
await Promise.allSettled([...instances.values()].map((entry) => stopEntry(entry, reason)));
|
|
260
|
+
},
|
|
261
|
+
async dispose(reason = "Doom loop-launchers service disposed.") {
|
|
262
|
+
if (disposed) return;
|
|
263
|
+
disposed = true;
|
|
264
|
+
launchers.clear();
|
|
265
|
+
await Promise.allSettled([...instances.values()].map((entry) => stopEntry(entry, reason)));
|
|
266
|
+
listeners.clear();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/services/loopTools/index.ts
|
|
272
|
+
function result(details) {
|
|
273
|
+
return {
|
|
274
|
+
content: [{
|
|
275
|
+
type: "text",
|
|
276
|
+
text: JSON.stringify(details, null, 2)
|
|
277
|
+
}],
|
|
278
|
+
details
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function createLoopTools(launchers, assertEnabled) {
|
|
282
|
+
return [
|
|
283
|
+
(0, _agimon_ai_doompi_core_piExtension.defineTool)({
|
|
284
|
+
name: "loop_list",
|
|
285
|
+
label: "List loops",
|
|
286
|
+
description: "List active session loops and available launcher types with their configuration schemas.",
|
|
287
|
+
parameters: LoopListSchema,
|
|
288
|
+
async execute(input, { signal }) {
|
|
289
|
+
assertEnabled();
|
|
290
|
+
signal?.throwIfAborted();
|
|
291
|
+
if (!(0, typebox_value.Check)(LoopListSchema, input)) throw new Error("loop_list takes no arguments.");
|
|
292
|
+
const service = launchers();
|
|
293
|
+
return result({
|
|
294
|
+
launchers: service.listLaunchers(),
|
|
295
|
+
instances: service.listInstances()
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}),
|
|
299
|
+
(0, _agimon_ai_doompi_core_piExtension.defineTool)({
|
|
300
|
+
name: "loop_start",
|
|
301
|
+
label: "Start loop",
|
|
302
|
+
description: "Start a session-scoped loop without operator dialogs. Read loop_list for launcher IDs and input schemas. Loops stop when the session shuts down.",
|
|
303
|
+
parameters: LoopStartSchema,
|
|
304
|
+
executionMode: "serial",
|
|
305
|
+
async execute(input, { signal }) {
|
|
306
|
+
assertEnabled();
|
|
307
|
+
signal?.throwIfAborted();
|
|
308
|
+
if (!(0, typebox_value.Check)(LoopStartSchema, input)) throw new Error("Provide launcherId, input, and optionally instanceId.");
|
|
309
|
+
return result(await launchers().launch(input.launcherId, {
|
|
310
|
+
...input,
|
|
311
|
+
interactive: false,
|
|
312
|
+
signal
|
|
313
|
+
}) ?? { cancelled: true });
|
|
314
|
+
}
|
|
315
|
+
}),
|
|
316
|
+
(0, _agimon_ai_doompi_core_piExtension.defineTool)({
|
|
317
|
+
name: "loop_stop",
|
|
318
|
+
label: "Stop loop",
|
|
319
|
+
description: "Stop one loop instance owned by the current session. Does not disable Loop mode or stop other loops.",
|
|
320
|
+
parameters: LoopStopSchema,
|
|
321
|
+
executionMode: "serial",
|
|
322
|
+
async execute(input, { signal }) {
|
|
323
|
+
assertEnabled();
|
|
324
|
+
signal?.throwIfAborted();
|
|
325
|
+
if (!(0, typebox_value.Check)(LoopStopSchema, input)) throw new Error("Provide instanceId and an optional reason.");
|
|
326
|
+
return result({ stopped: await launchers().stop(input.instanceId, input.reason ?? "Stopped by the agent.") });
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
];
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/types/loopView.ts
|
|
333
|
+
/** The browser-only status that carries active Loop instances into the activity dock. */
|
|
334
|
+
const LOOP_VIEW_STATUS_KEY = "doom-loop-instances";
|
|
335
|
+
new RegExp(String.raw`\u001b\[[0-9;]*m`, "gu");
|
|
336
|
+
/** Projects runtime snapshots into the JSON status consumed by the web plugin. */
|
|
337
|
+
function formatLoopStatusView(instances) {
|
|
338
|
+
if (instances.length === 0) return "";
|
|
339
|
+
return JSON.stringify(instances.map((instance) => ({
|
|
340
|
+
instanceId: instance.instanceId,
|
|
341
|
+
label: instance.label ?? instance.launcherLabel,
|
|
342
|
+
detail: instance.detail ?? instance.instanceId,
|
|
343
|
+
state: instance.state
|
|
344
|
+
})));
|
|
345
|
+
}
|
|
346
|
+
//#endregion
|
|
347
|
+
Object.defineProperty(exports, "ACTIVE_MODE_COLOR", {
|
|
348
|
+
enumerable: true,
|
|
349
|
+
get: function() {
|
|
350
|
+
return ACTIVE_MODE_COLOR;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
Object.defineProperty(exports, "CronLoopSchema", {
|
|
354
|
+
enumerable: true,
|
|
355
|
+
get: function() {
|
|
356
|
+
return CronLoopSchema;
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
Object.defineProperty(exports, "IntervalLoopSchema", {
|
|
360
|
+
enumerable: true,
|
|
361
|
+
get: function() {
|
|
362
|
+
return IntervalLoopSchema;
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
Object.defineProperty(exports, "LIST_COMMAND_DESCRIPTION", {
|
|
366
|
+
enumerable: true,
|
|
367
|
+
get: function() {
|
|
368
|
+
return LIST_COMMAND_DESCRIPTION;
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
Object.defineProperty(exports, "LIST_COMMAND_NAME", {
|
|
372
|
+
enumerable: true,
|
|
373
|
+
get: function() {
|
|
374
|
+
return LIST_COMMAND_NAME;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
Object.defineProperty(exports, "LOOP_VIEW_STATUS_KEY", {
|
|
378
|
+
enumerable: true,
|
|
379
|
+
get: function() {
|
|
380
|
+
return LOOP_VIEW_STATUS_KEY;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
Object.defineProperty(exports, "MODE_STATUS_ID", {
|
|
384
|
+
enumerable: true,
|
|
385
|
+
get: function() {
|
|
386
|
+
return MODE_STATUS_ID;
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
Object.defineProperty(exports, "NOTIFY_INFO_LEVEL", {
|
|
390
|
+
enumerable: true,
|
|
391
|
+
get: function() {
|
|
392
|
+
return NOTIFY_INFO_LEVEL;
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
Object.defineProperty(exports, "NOTIFY_WARNING_LEVEL", {
|
|
396
|
+
enumerable: true,
|
|
397
|
+
get: function() {
|
|
398
|
+
return NOTIFY_WARNING_LEVEL;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
Object.defineProperty(exports, "PACKAGE_SOURCE", {
|
|
402
|
+
enumerable: true,
|
|
403
|
+
get: function() {
|
|
404
|
+
return PACKAGE_SOURCE;
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
Object.defineProperty(exports, "START_COMMAND_DESCRIPTION", {
|
|
408
|
+
enumerable: true,
|
|
409
|
+
get: function() {
|
|
410
|
+
return START_COMMAND_DESCRIPTION;
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
Object.defineProperty(exports, "START_COMMAND_NAME", {
|
|
414
|
+
enumerable: true,
|
|
415
|
+
get: function() {
|
|
416
|
+
return START_COMMAND_NAME;
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
Object.defineProperty(exports, "STATUS_KEY", {
|
|
420
|
+
enumerable: true,
|
|
421
|
+
get: function() {
|
|
422
|
+
return STATUS_KEY;
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
Object.defineProperty(exports, "createDoomLoopLaunchersService", {
|
|
426
|
+
enumerable: true,
|
|
427
|
+
get: function() {
|
|
428
|
+
return createDoomLoopLaunchersService;
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
Object.defineProperty(exports, "createLoopTools", {
|
|
432
|
+
enumerable: true,
|
|
433
|
+
get: function() {
|
|
434
|
+
return createLoopTools;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
Object.defineProperty(exports, "formatLoopStatusView", {
|
|
438
|
+
enumerable: true,
|
|
439
|
+
get: function() {
|
|
440
|
+
return formatLoopStatusView;
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
Object.defineProperty(exports, "parseCronLoop", {
|
|
444
|
+
enumerable: true,
|
|
445
|
+
get: function() {
|
|
446
|
+
return parseCronLoop;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
Object.defineProperty(exports, "parseIntervalLoop", {
|
|
450
|
+
enumerable: true,
|
|
451
|
+
get: function() {
|
|
452
|
+
return parseIntervalLoop;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
//# sourceMappingURL=loopView-C_OPuy8L.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopView-C_OPuy8L.cjs","names":["Type","Check","defineTool","Check"],"sources":["../src/constants/piLoop.ts","../src/constants/loop.ts","../src/schemas/loopTools.ts","../src/services/loopLaunchers/index.ts","../src/services/loopTools/index.ts","../src/types/loopView.ts"],"sourcesContent":["export const PACKAGE_SOURCE = '@agimon-ai/doompi-loop';\nexport const LOOPS_GROUP_ORDER = 60;\nexport const STATUS_KEY = 'doom-loop';\nexport const MODE_STATUS_ID = 'loop.active';\nexport const ACTIVE_MODE_COLOR = 'warning';\nexport const NOTIFY_INFO_LEVEL = 'info';\nexport const NOTIFY_WARNING_LEVEL = 'warning';\n","export const START_COMMAND_DESCRIPTION = 'Start a registered loop';\nexport const LIST_COMMAND_DESCRIPTION = 'List and stop active loops';\nexport const START_COMMAND_NAME = 'loop';\nexport const LIST_COMMAND_NAME = 'loops';\n","import { type Static, Type } from 'typebox';\nimport { Check } from 'typebox/value';\n\nexport const LoopListSchema = Type.Object({}, { additionalProperties: false });\nexport const LoopStartSchema = Type.Object(\n {\n launcherId: Type.String({ minLength: 1, maxLength: 256 }),\n instanceId: Type.Optional(Type.String({ minLength: 1, maxLength: 256 })),\n input: Type.Record(Type.String(), Type.Unknown()),\n },\n { additionalProperties: false },\n);\nexport const LoopStopSchema = Type.Object(\n {\n instanceId: Type.String({ minLength: 1, maxLength: 256 }),\n reason: Type.Optional(Type.String({ minLength: 1, maxLength: 512 })),\n },\n { additionalProperties: false },\n);\n\nexport const IntervalLoopSchema = Type.Object(\n {\n prompt: Type.String({ minLength: 1, maxLength: 32768 }),\n intervalSeconds: Type.Integer({ minimum: 30, maximum: 3600 }),\n },\n { additionalProperties: false },\n);\nexport const CronLoopSchema = Type.Object(\n {\n prompt: Type.String({ minLength: 1, maxLength: 32768 }),\n cron: Type.String({ minLength: 1, maxLength: 256 }),\n timezone: Type.Optional(Type.String({ minLength: 1, maxLength: 128 })),\n },\n { additionalProperties: false },\n);\nexport type IntervalLoopInput = Static<typeof IntervalLoopSchema>;\nexport type CronLoopInput = Static<typeof CronLoopSchema>;\n\nexport function parseIntervalLoop(input: unknown): IntervalLoopInput {\n if (!Check(IntervalLoopSchema, input) || !input.prompt.trim()) {\n throw new Error('Provide a non-empty prompt and an integer intervalSeconds between 30 and 3600.');\n }\n return { ...input, prompt: input.prompt.trim() };\n}\n\nexport function parseCronLoop(input: unknown): CronLoopInput {\n if (!Check(CronLoopSchema, input) || !input.prompt.trim() || input.cron.trim().split(/\\s+/u).length !== 5) {\n throw new Error('Provide a non-empty prompt and a five-field cron expression, with an optional IANA timezone.');\n }\n const timezone = input.timezone ?? 'UTC';\n new Intl.DateTimeFormat('en', { timeZone: timezone }).format();\n return { ...input, prompt: input.prompt.trim(), cron: input.cron.trim(), timezone };\n}\n","import type {\n DoomLoopLaunchersService,\n LoopInstanceSnapshot,\n LoopLauncherDefinition,\n LoopLauncherRegistration,\n StoppableLoop,\n} from '../../schemas/loopLaunchers';\n\nconst MAX_ID_LENGTH = 256;\nconst MAX_GENERATION_LENGTH = 256;\nconst LAUNCHER_ID_LABEL = 'loop launcher id';\nconst INSTANCE_ID_LABEL = 'loop instance id';\n\ninterface LauncherEntry {\n readonly token: symbol;\n readonly definition: LoopLauncherDefinition;\n}\n\ninterface InstanceEntry {\n readonly instanceId: string;\n readonly launcher: LauncherEntry;\n readonly abortController: AbortController;\n state: LoopInstanceSnapshot['state'];\n handle?: StoppableLoop;\n startedAt?: string;\n}\n\nexport interface LoopLaunchersDependencies {\n readonly generation: string;\n readonly createInstanceId: () => string;\n readonly timestamp: () => string;\n}\n\nfunction validId(value: string, label: string): string {\n if (typeof value !== 'string') throw new TypeError(`Invalid ${label}.`);\n const normalized = value.trim();\n let hasControl = false;\n for (const character of normalized) {\n const code = character.codePointAt(0);\n if (code !== undefined && (code <= 0x1f || code === 0x7f)) {\n hasControl = true;\n break;\n }\n }\n if (!normalized || normalized.length > MAX_ID_LENGTH || hasControl) throw new Error(`Invalid ${label}.`);\n return normalized;\n}\n\nfunction snapshot(entry: InstanceEntry): LoopInstanceSnapshot {\n return {\n instanceId: entry.instanceId,\n launcherId: entry.launcher.definition.id,\n launcherLabel: entry.launcher.definition.label,\n ...(entry.handle?.label ? { label: entry.handle.label } : {}),\n ...(entry.handle?.detail ? { detail: entry.handle.detail } : {}),\n state: entry.state,\n ...(entry.startedAt ? { startedAt: entry.startedAt } : {}),\n };\n}\n\n/** Creates the provider-owned launcher registry for one active Doom session. */\nexport function createDoomLoopLaunchersService({\n generation,\n createInstanceId,\n timestamp,\n}: LoopLaunchersDependencies): DoomLoopLaunchersService {\n if (!generation || generation.length > MAX_GENERATION_LENGTH) {\n throw new TypeError('Doom loop launchers require a valid generation.');\n }\n\n const launchers = new Map<string, LauncherEntry>();\n const instances = new Map<string, InstanceEntry>();\n const listeners = new Set<() => void>();\n let registrationSequence = 0;\n let disposed = false;\n\n const ensureActive = (): void => {\n if (disposed) throw new Error('The Doom loop-launchers service is disposed.');\n };\n const notify = (): void => {\n for (const listener of listeners) listener();\n };\n const stopEntry = async (entry: InstanceEntry, reason?: string): Promise<void> => {\n if (instances.get(entry.instanceId) !== entry) return;\n entry.state = 'stopping';\n entry.abortController.abort(reason);\n notify();\n try {\n await entry.handle?.stop(reason);\n } finally {\n if (instances.get(entry.instanceId) === entry) instances.delete(entry.instanceId);\n notify();\n }\n };\n\n const service: DoomLoopLaunchersService = {\n generation,\n register(definition): LoopLauncherRegistration {\n ensureActive();\n const id = validId(definition.id, LAUNCHER_ID_LABEL);\n if (launchers.has(id)) throw new Error(`Loop launcher '${id}' is already registered.`);\n const token = Symbol(id);\n const entry: LauncherEntry = { token, definition: { ...definition, id } };\n launchers.set(id, entry);\n registrationSequence += 1;\n notify();\n let registrationDisposed = false;\n return Object.freeze({\n id,\n generation: `${generation}:launcher:${registrationSequence}`,\n async dispose(reason = 'Loop launcher disposed.'): Promise<void> {\n if (registrationDisposed) return;\n registrationDisposed = true;\n if (launchers.get(id)?.token !== token) return;\n launchers.delete(id);\n const owned = [...instances.values()].filter((instance) => instance.launcher.token === token);\n await Promise.allSettled(owned.map((instance) => stopEntry(instance, reason)));\n notify();\n },\n });\n },\n listLaunchers() {\n ensureActive();\n return [...launchers.values()]\n .map(({ definition }) => ({\n id: definition.id,\n source: definition.source,\n label: definition.label,\n ...(definition.description ? { description: definition.description } : {}),\n ...(definition.inputSchema ? { inputSchema: definition.inputSchema } : {}),\n }))\n .sort((left, right) => left.label.localeCompare(right.label) || left.id.localeCompare(right.id));\n },\n listInstances() {\n ensureActive();\n return [...instances.values()]\n .map(snapshot)\n .sort((left, right) => left.instanceId.localeCompare(right.instanceId));\n },\n subscribe(listener) {\n ensureActive();\n listeners.add(listener);\n let subscribed = true;\n return () => {\n if (!subscribed) return;\n subscribed = false;\n listeners.delete(listener);\n };\n },\n async launch(launcherId, options) {\n ensureActive();\n options?.signal?.throwIfAborted();\n const normalizedLauncherId = validId(launcherId, LAUNCHER_ID_LABEL);\n const launcher = launchers.get(normalizedLauncherId);\n if (!launcher) throw new Error(`Loop launcher '${normalizedLauncherId}' is unavailable.`);\n const instanceId = validId(options?.instanceId ?? createInstanceId(), INSTANCE_ID_LABEL);\n if (instances.has(instanceId)) throw new Error(`Loop instance '${instanceId}' already exists.`);\n const entry: InstanceEntry = { instanceId, launcher, abortController: new AbortController(), state: 'starting' };\n const abortSetup = (): void => entry.abortController.abort(options?.signal?.reason);\n options?.signal?.addEventListener('abort', abortSetup, { once: true });\n instances.set(instanceId, entry);\n notify();\n try {\n if (options?.interactive === false && !launcher.definition.inputSchema) {\n throw new Error(`Loop launcher '${normalizedLauncherId}' requires manual setup in Activity.`);\n }\n const handle = await launcher.definition.launch({\n instanceId,\n signal: entry.abortController.signal,\n ...(options?.input === undefined ? {} : { input: options.input }),\n ...(options?.interactive === undefined ? {} : { interactive: options.interactive }),\n });\n const active = !disposed && instances.get(instanceId) === entry && !entry.abortController.signal.aborted;\n if (!handle) {\n if (instances.get(instanceId) === entry) instances.delete(instanceId);\n notify();\n return undefined;\n }\n if (!active || handle.instanceId !== instanceId) {\n await handle.stop(active ? 'Loop launcher returned a mismatched instance id.' : 'Loop launch was cancelled.');\n if (instances.get(instanceId) === entry) instances.delete(instanceId);\n notify();\n if (active) throw new Error(`Loop launcher '${normalizedLauncherId}' returned a mismatched instance id.`);\n return undefined;\n }\n entry.handle = handle;\n entry.state = 'running';\n entry.startedAt = timestamp();\n notify();\n return snapshot(entry);\n } catch (error) {\n const cancelled = entry.abortController.signal.aborted || disposed;\n if (instances.get(instanceId) === entry) instances.delete(instanceId);\n notify();\n if (cancelled) return undefined;\n throw error;\n } finally {\n options?.signal?.removeEventListener('abort', abortSetup);\n }\n },\n async stop(instanceId, reason) {\n ensureActive();\n const entry = instances.get(validId(instanceId, INSTANCE_ID_LABEL));\n if (!entry) return false;\n await stopEntry(entry, reason);\n return true;\n },\n async stopAll(reason) {\n if (disposed && instances.size === 0) return;\n await Promise.allSettled([...instances.values()].map((entry) => stopEntry(entry, reason)));\n },\n async dispose(reason = 'Doom loop-launchers service disposed.') {\n if (disposed) return;\n disposed = true;\n launchers.clear();\n await Promise.allSettled([...instances.values()].map((entry) => stopEntry(entry, reason)));\n listeners.clear();\n },\n };\n\n return Object.freeze(service);\n}\n","import { defineTool, type DoomPluginTool, type DoomPluginToolResult } from '@agimon-ai/doompi-core/piExtension';\nimport { Check } from 'typebox/value';\n\nimport type { DoomLoopLaunchersService } from '../../schemas/loopLaunchers';\nimport { LoopListSchema, LoopStartSchema, LoopStopSchema } from '../../schemas/loopTools';\n\nfunction result(details: unknown): DoomPluginToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(details, null, 2) }], details };\n}\n\nexport function createLoopTools(\n launchers: () => DoomLoopLaunchersService,\n assertEnabled: () => void,\n): readonly DoomPluginTool[] {\n return [\n defineTool({\n name: 'loop_list',\n label: 'List loops',\n description: 'List active session loops and available launcher types with their configuration schemas.',\n parameters: LoopListSchema,\n async execute(input, { signal }) {\n assertEnabled();\n signal?.throwIfAborted();\n if (!Check(LoopListSchema, input)) throw new Error('loop_list takes no arguments.');\n const service = launchers();\n return result({ launchers: service.listLaunchers(), instances: service.listInstances() });\n },\n }),\n defineTool({\n name: 'loop_start',\n label: 'Start loop',\n description:\n 'Start a session-scoped loop without operator dialogs. Read loop_list for launcher IDs and input schemas. Loops stop when the session shuts down.',\n parameters: LoopStartSchema,\n executionMode: 'serial',\n async execute(input, { signal }) {\n assertEnabled();\n signal?.throwIfAborted();\n if (!Check(LoopStartSchema, input)) throw new Error('Provide launcherId, input, and optionally instanceId.');\n return result(\n (await launchers().launch(input.launcherId, { ...input, interactive: false, signal })) ?? { cancelled: true },\n );\n },\n }),\n defineTool({\n name: 'loop_stop',\n label: 'Stop loop',\n description:\n 'Stop one loop instance owned by the current session. Does not disable Loop mode or stop other loops.',\n parameters: LoopStopSchema,\n executionMode: 'serial',\n async execute(input, { signal }) {\n assertEnabled();\n signal?.throwIfAborted();\n if (!Check(LoopStopSchema, input)) throw new Error('Provide instanceId and an optional reason.');\n return result({ stopped: await launchers().stop(input.instanceId, input.reason ?? 'Stopped by the agent.') });\n },\n }),\n ];\n}\n","/** The browser-only status that carries active Loop instances into the activity dock. */\nexport const LOOP_VIEW_STATUS_KEY = 'doom-loop-instances';\n\nexport type LoopStatusState = 'starting' | 'running' | 'stopping';\n\n/** The small, serializable Loop view the cockpit needs for one activity row. */\nexport interface LoopStatusItem {\n readonly instanceId: string;\n readonly label: string;\n readonly detail: string;\n readonly state: LoopStatusState;\n}\n\ninterface LoopStatusSource {\n readonly instanceId: string;\n readonly launcherLabel: string;\n readonly label?: string;\n readonly detail?: string;\n readonly state: LoopStatusState;\n}\n\nconst ANSI = new RegExp(String.raw`\\u001b\\[[0-9;]*m`, 'gu');\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isState(value: unknown): value is LoopStatusState {\n return value === 'starting' || value === 'running' || value === 'stopping';\n}\n\n/** Projects runtime snapshots into the JSON status consumed by the web plugin. */\nexport function formatLoopStatusView(instances: readonly LoopStatusSource[]): string {\n if (instances.length === 0) return '';\n return JSON.stringify(\n instances.map((instance) => ({\n instanceId: instance.instanceId,\n label: instance.label ?? instance.launcherLabel,\n detail: instance.detail ?? instance.instanceId,\n state: instance.state,\n })),\n );\n}\n\n/** Reads a Loop status without letting malformed session data crash the activity dock. */\nexport function parseLoopStatusView(raw: string | undefined): LoopStatusItem[] | undefined {\n if (raw === undefined) return undefined;\n const text = raw.replace(ANSI, '').trim();\n if (text === '') return undefined;\n\n try {\n const value: unknown = JSON.parse(text);\n if (!Array.isArray(value) || value.length === 0) return undefined;\n const items: LoopStatusItem[] = [];\n for (const item of value) {\n if (\n !isRecord(item) ||\n typeof item.instanceId !== 'string' ||\n item.instanceId.trim() === '' ||\n typeof item.label !== 'string' ||\n item.label.trim() === '' ||\n typeof item.detail !== 'string' ||\n !isState(item.state)\n ) {\n return undefined;\n }\n items.push({ instanceId: item.instanceId, label: item.label, detail: item.detail, state: item.state });\n }\n return items;\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Doom Pi Loop
|
|
2
|
+
|
|
3
|
+
## Resources
|
|
4
|
+
|
|
5
|
+
- [Package README](./README.md): Commands, interval limits, lifecycle, cost, and cross-extension launchers.
|
|
6
|
+
|
|
7
|
+
## How to use
|
|
8
|
+
|
|
9
|
+
- [doompi-use-loop](./src/prompts/doompi-use-loop/SKILL.md): Start, inspect, and stop session-scoped recurring prompts safely.
|
package/package.json
CHANGED
|
@@ -1,16 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-loop",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.1-alpha.91",
|
|
4
|
+
"description": "Session-scoped recurring prompt scheduler and loop controls for Pi coding agents.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"automation",
|
|
8
|
+
"coding-agent",
|
|
9
|
+
"developer-tools",
|
|
10
|
+
"doompi",
|
|
11
|
+
"pi-coding-agent",
|
|
12
|
+
"pi-extension",
|
|
13
|
+
"pi-package",
|
|
14
|
+
"prompt-scheduler",
|
|
15
|
+
"recurring-tasks"
|
|
16
|
+
],
|
|
5
17
|
"homepage": "https://agimon.ai",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/AgiFlow/doompi/issues"
|
|
20
|
+
},
|
|
6
21
|
"license": "MIT",
|
|
7
22
|
"author": "Vuong Ngo",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/AgiFlow/doompi.git",
|
|
26
|
+
"directory": "packages/minor/doompi-loop"
|
|
27
|
+
},
|
|
8
28
|
"files": [
|
|
9
29
|
"dist",
|
|
30
|
+
"llms.txt",
|
|
31
|
+
"src/prompts",
|
|
32
|
+
"src/types/loopView.ts",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE",
|
|
10
35
|
"package.json"
|
|
11
36
|
],
|
|
12
37
|
"type": "module",
|
|
13
38
|
"main": "./dist/index.cjs",
|
|
39
|
+
"module": "./dist/index.mjs",
|
|
14
40
|
"types": "./dist/index.d.mts",
|
|
15
41
|
"jsnext:main": "./dist/index.mjs",
|
|
16
42
|
"exports": {
|
|
@@ -24,27 +50,50 @@
|
|
|
24
50
|
"import": "./dist/extensions/pi.mjs",
|
|
25
51
|
"require": "./dist/extensions/pi.cjs"
|
|
26
52
|
},
|
|
53
|
+
"./extensions/server": {
|
|
54
|
+
"types": "./dist/extensions/server.d.mts",
|
|
55
|
+
"import": "./dist/extensions/server.mjs",
|
|
56
|
+
"require": "./dist/extensions/server.cjs"
|
|
57
|
+
},
|
|
58
|
+
"./extensions/web": {
|
|
59
|
+
"import": "./dist/extensions/web.mjs"
|
|
60
|
+
},
|
|
61
|
+
"./loopLaunchers": {
|
|
62
|
+
"types": "./dist/loopLaunchers.d.mts",
|
|
63
|
+
"import": "./dist/loopLaunchers.mjs",
|
|
64
|
+
"require": "./dist/loopLaunchers.cjs"
|
|
65
|
+
},
|
|
27
66
|
"./package.json": "./package.json"
|
|
28
67
|
},
|
|
29
68
|
"publishConfig": {
|
|
30
69
|
"access": "public"
|
|
31
70
|
},
|
|
32
71
|
"dependencies": {
|
|
33
|
-
"@agimon-ai/doompi-
|
|
34
|
-
"@agimon-ai/doompi-
|
|
72
|
+
"@agimon-ai/doompi-core": "0.0.1-alpha.90",
|
|
73
|
+
"@agimon-ai/doompi-minor-mode": "0.0.1-alpha.90",
|
|
74
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.90",
|
|
75
|
+
"@agimon-ai/doompi-web-components": "0.0.1-alpha.48",
|
|
76
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
77
|
+
"croner": "10.0.1",
|
|
78
|
+
"typebox": "1.3.34"
|
|
35
79
|
},
|
|
36
80
|
"devDependencies": {
|
|
37
|
-
"@
|
|
38
|
-
"@earendil-works/pi-
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"vitest": "
|
|
81
|
+
"@agimon-ai/doompi-build": "0.0.1-alpha.15",
|
|
82
|
+
"@earendil-works/pi-coding-agent": "0.87.1",
|
|
83
|
+
"@earendil-works/pi-tui": "0.87.1",
|
|
84
|
+
"@types/node": "26.6.1",
|
|
85
|
+
"@types/react": "19.3.0",
|
|
86
|
+
"@types/react-dom": "19.3.0",
|
|
87
|
+
"@vitest/coverage-v8": "5.0.1",
|
|
88
|
+
"react": "19.3.0",
|
|
89
|
+
"react-dom": "19.3.0",
|
|
90
|
+
"tsdown": "0.23.0",
|
|
91
|
+
"typescript": "7.0.2",
|
|
92
|
+
"vitest": "5.0.1"
|
|
44
93
|
},
|
|
45
94
|
"peerDependencies": {
|
|
46
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
47
|
-
"@earendil-works/pi-tui": "0.
|
|
95
|
+
"@earendil-works/pi-coding-agent": "0.87.1",
|
|
96
|
+
"@earendil-works/pi-tui": "0.87.1"
|
|
48
97
|
},
|
|
49
98
|
"peerDependenciesMeta": {
|
|
50
99
|
"@earendil-works/pi-coding-agent": {
|
|
@@ -57,6 +106,25 @@
|
|
|
57
106
|
"engines": {
|
|
58
107
|
"node": ">=22.19.0"
|
|
59
108
|
},
|
|
109
|
+
"doompiServer": {
|
|
110
|
+
"entry": "./generated/server.ts",
|
|
111
|
+
"dist": "./dist/extensions/server.mjs",
|
|
112
|
+
"scopes": [
|
|
113
|
+
"session"
|
|
114
|
+
],
|
|
115
|
+
"contracts": {
|
|
116
|
+
"entry": "./src/exports/apiContracts.ts",
|
|
117
|
+
"dist": "./dist/apiContracts.mjs"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"doompiWeb": {
|
|
121
|
+
"pluginId": "loop",
|
|
122
|
+
"channels": [],
|
|
123
|
+
"client": "./dist/extensions/web.mjs",
|
|
124
|
+
"scopes": [
|
|
125
|
+
"session"
|
|
126
|
+
]
|
|
127
|
+
},
|
|
60
128
|
"pi": {
|
|
61
129
|
"extensions": [
|
|
62
130
|
"./dist/extensions/pi.mjs"
|
|
@@ -65,7 +133,7 @@
|
|
|
65
133
|
"scripts": {
|
|
66
134
|
"build": "tsdown",
|
|
67
135
|
"test": "vitest --run",
|
|
68
|
-
"typecheck": "tsc --noEmit",
|
|
136
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json",
|
|
69
137
|
"lint": "oxlint . && oxfmt . --check",
|
|
70
138
|
"fixcode": "oxlint . --fix && oxfmt ."
|
|
71
139
|
}
|