@andreroggeri/adapter-pi-local-serialized 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/cli/format-event.d.ts +2 -0
- package/dist/cli/format-event.d.ts.map +1 -0
- package/dist/cli/format-event.js +99 -0
- package/dist/cli/format-event.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/server/concurrency.d.ts +2 -0
- package/dist/server/concurrency.d.ts.map +1 -0
- package/dist/server/concurrency.js +25 -0
- package/dist/server/concurrency.js.map +1 -0
- package/dist/server/execute.d.ts +3 -0
- package/dist/server/execute.d.ts.map +1 -0
- package/dist/server/execute.js +675 -0
- package/dist/server/execute.js.map +1 -0
- package/dist/server/execute.remote.test.d.ts +2 -0
- package/dist/server/execute.remote.test.d.ts.map +1 -0
- package/dist/server/execute.remote.test.js +466 -0
- package/dist/server/execute.remote.test.js.map +1 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +51 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/models.d.ts +20 -0
- package/dist/server/models.d.ts.map +1 -0
- package/dist/server/models.js +163 -0
- package/dist/server/models.js.map +1 -0
- package/dist/server/models.test.d.ts +2 -0
- package/dist/server/models.test.d.ts.map +1 -0
- package/dist/server/models.test.js +22 -0
- package/dist/server/models.test.js.map +1 -0
- package/dist/server/parse.d.ts +23 -0
- package/dist/server/parse.d.ts.map +1 -0
- package/dist/server/parse.js +195 -0
- package/dist/server/parse.js.map +1 -0
- package/dist/server/parse.test.d.ts +2 -0
- package/dist/server/parse.test.d.ts.map +1 -0
- package/dist/server/parse.test.js +249 -0
- package/dist/server/parse.test.js.map +1 -0
- package/dist/server/skills.d.ts +8 -0
- package/dist/server/skills.d.ts.map +1 -0
- package/dist/server/skills.js +69 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/test.d.ts +3 -0
- package/dist/server/test.d.ts.map +1 -0
- package/dist/server/test.js +309 -0
- package/dist/server/test.js.map +1 -0
- package/dist/ui/build-config.d.ts +3 -0
- package/dist/ui/build-config.d.ts.map +1 -0
- package/dist/ui/build-config.js +78 -0
- package/dist/ui/build-config.js.map +1 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/parse-stdout.d.ts +4 -0
- package/dist/ui/parse-stdout.d.ts.map +1 -0
- package/dist/ui/parse-stdout.js +271 -0
- package/dist/ui/parse-stdout.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paperclip AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @andreroggeri/adapter-pi-local-serialized
|
|
2
|
+
|
|
3
|
+
A fork of `@paperclipai/adapter-pi-local` that enforces a **global concurrency of 1** across all agents using this adapter within the same server process. Built for setups running local LLMs (e.g. ollama, llama.cpp) that can't handle parallel inference.
|
|
4
|
+
|
|
5
|
+
## What it does differently
|
|
6
|
+
|
|
7
|
+
A single module-level promise queue (mutex) in `src/server/concurrency.ts` ensures that only one Pi process runs at a time. All the setup work (env building, session resolution, workspace sync) still happens concurrently — only the actual `pi` process invocation that talks to the LLM is serialized. Queued runs log a `queuing "<agent-id>"...` message so you can see them waiting in the run output.
|
|
8
|
+
|
|
9
|
+
## How to recreate
|
|
10
|
+
|
|
11
|
+
If this package gets clobbered by merge conflicts, recreate it from the current `packages/adapters/pi-local`:
|
|
12
|
+
|
|
13
|
+
1. Copy the package:
|
|
14
|
+
```bash
|
|
15
|
+
cp -r packages/adapters/pi-local packages/adapters/pi-local-serialized
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. Update `package.json`:
|
|
19
|
+
- `name`: `@andreroggeri/adapter-pi-local-serialized`
|
|
20
|
+
- `version`: `0.1.0`
|
|
21
|
+
- `repository.directory`: `packages/adapters/pi-local-serialized`
|
|
22
|
+
|
|
23
|
+
3. Update `src/index.ts`:
|
|
24
|
+
- `type`: `"pi_local_serialized"`
|
|
25
|
+
- `label`: `"Pi (local, serialized)"`
|
|
26
|
+
|
|
27
|
+
4. Create `src/server/concurrency.ts`:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
let tail: Promise<void> = Promise.resolve();
|
|
31
|
+
|
|
32
|
+
export async function withSerializedExecution<T>(
|
|
33
|
+
label: string,
|
|
34
|
+
onLog: (stream: "stdout" | "stderr", chunk: string) => Promise<void>,
|
|
35
|
+
fn: () => Promise<T>,
|
|
36
|
+
): Promise<T> {
|
|
37
|
+
let release!: () => void;
|
|
38
|
+
const next = new Promise<void>((resolve) => { release = resolve; });
|
|
39
|
+
const wait = tail;
|
|
40
|
+
tail = tail.then(() => next);
|
|
41
|
+
|
|
42
|
+
if (wait !== Promise.resolve()) {
|
|
43
|
+
await onLog("stdout", `[paperclip] pi_local_serialized: another run is in progress, queuing "${label}"...\n`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await wait;
|
|
47
|
+
try {
|
|
48
|
+
return await fn();
|
|
49
|
+
} finally {
|
|
50
|
+
release();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
5. In `src/server/execute.ts`:
|
|
56
|
+
- Add import: `import { withSerializedExecution } from "./concurrency.js";`
|
|
57
|
+
- Wrap the `try` block's body (the `runAttempt` calls and return) in:
|
|
58
|
+
```ts
|
|
59
|
+
return await withSerializedExecution(agent.id, onLog, async () => { ... });
|
|
60
|
+
```
|
|
61
|
+
Leave the `finally` block (bridge/workspace cleanup) outside the mutex.
|
|
62
|
+
|
|
63
|
+
6. Run `pnpm install && pnpm build` from the repo root to verify.
|
|
64
|
+
|
|
65
|
+
## Publishing
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cd packages/adapters/pi-local-serialized
|
|
69
|
+
npm login # as andreroggeri
|
|
70
|
+
pnpm publish --access public
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Keeping in sync with pi-local
|
|
74
|
+
|
|
75
|
+
This package tracks `pi-local` loosely — only `execute.ts` diverges. When `pi-local` gets meaningful updates (new flags, session handling changes, etc.), apply them to this package's `execute.ts` and re-wrap the mutex around the `runAttempt` block.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.d.ts","sourceRoot":"","sources":["../../src/cli/format-event.ts"],"names":[],"mappings":"AA4BA,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CA8ErE"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
function safeJsonParse(text) {
|
|
3
|
+
try {
|
|
4
|
+
return JSON.parse(text);
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function asRecord(value) {
|
|
11
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
12
|
+
return null;
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function asString(value, fallback = "") {
|
|
16
|
+
return typeof value === "string" ? value : fallback;
|
|
17
|
+
}
|
|
18
|
+
function extractTextContent(content) {
|
|
19
|
+
if (typeof content === "string")
|
|
20
|
+
return content;
|
|
21
|
+
if (!Array.isArray(content))
|
|
22
|
+
return "";
|
|
23
|
+
return content
|
|
24
|
+
.filter((c) => c.type === "text" && c.text)
|
|
25
|
+
.map((c) => c.text)
|
|
26
|
+
.join("");
|
|
27
|
+
}
|
|
28
|
+
export function printPiStreamEvent(raw, _debug) {
|
|
29
|
+
const line = raw.trim();
|
|
30
|
+
if (!line)
|
|
31
|
+
return;
|
|
32
|
+
const parsed = asRecord(safeJsonParse(line));
|
|
33
|
+
if (!parsed) {
|
|
34
|
+
console.log(line);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const type = asString(parsed.type);
|
|
38
|
+
if (type === "agent_start") {
|
|
39
|
+
console.log(pc.blue("Pi agent started"));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (type === "agent_end") {
|
|
43
|
+
console.log(pc.blue("Pi agent finished"));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (type === "turn_start") {
|
|
47
|
+
console.log(pc.blue("Turn started"));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (type === "turn_end") {
|
|
51
|
+
const message = asRecord(parsed.message);
|
|
52
|
+
if (message) {
|
|
53
|
+
const content = message.content;
|
|
54
|
+
const text = extractTextContent(content);
|
|
55
|
+
if (text) {
|
|
56
|
+
console.log(pc.green(`assistant: ${text}`));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (type === "message_update") {
|
|
62
|
+
const assistantEvent = asRecord(parsed.assistantMessageEvent);
|
|
63
|
+
if (assistantEvent) {
|
|
64
|
+
const msgType = asString(assistantEvent.type);
|
|
65
|
+
if (msgType === "text_delta") {
|
|
66
|
+
const delta = asString(assistantEvent.delta);
|
|
67
|
+
if (delta) {
|
|
68
|
+
console.log(pc.green(delta));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (type === "tool_execution_start") {
|
|
75
|
+
const toolName = asString(parsed.toolName);
|
|
76
|
+
const args = parsed.args;
|
|
77
|
+
console.log(pc.yellow(`tool_start: ${toolName}`));
|
|
78
|
+
if (args !== undefined) {
|
|
79
|
+
try {
|
|
80
|
+
console.log(pc.gray(JSON.stringify(args, null, 2)));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
console.log(pc.gray(String(args)));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (type === "tool_execution_end") {
|
|
89
|
+
const result = parsed.result;
|
|
90
|
+
const isError = parsed.isError === true;
|
|
91
|
+
const output = typeof result === "string" ? result : JSON.stringify(result);
|
|
92
|
+
if (output) {
|
|
93
|
+
console.log((isError ? pc.red : pc.gray)(output));
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
console.log(line);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=format-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.js","sourceRoot":"","sources":["../../src/cli/format-event.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AdapterModelProfileDefinition } from "@paperclipai/adapter-utils";
|
|
2
|
+
export declare const type = "pi_local_serialized";
|
|
3
|
+
export declare const label = "Pi (local, serialized)";
|
|
4
|
+
export declare const SANDBOX_INSTALL_COMMAND = "npm install -g @earendil-works/pi-coding-agent@0.74.0";
|
|
5
|
+
export declare const models: Array<{
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
}>;
|
|
9
|
+
export declare const modelProfiles: AdapterModelProfileDefinition[];
|
|
10
|
+
export declare const agentConfigurationDoc = "# pi_local_serialized agent configuration\n\nAdapter: pi_local_serialized\n\nLike pi_local but enforces a global concurrency of 1 across all agents using this\nadapter within the same server process. Useful when running local LLMs that cannot\nhandle parallel inference load \u2014 runs are queued and executed one at a time.\n\nUse when:\n- You want Paperclip to run Pi (the AI coding agent) locally as the agent runtime\n- Your LLM backend cannot handle concurrent requests (e.g. local ollama, llama.cpp)\n- You want provider/model routing in Pi format (--provider <name> --model <id>)\n- You want Pi session resume across heartbeats via --session\n- You need Pi's tool set (read, bash, edit, write, grep, find, ls)\n\nDon't use when:\n- You need webhook-style external invocation (use openclaw_gateway or http)\n- You only need one-shot shell commands (use process)\n- Pi CLI is not installed on the machine\n- Your LLM backend supports concurrent requests (use pi_local instead)\n\nCore fields:\n- cwd (string, optional): default absolute working directory fallback for the agent process (created if missing when possible)\n- instructionsFilePath (string, optional): absolute path to a markdown instructions file appended to system prompt via --append-system-prompt\n- promptTemplate (string, optional): user prompt template passed via -p flag\n- model (string, required): Pi model id in provider/model format (for example ollama/qwen2.5-coder)\n- thinking (string, optional): thinking level (off, minimal, low, medium, high, xhigh)\n- command (string, optional): defaults to \"pi\"\n- env (object, optional): KEY=VALUE environment variables\n\nOperational fields:\n- timeoutSec (number, optional): run timeout in seconds\n- graceSec (number, optional): SIGTERM grace period in seconds\n\nNotes:\n- Pi supports multiple providers and models. Use `pi --list-models` to list available options.\n- Paperclip requires an explicit `model` value for `pi_local_serialized` agents.\n- Sessions are stored in ~/.pi/paperclips/ and resumed with --session.\n- All tools (read, bash, edit, write, grep, find, ls) are enabled by default.\n- Agent instructions are appended to Pi's system prompt via --append-system-prompt, while the user task is sent via -p.\n- Concurrency is enforced in-process. If you run multiple Paperclip server replicas,\n each replica has its own queue \u2014 use a single replica when strict global serialization matters.\n";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAEhF,eAAO,MAAM,IAAI,wBAAwB,CAAC;AAC1C,eAAO,MAAM,KAAK,2BAA2B,CAAC;AAE9C,eAAO,MAAM,uBAAuB,0DAA0D,CAAC;AAE/F,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAM,CAAC;AAE/D,eAAO,MAAM,aAAa,EAAE,6BAA6B,EAAO,CAAC;AAEjE,eAAO,MAAM,qBAAqB,84EA0CjC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const type = "pi_local_serialized";
|
|
2
|
+
export const label = "Pi (local, serialized)";
|
|
3
|
+
export const SANDBOX_INSTALL_COMMAND = "npm install -g @earendil-works/pi-coding-agent@0.74.0";
|
|
4
|
+
export const models = [];
|
|
5
|
+
export const modelProfiles = [];
|
|
6
|
+
export const agentConfigurationDoc = `# pi_local_serialized agent configuration
|
|
7
|
+
|
|
8
|
+
Adapter: pi_local_serialized
|
|
9
|
+
|
|
10
|
+
Like pi_local but enforces a global concurrency of 1 across all agents using this
|
|
11
|
+
adapter within the same server process. Useful when running local LLMs that cannot
|
|
12
|
+
handle parallel inference load — runs are queued and executed one at a time.
|
|
13
|
+
|
|
14
|
+
Use when:
|
|
15
|
+
- You want Paperclip to run Pi (the AI coding agent) locally as the agent runtime
|
|
16
|
+
- Your LLM backend cannot handle concurrent requests (e.g. local ollama, llama.cpp)
|
|
17
|
+
- You want provider/model routing in Pi format (--provider <name> --model <id>)
|
|
18
|
+
- You want Pi session resume across heartbeats via --session
|
|
19
|
+
- You need Pi's tool set (read, bash, edit, write, grep, find, ls)
|
|
20
|
+
|
|
21
|
+
Don't use when:
|
|
22
|
+
- You need webhook-style external invocation (use openclaw_gateway or http)
|
|
23
|
+
- You only need one-shot shell commands (use process)
|
|
24
|
+
- Pi CLI is not installed on the machine
|
|
25
|
+
- Your LLM backend supports concurrent requests (use pi_local instead)
|
|
26
|
+
|
|
27
|
+
Core fields:
|
|
28
|
+
- cwd (string, optional): default absolute working directory fallback for the agent process (created if missing when possible)
|
|
29
|
+
- instructionsFilePath (string, optional): absolute path to a markdown instructions file appended to system prompt via --append-system-prompt
|
|
30
|
+
- promptTemplate (string, optional): user prompt template passed via -p flag
|
|
31
|
+
- model (string, required): Pi model id in provider/model format (for example ollama/qwen2.5-coder)
|
|
32
|
+
- thinking (string, optional): thinking level (off, minimal, low, medium, high, xhigh)
|
|
33
|
+
- command (string, optional): defaults to "pi"
|
|
34
|
+
- env (object, optional): KEY=VALUE environment variables
|
|
35
|
+
|
|
36
|
+
Operational fields:
|
|
37
|
+
- timeoutSec (number, optional): run timeout in seconds
|
|
38
|
+
- graceSec (number, optional): SIGTERM grace period in seconds
|
|
39
|
+
|
|
40
|
+
Notes:
|
|
41
|
+
- Pi supports multiple providers and models. Use \`pi --list-models\` to list available options.
|
|
42
|
+
- Paperclip requires an explicit \`model\` value for \`pi_local_serialized\` agents.
|
|
43
|
+
- Sessions are stored in ~/.pi/paperclips/ and resumed with --session.
|
|
44
|
+
- All tools (read, bash, edit, write, grep, find, ls) are enabled by default.
|
|
45
|
+
- Agent instructions are appended to Pi's system prompt via --append-system-prompt, while the user task is sent via -p.
|
|
46
|
+
- Concurrency is enforced in-process. If you run multiple Paperclip server replicas,
|
|
47
|
+
each replica has its own queue — use a single replica when strict global serialization matters.
|
|
48
|
+
`;
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,IAAI,GAAG,qBAAqB,CAAC;AAC1C,MAAM,CAAC,MAAM,KAAK,GAAG,wBAAwB,CAAC;AAE9C,MAAM,CAAC,MAAM,uBAAuB,GAAG,uDAAuD,CAAC;AAE/F,MAAM,CAAC,MAAM,MAAM,GAAyC,EAAE,CAAC;AAE/D,MAAM,CAAC,MAAM,aAAa,GAAoC,EAAE,CAAC;AAEjE,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../src/server/concurrency.ts"],"names":[],"mappings":"AAMA,wBAAsB,uBAAuB,CAAC,CAAC,EAC7C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EACpE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAsBZ"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Global mutex ensuring at most one pi_local_serialized execution runs at a time.
|
|
2
|
+
// Implemented as a promise chain — each caller appends to the tail and waits
|
|
3
|
+
// for the previous occupant to release before proceeding.
|
|
4
|
+
let tail = Promise.resolve();
|
|
5
|
+
export async function withSerializedExecution(label, onLog, fn) {
|
|
6
|
+
let release;
|
|
7
|
+
const next = new Promise((resolve) => {
|
|
8
|
+
release = resolve;
|
|
9
|
+
});
|
|
10
|
+
// Snapshot the current tail and atomically replace it with our waiter.
|
|
11
|
+
const wait = tail;
|
|
12
|
+
tail = tail.then(() => next);
|
|
13
|
+
if (wait !== Promise.resolve()) {
|
|
14
|
+
// There's something ahead of us — let the agent know it's queued.
|
|
15
|
+
await onLog("stdout", `[paperclip] pi_local_serialized: another run is in progress, queuing "${label}"...\n`);
|
|
16
|
+
}
|
|
17
|
+
await wait;
|
|
18
|
+
try {
|
|
19
|
+
return await fn();
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
release();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=concurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/server/concurrency.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,6EAA6E;AAC7E,0DAA0D;AAE1D,IAAI,IAAI,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa,EACb,KAAoE,EACpE,EAAoB;IAEpB,IAAI,OAAoB,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACzC,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,uEAAuE;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC;IAClB,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/B,kEAAkE;QAClE,MAAM,KAAK,CAAC,QAAQ,EAAE,yEAAyE,KAAK,QAAQ,CAAC,CAAC;IAChH,CAAC;IAED,MAAM,IAAI,CAAC;IAEX,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/server/execute.ts"],"names":[],"mappings":"AAIA,OAAO,EAA+B,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAkNpI,wBAAsB,OAAO,CAAC,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA6lB3F"}
|