@agimon-ai/doompi 0.0.1-alpha.100 → 0.0.1-alpha.101
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 +2 -2
- package/dist/bin/serve.cjs +7 -2
- package/dist/bin/serve.cjs.map +1 -1
- package/dist/bin/serve.mjs +6 -2
- package/dist/bin/serve.mjs.map +1 -1
- package/dist/src/builders/server/executionBudget.cjs +64 -0
- package/dist/src/builders/server/executionBudget.cjs.map +1 -0
- package/dist/src/builders/server/executionBudget.mjs +64 -0
- package/dist/src/builders/server/executionBudget.mjs.map +1 -0
- package/dist/src/builders/server/runtime.cjs +46 -31
- package/dist/src/builders/server/runtime.cjs.map +1 -1
- package/dist/src/builders/server/runtime.mjs +47 -32
- package/dist/src/builders/server/runtime.mjs.map +1 -1
- package/dist/src/builders/server/sessionArguments.cjs +40 -0
- package/dist/src/builders/server/sessionArguments.cjs.map +1 -1
- package/dist/src/builders/server/sessionArguments.mjs +40 -1
- package/dist/src/builders/server/sessionArguments.mjs.map +1 -1
- package/dist/src/builders/server/shutdown.cjs +16 -0
- package/dist/src/builders/server/shutdown.cjs.map +1 -0
- package/dist/src/builders/server/shutdown.mjs +16 -0
- package/dist/src/builders/server/shutdown.mjs.map +1 -0
- package/dist/src/builders/web/webPluginGenerate.cjs +22 -1
- package/dist/src/builders/web/webPluginGenerate.cjs.map +1 -1
- package/dist/src/builders/web/webPluginGenerate.d.mts.map +1 -1
- package/dist/src/builders/web/webPluginGenerate.mjs +22 -1
- package/dist/src/builders/web/webPluginGenerate.mjs.map +1 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -437,8 +437,8 @@ configured.
|
|
|
437
437
|
A promise to "only plan" is not a permission boundary. [`@agimon-ai/doompi-plan`][pkg-doompi-plan]
|
|
438
438
|
removes Pi's `edit` and `write` tools while the agent explores, persists the plan, and hands it back
|
|
439
439
|
for approval. It does not sandbox Bash, external tools, or the operating system. `SPC p e` enters
|
|
440
|
-
normal planning and leaves it again once on; `SPC p d` is debug planning and `SPC p
|
|
441
|
-
|
|
440
|
+
normal planning and leaves it again once on; `SPC p d` is debug planning and `SPC p r` is Code Review
|
|
441
|
+
planning, with actionable findings and proposed fixes for approval.
|
|
442
442
|
Turn it on when the approach should be settled before the files move.
|
|
443
443
|
|
|
444
444
|
#### Loop mode
|
package/dist/bin/serve.cjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
const require_run = require("../src/cli/server/run.cjs");
|
|
2
3
|
//#region src/bin/serve.ts
|
|
3
|
-
|
|
4
|
+
function finish(code) {
|
|
4
5
|
process.exitCode = code;
|
|
6
|
+
setTimeout(() => process.exit(code), 2e3).unref();
|
|
7
|
+
}
|
|
8
|
+
require_run.runServer(process.argv.slice(2)).then((code) => {
|
|
9
|
+
finish(code);
|
|
5
10
|
}, (error) => {
|
|
6
11
|
process.stderr.write(`[doompi-server] ${error instanceof Error ? error.message : String(error)}\n`);
|
|
7
|
-
|
|
12
|
+
finish(1);
|
|
8
13
|
});
|
|
9
14
|
//#endregion
|
|
10
15
|
|
package/dist/bin/serve.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.cjs","names":["runServer"],"sources":["../../src/bin/serve.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runServer } from '../cli/server/run';\n\nrunServer(process.argv.slice(2)).then(\n (code) => {\n
|
|
1
|
+
{"version":3,"file":"serve.cjs","names":["runServer"],"sources":["../../src/bin/serve.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runServer } from '../cli/server/run';\n\n// The library finishes bounded cleanup first. A stale handle must not keep this\n// standalone CLI alive forever; an unreferenced deadline still lets output drain.\nfunction finish(code: number): void {\n process.exitCode = code;\n setTimeout(() => process.exit(code), 2_000).unref();\n}\n\nrunServer(process.argv.slice(2)).then(\n (code) => {\n finish(code);\n },\n (error: unknown) => {\n process.stderr.write(`[doompi-server] ${error instanceof Error ? error.message : String(error)}\\n`);\n finish(1);\n },\n);\n"],"mappings":";;;AAKA,SAAS,OAAO,MAAoB;CAClC,QAAQ,WAAW;CACnB,iBAAiB,QAAQ,KAAK,IAAI,GAAG,GAAK,CAAC,CAAC,MAAM;AACpD;AAEAA,YAAAA,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAC9B,SAAS;CACR,OAAO,IAAI;AACb,IACC,UAAmB;CAClB,QAAQ,OAAO,MAAM,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG;CAClG,OAAO,CAAC;AACV,CACF"}
|
package/dist/bin/serve.mjs
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { runServer } from "../src/cli/server/run.mjs";
|
|
3
3
|
//#region src/bin/serve.ts
|
|
4
|
-
|
|
4
|
+
function finish(code) {
|
|
5
5
|
process.exitCode = code;
|
|
6
|
+
setTimeout(() => process.exit(code), 2e3).unref();
|
|
7
|
+
}
|
|
8
|
+
runServer(process.argv.slice(2)).then((code) => {
|
|
9
|
+
finish(code);
|
|
6
10
|
}, (error) => {
|
|
7
11
|
process.stderr.write(`[doompi-server] ${error instanceof Error ? error.message : String(error)}\n`);
|
|
8
|
-
|
|
12
|
+
finish(1);
|
|
9
13
|
});
|
|
10
14
|
//#endregion
|
|
11
15
|
export {};
|
package/dist/bin/serve.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.mjs","names":[],"sources":["../../src/bin/serve.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runServer } from '../cli/server/run';\n\nrunServer(process.argv.slice(2)).then(\n (code) => {\n
|
|
1
|
+
{"version":3,"file":"serve.mjs","names":[],"sources":["../../src/bin/serve.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runServer } from '../cli/server/run';\n\n// The library finishes bounded cleanup first. A stale handle must not keep this\n// standalone CLI alive forever; an unreferenced deadline still lets output drain.\nfunction finish(code: number): void {\n process.exitCode = code;\n setTimeout(() => process.exit(code), 2_000).unref();\n}\n\nrunServer(process.argv.slice(2)).then(\n (code) => {\n finish(code);\n },\n (error: unknown) => {\n process.stderr.write(`[doompi-server] ${error instanceof Error ? error.message : String(error)}\\n`);\n finish(1);\n },\n);\n"],"mappings":";;;AAKA,SAAS,OAAO,MAAoB;CAClC,QAAQ,WAAW;CACnB,iBAAiB,QAAQ,KAAK,IAAI,GAAG,GAAK,CAAC,CAAC,MAAM;AACpD;AAEA,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAC9B,SAAS;CACR,OAAO,IAAI;AACb,IACC,UAAmB;CAClB,QAAQ,OAAO,MAAM,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG;CAClG,OAAO,CAAC;AACV,CACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/builders/server/executionBudget.ts
|
|
2
|
+
const MAX_QUEUED_JOBS = 128;
|
|
3
|
+
/** One host owns the queue; session callers only borrow execution slots. */
|
|
4
|
+
function createExecutionBudget(limit = 2) {
|
|
5
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("Heavy-job limit must be a positive integer");
|
|
6
|
+
let running = 0;
|
|
7
|
+
let closed = false;
|
|
8
|
+
const queue = [];
|
|
9
|
+
const drain = () => {
|
|
10
|
+
while (!closed && running < limit && queue.length) queue.shift().grant();
|
|
11
|
+
};
|
|
12
|
+
const lease = () => {
|
|
13
|
+
running++;
|
|
14
|
+
let released = false;
|
|
15
|
+
return () => {
|
|
16
|
+
if (released) return;
|
|
17
|
+
released = true;
|
|
18
|
+
running--;
|
|
19
|
+
drain();
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
async acquire(signal) {
|
|
24
|
+
if (closed) throw new Error("The host execution budget is closed");
|
|
25
|
+
signal?.throwIfAborted();
|
|
26
|
+
if (running < limit) return lease();
|
|
27
|
+
if (queue.length >= MAX_QUEUED_JOBS) throw new Error("The host heavy-job queue is full");
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
const detach = () => signal?.removeEventListener("abort", onAbort);
|
|
30
|
+
const waiter = {
|
|
31
|
+
grant: () => {
|
|
32
|
+
detach();
|
|
33
|
+
if (signal?.aborted) reject(signal.reason);
|
|
34
|
+
else resolve(lease());
|
|
35
|
+
},
|
|
36
|
+
cancel: (reason) => {
|
|
37
|
+
detach();
|
|
38
|
+
const index = queue.indexOf(waiter);
|
|
39
|
+
if (index >= 0) queue.splice(index, 1);
|
|
40
|
+
reject(reason);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const onAbort = () => waiter.cancel(signal?.reason);
|
|
44
|
+
queue.push(waiter);
|
|
45
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
46
|
+
if (signal?.aborted) onAbort();
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
getSnapshot: () => ({
|
|
50
|
+
running,
|
|
51
|
+
queued: queue.length,
|
|
52
|
+
limit
|
|
53
|
+
}),
|
|
54
|
+
close() {
|
|
55
|
+
if (closed) return;
|
|
56
|
+
closed = true;
|
|
57
|
+
for (const waiter of queue.splice(0)) waiter.cancel(/* @__PURE__ */ new Error("The host execution budget is closed"));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
exports.createExecutionBudget = createExecutionBudget;
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=executionBudget.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executionBudget.cjs","names":[],"sources":["../../../../src/builders/server/executionBudget.ts"],"sourcesContent":["import type { DoomHostExecutionBudget } from '@agimon-ai/doompi-core/packageApi';\n\nconst MAX_QUEUED_JOBS = 128;\n\n/** One host owns the queue; session callers only borrow execution slots. */\nexport function createExecutionBudget(limit = 2): DoomHostExecutionBudget & { close(): void } {\n if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError('Heavy-job limit must be a positive integer');\n let running = 0;\n let closed = false;\n const queue: Array<{ grant(): void; cancel(reason: unknown): void }> = [];\n\n const drain = (): void => {\n while (!closed && running < limit && queue.length) queue.shift()!.grant();\n };\n const lease = (): (() => void) => {\n running++;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n running--;\n drain();\n };\n };\n\n return {\n async acquire(signal) {\n if (closed) throw new Error('The host execution budget is closed');\n signal?.throwIfAborted();\n if (running < limit) return lease();\n if (queue.length >= MAX_QUEUED_JOBS) throw new Error('The host heavy-job queue is full');\n return new Promise<() => void>((resolve, reject) => {\n const detach = (): void => signal?.removeEventListener('abort', onAbort);\n const waiter = {\n grant: () => {\n detach();\n if (signal?.aborted) reject(signal.reason);\n else resolve(lease());\n },\n cancel: (reason: unknown) => {\n detach();\n const index = queue.indexOf(waiter);\n if (index >= 0) queue.splice(index, 1);\n reject(reason);\n },\n };\n const onAbort = (): void => waiter.cancel(signal?.reason);\n queue.push(waiter);\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) onAbort();\n });\n },\n getSnapshot: () => ({ running, queued: queue.length, limit }),\n close() {\n if (closed) return;\n closed = true;\n for (const waiter of queue.splice(0)) waiter.cancel(new Error('The host execution budget is closed'));\n },\n };\n}\n"],"mappings":";AAEA,MAAM,kBAAkB;;AAGxB,SAAgB,sBAAsB,QAAQ,GAAgD;CAC5F,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAAG,MAAM,IAAI,WAAW,4CAA4C;CAChH,IAAI,UAAU;CACd,IAAI,SAAS;CACb,MAAM,QAAiE,CAAC;CAExE,MAAM,cAAoB;EACxB,OAAO,CAAC,UAAU,UAAU,SAAS,MAAM,QAAQ,MAAM,MAAM,CAAC,CAAE,MAAM;CAC1E;CACA,MAAM,cAA4B;EAChC;EACA,IAAI,WAAW;EACf,aAAa;GACX,IAAI,UAAU;GACd,WAAW;GACX;GACA,MAAM;EACR;CACF;CAEA,OAAO;EACL,MAAM,QAAQ,QAAQ;GACpB,IAAI,QAAQ,MAAM,IAAI,MAAM,qCAAqC;GACjE,QAAQ,eAAe;GACvB,IAAI,UAAU,OAAO,OAAO,MAAM;GAClC,IAAI,MAAM,UAAU,iBAAiB,MAAM,IAAI,MAAM,kCAAkC;GACvF,OAAO,IAAI,SAAqB,SAAS,WAAW;IAClD,MAAM,eAAqB,QAAQ,oBAAoB,SAAS,OAAO;IACvE,MAAM,SAAS;KACb,aAAa;MACX,OAAO;MACP,IAAI,QAAQ,SAAS,OAAO,OAAO,MAAM;WACpC,QAAQ,MAAM,CAAC;KACtB;KACA,SAAS,WAAoB;MAC3B,OAAO;MACP,MAAM,QAAQ,MAAM,QAAQ,MAAM;MAClC,IAAI,SAAS,GAAG,MAAM,OAAO,OAAO,CAAC;MACrC,OAAO,MAAM;KACf;IACF;IACA,MAAM,gBAAsB,OAAO,OAAO,QAAQ,MAAM;IACxD,MAAM,KAAK,MAAM;IACjB,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;IACzD,IAAI,QAAQ,SAAS,QAAQ;GAC/B,CAAC;EACH;EACA,oBAAoB;GAAE;GAAS,QAAQ,MAAM;GAAQ;EAAM;EAC3D,QAAQ;GACN,IAAI,QAAQ;GACZ,SAAS;GACT,KAAK,MAAM,UAAU,MAAM,OAAO,CAAC,GAAG,OAAO,uBAAO,IAAI,MAAM,qCAAqC,CAAC;EACtG;CACF;AACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/builders/server/executionBudget.ts
|
|
2
|
+
const MAX_QUEUED_JOBS = 128;
|
|
3
|
+
/** One host owns the queue; session callers only borrow execution slots. */
|
|
4
|
+
function createExecutionBudget(limit = 2) {
|
|
5
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("Heavy-job limit must be a positive integer");
|
|
6
|
+
let running = 0;
|
|
7
|
+
let closed = false;
|
|
8
|
+
const queue = [];
|
|
9
|
+
const drain = () => {
|
|
10
|
+
while (!closed && running < limit && queue.length) queue.shift().grant();
|
|
11
|
+
};
|
|
12
|
+
const lease = () => {
|
|
13
|
+
running++;
|
|
14
|
+
let released = false;
|
|
15
|
+
return () => {
|
|
16
|
+
if (released) return;
|
|
17
|
+
released = true;
|
|
18
|
+
running--;
|
|
19
|
+
drain();
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
async acquire(signal) {
|
|
24
|
+
if (closed) throw new Error("The host execution budget is closed");
|
|
25
|
+
signal?.throwIfAborted();
|
|
26
|
+
if (running < limit) return lease();
|
|
27
|
+
if (queue.length >= MAX_QUEUED_JOBS) throw new Error("The host heavy-job queue is full");
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
const detach = () => signal?.removeEventListener("abort", onAbort);
|
|
30
|
+
const waiter = {
|
|
31
|
+
grant: () => {
|
|
32
|
+
detach();
|
|
33
|
+
if (signal?.aborted) reject(signal.reason);
|
|
34
|
+
else resolve(lease());
|
|
35
|
+
},
|
|
36
|
+
cancel: (reason) => {
|
|
37
|
+
detach();
|
|
38
|
+
const index = queue.indexOf(waiter);
|
|
39
|
+
if (index >= 0) queue.splice(index, 1);
|
|
40
|
+
reject(reason);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const onAbort = () => waiter.cancel(signal?.reason);
|
|
44
|
+
queue.push(waiter);
|
|
45
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
46
|
+
if (signal?.aborted) onAbort();
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
getSnapshot: () => ({
|
|
50
|
+
running,
|
|
51
|
+
queued: queue.length,
|
|
52
|
+
limit
|
|
53
|
+
}),
|
|
54
|
+
close() {
|
|
55
|
+
if (closed) return;
|
|
56
|
+
closed = true;
|
|
57
|
+
for (const waiter of queue.splice(0)) waiter.cancel(/* @__PURE__ */ new Error("The host execution budget is closed"));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { createExecutionBudget };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=executionBudget.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executionBudget.mjs","names":[],"sources":["../../../../src/builders/server/executionBudget.ts"],"sourcesContent":["import type { DoomHostExecutionBudget } from '@agimon-ai/doompi-core/packageApi';\n\nconst MAX_QUEUED_JOBS = 128;\n\n/** One host owns the queue; session callers only borrow execution slots. */\nexport function createExecutionBudget(limit = 2): DoomHostExecutionBudget & { close(): void } {\n if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError('Heavy-job limit must be a positive integer');\n let running = 0;\n let closed = false;\n const queue: Array<{ grant(): void; cancel(reason: unknown): void }> = [];\n\n const drain = (): void => {\n while (!closed && running < limit && queue.length) queue.shift()!.grant();\n };\n const lease = (): (() => void) => {\n running++;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n running--;\n drain();\n };\n };\n\n return {\n async acquire(signal) {\n if (closed) throw new Error('The host execution budget is closed');\n signal?.throwIfAborted();\n if (running < limit) return lease();\n if (queue.length >= MAX_QUEUED_JOBS) throw new Error('The host heavy-job queue is full');\n return new Promise<() => void>((resolve, reject) => {\n const detach = (): void => signal?.removeEventListener('abort', onAbort);\n const waiter = {\n grant: () => {\n detach();\n if (signal?.aborted) reject(signal.reason);\n else resolve(lease());\n },\n cancel: (reason: unknown) => {\n detach();\n const index = queue.indexOf(waiter);\n if (index >= 0) queue.splice(index, 1);\n reject(reason);\n },\n };\n const onAbort = (): void => waiter.cancel(signal?.reason);\n queue.push(waiter);\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) onAbort();\n });\n },\n getSnapshot: () => ({ running, queued: queue.length, limit }),\n close() {\n if (closed) return;\n closed = true;\n for (const waiter of queue.splice(0)) waiter.cancel(new Error('The host execution budget is closed'));\n },\n };\n}\n"],"mappings":";AAEA,MAAM,kBAAkB;;AAGxB,SAAgB,sBAAsB,QAAQ,GAAgD;CAC5F,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAAG,MAAM,IAAI,WAAW,4CAA4C;CAChH,IAAI,UAAU;CACd,IAAI,SAAS;CACb,MAAM,QAAiE,CAAC;CAExE,MAAM,cAAoB;EACxB,OAAO,CAAC,UAAU,UAAU,SAAS,MAAM,QAAQ,MAAM,MAAM,CAAC,CAAE,MAAM;CAC1E;CACA,MAAM,cAA4B;EAChC;EACA,IAAI,WAAW;EACf,aAAa;GACX,IAAI,UAAU;GACd,WAAW;GACX;GACA,MAAM;EACR;CACF;CAEA,OAAO;EACL,MAAM,QAAQ,QAAQ;GACpB,IAAI,QAAQ,MAAM,IAAI,MAAM,qCAAqC;GACjE,QAAQ,eAAe;GACvB,IAAI,UAAU,OAAO,OAAO,MAAM;GAClC,IAAI,MAAM,UAAU,iBAAiB,MAAM,IAAI,MAAM,kCAAkC;GACvF,OAAO,IAAI,SAAqB,SAAS,WAAW;IAClD,MAAM,eAAqB,QAAQ,oBAAoB,SAAS,OAAO;IACvE,MAAM,SAAS;KACb,aAAa;MACX,OAAO;MACP,IAAI,QAAQ,SAAS,OAAO,OAAO,MAAM;WACpC,QAAQ,MAAM,CAAC;KACtB;KACA,SAAS,WAAoB;MAC3B,OAAO;MACP,MAAM,QAAQ,MAAM,QAAQ,MAAM;MAClC,IAAI,SAAS,GAAG,MAAM,OAAO,OAAO,CAAC;MACrC,OAAO,MAAM;KACf;IACF;IACA,MAAM,gBAAsB,OAAO,OAAO,QAAQ,MAAM;IACxD,MAAM,KAAK,MAAM;IACjB,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;IACzD,IAAI,QAAQ,SAAS,QAAQ;GAC/B,CAAC;EACH;EACA,oBAAoB;GAAE;GAAS,QAAQ,MAAM;GAAQ;EAAM;EAC3D,QAAQ;GACN,IAAI,QAAQ;GACZ,SAAS;GACT,KAAK,MAAM,UAAU,MAAM,OAAO,CAAC,GAAG,OAAO,uBAAO,IAAI,MAAM,qCAAqC,CAAC;EACtG;CACF;AACF"}
|
|
@@ -7,10 +7,12 @@ const require_index$4 = require("../../composition/syncDrift/index.cjs");
|
|
|
7
7
|
const require_harnessContext = require("../cli/harnessContext.cjs");
|
|
8
8
|
const require_computerUseBinding = require("./computerUseBinding.cjs");
|
|
9
9
|
const require_defaultWorkspace = require("./defaultWorkspace.cjs");
|
|
10
|
+
const require_executionBudget = require("./executionBudget.cjs");
|
|
10
11
|
const require_logSink = require("./logSink.cjs");
|
|
11
12
|
const require_selectionStatus = require("./selectionStatus.cjs");
|
|
12
13
|
const require_sessionArguments = require("./sessionArguments.cjs");
|
|
13
14
|
const require_sessionArtifact = require("./sessionArtifact.cjs");
|
|
15
|
+
const require_shutdown = require("./shutdown.cjs");
|
|
14
16
|
const require_workspaceCheckout = require("./workspaceCheckout.cjs");
|
|
15
17
|
let node_fs = require("node:fs");
|
|
16
18
|
node_fs = require_runtime.__toESM(node_fs, 1);
|
|
@@ -43,17 +45,11 @@ ws = require_runtime.__toESM(ws, 1);
|
|
|
43
45
|
let _agimon_ai_doompi_config_harnessStore = require("@agimon-ai/doompi-config/harnessStore");
|
|
44
46
|
let _agimon_ai_doompi_config_harnessState = require("@agimon-ai/doompi-config/harnessState");
|
|
45
47
|
//#region src/builders/server/runtime.ts
|
|
46
|
-
const TELEMETRY_SHUTDOWN_TIMEOUT_MS = 2e3;
|
|
47
48
|
async function bounded(operation, label, notice) {
|
|
48
|
-
let timeout;
|
|
49
49
|
try {
|
|
50
|
-
await
|
|
51
|
-
timeout = setTimeout(resolve, TELEMETRY_SHUTDOWN_TIMEOUT_MS);
|
|
52
|
-
})]);
|
|
50
|
+
await require_shutdown.withShutdownDeadline(() => operation, label);
|
|
53
51
|
} catch (error) {
|
|
54
52
|
notice(`${label} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
55
|
-
} finally {
|
|
56
|
-
if (timeout) clearTimeout(timeout);
|
|
57
53
|
}
|
|
58
54
|
}
|
|
59
55
|
async function runServerRuntime(options, runtime) {
|
|
@@ -62,6 +58,7 @@ async function runServerRuntime(options, runtime) {
|
|
|
62
58
|
...incomingEnvironment,
|
|
63
59
|
LOG_SINK_INSTANCE: "global"
|
|
64
60
|
};
|
|
61
|
+
const executionBudget = require_executionBudget.createExecutionBudget(Number(baseEnvironment.DOOM_RUNNER_MAX_HEAVY_JOBS ?? 2));
|
|
65
62
|
await require_logSink.ensureGlobalLogSink({
|
|
66
63
|
cwd: baseCwd,
|
|
67
64
|
env: baseEnvironment,
|
|
@@ -111,9 +108,21 @@ async function runServerRuntime(options, runtime) {
|
|
|
111
108
|
homeDirectory,
|
|
112
109
|
onNotice: notice
|
|
113
110
|
});
|
|
111
|
+
let lastBudgetSnapshot = "";
|
|
114
112
|
let nextEventLoopTick = performance.now() + 1e3;
|
|
115
113
|
const eventLoopMonitor = setInterval(() => {
|
|
116
114
|
const now = performance.now();
|
|
115
|
+
const budget = executionBudget.getSnapshot();
|
|
116
|
+
const snapshot = JSON.stringify(budget);
|
|
117
|
+
if (snapshot !== lastBudgetSnapshot) {
|
|
118
|
+
lastBudgetSnapshot = snapshot;
|
|
119
|
+
telemetry.recordEvent("doompi_server.execution_budget", {
|
|
120
|
+
host_pid: process.pid,
|
|
121
|
+
running_jobs: budget.running,
|
|
122
|
+
queued_jobs: budget.queued,
|
|
123
|
+
limit: budget.limit
|
|
124
|
+
}).catch((error) => notice(`execution budget telemetry failed: ${String(error)}`));
|
|
125
|
+
}
|
|
117
126
|
const delay = Math.max(0, now - nextEventLoopTick);
|
|
118
127
|
nextEventLoopTick = now + 1e3;
|
|
119
128
|
if (delay >= 100) telemetry.recordEvent("doompi_server.event_loop_delay", { duration_ms: Math.round(delay) }).catch((error) => notice(`event loop telemetry failed: ${String(error)}`));
|
|
@@ -142,8 +151,8 @@ async function runServerRuntime(options, runtime) {
|
|
|
142
151
|
* it exists to survive.
|
|
143
152
|
*/
|
|
144
153
|
let shuttingDown = false;
|
|
145
|
-
const closeManagedSession = async (sessionId) => {
|
|
146
|
-
if (!shuttingDown) openSessions.remove(sessionId);
|
|
154
|
+
const closeManagedSession = async (sessionId, options) => {
|
|
155
|
+
if (!shuttingDown && options?.keepDormant !== true) openSessions.remove(sessionId);
|
|
147
156
|
const artifacts = sessionArtifacts.get(sessionId);
|
|
148
157
|
sessionArtifacts.delete(sessionId);
|
|
149
158
|
webCompositions?.remove({
|
|
@@ -152,17 +161,17 @@ async function runServerRuntime(options, runtime) {
|
|
|
152
161
|
});
|
|
153
162
|
const failures = [];
|
|
154
163
|
try {
|
|
155
|
-
await baseSessionManager.closeSession(sessionId);
|
|
164
|
+
await require_shutdown.withShutdownDeadline(() => baseSessionManager.closeSession(sessionId), `Session '${sessionId}' runtime shutdown`);
|
|
156
165
|
} catch (error) {
|
|
157
166
|
failures.push(error);
|
|
158
167
|
}
|
|
159
168
|
try {
|
|
160
|
-
await artifacts?.apis.close();
|
|
169
|
+
await require_shutdown.withShutdownDeadline(() => artifacts?.apis.close(), `Session '${sessionId}' API shutdown`);
|
|
161
170
|
} catch (error) {
|
|
162
171
|
failures.push(error);
|
|
163
172
|
}
|
|
164
173
|
try {
|
|
165
|
-
await artifacts?.cleanup();
|
|
174
|
+
await require_shutdown.withShutdownDeadline(() => artifacts?.cleanup(), `Session '${sessionId}' artifact cleanup`);
|
|
166
175
|
} catch (error) {
|
|
167
176
|
failures.push(error);
|
|
168
177
|
}
|
|
@@ -318,6 +327,7 @@ async function runServerRuntime(options, runtime) {
|
|
|
318
327
|
hubToken: token,
|
|
319
328
|
sessionService: hub.sessionService,
|
|
320
329
|
mediaArbitration,
|
|
330
|
+
executionBudget,
|
|
321
331
|
peerAgents,
|
|
322
332
|
directEvents: hub.directEvents,
|
|
323
333
|
requestApi: (mount, basePath, request) => hub.requestApi(mount, basePath, request),
|
|
@@ -498,7 +508,7 @@ async function runServerRuntime(options, runtime) {
|
|
|
498
508
|
notice(`Workspace '${workspace.root}' could not be restored: ${error instanceof Error ? error.message : String(error)}`);
|
|
499
509
|
}
|
|
500
510
|
}
|
|
501
|
-
const sessionHostOptions = (context, bundle, mcpBundle, registration, identity, workspace) => {
|
|
511
|
+
const sessionHostOptions = (context, bundle, mcpBundle, registration, identity, workspace, explicit = { pinned: [] }) => {
|
|
502
512
|
const policyOptions = context.options;
|
|
503
513
|
const sessionSelection = {
|
|
504
514
|
root: policyOptions.repoRoot,
|
|
@@ -506,7 +516,7 @@ async function runServerRuntime(options, runtime) {
|
|
|
506
516
|
activeLayers: context.selectedLayers,
|
|
507
517
|
domains: policyOptions.domains,
|
|
508
518
|
profile: context.profile,
|
|
509
|
-
state: { "minor-mode": [] }
|
|
519
|
+
state: { "minor-mode": [...explicit.minorModes ?? []] }
|
|
510
520
|
};
|
|
511
521
|
const piBootstrap = require_index$3.readRegisteredBootstrapStatus(registration, void 0, homeDirectory);
|
|
512
522
|
if (!piBootstrap.fresh || piBootstrap.bootstrap === void 0) throw new Error(`The admitted DoomPi bootstrap for generation '${registration.generation}' is unavailable.`);
|
|
@@ -528,11 +538,13 @@ async function runServerRuntime(options, runtime) {
|
|
|
528
538
|
environment: Object.freeze({ ...context.environment }),
|
|
529
539
|
piExtensionPaths: [piBootstrap.bootstrap],
|
|
530
540
|
selection: sessionSelection,
|
|
541
|
+
...explicit.allowedTools === void 0 ? {} : { allowedTools: explicit.allowedTools },
|
|
531
542
|
selectionOverrides: [
|
|
532
543
|
"majorMode",
|
|
533
544
|
"domains",
|
|
534
545
|
"profile"
|
|
535
546
|
].filter((axis) => {
|
|
547
|
+
if (explicit.pinned.includes(axis)) return true;
|
|
536
548
|
const flag = axis === "majorMode" ? "--major-mode" : `--${axis}`;
|
|
537
549
|
return identity.sessionId === resolved.identity.sessionId && resolved.agentArgs.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
538
550
|
}),
|
|
@@ -583,6 +595,7 @@ async function runServerRuntime(options, runtime) {
|
|
|
583
595
|
hubToken: token,
|
|
584
596
|
sessionService: hub.sessionService,
|
|
585
597
|
mediaArbitration,
|
|
598
|
+
executionBudget,
|
|
586
599
|
peerAgents,
|
|
587
600
|
pluginRegistry: hub.pluginRegistry,
|
|
588
601
|
apis: [],
|
|
@@ -687,9 +700,13 @@ async function runServerRuntime(options, runtime) {
|
|
|
687
700
|
};
|
|
688
701
|
const inheritedWorkspaceId = groupingWorkspaceId ?? (request.parentSessionId ? hub.session(request.parentSessionId)?.workspaceId ?? openSessions.list().find((record) => record.sessionId === request.parentSessionId)?.workspaceId : void 0);
|
|
689
702
|
const parentArtifact = request.parentSessionId === void 0 ? void 0 : sessionArtifacts.get(request.parentSessionId)?.registration ?? pendingSessions.get(request.parentSessionId)?.registration ?? openSessions.list().find((record) => record.sessionId === request.parentSessionId)?.artifact;
|
|
703
|
+
const explicit = require_sessionArguments.sessionSelectionArgs(request);
|
|
690
704
|
const start = (async () => {
|
|
691
705
|
const childIdentity = require_sessionArguments.resolveSessionIdentity([], identity);
|
|
692
|
-
const childEnvironment = {
|
|
706
|
+
const childEnvironment = {
|
|
707
|
+
...baseEnvironment,
|
|
708
|
+
...request.environment
|
|
709
|
+
};
|
|
693
710
|
for (const key of [_agimon_ai_doompi_config_harnessStore.HARNESS_STATE_POINTER, ...Object.values(_agimon_ai_doompi_config_harnessState.HARNESS_STATE_KEYS)]) delete childEnvironment[key];
|
|
694
711
|
const workspace = inheritedWorkspaceId === void 0 ? await admitWorkspace(request.cwd) : hub.workspaces().find((candidate) => candidate.id === inheritedWorkspaceId && candidate.available !== false);
|
|
695
712
|
if (workspace === void 0) throw new Error("The session workspace is unavailable.");
|
|
@@ -698,7 +715,8 @@ async function runServerRuntime(options, runtime) {
|
|
|
698
715
|
args: [
|
|
699
716
|
"--cwd",
|
|
700
717
|
request.cwd,
|
|
701
|
-
...childIdentity.agentArgs
|
|
718
|
+
...childIdentity.agentArgs,
|
|
719
|
+
...explicit.args
|
|
702
720
|
],
|
|
703
721
|
cwd: request.cwd,
|
|
704
722
|
environment: childEnvironment,
|
|
@@ -732,7 +750,11 @@ async function runServerRuntime(options, runtime) {
|
|
|
732
750
|
mcpBundle,
|
|
733
751
|
registration
|
|
734
752
|
});
|
|
735
|
-
const created = await hub.create(sessionHostOptions(childContext, bundle, mcpBundle, registration, identity, workspace
|
|
753
|
+
const created = await hub.create(sessionHostOptions(childContext, bundle, mcpBundle, registration, identity, workspace, {
|
|
754
|
+
pinned: explicit.pinned,
|
|
755
|
+
...request.selection?.minorModes === void 0 ? {} : { minorModes: request.selection.minorModes },
|
|
756
|
+
...request.tools === void 0 ? {} : { allowedTools: request.tools }
|
|
757
|
+
}));
|
|
736
758
|
request.signal?.throwIfAborted();
|
|
737
759
|
if (created.workspaceId !== void 0) {
|
|
738
760
|
if (openSessions.add({
|
|
@@ -939,29 +961,22 @@ async function runServerRuntime(options, runtime) {
|
|
|
939
961
|
}
|
|
940
962
|
} finally {
|
|
941
963
|
shuttingDown = true;
|
|
964
|
+
executionBudget.close();
|
|
942
965
|
stopPersistSessionNames();
|
|
943
966
|
clearInterval(eventLoopMonitor);
|
|
944
967
|
await bounded(telemetry.recordEvent("doompi_server.shutdown"), "shutdown telemetry", notice);
|
|
945
|
-
await
|
|
968
|
+
await bounded(require_shutdown.withShutdownDeadline(() => cockpit?.close(), "listener shutdown"), "listener shutdown", notice);
|
|
946
969
|
await bounded(remoteRuntime?.close() ?? Promise.resolve(), "remote control shutdown", notice);
|
|
947
|
-
try {
|
|
948
|
-
await hub.close();
|
|
949
|
-
} catch (error) {
|
|
950
|
-
notice(error instanceof Error ? error.message : String(error));
|
|
951
|
-
}
|
|
952
|
-
try {
|
|
953
|
-
await requestReceipts.close();
|
|
954
|
-
} catch (error) {
|
|
955
|
-
notice(error instanceof Error ? error.message : String(error));
|
|
956
|
-
}
|
|
957
970
|
try {
|
|
958
971
|
await sessionManager.close();
|
|
959
972
|
} catch (error) {
|
|
960
973
|
notice(error instanceof Error ? error.message : String(error));
|
|
961
974
|
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
975
|
+
await bounded(require_shutdown.withShutdownDeadline(() => hub.close(), "hub shutdown"), "hub shutdown", notice);
|
|
976
|
+
await bounded(require_shutdown.withShutdownDeadline(() => requestReceipts.close(), "receipt shutdown"), "receipt shutdown", notice);
|
|
977
|
+
await bounded(require_shutdown.withShutdownDeadline(() => computerUse?.close?.(), "computer use shutdown"), "computer use shutdown", notice);
|
|
978
|
+
await bounded(require_shutdown.withShutdownDeadline(() => webCompositions?.close(), "web composition shutdown"), "web composition shutdown", notice);
|
|
979
|
+
const pendingCleanups = [...pendingSessions.values()].map((setup) => bounded(require_shutdown.withShutdownDeadline(() => setup.cleanup(), "pending session cleanup"), "pending session cleanup", notice));
|
|
965
980
|
pendingSessions.clear();
|
|
966
981
|
await Promise.allSettled(pendingCleanups);
|
|
967
982
|
await bounded(harnessTelemetry.flush(), "harness telemetry flush", notice);
|