@subshell-ai/plugin-codex 0.1.1 → 0.2.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/dist/index.d.ts +27 -23
- package/dist/index.js +39 -23
- package/icon.svg +4 -0
- package/package.json +4 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../../plugin-api/dist/types-
|
|
1
|
+
//#region ../../plugin-api/dist/types-B_wiApwK.d.ts
|
|
2
2
|
//#region src/types.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The contract a Subshell plugin implements.
|
|
@@ -27,9 +27,9 @@ type PluginType = "agent-harness" | "terminal";
|
|
|
27
27
|
* branches on {@link PluginType}.
|
|
28
28
|
*/
|
|
29
29
|
type PluginCapability = "mcp" | "resume" | "attention" | "settings";
|
|
30
|
-
/** A harness
|
|
31
|
-
interface
|
|
32
|
-
/** Human-friendly
|
|
30
|
+
/** A harness preset as defined by the user (decoded JSON blobs). */
|
|
31
|
+
interface PresetDefinition {
|
|
32
|
+
/** Human-friendly preset name */
|
|
33
33
|
name: string;
|
|
34
34
|
/** Optional longer description */
|
|
35
35
|
description?: string | null;
|
|
@@ -39,21 +39,21 @@ interface ProfileDefinition {
|
|
|
39
39
|
flags: string[];
|
|
40
40
|
/** Settings blob passed to the harness (e.g. claude --settings JSON) */
|
|
41
41
|
settings: Record<string, unknown> | null;
|
|
42
|
-
/** If true, only this
|
|
42
|
+
/** If true, only this preset's config sources apply (isolation) */
|
|
43
43
|
configIsolation: boolean;
|
|
44
|
-
/** If true, new subshells from this
|
|
44
|
+
/** If true, new subshells from this preset auto-restart on exit */
|
|
45
45
|
restartOnExit?: boolean;
|
|
46
46
|
}
|
|
47
|
-
/** Snapshot of a single field-level validation error on a
|
|
48
|
-
interface
|
|
47
|
+
/** Snapshot of a single field-level validation error on a preset. */
|
|
48
|
+
interface PresetValidationIssue {
|
|
49
49
|
/** Field name (e.g. "name", "env", "settings") */
|
|
50
50
|
field: string;
|
|
51
51
|
/** Human-readable problem description */
|
|
52
52
|
message: string;
|
|
53
53
|
}
|
|
54
|
-
interface
|
|
54
|
+
interface PresetValidationResult {
|
|
55
55
|
valid: boolean;
|
|
56
|
-
issues:
|
|
56
|
+
issues: PresetValidationIssue[];
|
|
57
57
|
}
|
|
58
58
|
/** Everything a plugin needs to build a launch command. */
|
|
59
59
|
interface BuildCommandInput {
|
|
@@ -61,8 +61,8 @@ interface BuildCommandInput {
|
|
|
61
61
|
binary: string;
|
|
62
62
|
/** Working directory the harness runs in */
|
|
63
63
|
cwd: string;
|
|
64
|
-
/** The validated
|
|
65
|
-
|
|
64
|
+
/** The validated preset being used */
|
|
65
|
+
preset: PresetDefinition;
|
|
66
66
|
/** Subshell display name ("" = let the harness pick a default) */
|
|
67
67
|
subshellName: string;
|
|
68
68
|
/** Any additional CLI flags from route/request context */
|
|
@@ -169,12 +169,12 @@ interface McpRegistration {
|
|
|
169
169
|
args?: string[];
|
|
170
170
|
/**
|
|
171
171
|
* Extra pane env the harness needs to discover the file (e.g. OPENCODE_CONFIG).
|
|
172
|
-
* Consumed by the HOST, which bakes it into the pane env ahead of
|
|
172
|
+
* Consumed by the HOST, which bakes it into the pane env ahead of preset env;
|
|
173
173
|
* plugins never read it back.
|
|
174
174
|
*/
|
|
175
175
|
env?: Record<string, string>;
|
|
176
176
|
}
|
|
177
|
-
/** One copy-paste line shown in the
|
|
177
|
+
/** One copy-paste line shown in the preset editor for manual-setup harnesses. */
|
|
178
178
|
interface McpSetupStep {
|
|
179
179
|
/** What the user should do, and where the text goes */
|
|
180
180
|
label: string;
|
|
@@ -259,8 +259,8 @@ interface PluginHost {
|
|
|
259
259
|
interface SubshellPlugin {
|
|
260
260
|
/** Builds the argv (no shell) used to launch a subshell. */
|
|
261
261
|
buildCommand(input: BuildCommandInput): string[];
|
|
262
|
-
/** Validates a
|
|
263
|
-
|
|
262
|
+
/** Validates a preset definition before saving. */
|
|
263
|
+
validatePreset(preset: PresetDefinition): PresetValidationResult;
|
|
264
264
|
/** Which optional members below are meaningful on this plugin. */
|
|
265
265
|
capabilities(): PluginCapability[];
|
|
266
266
|
/** Maps a harness exit code to a human label (null = unknown). */
|
|
@@ -292,14 +292,14 @@ interface SubshellPlugin {
|
|
|
292
292
|
mcpRegistration?(launch: McpLaunchSpec, configPath: string): McpRegistration;
|
|
293
293
|
/** How users obtain the subshell MCP tools here. Declare the `mcp` capability with it. */
|
|
294
294
|
mcpSetup?(launch: McpLaunchSpec): McpSetupInfo;
|
|
295
|
-
/** Settings rendered in the
|
|
296
|
-
|
|
297
|
-
/** Known extra env var suggestions for the
|
|
295
|
+
/** Settings rendered in the PRESET editor and stored on the preset. */
|
|
296
|
+
presetSettings?(): SettingsField[];
|
|
297
|
+
/** Known extra env var suggestions for the preset editor. */
|
|
298
298
|
suggestedEnv?(): {
|
|
299
299
|
key: string;
|
|
300
300
|
description: string;
|
|
301
301
|
}[];
|
|
302
|
-
/** Known CLI flag suggestions for the
|
|
302
|
+
/** Known CLI flag suggestions for the preset editor. */
|
|
303
303
|
suggestedFlags?(): {
|
|
304
304
|
flag: string;
|
|
305
305
|
description: string;
|
|
@@ -337,7 +337,11 @@ interface SubshellManifest {
|
|
|
337
337
|
name: string;
|
|
338
338
|
/** One-line description shown in the UI */
|
|
339
339
|
description: string;
|
|
340
|
-
/**
|
|
340
|
+
/**
|
|
341
|
+
* Relative path to this plugin's icon file, e.g. `icon.svg`. Served by
|
|
342
|
+
* the control plane at `/api/plugins/<id>/icon`; absent means the UI
|
|
343
|
+
* renders a monogram instead.
|
|
344
|
+
*/
|
|
341
345
|
icon?: string;
|
|
342
346
|
/** Module to import, relative to the package directory */
|
|
343
347
|
entry: string;
|
|
@@ -366,7 +370,7 @@ declare const manifest: SubshellManifest;
|
|
|
366
370
|
*
|
|
367
371
|
* Launch shape:
|
|
368
372
|
* codex [-m <model>] [-s <sandbox>] [-a <approval>] [mcp -c pairs]
|
|
369
|
-
* [
|
|
373
|
+
* [preset flags] [extra flags]
|
|
370
374
|
* A bare launch (no subcommand, no prompt) opens the interactive TUI. Codex
|
|
371
375
|
* has no create-time flag for naming its own session and no way to pin a
|
|
372
376
|
* conversation id, so neither the subshell name nor a resume capability is
|
|
@@ -374,7 +378,7 @@ declare const manifest: SubshellManifest;
|
|
|
374
378
|
* The pane's
|
|
375
379
|
* cwd is already the working directory, so `-C/--cd` is never passed, and
|
|
376
380
|
* `--dangerously-bypass-approvals-and-sandbox` is NEVER baked into a launch
|
|
377
|
-
* (a user may put it in their own
|
|
381
|
+
* (a user may put it in their own preset flags — that is their call).
|
|
378
382
|
*
|
|
379
383
|
* subshell MCP is wired automatically WITHOUT touching user state: every
|
|
380
384
|
* launch carries `-c mcp_servers.subshell.command=… -c mcp_servers.subshell.args=…`
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../../plugin-api/dist/manifest-
|
|
1
|
+
//#region ../../plugin-api/dist/manifest-Czd9ea1g.js
|
|
2
2
|
/** Every {@link PluginType}, for anything that has to iterate or validate them. */
|
|
3
3
|
const PLUGIN_TYPES = ["agent-harness", "terminal"];
|
|
4
4
|
/**
|
|
@@ -9,6 +9,17 @@ const PLUGIN_TYPES = ["agent-harness", "terminal"];
|
|
|
9
9
|
*/
|
|
10
10
|
const MCP_SERVER_NAME = "subshell";
|
|
11
11
|
/**
|
|
12
|
+
* Image formats a plugin icon may be. The server maps these to a Content-Type
|
|
13
|
+
* from a fixed table rather than sniffing the file, so this list and that
|
|
14
|
+
* table are one decision: adding a format here without adding it there leaves
|
|
15
|
+
* an icon that parses and then 500s when something asks for it.
|
|
16
|
+
*/
|
|
17
|
+
const ICON_EXTENSIONS = [
|
|
18
|
+
".svg",
|
|
19
|
+
".png",
|
|
20
|
+
".webp"
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
12
23
|
* Ids become directory names under `<dataDir>/plugins/`, so they are path
|
|
13
24
|
* segments and nothing else: no separators, no traversal, no surprises from a
|
|
14
25
|
* case-insensitive filesystem.
|
|
@@ -31,13 +42,18 @@ function parseManifest(pkgJson) {
|
|
|
31
42
|
const block = pkgJson.subshell;
|
|
32
43
|
if (!isRecord(block)) return { error: "package.json has no `subshell` block, so it is not a Subshell plugin" };
|
|
33
44
|
if (typeof block.apiVersion !== "number" || !Number.isInteger(block.apiVersion)) return { error: "`subshell.apiVersion` must be an integer" };
|
|
34
|
-
if (block.apiVersion < 1) return { error: `this plugin declares plugin-api ${block.apiVersion}, which is not a version; the lowest is 1 and this host implements
|
|
35
|
-
if (block.apiVersion >
|
|
45
|
+
if (block.apiVersion < 1) return { error: `this plugin declares plugin-api ${block.apiVersion}, which is not a version; the lowest is 1 and this host implements 2` };
|
|
46
|
+
if (block.apiVersion > 2) return { error: `this plugin needs plugin-api ${block.apiVersion}, but this host implements 2; upgrade the agent` };
|
|
36
47
|
if (typeof block.id !== "string" || !ID_RE.test(block.id)) return { error: "`subshell.id` must be lowercase letters, digits and hyphens, starting alphanumeric (it becomes a directory name)" };
|
|
37
48
|
if (typeof block.type !== "string" || !PLUGIN_TYPES.includes(block.type)) return { error: `\`subshell.type\` must be one of: ${PLUGIN_TYPES.join(", ")}` };
|
|
38
49
|
if (typeof block.name !== "string" || block.name.trim() === "") return { error: "`subshell.name` must be a non-empty string" };
|
|
39
50
|
if (typeof block.description !== "string") return { error: "`subshell.description` must be a string" };
|
|
40
|
-
if (block.icon !== void 0
|
|
51
|
+
if (block.icon !== void 0) {
|
|
52
|
+
if (typeof block.icon !== "string" || block.icon.trim() === "") return { error: "`subshell.icon` must be a non-empty relative path to an image in the package" };
|
|
53
|
+
if (block.icon.startsWith("/") || block.icon.split("/").includes("..")) return { error: "`subshell.icon` must stay inside the package (no leading `/` and no `..` segment)" };
|
|
54
|
+
const icon = block.icon;
|
|
55
|
+
if (!ICON_EXTENSIONS.some((ext) => icon.endsWith(ext))) return { error: `\`subshell.icon\` must end in one of: ${ICON_EXTENSIONS.join(", ")}` };
|
|
56
|
+
}
|
|
41
57
|
if (typeof block.entry !== "string" || block.entry.trim() === "") return { error: "`subshell.entry` must be a non-empty relative path" };
|
|
42
58
|
if (block.entry.startsWith("/") || block.entry.split("/").includes("..")) return { error: "`subshell.entry` must stay inside the package (no leading `/` and no `..` segment)" };
|
|
43
59
|
let detect;
|
|
@@ -80,23 +96,23 @@ function parseManifest(pkgJson) {
|
|
|
80
96
|
//#endregion
|
|
81
97
|
//#region ../../plugin-api/dist/index.js
|
|
82
98
|
/**
|
|
83
|
-
* The
|
|
99
|
+
* The preset checks every built-in harness performs unchanged: a non-empty
|
|
84
100
|
* name, string env values, and flags that look like flags. Harnesses with
|
|
85
101
|
* extra rules run their own checks on top of these.
|
|
86
|
-
* @param
|
|
102
|
+
* @param preset - The decoded preset definition to check
|
|
87
103
|
* @returns Issues per field; `valid` is true when no issues were found
|
|
88
104
|
*/
|
|
89
|
-
function
|
|
105
|
+
function validateGenericPreset(preset) {
|
|
90
106
|
const issues = [];
|
|
91
|
-
if (!
|
|
107
|
+
if (!preset.name || preset.name.trim().length === 0) issues.push({
|
|
92
108
|
field: "name",
|
|
93
|
-
message: "
|
|
109
|
+
message: "Preset name is required."
|
|
94
110
|
});
|
|
95
|
-
for (const [key, value] of Object.entries(
|
|
111
|
+
for (const [key, value] of Object.entries(preset.env)) if (typeof value !== "string") issues.push({
|
|
96
112
|
field: "env",
|
|
97
113
|
message: `Env var "${key}" must be a string.`
|
|
98
114
|
});
|
|
99
|
-
for (const flag of
|
|
115
|
+
for (const flag of preset.flags) if (!flag.startsWith("-")) issues.push({
|
|
100
116
|
field: "flags",
|
|
101
117
|
message: `Flag "${flag}" must start with "-".`
|
|
102
118
|
});
|
|
@@ -118,7 +134,7 @@ function validateGenericProfile(profile) {
|
|
|
118
134
|
const parsed = parseManifest({
|
|
119
135
|
name: "@subshell-ai/plugin-codex",
|
|
120
136
|
description: "Codex harness plugin for Subshell",
|
|
121
|
-
version: "0.
|
|
137
|
+
version: "0.2.0",
|
|
122
138
|
license: "Apache-2.0",
|
|
123
139
|
type: "module",
|
|
124
140
|
main: "dist/index.js",
|
|
@@ -152,15 +168,15 @@ const parsed = parseManifest({
|
|
|
152
168
|
"tsdown": "0.22.14",
|
|
153
169
|
"typescript": "7.0.2"
|
|
154
170
|
},
|
|
155
|
-
files: ["dist"],
|
|
171
|
+
files: ["dist", "icon.svg"],
|
|
156
172
|
publishConfig: { "access": "public" },
|
|
157
173
|
subshell: {
|
|
158
|
-
"apiVersion":
|
|
174
|
+
"apiVersion": 2,
|
|
159
175
|
"id": "codex",
|
|
160
176
|
"type": "agent-harness",
|
|
161
177
|
"name": "Codex",
|
|
162
178
|
"description": "OpenAI's agentic coding CLI (interactive TUI)",
|
|
163
|
-
"icon": "
|
|
179
|
+
"icon": "icon.svg",
|
|
164
180
|
"entry": "dist/index.js",
|
|
165
181
|
"detect": {
|
|
166
182
|
"binaryName": "codex",
|
|
@@ -239,7 +255,7 @@ function tomlStringArray(values) {
|
|
|
239
255
|
*
|
|
240
256
|
* Launch shape:
|
|
241
257
|
* codex [-m <model>] [-s <sandbox>] [-a <approval>] [mcp -c pairs]
|
|
242
|
-
* [
|
|
258
|
+
* [preset flags] [extra flags]
|
|
243
259
|
* A bare launch (no subcommand, no prompt) opens the interactive TUI. Codex
|
|
244
260
|
* has no create-time flag for naming its own session and no way to pin a
|
|
245
261
|
* conversation id, so neither the subshell name nor a resume capability is
|
|
@@ -247,7 +263,7 @@ function tomlStringArray(values) {
|
|
|
247
263
|
* The pane's
|
|
248
264
|
* cwd is already the working directory, so `-C/--cd` is never passed, and
|
|
249
265
|
* `--dangerously-bypass-approvals-and-sandbox` is NEVER baked into a launch
|
|
250
|
-
* (a user may put it in their own
|
|
266
|
+
* (a user may put it in their own preset flags — that is their call).
|
|
251
267
|
*
|
|
252
268
|
* subshell MCP is wired automatically WITHOUT touching user state: every
|
|
253
269
|
* launch carries `-c mcp_servers.subshell.command=… -c mcp_servers.subshell.args=…`
|
|
@@ -268,14 +284,14 @@ function tomlStringArray(values) {
|
|
|
268
284
|
const createPlugin = (_host) => ({
|
|
269
285
|
capabilities: () => ["mcp", "settings"],
|
|
270
286
|
buildCommand(input) {
|
|
271
|
-
const { binary,
|
|
287
|
+
const { binary, preset, extraFlags, mcp } = input;
|
|
272
288
|
const args = [binary];
|
|
273
|
-
const s =
|
|
289
|
+
const s = preset.settings ?? {};
|
|
274
290
|
if (typeof s.model === "string" && s.model) args.push("-m", s.model);
|
|
275
291
|
if (typeof s.sandbox === "string" && s.sandbox) args.push("-s", s.sandbox);
|
|
276
292
|
if (typeof s.askForApproval === "string" && s.askForApproval) args.push("-a", s.askForApproval);
|
|
277
293
|
if (mcp?.args) args.push(...mcp.args);
|
|
278
|
-
for (const flag of
|
|
294
|
+
for (const flag of preset.flags) args.push(flag);
|
|
279
295
|
if (extraFlags) args.push(...extraFlags);
|
|
280
296
|
return args;
|
|
281
297
|
},
|
|
@@ -317,10 +333,10 @@ const createPlugin = (_host) => ({
|
|
|
317
333
|
summary: "Subshell registers itself with every Codex subshell automatically (per-invocation -c mcp_servers.subshell.* overrides; your ~/.codex config is never modified)."
|
|
318
334
|
};
|
|
319
335
|
},
|
|
320
|
-
|
|
321
|
-
return
|
|
336
|
+
validatePreset(preset) {
|
|
337
|
+
return validateGenericPreset(preset);
|
|
322
338
|
},
|
|
323
|
-
|
|
339
|
+
presetSettings() {
|
|
324
340
|
return CODEX_SETTINGS_FIELDS;
|
|
325
341
|
},
|
|
326
342
|
suggestedEnv() {
|
package/icon.svg
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Codex</title>
|
|
2
|
+
<circle cx="12" cy="12" r="12" fill="#0080F7"/>
|
|
3
|
+
<path d="M9.94494 9.59163V8.13227C9.94494 8.00935 9.99105 7.91713 10.0985 7.85575L13.0327 6.16599C13.4321 5.93558 13.9083 5.8281 14.3998 5.8281C16.2432 5.8281 17.4108 7.25677 17.4108 8.77751C17.4108 8.885 17.4108 9.00792 17.3953 9.13083L14.3537 7.34884C14.1694 7.24135 13.985 7.24135 13.8007 7.34884L9.94494 9.59163ZM16.7963 15.2755V11.7883C16.7963 11.5732 16.704 11.4196 16.5197 11.3121L12.664 9.0693L13.9236 8.34725C14.0311 8.28587 14.1234 8.28587 14.2308 8.34725L17.165 10.037C18.0099 10.5287 18.5782 11.5732 18.5782 12.587C18.5782 13.7544 17.887 14.8298 16.7963 15.2753V15.2755ZM9.03861 12.2031L7.77896 11.4658C7.67146 11.4045 7.62535 11.3122 7.62535 11.1893V7.8098C7.62535 6.16613 8.88501 4.92176 10.5902 4.92176C11.2354 4.92176 11.8344 5.13689 12.3415 5.52089L9.31526 7.27218C9.13097 7.37968 9.03875 7.53328 9.03875 7.74841V12.2033L9.03861 12.2031ZM11.75 13.77L9.94494 12.7562V10.6056L11.75 9.59178L13.5549 10.6056V12.7562L11.75 13.77ZM12.9098 18.44C12.2645 18.44 11.6655 18.2249 11.1585 17.8409L14.1847 16.0896C14.369 15.9821 14.4612 15.8285 14.4612 15.6134V11.1585L15.7363 11.8958C15.8438 11.9572 15.8899 12.0494 15.8899 12.1723V15.5519C15.8899 17.1955 14.6148 18.44 12.9098 18.44ZM9.26901 15.0144L6.33486 13.3246C5.4899 12.833 4.92161 11.7885 4.92161 10.7746C4.92161 9.59177 5.62824 8.53183 6.71886 8.0863V11.5887C6.71886 11.8039 6.81109 11.9575 6.99538 12.065L10.8359 14.2923L9.57621 15.0144C9.46872 15.0758 9.37649 15.0758 9.26901 15.0144ZM9.10013 17.5337C7.36426 17.5337 6.08919 16.2279 6.08919 14.6149C6.08919 14.492 6.1046 14.3691 6.11988 14.2462L9.1461 15.9975C9.33039 16.105 9.51483 16.105 9.69912 15.9975L13.5549 13.7702V15.2295C13.5549 15.3524 13.5088 15.4446 13.4013 15.506L10.4671 17.1958C10.0677 17.4262 9.59148 17.5337 9.09999 17.5337H9.10013ZM12.9098 19.3616C14.7685 19.3616 16.32 18.0406 16.6735 16.2893C18.3939 15.8438 19.5 14.2308 19.5 12.5872C19.5 11.5118 19.0391 10.4673 18.2096 9.71454C18.2864 9.39192 18.3326 9.0693 18.3326 8.74682C18.3326 6.55014 16.5505 4.90634 14.4921 4.90634C14.0774 4.90634 13.6779 4.96772 13.2785 5.10605C12.5872 4.43011 11.6347 4 10.5902 4C8.7314 4 7.17996 5.32103 6.8265 7.07232C5.10605 7.51786 4 9.13083 4 10.7745C4 11.8498 4.4608 12.8944 5.29035 13.6471C5.21354 13.9697 5.16743 14.2923 5.16743 14.6148C5.16743 16.8114 6.94941 18.4552 9.00792 18.4552C9.42261 18.4552 9.82204 18.3939 10.2215 18.2556C10.9127 18.9315 11.8651 19.3616 12.9098 19.3616Z" fill="white"/>
|
|
4
|
+
</svg>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subshell-ai/plugin-codex",
|
|
3
3
|
"description": "Codex harness plugin for Subshell",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -39,19 +39,17 @@
|
|
|
39
39
|
"tsdown": "0.22.14",
|
|
40
40
|
"typescript": "7.0.2"
|
|
41
41
|
},
|
|
42
|
-
"files": [
|
|
43
|
-
"dist"
|
|
44
|
-
],
|
|
42
|
+
"files": ["dist", "icon.svg"],
|
|
45
43
|
"publishConfig": {
|
|
46
44
|
"access": "public"
|
|
47
45
|
},
|
|
48
46
|
"subshell": {
|
|
49
|
-
"apiVersion":
|
|
47
|
+
"apiVersion": 2,
|
|
50
48
|
"id": "codex",
|
|
51
49
|
"type": "agent-harness",
|
|
52
50
|
"name": "Codex",
|
|
53
51
|
"description": "OpenAI's agentic coding CLI (interactive TUI)",
|
|
54
|
-
"icon": "
|
|
52
|
+
"icon": "icon.svg",
|
|
55
53
|
"entry": "dist/index.js",
|
|
56
54
|
"detect": {
|
|
57
55
|
"binaryName": "codex",
|