@tiens.nguyen/gu-cli 1.0.686
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 +52 -0
- package/agent-model-command.mjs +259 -0
- package/agent-model-label.mjs +159 -0
- package/clear-state.mjs +149 -0
- package/client-expert-api.mjs +736 -0
- package/client-expert-run.mjs +892 -0
- package/client-expert-setup.mjs +616 -0
- package/coding-choice-tags.mjs +69 -0
- package/coding-key-prompt.mjs +229 -0
- package/coding-provider-setup.mjs +808 -0
- package/completed-flush.mjs +105 -0
- package/daemon-control.mjs +462 -0
- package/device-login.mjs +212 -0
- package/doctor-check.mjs +239 -0
- package/embed-model-command.mjs +157 -0
- package/first-run-steps.mjs +171 -0
- package/gonext_agent_chat.py +12299 -0
- package/gonext_mlx_embed.py +155 -0
- package/gonext_probe_agent.py +93 -0
- package/gonext_transcribe.py +130 -0
- package/gu-cli.mjs +4930 -0
- package/gu-repl.mjs +10326 -0
- package/job-pools.mjs +89 -0
- package/model-doctor.mjs +1494 -0
- package/node-version.mjs +40 -0
- package/ollama-setup.mjs +832 -0
- package/package.json +100 -0
- package/platform-tools.mjs +520 -0
- package/poll-errors.mjs +141 -0
- package/proxy-command.mjs +165 -0
- package/proxy-config.mjs +255 -0
- package/proxy-dispatcher.mjs +132 -0
- package/proxy-selftest.mjs +234 -0
- package/proxy-store.mjs +69 -0
- package/rag-job-config.mjs +59 -0
- package/rag-selftest.mjs +215 -0
- package/s3-setup.mjs +85 -0
- package/terminal-copy.mjs +248 -0
- package/terminal-hover.mjs +153 -0
- package/terminal-layout.mjs +2507 -0
- package/terminal-viewport.mjs +602 -0
- package/thinking_words.txt +1003 -0
- package/version-check.mjs +72 -0
package/job-pools.mjs
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concurrency for the worker's claim loop (task #152).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS A MODULE. An agent turn used to be `await runAgentChatJob(job); return;` inside
|
|
5
|
+
* the poll loop, so one folder's turn — 100 seconds to an hour — held the loop for its whole
|
|
6
|
+
* duration and a second `gu` in another folder was told "no worker has claimed the job".
|
|
7
|
+
* The claim loop itself cannot be unit-tested (importing gu-cli.mjs starts a daemon), and
|
|
8
|
+
* the two things that decide whether concurrent folders work correctly are exactly the two
|
|
9
|
+
* things worth testing: how many turns may run, and what happens to work that arrives while
|
|
10
|
+
* the resource is taken.
|
|
11
|
+
*
|
|
12
|
+
* Both are deliberately tiny and pure. The bug being fixed was not complicated — it was
|
|
13
|
+
* invisible, because it lived in a line of control flow nothing could assert on.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A bounded set of in-flight promises.
|
|
18
|
+
*
|
|
19
|
+
* `track` never rejects: a task that throws must still free its slot, or one failure
|
|
20
|
+
* permanently shrinks the pool — the kind of leak that only shows up after a long uptime.
|
|
21
|
+
*/
|
|
22
|
+
export function createTaskPool({ limit = 1 } = {}) {
|
|
23
|
+
const max = Math.max(1, Number(limit) || 1);
|
|
24
|
+
const inFlight = new Set();
|
|
25
|
+
return {
|
|
26
|
+
get size() {
|
|
27
|
+
return inFlight.size;
|
|
28
|
+
},
|
|
29
|
+
get limit() {
|
|
30
|
+
return max;
|
|
31
|
+
},
|
|
32
|
+
hasRoom: () => inFlight.size < max,
|
|
33
|
+
track(task) {
|
|
34
|
+
inFlight.add(task);
|
|
35
|
+
Promise.resolve(task)
|
|
36
|
+
.catch(() => {})
|
|
37
|
+
.finally(() => inFlight.delete(task));
|
|
38
|
+
return task;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Serialise work across folders WITHOUT throwing any of it away.
|
|
45
|
+
*
|
|
46
|
+
* The between-turns RAG index used a single boolean and `return`ed when it was set, so while
|
|
47
|
+
* folder A indexed, folder B's pass was silently DROPPED — folder B was then left with no
|
|
48
|
+
* knowledge base and nothing said why. The GPU reasoning behind serialising was right; the
|
|
49
|
+
* disposal was the bug.
|
|
50
|
+
*
|
|
51
|
+
* One pending entry per folder, newest wins: a folder that asks twice while waiting wants the
|
|
52
|
+
* later state of its files, not two passes over the earlier one.
|
|
53
|
+
*/
|
|
54
|
+
export function createFolderQueue() {
|
|
55
|
+
const running = new Set();
|
|
56
|
+
const pending = new Map();
|
|
57
|
+
return {
|
|
58
|
+
get runningCount() {
|
|
59
|
+
return running.size;
|
|
60
|
+
},
|
|
61
|
+
get pendingCount() {
|
|
62
|
+
return pending.size;
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* @returns "start" — run it now (the caller must call finish() when done)
|
|
66
|
+
* "already" — this folder is mid-run; nothing to do
|
|
67
|
+
* "queued" — another folder holds the slot; it will run later
|
|
68
|
+
*/
|
|
69
|
+
request(folder, args) {
|
|
70
|
+
if (running.has(folder)) return "already";
|
|
71
|
+
if (running.size > 0) {
|
|
72
|
+
pending.set(folder, args); // newest supersedes an older wait for the same folder
|
|
73
|
+
return "queued";
|
|
74
|
+
}
|
|
75
|
+
running.add(folder);
|
|
76
|
+
return "start";
|
|
77
|
+
},
|
|
78
|
+
/** Release `folder` and hand the slot to whoever waited longest. */
|
|
79
|
+
finish(folder) {
|
|
80
|
+
running.delete(folder);
|
|
81
|
+
const next = pending.entries().next();
|
|
82
|
+
if (next.done) return null;
|
|
83
|
+
const [nextFolder, args] = next.value;
|
|
84
|
+
pending.delete(nextFolder);
|
|
85
|
+
running.add(nextFolder);
|
|
86
|
+
return { folder: nextFolder, args };
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|