codedeck 0.7.3 → 0.7.4

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.
@@ -0,0 +1,158 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD";
4
+ function isWindows(opts) {
5
+ return (opts?.platform ?? process.platform) === "win32";
6
+ }
7
+ function pathApi(opts) {
8
+ return isWindows(opts) ? path.win32 : path.posix;
9
+ }
10
+ // Windows env names are case-insensitive, but a spread copy of process.env
11
+ // is a plain object: read "Path" as well as "PATH".
12
+ function envValue(env, name) {
13
+ if (env[name] !== undefined)
14
+ return env[name];
15
+ const key = Object.keys(env).find((k) => k.toUpperCase() === name);
16
+ return key === undefined ? undefined : env[key];
17
+ }
18
+ function windowsExtensions(env) {
19
+ const raw = envValue(env, "PATHEXT") || DEFAULT_PATHEXT;
20
+ return raw
21
+ .split(";")
22
+ .map((ext) => ext.trim().toLowerCase())
23
+ .filter((ext) => ext.startsWith("."));
24
+ }
25
+ function isRunnableFile(candidate, opts) {
26
+ const io = opts?.fs ?? fs;
27
+ try {
28
+ if (!io.statSync(candidate).isFile())
29
+ return false;
30
+ // Windows has no executable bit; the extension decides runnability.
31
+ if (!isWindows(opts))
32
+ io.accessSync(candidate, fs.constants.X_OK);
33
+ return true;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ // Candidate file names for one base path. On Windows a name that already
40
+ // carries a PATHEXT extension is tried as is; otherwise only the PATHEXT
41
+ // spellings are tried, never the bare name, so npm's extensionless POSIX
42
+ // shim next to `claude.cmd` is skipped exactly as cmd.exe skips it.
43
+ function candidates(base, opts) {
44
+ if (!isWindows(opts))
45
+ return [base];
46
+ const exts = windowsExtensions(opts?.env ?? process.env);
47
+ const ext = path.win32.extname(base).toLowerCase();
48
+ if (ext && exts.includes(ext))
49
+ return [base];
50
+ return exts.map((e) => base + e);
51
+ }
52
+ /**
53
+ * Resolve a command to an absolute runnable file, like `which` on POSIX and
54
+ * `where` on Windows. A name containing a path separator is resolved against
55
+ * the cwd instead of PATH. Returns undefined when nothing runnable is found.
56
+ */
57
+ export function resolveCommand(command, opts) {
58
+ if (!command)
59
+ return undefined;
60
+ const windows = isWindows(opts);
61
+ const p = pathApi(opts);
62
+ const env = opts?.env ?? process.env;
63
+ const cwd = opts?.cwd ?? process.cwd();
64
+ const hasSeparator = command.includes("/") || (windows && command.includes("\\"));
65
+ if (hasSeparator || p.isAbsolute(command)) {
66
+ const base = p.resolve(cwd, command);
67
+ return candidates(base, opts).find((c) => isRunnableFile(c, opts));
68
+ }
69
+ const dirs = (envValue(env, "PATH") ?? "").split(p.delimiter);
70
+ // cmd.exe searches the current directory first; spawn/CreateProcess does
71
+ // not, and a planted claude.cmd in a repo must never win. Skip it.
72
+ for (const dir of dirs) {
73
+ const clean = dir.trim().replace(/^"(.*)"$/, "$1");
74
+ if (!clean)
75
+ continue;
76
+ const base = p.resolve(cwd, clean, command);
77
+ const hit = candidates(base, opts).find((c) => isRunnableFile(c, opts));
78
+ if (hit)
79
+ return hit;
80
+ }
81
+ return undefined;
82
+ }
83
+ // npm's cmd-shim ends with: "%_prog%" "%dp0%\node_modules\pkg\cli.js" %*
84
+ // (older shims spell it "%~dp0\..."). Capture the target relative to the shim.
85
+ const CMD_SHIM_TARGET = /"%(?:~?dp0)%?\\([^"]+)"\s+%\*/i;
86
+ /**
87
+ * For an npm cmd-shim, the file it launches. Running that directly keeps
88
+ * prompts away from cmd.exe, which truncates arguments at a newline and
89
+ * expands `%VAR%` and `^` inside them.
90
+ */
91
+ export function unwrapCmdShim(shimPath, opts) {
92
+ const io = opts?.fs ?? fs;
93
+ let text;
94
+ try {
95
+ text = String(io.readFileSync(shimPath, "utf8"));
96
+ }
97
+ catch {
98
+ return undefined;
99
+ }
100
+ const match = CMD_SHIM_TARGET.exec(text);
101
+ if (!match)
102
+ return undefined;
103
+ const target = path.win32.resolve(path.win32.dirname(shimPath), match[1]);
104
+ if (!io.existsSync(target))
105
+ return undefined;
106
+ if (/\.(c|m)?js$/i.test(target)) {
107
+ // The shim prefers a node.exe that sits next to it.
108
+ const localNode = path.win32.join(path.win32.dirname(shimPath), "node.exe");
109
+ return { cmd: io.existsSync(localNode) ? localNode : process.execPath, prefix: [target] };
110
+ }
111
+ if (/\.(exe|com)$/i.test(target))
112
+ return { cmd: target, prefix: [] };
113
+ return undefined;
114
+ }
115
+ // cmd.exe metacharacters, escaped with ^ (same set as cross-spawn).
116
+ const CMD_META = /([()\][%!^"`<>&|;, *?])/g;
117
+ function escapeCmdArgument(arg, doubleEscape) {
118
+ // CommandLineToArgvW quoting first, then cmd.exe caret escaping.
119
+ let quoted = arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1");
120
+ quoted = `"${quoted}"`.replace(CMD_META, "^$1");
121
+ return doubleEscape ? quoted.replace(CMD_META, "^$1") : quoted;
122
+ }
123
+ /**
124
+ * How to spawn `command` with `args` on this platform. POSIX passes through.
125
+ * Windows resolves PATHEXT (so `claude` becomes `...\npm\claude.cmd`), runs
126
+ * an npm shim's real target directly, and only falls back to cmd.exe, with
127
+ * its quoting, for a batch file it cannot unwrap.
128
+ */
129
+ export function spawnTarget(command, args, opts) {
130
+ if (!isWindows(opts))
131
+ return { cmd: command, args };
132
+ const resolved = resolveCommand(command, opts) ?? command;
133
+ if (!/\.(cmd|bat)$/i.test(resolved))
134
+ return { cmd: resolved, args };
135
+ const shim = unwrapCmdShim(resolved, opts);
136
+ if (shim)
137
+ return { cmd: shim.cmd, args: [...shim.prefix, ...args] };
138
+ const env = opts?.env ?? process.env;
139
+ const comspec = envValue(env, "COMSPEC") || "cmd.exe";
140
+ const doubleEscape = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i.test(resolved);
141
+ const line = [resolved.replace(CMD_META, "^$1"), ...args.map((a) => escapeCmdArgument(a, doubleEscape))].join(" ");
142
+ return {
143
+ cmd: comspec,
144
+ args: ["/d", "/s", "/c", `"${line}"`],
145
+ windowsVerbatimArguments: true,
146
+ };
147
+ }
148
+ /**
149
+ * An installer's fixed location (`~/.local/bin/agy`, `~/.opencode/bin/opencode`).
150
+ * POSIX keeps the plain existence check; Windows also tries the PATHEXT
151
+ * spellings, because the installer writes `agy.exe`, not `agy`.
152
+ */
153
+ export function findLocalBinary(file, opts) {
154
+ if (!isWindows(opts))
155
+ return (opts?.fs ?? fs).existsSync(file) ? file : undefined;
156
+ return resolveCommand(file, opts);
157
+ }
158
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/utils/command.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codedeck",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "CodeDeck, a local runtime for coding agents with session management, process supervision, event normalization, and git isolation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,196 +0,0 @@
1
- import { extractProfileSnapshot, getProfileSnapshot, listProfiles, loadConfig, parseProfileName, resolveEffectiveConfig, saveConfig, serializeConfig, } from "../../config/config.js";
2
- import { ROLES } from "../../core/roles.js";
3
- export const PROFILE_ACTIONS = ["list", "show", "save", "use", "delete"];
4
- export class ProfileUsageError extends Error {
5
- constructor(message) {
6
- super(message);
7
- this.name = "ProfileUsageError";
8
- }
9
- }
10
- function isProfileAction(value) {
11
- return PROFILE_ACTIONS.includes(value);
12
- }
13
- export function parseProfileArgs(args) {
14
- let action;
15
- let name;
16
- let json = false;
17
- for (const arg of args) {
18
- if (arg === "--json") {
19
- json = true;
20
- continue;
21
- }
22
- if (arg.startsWith("-"))
23
- throw new ProfileUsageError(`Unknown option "${arg}".`);
24
- if (action === undefined) {
25
- if (!isProfileAction(arg)) {
26
- throw new ProfileUsageError(`Unknown action "${arg}". Available: ${PROFILE_ACTIONS.join(", ")}.`);
27
- }
28
- action = arg;
29
- continue;
30
- }
31
- if (name !== undefined)
32
- throw new ProfileUsageError(`Unexpected argument "${arg}".`);
33
- name = arg;
34
- }
35
- if (action === undefined) {
36
- throw new ProfileUsageError(`Missing action. Available: ${PROFILE_ACTIONS.join(", ")}.`);
37
- }
38
- if (action !== "list" && name === undefined) {
39
- throw new ProfileUsageError(`profile ${action} needs a name.`);
40
- }
41
- if (action === "list" && name !== undefined) {
42
- throw new ProfileUsageError(`Unexpected argument "${name}".`);
43
- }
44
- return { action, ...(name === undefined ? {} : { name }), json };
45
- }
46
- function agentSummary(snapshot) {
47
- return ROLES.map((role) => {
48
- const binding = snapshot.agents?.[role];
49
- return `${role} ${binding ? `${binding.harness}:${binding.model}` : "unset"}`;
50
- }).join(" · ");
51
- }
52
- /**
53
- * Pure profile transition over the loaded file. IO stays in the caller so
54
- * the whole matrix is testable without touching the disk.
55
- */
56
- export function applyProfileAction(config, action, rawName) {
57
- if (action === "list") {
58
- const names = listProfiles(config);
59
- const active = config.activeProfile;
60
- const text = names.length === 0
61
- ? "No profiles saved yet."
62
- : names.map((name) => `${active === name ? "*" : " "} ${name}`).join("\n");
63
- return { config, save: false, text, payload: { active: active ?? null, profiles: names } };
64
- }
65
- const name = parseProfileName(rawName);
66
- if (action === "show") {
67
- const snapshot = getProfileSnapshot(config, name);
68
- if (!snapshot) {
69
- const available = listProfiles(config);
70
- throw new ProfileUsageError(`Unknown profile "${name}". Available: ${available.join(", ") || "none"}.`);
71
- }
72
- return { config, save: false, text: serializeConfig(snapshot), payload: snapshot };
73
- }
74
- if (action === "save") {
75
- // Re-save an existing target explicitly. A new name clones the effective
76
- // setup currently in use, so saving a profile works as a "save as" action
77
- // without changing which profile remains active.
78
- const existing = getProfileSnapshot(config, name);
79
- const source = existing === undefined ? resolveEffectiveConfig(config) : resolveEffectiveConfig(config, name);
80
- const snapshot = extractProfileSnapshot(source);
81
- const profiles = { ...(config.profiles ?? {}), [name]: snapshot };
82
- const next = { ...config, profiles };
83
- return {
84
- config: next,
85
- save: true,
86
- text: `saved profile "${name}": ${agentSummary(snapshot)}`,
87
- payload: { name, profile: snapshot },
88
- };
89
- }
90
- if (action === "use") {
91
- if (!getProfileSnapshot(config, name)) {
92
- const available = listProfiles(config);
93
- throw new ProfileUsageError(`Unknown profile "${name}". Available: ${available.join(", ") || "none"}.`);
94
- }
95
- if (config.activeProfile === name) {
96
- return { config, save: false, text: `profile "${name}" is already active.`, payload: { name } };
97
- }
98
- return {
99
- config: { ...config, activeProfile: name },
100
- save: true,
101
- text: `using profile "${name}"`,
102
- payload: { name },
103
- };
104
- }
105
- if (!getProfileSnapshot(config, name)) {
106
- const available = listProfiles(config);
107
- throw new ProfileUsageError(`Unknown profile "${name}". Available: ${available.join(", ") || "none"}.`);
108
- }
109
- const profiles = { ...(config.profiles ?? {}) };
110
- delete profiles[name];
111
- const next = { ...config, profiles };
112
- if (Object.keys(profiles).length === 0)
113
- delete next.profiles;
114
- if (next.activeProfile === name)
115
- delete next.activeProfile;
116
- return { config: next, save: true, text: `deleted profile "${name}"`, payload: { name } };
117
- }
118
- export async function executeProfileAction(args, dependencies = {}) {
119
- const stdout = dependencies.stdout ?? process.stdout;
120
- const stderr = dependencies.stderr ?? process.stderr;
121
- const fail = (message) => {
122
- stderr.write(`${message}\n`);
123
- return 2;
124
- };
125
- let parsed;
126
- try {
127
- parsed = parseProfileArgs(args);
128
- }
129
- catch (error) {
130
- return fail(error instanceof Error ? error.message : String(error));
131
- }
132
- let config;
133
- try {
134
- config = (dependencies.load ?? loadConfig)();
135
- }
136
- catch (error) {
137
- stderr.write(`Cannot read config: ${error instanceof Error ? error.message : String(error)}\n`);
138
- return 1;
139
- }
140
- let result;
141
- try {
142
- result = applyProfileAction(config, parsed.action, parsed.name);
143
- }
144
- catch (error) {
145
- return fail(error instanceof Error ? error.message : String(error));
146
- }
147
- if (parsed.json) {
148
- stdout.write(`${JSON.stringify(result.payload, null, 2)}\n`);
149
- }
150
- else {
151
- stdout.write(`${result.text}\n`);
152
- }
153
- if (!result.save)
154
- return 0;
155
- try {
156
- (dependencies.save ?? saveConfig)(result.config);
157
- }
158
- catch (error) {
159
- stderr.write(`Cannot save config: ${error instanceof Error ? error.message : String(error)}\n`);
160
- return 1;
161
- }
162
- return 0;
163
- }
164
- export function registerProfileCommand(program) {
165
- const profile = program
166
- .command("profile")
167
- .description("Save and switch named agent setups");
168
- const run = (args) => async (opts) => {
169
- const tokens = [...args];
170
- if (opts.json)
171
- tokens.push("--json");
172
- process.exitCode = await executeProfileAction(tokens);
173
- };
174
- profile
175
- .command("list")
176
- .description("list saved profiles (* marks the active one)")
177
- .option("--json", "output JSON")
178
- .action(run(["list"]));
179
- const named = [
180
- { action: "show", description: "print a saved profile" },
181
- { action: "save", description: "snapshot the current setup as a profile (the active profile itself re-saves its own setup)" },
182
- { action: "use", description: "make a profile the active setup" },
183
- { action: "delete", description: "delete a saved profile" },
184
- ];
185
- for (const { action, description } of named) {
186
- profile
187
- .command(action)
188
- .description(description)
189
- .argument("<name>", "profile name")
190
- .option("--json", "output JSON")
191
- .action(async (name, opts) => {
192
- process.exitCode = await executeProfileAction(opts.json ? [action, name, "--json"] : [action, name]);
193
- });
194
- }
195
- }
196
- //# sourceMappingURL=profile.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/cli/commands/profile.ts"],"names":[],"mappings":"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"}