ccdeck 1.43.0 → 1.45.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/README.md +210 -12
- package/bin/agent-dag.js +505 -0
- package/bin/deck.js +1051 -0
- package/dist/web/assets/index-Bdl1LX0-.css +1 -0
- package/dist/web/assets/index-jXBjwwZC.js +89 -0
- package/dist/web/index.html +49 -0
- package/hook/hook.js +496 -0
- package/package.json +42 -9
- package/src/server/args.mjs +156 -0
- package/src/server/brand.mjs +16 -0
- package/src/server/ccusage.mjs +1052 -0
- package/src/server/claude-accounts.mjs +653 -0
- package/src/server/claude-dir.mjs +213 -0
- package/src/server/codex-auth.mjs +388 -0
- package/src/server/codex-dir.mjs +171 -0
- package/src/server/codex-quota.mjs +445 -0
- package/src/server/codex-usage.mjs +411 -0
- package/src/server/cswap-admin.mjs +1034 -0
- package/src/server/cswap-auto.mjs +595 -0
- package/src/server/cswap-install.mjs +583 -0
- package/src/server/exec.mjs +938 -0
- package/src/server/index.mjs +5109 -0
- package/src/server/installer.mjs +763 -0
- package/src/server/invoked-as.mjs +144 -0
- package/src/server/log-writer.mjs +283 -0
- package/src/server/npx.mjs +259 -0
- package/src/server/quota.mjs +684 -0
- package/src/server/reset-label.mjs +78 -0
- package/src/server/retire-sound-hook.mjs +315 -0
- package/src/server/self-update.mjs +1331 -0
- package/src/server/supervisor.mjs +302 -0
- package/src/server/system-metrics.mjs +619 -0
- package/src/server/term.mjs +570 -0
- package/src/server/uv-bootstrap.mjs +301 -0
- package/bin/ccdeck.js +0 -194
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// The command line, parsed: everything the deck recognises, and everything it
|
|
2
|
+
// does not.
|
|
3
|
+
//
|
|
4
|
+
// Its own module rather than a function inside bin/deck.js, for one reason —
|
|
5
|
+
// importing bin/deck.js RUNS a deck. That file installs hooks, binds a port and
|
|
6
|
+
// opens a browser at module scope, so there was no way to ask what `--prot`
|
|
7
|
+
// parses to without starting a server to find out. Nothing here does any of
|
|
8
|
+
// that: strings in, a plain object out, no I/O, no process, no terminal.
|
|
9
|
+
//
|
|
10
|
+
// bin/deck.js is the only caller. The parser is the whole of the module's
|
|
11
|
+
// surface; the tables it matches against stay inside it.
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Is this token a flag rather than somebody's value?
|
|
15
|
+
*
|
|
16
|
+
* A leading `-` and nothing else, because the alternatives are worse. Matching
|
|
17
|
+
* the known flag list would refuse `--workspace --prot` — a typo eating the next
|
|
18
|
+
* token is the same accident as a real flag eating it, and the one shape that
|
|
19
|
+
* must be caught is the one nobody spelled right. Refusing every value that
|
|
20
|
+
* begins with `-` would refuse `--port -1`, which is a number the user meant and
|
|
21
|
+
* which deserves the port error below rather than a "missing value" one.
|
|
22
|
+
*
|
|
23
|
+
* So: a leading `-`, except a plain negative number. The negative-number carve
|
|
24
|
+
* is the only exception, and it is small on purpose.
|
|
25
|
+
*
|
|
26
|
+
* WHAT THIS DOES ON EACH PLATFORM. Nothing, is the intent, to any real path.
|
|
27
|
+
* POSIX absolute (`/srv/proj`), POSIX relative (`./sub`, `sub`), `~/proj`, a
|
|
28
|
+
* Windows drive letter (`C:\Users\u\proj`, `c:/users/u/proj`), a UNC share
|
|
29
|
+
* (`\\srv\share\proj`), a Windows long path (`\\?\C:\proj`) and a bare
|
|
30
|
+
* `events.jsonl` all begin with something other than `-`, so all of them are
|
|
31
|
+
* values. A drive letter is not a flag on any platform and is never read as one:
|
|
32
|
+
* `C:` starts with `C`. What IS refused is a directory whose name really begins
|
|
33
|
+
* with a dash, which the user can still pass as `./-weird` — a two-character
|
|
34
|
+
* price for catching `--workspace $UNSET --no-persist`.
|
|
35
|
+
*/
|
|
36
|
+
export function looksLikeFlag(token) {
|
|
37
|
+
return typeof token === "string" && token.startsWith("-") && !/^-\d+(?:\.\d+)?$/.test(token);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Is this a port the deck could bind? Digits only, inside the range Node's
|
|
42
|
+
* `listen` accepts.
|
|
43
|
+
*
|
|
44
|
+
* `Number()` alone is far too willing: it takes `" 4500 "`, `0x10e4`, `1e3` and
|
|
45
|
+
* `Infinity`, and turns everything else into the `NaN` that used to reach
|
|
46
|
+
* `listen` and die there. The whole point of asking here is to answer BEFORE the
|
|
47
|
+
* deck has installed hooks and probed for tools, and to answer about the string
|
|
48
|
+
* the user actually typed. See bin/deck.js, which prints the flag and the value
|
|
49
|
+
* back at them.
|
|
50
|
+
*/
|
|
51
|
+
export function isPortValue(raw) {
|
|
52
|
+
if (typeof raw !== "string" && typeof raw !== "number") return false;
|
|
53
|
+
const s = String(raw).trim();
|
|
54
|
+
if (!/^\d+$/.test(s)) return false;
|
|
55
|
+
const n = Number(s);
|
|
56
|
+
return n >= 0 && n <= 65535;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse `process.argv.slice(2)`.
|
|
61
|
+
*
|
|
62
|
+
* Returns the flags that were set, plus two lists that are always present and
|
|
63
|
+
* always arrays:
|
|
64
|
+
*
|
|
65
|
+
* `unknown` — every token the loop did not recognise, in the order it met
|
|
66
|
+
* them. That list is the point of this module: the loop used
|
|
67
|
+
* to have no `else`, so `ccdeck --prot 4500` booted on 4317 and
|
|
68
|
+
* said nothing, and a typo was indistinguishable from a flag
|
|
69
|
+
* that worked.
|
|
70
|
+
* `incomplete` — every value-taking flag that was given no value it could
|
|
71
|
+
* use, as `{ flag, expects }`, `flag` spelled the way the user
|
|
72
|
+
* spelled it. bin/deck.js prints one row per entry.
|
|
73
|
+
*
|
|
74
|
+
* THE THREE FLAGS THAT TAKE A VALUE (`--port`/`-p`, `--workspace`, `--history`)
|
|
75
|
+
* used to consume the next token with `args[++i]` whatever it was. That is right
|
|
76
|
+
* for `--port 4500` — the value must never be re-examined as a token of its own,
|
|
77
|
+
* or every correct command line would report its own port as an unknown option,
|
|
78
|
+
* and a warning that fires on correct input is a warning everybody learns to
|
|
79
|
+
* ignore. It was wrong for a value that is itself a flag (#697): `ccdeck
|
|
80
|
+
* --workspace $PROJ --no-persist` with `PROJ` unset is, after word splitting,
|
|
81
|
+
* `ccdeck --workspace --no-persist`. The deck scoped itself to a directory
|
|
82
|
+
* called `--no-persist`, wrote to the shared events log anyway, and reported
|
|
83
|
+
* neither — `unknown` stayed empty, because the token that would have gone in it
|
|
84
|
+
* had been eaten.
|
|
85
|
+
*
|
|
86
|
+
* So the consume is conditional now, and it refuses three shapes:
|
|
87
|
+
*
|
|
88
|
+
* * the next token looks like a flag — NOT consumed, so the loop meets it on
|
|
89
|
+
* the next pass and it is parsed as the flag it is, or reported as unknown.
|
|
90
|
+
* That is also what fixes the supervisor case in bin/agent-dag.js: a
|
|
91
|
+
* respawn appends `--port <bound>` to the user's argv, and an argv ending in
|
|
92
|
+
* a bare `--workspace` used to eat the `--port` and drop the deck back on
|
|
93
|
+
* 4317, out from under the tab the user was looking at.
|
|
94
|
+
* * there is no next token at all — the trailing `--workspace`, which used to
|
|
95
|
+
* set `undefined` and mean "the default", silently.
|
|
96
|
+
* * the next token is empty or blank — consumed (it was quoted, so it was
|
|
97
|
+
* meant as the value) but not used. `--workspace ""` is a variable that did
|
|
98
|
+
* not expand, not a request for machine-wide capture, and answering it with
|
|
99
|
+
* the widest possible scope is the one answer that cannot be recovered from.
|
|
100
|
+
*
|
|
101
|
+
* In all three the flag is left UNSET, so the deck falls back to its documented
|
|
102
|
+
* default, and the flag is named in `incomplete` so the fallback is said out
|
|
103
|
+
* loud rather than discovered later.
|
|
104
|
+
*
|
|
105
|
+
* A bare word is `unknown` too, and deliberately: the deck takes no positional
|
|
106
|
+
* arguments at all, so `ccdeck ~/proj` is the same mistake as `ccdeck --workpace
|
|
107
|
+
* ~/proj` — something the deck read and then did nothing with. It is also how
|
|
108
|
+
* an unquoted path with a space in it becomes visible, which is a failure this
|
|
109
|
+
* repo already knew about and could not previously report: `--workspace
|
|
110
|
+
* C:\Users\John Smith\proj` reaches the parser as two arguments, and the second
|
|
111
|
+
* one used to be dropped in silence (see launchNpx in bin/agent-dag.js).
|
|
112
|
+
*/
|
|
113
|
+
export function parseArgs(args) {
|
|
114
|
+
const out = { unknown: [], incomplete: [] };
|
|
115
|
+
for (let i = 0; i < args.length; i++) {
|
|
116
|
+
const a = args[i];
|
|
117
|
+
// The value of the flag just matched, or `undefined` when there is nothing
|
|
118
|
+
// usable there. Closes over `i` so it can decline to advance it: not
|
|
119
|
+
// consuming is what hands the token back to the loop.
|
|
120
|
+
const value = (expects) => {
|
|
121
|
+
const next = args[i + 1];
|
|
122
|
+
if (next === undefined || looksLikeFlag(next)) {
|
|
123
|
+
out.incomplete.push({ flag: a, expects });
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
i++;
|
|
127
|
+
if (String(next).trim() === "") {
|
|
128
|
+
out.incomplete.push({ flag: a, expects });
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
return next;
|
|
132
|
+
};
|
|
133
|
+
// Assigned only when there is a value, so an unusable one leaves the key
|
|
134
|
+
// absent and the deck on its default — see the doc comment.
|
|
135
|
+
const set = (key, expects) => {
|
|
136
|
+
const v = value(expects);
|
|
137
|
+
if (v !== undefined) out[key] = v;
|
|
138
|
+
};
|
|
139
|
+
if (a === "-h" || a === "--help") out.help = true;
|
|
140
|
+
else if (a === "-v" || a === "--version") out.version = true;
|
|
141
|
+
else if (a === "-p" || a === "--port") set("port", "a port number");
|
|
142
|
+
else if (a === "--no-open") out.noOpen = true;
|
|
143
|
+
else if (a === "--uninstall") out.uninstall = true;
|
|
144
|
+
else if (a === "--workspace") set("workspace", "a path");
|
|
145
|
+
else if (a === "--scope") out.scope = true;
|
|
146
|
+
else if (a === "--all") out.all = true; // legacy no-op (now default)
|
|
147
|
+
else if (a === "--no-persist") out.noPersist = true;
|
|
148
|
+
else if (a === "--history") set("history", "a path");
|
|
149
|
+
else if (a === "--codex") out.codex = true;
|
|
150
|
+
else if (a === "--no-codex") out.noCodex = true;
|
|
151
|
+
else if (a === "--claude") out.claude = true;
|
|
152
|
+
else if (a === "--no-claude") out.noClaude = true;
|
|
153
|
+
else out.unknown.push(a);
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The name the server prints, in one place — the console half of what
|
|
2
|
+
// src/web/brand.ts holds for the browser and src/server/term.mjs draws as the
|
|
3
|
+
// banner wordmark. Every `PRODUCT:` prefix below is a line a user reads when
|
|
4
|
+
// something has already gone wrong, which is the worst moment to introduce
|
|
5
|
+
// yourself by a name that appears nowhere else they have seen.
|
|
6
|
+
//
|
|
7
|
+
// Display name only. The package published to npm is still `agents-deck`, so
|
|
8
|
+
// self-update.mjs's `name` defaults stay as they are — that string is what the
|
|
9
|
+
// registry is queried for and what `npm i -g` installs, and an install that
|
|
10
|
+
// names the product instead of the package installs nothing. Same for the
|
|
11
|
+
// marker files under ~/.agents-deck, the event log under ~/.claude/agent-dag,
|
|
12
|
+
// the AGENTS_DECK_* variables and the `user-agent` headers: identifiers outlive
|
|
13
|
+
// a rename, and moving one orphans a running deck from its own state.
|
|
14
|
+
|
|
15
|
+
/** The prefix on every line the deck writes to a console or a log. */
|
|
16
|
+
export const PRODUCT = "ccdeck";
|