@subshell-ai/plugin-codex 0.1.0 → 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/LICENSE ADDED
@@ -0,0 +1,203 @@
1
+ Copyright 2026 Disaresta, LLC
2
+
3
+ Apache License
4
+ Version 2.0, January 2004
5
+ http://www.apache.org/licenses/
6
+
7
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
+
9
+ 1. Definitions.
10
+
11
+ "License" shall mean the terms and conditions for use, reproduction,
12
+ and distribution as defined by Sections 1 through 9 of this document.
13
+
14
+ "Licensor" shall mean the copyright owner or entity authorized by
15
+ the copyright owner that is granting the License.
16
+
17
+ "Legal Entity" shall mean the union of the acting entity and all
18
+ other entities that control, are controlled by, or are under common
19
+ control with that entity. For the purposes of this definition,
20
+ "control" means (i) the power, direct or indirect, to cause the
21
+ direction or management of such entity, whether by contract or
22
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
23
+ outstanding shares, or (iii) beneficial ownership of such entity.
24
+
25
+ "You" (or "Your") shall mean an individual or Legal Entity
26
+ exercising permissions granted by this License.
27
+
28
+ "Source" form shall mean the preferred form for making modifications,
29
+ including but not limited to software source code, documentation
30
+ source, and configuration files.
31
+
32
+ "Object" form shall mean any form resulting from mechanical
33
+ transformation or translation of a Source form, including but
34
+ not limited to compiled object code, generated documentation,
35
+ and conversions to other media types.
36
+
37
+ "Work" shall mean the work of authorship, whether in Source or
38
+ Object form, made available under the License, as indicated by a
39
+ copyright notice that is included in or attached to the work
40
+ (an example is provided in the Appendix below).
41
+
42
+ "Derivative Works" shall mean any work, whether in Source or Object
43
+ form, that is based on (or derived from) the Work and for which the
44
+ editorial revisions, annotations, elaborations, or other modifications
45
+ represent, as a whole, an original work of authorship. For the purposes
46
+ of this License, Derivative Works shall not include works that remain
47
+ separable from, or merely link (or bind by name) to the interfaces of,
48
+ the Work and Derivative Works thereof.
49
+
50
+ "Contribution" shall mean any work of authorship, including
51
+ the original version of the Work and any modifications or additions
52
+ to that Work or Derivative Works thereof, that is intentionally
53
+ submitted to Licensor for inclusion in the Work by the copyright owner
54
+ or by an individual or Legal Entity authorized to submit on behalf of
55
+ the copyright owner. For the purposes of this definition, "submitted"
56
+ means any form of electronic, verbal, or written communication sent
57
+ to the Licensor or its representatives, including but not limited to
58
+ communication on electronic mailing lists, source code control systems,
59
+ and issue tracking systems that are managed by, or on behalf of, the
60
+ Licensor for the purpose of discussing and improving the Work, but
61
+ excluding communication that is conspicuously marked or otherwise
62
+ designated in writing by the copyright owner as "Not a Contribution."
63
+
64
+ "Contributor" shall mean Licensor and any individual or Legal Entity
65
+ on behalf of whom a Contribution has been received by Licensor and
66
+ subsequently incorporated within the Work.
67
+
68
+ 2. Grant of Copyright License. Subject to the terms and conditions of
69
+ this License, each Contributor hereby grants to You a perpetual,
70
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71
+ copyright license to reproduce, prepare Derivative Works of,
72
+ publicly display, publicly perform, sublicense, and distribute the
73
+ Work and such Derivative Works in Source or Object form.
74
+
75
+ 3. Grant of Patent License. Subject to the terms and conditions of
76
+ this License, each Contributor hereby grants to You a perpetual,
77
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78
+ (except as stated in this section) patent license to make, have made,
79
+ use, offer to sell, sell, import, and otherwise transfer the Work,
80
+ where such license applies only to those patent claims licensable
81
+ by such Contributor that are necessarily infringed by their
82
+ Contribution(s) alone or by combination of their Contribution(s)
83
+ with the Work to which such Contribution(s) was submitted. If You
84
+ institute patent litigation against any entity (including a
85
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
86
+ or a Contribution incorporated within the Work constitutes direct
87
+ or contributory patent infringement, then any patent licenses
88
+ granted to You under this License for that Work shall terminate
89
+ as of the date such litigation is filed.
90
+
91
+ 4. Redistribution. You may reproduce and distribute copies of the
92
+ Work or Derivative Works thereof in any medium, with or without
93
+ modifications, and in Source or Object form, provided that You
94
+ meet the following conditions:
95
+
96
+ (a) You must give any other recipients of the Work or
97
+ Derivative Works a copy of this License; and
98
+
99
+ (b) You must cause any modified files to carry prominent notices
100
+ stating that You changed the files; and
101
+
102
+ (c) You must retain, in the Source form of any Derivative Works
103
+ that You distribute, all copyright, patent, trademark, and
104
+ attribution notices from the Source form of the Work,
105
+ excluding those notices that do not pertain to any part of
106
+ the Derivative Works; and
107
+
108
+ (d) If the Work includes a "NOTICE" text file as part of its
109
+ distribution, then any Derivative Works that You distribute must
110
+ include a readable copy of the attribution notices contained
111
+ within such NOTICE file, excluding those notices that do not
112
+ pertain to any part of the Derivative Works, in at least one
113
+ of the following places: within a NOTICE text file distributed
114
+ as part of the Derivative Works; within the Source form or
115
+ documentation, if provided along with the Derivative Works; or,
116
+ within a display generated by the Derivative Works, if and
117
+ wherever such third-party notices normally appear. The contents
118
+ of the NOTICE file are for informational purposes only and
119
+ do not modify the License. You may add Your own attribution
120
+ notices within Derivative Works that You distribute, alongside
121
+ or as an addendum to the NOTICE text from the Work, provided
122
+ that such additional attribution notices cannot be construed
123
+ as modifying the License.
124
+
125
+ You may add Your own copyright statement to Your modifications and
126
+ may provide additional or different license terms and conditions
127
+ for use, reproduction, or distribution of Your modifications, or
128
+ for any such Derivative Works as a whole, provided Your use,
129
+ reproduction, and distribution of the Work otherwise complies with
130
+ the conditions stated in this License.
131
+
132
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
133
+ any Contribution intentionally submitted for inclusion in the Work
134
+ by You to the Licensor shall be under the terms and conditions of
135
+ this License, without any additional terms or conditions.
136
+ Notwithstanding the above, nothing herein shall supersede or modify
137
+ the terms of any separate license agreement you may have executed
138
+ with Licensor regarding such Contributions.
139
+
140
+ 6. Trademarks. This License does not grant permission to use the trade
141
+ names, trademarks, service marks, or product names of the Licensor,
142
+ except as required for reasonable and customary use in describing the
143
+ origin of the Work and reproducing the content of the NOTICE file.
144
+
145
+ 7. Disclaimer of Warranty. Unless required by applicable law or
146
+ agreed to in writing, Licensor provides the Work (and each
147
+ Contributor provides its Contributions) on an "AS IS" BASIS,
148
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149
+ implied, including, without limitation, any warranties or conditions
150
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151
+ PARTICULAR PURPOSE. You are solely responsible for determining the
152
+ appropriateness of using or redistributing the Work and assume any
153
+ risks associated with Your exercise of permissions under this License.
154
+
155
+ 8. Limitation of Liability. In no event and under no legal theory,
156
+ whether in tort (including negligence), contract, or otherwise,
157
+ unless required by applicable law (such as deliberate and grossly
158
+ negligent acts) or agreed to in writing, shall any Contributor be
159
+ liable to You for damages, including any direct, indirect, special,
160
+ incidental, or consequential damages of any character arising as a
161
+ result of this License or out of the use or inability to use the
162
+ Work (including but not limited to damages for loss of goodwill,
163
+ work stoppage, computer failure or malfunction, or any and all
164
+ other commercial damages or losses), even if such Contributor
165
+ has been advised of the possibility of such damages.
166
+
167
+ 9. Accepting Warranty or Additional Liability. While redistributing
168
+ the Work or Derivative Works thereof, You may choose to offer,
169
+ and charge a fee for, acceptance of support, warranty, indemnity,
170
+ or other liability obligations and/or rights consistent with this
171
+ License. However, in accepting such obligations, You may act only
172
+ on Your own behalf and on Your sole responsibility, not on behalf
173
+ of any other Contributor, and only if You agree to indemnify,
174
+ defend, and hold each Contributor harmless for any liability
175
+ incurred by, or claims asserted against, such Contributor by reason
176
+ of your accepting any such warranty or additional liability.
177
+
178
+ END OF TERMS AND CONDITIONS
179
+
180
+ APPENDIX: How to apply the Apache License to your work.
181
+
182
+ To apply the Apache License to your work, attach the following
183
+ boilerplate notice, with the fields enclosed by brackets "[]"
184
+ replaced with your own identifying information. (Don't include
185
+ the brackets!) The text should be enclosed in the appropriate
186
+ comment syntax for the file format. We also recommend that a
187
+ file or class name and description of purpose be included on the
188
+ same "printed page" as the copyright notice for easier
189
+ identification within third-party archives.
190
+
191
+ Copyright [yyyy] [name of copyright owner]
192
+
193
+ Licensed under the Apache License, Version 2.0 (the "License");
194
+ you may not use this file except in compliance with the License.
195
+ You may obtain a copy of the License at
196
+
197
+ http://www.apache.org/licenses/LICENSE-2.0
198
+
199
+ Unless required by applicable law or agreed to in writing, software
200
+ distributed under the License is distributed on an "AS IS" BASIS,
201
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202
+ See the License for the specific language governing permissions and
203
+ limitations under the License.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- //#region ../../plugin-api/dist/types-CzNsDcbd.d.ts
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 profile as defined by the user (decoded JSON blobs). */
31
- interface ProfileDefinition {
32
- /** Human-friendly profile name */
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 profile's config sources apply (isolation) */
42
+ /** If true, only this preset's config sources apply (isolation) */
43
43
  configIsolation: boolean;
44
- /** If true, new subshells from this profile auto-restart on exit */
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 profile. */
48
- interface ProfileValidationIssue {
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 ProfileValidationResult {
54
+ interface PresetValidationResult {
55
55
  valid: boolean;
56
- issues: ProfileValidationIssue[];
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 profile being used */
65
- profile: ProfileDefinition;
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 */
@@ -88,6 +88,39 @@ interface BuildCommandInput {
88
88
  id: string;
89
89
  mode: "start" | "resume";
90
90
  };
91
+ /**
92
+ * How a harness hook re-enters the subshell binary on the PANE's machine, as
93
+ * the host resolved it for that machine: `{ command, args }` with the
94
+ * reporting subcommand already appended, so a plugin adds only its own verb
95
+ * words. Splice it into whatever hook mechanism the harness has.
96
+ *
97
+ * A hook runs where the pane runs, and the only program guaranteed to exist
98
+ * there is the binary that launched the pane — which is why this arrives
99
+ * from the host rather than being a command a plugin writes for itself. The
100
+ * hooks here were once `bun -e '<inlined JS>'`, and every machine without a
101
+ * bun on its PATH (i.e. most of them) opened its harness on
102
+ * `bun: command not found`.
103
+ *
104
+ * Undefined means the host could not resolve one. OMIT the hooks then: a
105
+ * command the pane cannot run costs the same signal and adds an error to
106
+ * every session.
107
+ */
108
+ reporter?: ReporterSpec;
109
+ }
110
+ /**
111
+ * A command prefix that re-enters the subshell binary on a pane's machine,
112
+ * ready for a plugin's own verb words to be appended.
113
+ *
114
+ * Shaped like {@link McpLaunchSpec} and resolved from the same host question
115
+ * ("am I a compiled binary, or is `bun` running my entry script?"), but kept
116
+ * separate because they carry different subcommands and the MCP one is
117
+ * operator-overridable while this one is not.
118
+ */
119
+ interface ReporterSpec {
120
+ /** Executable to run (the binary itself, or the interpreter running it). */
121
+ command: string;
122
+ /** Everything before the plugin's verb words (any entry script, then the subcommand). */
123
+ args: string[];
91
124
  }
92
125
  /**
93
126
  * Restart-resume, implemented only by plugins that can continue a previous
@@ -136,12 +169,12 @@ interface McpRegistration {
136
169
  args?: string[];
137
170
  /**
138
171
  * Extra pane env the harness needs to discover the file (e.g. OPENCODE_CONFIG).
139
- * Consumed by the HOST, which bakes it into the pane env ahead of profile env;
172
+ * Consumed by the HOST, which bakes it into the pane env ahead of preset env;
140
173
  * plugins never read it back.
141
174
  */
142
175
  env?: Record<string, string>;
143
176
  }
144
- /** One copy-paste line shown in the profile editor for manual-setup harnesses. */
177
+ /** One copy-paste line shown in the preset editor for manual-setup harnesses. */
145
178
  interface McpSetupStep {
146
179
  /** What the user should do, and where the text goes */
147
180
  label: string;
@@ -226,8 +259,8 @@ interface PluginHost {
226
259
  interface SubshellPlugin {
227
260
  /** Builds the argv (no shell) used to launch a subshell. */
228
261
  buildCommand(input: BuildCommandInput): string[];
229
- /** Validates a profile definition before saving. */
230
- validateProfile(profile: ProfileDefinition): ProfileValidationResult;
262
+ /** Validates a preset definition before saving. */
263
+ validatePreset(preset: PresetDefinition): PresetValidationResult;
231
264
  /** Which optional members below are meaningful on this plugin. */
232
265
  capabilities(): PluginCapability[];
233
266
  /** Maps a harness exit code to a human label (null = unknown). */
@@ -259,14 +292,14 @@ interface SubshellPlugin {
259
292
  mcpRegistration?(launch: McpLaunchSpec, configPath: string): McpRegistration;
260
293
  /** How users obtain the subshell MCP tools here. Declare the `mcp` capability with it. */
261
294
  mcpSetup?(launch: McpLaunchSpec): McpSetupInfo;
262
- /** Settings rendered in the PROFILE editor and stored on the profile. */
263
- profileSettings?(): SettingsField[];
264
- /** Known extra env var suggestions for the profile editor. */
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. */
265
298
  suggestedEnv?(): {
266
299
  key: string;
267
300
  description: string;
268
301
  }[];
269
- /** Known CLI flag suggestions for the profile editor. */
302
+ /** Known CLI flag suggestions for the preset editor. */
270
303
  suggestedFlags?(): {
271
304
  flag: string;
272
305
  description: string;
@@ -304,7 +337,11 @@ interface SubshellManifest {
304
337
  name: string;
305
338
  /** One-line description shown in the UI */
306
339
  description: string;
307
- /** Optional emoji/glyph */
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
+ */
308
345
  icon?: string;
309
346
  /** Module to import, relative to the package directory */
310
347
  entry: string;
@@ -333,7 +370,7 @@ declare const manifest: SubshellManifest;
333
370
  *
334
371
  * Launch shape:
335
372
  * codex [-m <model>] [-s <sandbox>] [-a <approval>] [mcp -c pairs]
336
- * [profile flags] [extra flags]
373
+ * [preset flags] [extra flags]
337
374
  * A bare launch (no subcommand, no prompt) opens the interactive TUI. Codex
338
375
  * has no create-time flag for naming its own session and no way to pin a
339
376
  * conversation id, so neither the subshell name nor a resume capability is
@@ -341,7 +378,7 @@ declare const manifest: SubshellManifest;
341
378
  * The pane's
342
379
  * cwd is already the working directory, so `-C/--cd` is never passed, and
343
380
  * `--dangerously-bypass-approvals-and-sandbox` is NEVER baked into a launch
344
- * (a user may put it in their own profile flags — that is their call).
381
+ * (a user may put it in their own preset flags — that is their call).
345
382
  *
346
383
  * subshell MCP is wired automatically WITHOUT touching user state: every
347
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-UFScnYqn.js
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 1` };
35
- if (block.apiVersion > 1) return { error: `this plugin needs plugin-api ${block.apiVersion}, but this host implements 1; upgrade the agent` };
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 && typeof block.icon !== "string") return { error: "`subshell.icon` must be a string" };
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 profile checks every built-in harness performs unchanged: a non-empty
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 profile - The decoded profile definition to check
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 validateGenericProfile(profile) {
105
+ function validateGenericPreset(preset) {
90
106
  const issues = [];
91
- if (!profile.name || profile.name.trim().length === 0) issues.push({
107
+ if (!preset.name || preset.name.trim().length === 0) issues.push({
92
108
  field: "name",
93
- message: "Profile name is required."
109
+ message: "Preset name is required."
94
110
  });
95
- for (const [key, value] of Object.entries(profile.env)) if (typeof value !== "string") issues.push({
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 profile.flags) if (!flag.startsWith("-")) issues.push({
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.1.0",
137
+ version: "0.2.0",
122
138
  license: "Apache-2.0",
123
139
  type: "module",
124
140
  main: "dist/index.js",
@@ -127,6 +143,13 @@ const parsed = parseManifest({
127
143
  "import": "./dist/index.js"
128
144
  } },
129
145
  types: "dist/index.d.ts",
146
+ homepage: "https://subshell.sh",
147
+ repository: {
148
+ "type": "git",
149
+ "url": "git+https://github.com/subshell-ai/subshell.git",
150
+ "directory": "packages/plugins/codex"
151
+ },
152
+ bugs: { "url": "https://github.com/subshell-ai/subshell/issues" },
130
153
  scripts: {
131
154
  "build": "tsdown",
132
155
  "build:dev": "hash-runner",
@@ -145,15 +168,15 @@ const parsed = parseManifest({
145
168
  "tsdown": "0.22.14",
146
169
  "typescript": "7.0.2"
147
170
  },
148
- files: ["dist"],
171
+ files: ["dist", "icon.svg"],
149
172
  publishConfig: { "access": "public" },
150
173
  subshell: {
151
- "apiVersion": 1,
174
+ "apiVersion": 2,
152
175
  "id": "codex",
153
176
  "type": "agent-harness",
154
177
  "name": "Codex",
155
178
  "description": "OpenAI's agentic coding CLI (interactive TUI)",
156
- "icon": "📖",
179
+ "icon": "icon.svg",
157
180
  "entry": "dist/index.js",
158
181
  "detect": {
159
182
  "binaryName": "codex",
@@ -232,7 +255,7 @@ function tomlStringArray(values) {
232
255
  *
233
256
  * Launch shape:
234
257
  * codex [-m <model>] [-s <sandbox>] [-a <approval>] [mcp -c pairs]
235
- * [profile flags] [extra flags]
258
+ * [preset flags] [extra flags]
236
259
  * A bare launch (no subcommand, no prompt) opens the interactive TUI. Codex
237
260
  * has no create-time flag for naming its own session and no way to pin a
238
261
  * conversation id, so neither the subshell name nor a resume capability is
@@ -240,7 +263,7 @@ function tomlStringArray(values) {
240
263
  * The pane's
241
264
  * cwd is already the working directory, so `-C/--cd` is never passed, and
242
265
  * `--dangerously-bypass-approvals-and-sandbox` is NEVER baked into a launch
243
- * (a user may put it in their own profile flags — that is their call).
266
+ * (a user may put it in their own preset flags — that is their call).
244
267
  *
245
268
  * subshell MCP is wired automatically WITHOUT touching user state: every
246
269
  * launch carries `-c mcp_servers.subshell.command=… -c mcp_servers.subshell.args=…`
@@ -261,14 +284,14 @@ function tomlStringArray(values) {
261
284
  const createPlugin = (_host) => ({
262
285
  capabilities: () => ["mcp", "settings"],
263
286
  buildCommand(input) {
264
- const { binary, profile, extraFlags, mcp } = input;
287
+ const { binary, preset, extraFlags, mcp } = input;
265
288
  const args = [binary];
266
- const s = profile.settings ?? {};
289
+ const s = preset.settings ?? {};
267
290
  if (typeof s.model === "string" && s.model) args.push("-m", s.model);
268
291
  if (typeof s.sandbox === "string" && s.sandbox) args.push("-s", s.sandbox);
269
292
  if (typeof s.askForApproval === "string" && s.askForApproval) args.push("-a", s.askForApproval);
270
293
  if (mcp?.args) args.push(...mcp.args);
271
- for (const flag of profile.flags) args.push(flag);
294
+ for (const flag of preset.flags) args.push(flag);
272
295
  if (extraFlags) args.push(...extraFlags);
273
296
  return args;
274
297
  },
@@ -310,10 +333,10 @@ const createPlugin = (_host) => ({
310
333
  summary: "Subshell registers itself with every Codex subshell automatically (per-invocation -c mcp_servers.subshell.* overrides; your ~/.codex config is never modified)."
311
334
  };
312
335
  },
313
- validateProfile(profile) {
314
- return validateGenericProfile(profile);
336
+ validatePreset(preset) {
337
+ return validateGenericPreset(preset);
315
338
  },
316
- profileSettings() {
339
+ presetSettings() {
317
340
  return CODEX_SETTINGS_FIELDS;
318
341
  },
319
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.1.0",
4
+ "version": "0.2.0",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -12,6 +12,15 @@
12
12
  }
13
13
  },
14
14
  "types": "dist/index.d.ts",
15
+ "homepage": "https://subshell.sh",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/subshell-ai/subshell.git",
19
+ "directory": "packages/plugins/codex"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/subshell-ai/subshell/issues"
23
+ },
15
24
  "scripts": {
16
25
  "build": "tsdown",
17
26
  "build:dev": "hash-runner",
@@ -30,19 +39,17 @@
30
39
  "tsdown": "0.22.14",
31
40
  "typescript": "7.0.2"
32
41
  },
33
- "files": [
34
- "dist"
35
- ],
42
+ "files": ["dist", "icon.svg"],
36
43
  "publishConfig": {
37
44
  "access": "public"
38
45
  },
39
46
  "subshell": {
40
- "apiVersion": 1,
47
+ "apiVersion": 2,
41
48
  "id": "codex",
42
49
  "type": "agent-harness",
43
50
  "name": "Codex",
44
51
  "description": "OpenAI's agentic coding CLI (interactive TUI)",
45
- "icon": "\ud83d\udcd6",
52
+ "icon": "icon.svg",
46
53
  "entry": "dist/index.js",
47
54
  "detect": {
48
55
  "binaryName": "codex",