@cjhyy/code-shell-core 0.5.0-rc.1 → 0.5.0-rc.2

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.
Files changed (278) hide show
  1. package/dist/agent/agent-definition-registry.d.ts +18 -3
  2. package/dist/agent/agent-definition-registry.js +47 -18
  3. package/dist/agent/agent-definition.d.ts +17 -0
  4. package/dist/agent/agent-definition.js +22 -1
  5. package/dist/arena/arena.js +11 -12
  6. package/dist/arena/context/context-tools.js +2 -4
  7. package/dist/arena/context/within-root.d.ts +7 -0
  8. package/dist/arena/context/within-root.js +15 -0
  9. package/dist/arena/iterate/phases/argue.js +8 -2
  10. package/dist/arena/iterate/phases/revise.js +1 -1
  11. package/dist/arena/iterate/phases/tournament.js +3 -3
  12. package/dist/arena/phases/adjudication.js +1 -4
  13. package/dist/arena/phases/build-consensus.js +1 -4
  14. package/dist/arena/phases/cross-review.js +2 -8
  15. package/dist/arena/phases/debate-rounds.js +1 -4
  16. package/dist/arena/phases/participant-research.js +1 -4
  17. package/dist/arena/phases/planning-detail-expansion.js +8 -10
  18. package/dist/arena/planner.js +0 -1
  19. package/dist/arena/providers/docs.d.ts +1 -0
  20. package/dist/arena/providers/docs.js +5 -2
  21. package/dist/arena/providers/repo.d.ts +1 -0
  22. package/dist/arena/providers/repo.js +5 -2
  23. package/dist/arena/strategies/utils.js +36 -3
  24. package/dist/arena/transitions.d.ts +7 -2
  25. package/dist/arena/transitions.js +9 -4
  26. package/dist/arena/types.d.ts +8 -2
  27. package/dist/automation/cron-expr.d.ts +31 -0
  28. package/dist/automation/cron-expr.js +151 -0
  29. package/dist/automation/index.d.ts +41 -0
  30. package/dist/automation/index.js +39 -0
  31. package/dist/automation/runner.d.ts +67 -0
  32. package/dist/automation/runner.js +56 -0
  33. package/dist/automation/scheduler.d.ts +156 -0
  34. package/dist/automation/scheduler.js +546 -0
  35. package/dist/automation/store.d.ts +39 -0
  36. package/dist/automation/store.js +119 -0
  37. package/dist/automation/write-policy.d.ts +34 -0
  38. package/dist/automation/write-policy.js +113 -0
  39. package/dist/automation/write-run.d.ts +51 -0
  40. package/dist/automation/write-run.js +38 -0
  41. package/dist/capability-control/index.d.ts +5 -0
  42. package/dist/capability-control/index.js +3 -0
  43. package/dist/capability-control/overlay.d.ts +49 -0
  44. package/dist/capability-control/overlay.js +89 -0
  45. package/dist/capability-control/project.d.ts +65 -0
  46. package/dist/capability-control/project.js +147 -0
  47. package/dist/capability-control/service.d.ts +70 -0
  48. package/dist/capability-control/service.js +147 -0
  49. package/dist/capability-control/types.d.ts +62 -0
  50. package/dist/capability-control/types.js +17 -0
  51. package/dist/cli/agent-server-stdio.d.ts +12 -1
  52. package/dist/cli/agent-server-stdio.js +114 -19
  53. package/dist/cli/agent-server-tcp.d.ts +20 -0
  54. package/dist/cli/agent-server-tcp.js +120 -0
  55. package/dist/cli/graceful-shutdown.d.ts +27 -0
  56. package/dist/cli/graceful-shutdown.js +30 -0
  57. package/dist/context/compaction.js +23 -15
  58. package/dist/context/manager.d.ts +0 -20
  59. package/dist/context/manager.js +0 -37
  60. package/dist/cron/cron-runtime.d.ts +2 -0
  61. package/dist/cron/cron-runtime.js +2 -0
  62. package/dist/cron/cron-store.d.ts +2 -0
  63. package/dist/cron/cron-store.js +2 -0
  64. package/dist/cron/scheduler.d.ts +5 -32
  65. package/dist/cron/scheduler.js +5 -113
  66. package/dist/data/openrouter-sync.js +1 -1
  67. package/dist/engine/engine.d.ts +208 -14
  68. package/dist/engine/engine.js +754 -169
  69. package/dist/engine/goal.d.ts +42 -0
  70. package/dist/engine/goal.js +52 -0
  71. package/dist/engine/image-compression.d.ts +81 -0
  72. package/dist/engine/image-compression.js +186 -0
  73. package/dist/engine/image-policy.d.ts +152 -0
  74. package/dist/engine/image-policy.js +165 -0
  75. package/dist/engine/reactive-threshold.d.ts +13 -0
  76. package/dist/engine/reactive-threshold.js +17 -0
  77. package/dist/engine/runtime.js +7 -0
  78. package/dist/engine/session-title.d.ts +13 -0
  79. package/dist/engine/session-title.js +34 -0
  80. package/dist/engine/turn-loop.d.ts +29 -8
  81. package/dist/engine/turn-loop.js +498 -316
  82. package/dist/git/parse-log.d.ts +13 -0
  83. package/dist/git/parse-log.js +21 -0
  84. package/dist/git/utils.d.ts +8 -6
  85. package/dist/git/utils.js +57 -26
  86. package/dist/git/worktree.js +33 -18
  87. package/dist/hooks/events.d.ts +23 -1
  88. package/dist/hooks/goal-stop-hook.d.ts +30 -0
  89. package/dist/hooks/goal-stop-hook.js +102 -0
  90. package/dist/hooks/hook-output.d.ts +33 -0
  91. package/dist/hooks/hook-output.js +79 -0
  92. package/dist/hooks/registry.d.ts +7 -0
  93. package/dist/hooks/registry.js +38 -1
  94. package/dist/hooks/shell-runner.d.ts +2 -0
  95. package/dist/hooks/shell-runner.js +43 -2
  96. package/dist/index.d.ts +31 -6
  97. package/dist/index.js +30 -3
  98. package/dist/llm/capabilities/reasoning-control.d.ts +24 -0
  99. package/dist/llm/capabilities/reasoning-control.js +38 -0
  100. package/dist/llm/capabilities/rules.js +33 -3
  101. package/dist/llm/capabilities/types.d.ts +22 -2
  102. package/dist/llm/clamp-max-tokens.d.ts +11 -0
  103. package/dist/llm/clamp-max-tokens.js +17 -0
  104. package/dist/llm/client-base.d.ts +41 -4
  105. package/dist/llm/client-base.js +67 -13
  106. package/dist/llm/client-factory.d.ts +3 -3
  107. package/dist/llm/client-factory.js +2 -2
  108. package/dist/llm/model-pool.d.ts +15 -11
  109. package/dist/llm/model-pool.js +23 -20
  110. package/dist/llm/provider-catalog.d.ts +2 -2
  111. package/dist/llm/providers/anthropic.d.ts +32 -2
  112. package/dist/llm/providers/anthropic.js +147 -8
  113. package/dist/llm/providers/openai.d.ts +11 -2
  114. package/dist/llm/providers/openai.js +253 -52
  115. package/dist/llm/reasoning-setting.d.ts +51 -0
  116. package/dist/llm/reasoning-setting.js +32 -0
  117. package/dist/llm/stop-reason.d.ts +13 -0
  118. package/dist/llm/stop-reason.js +21 -0
  119. package/dist/llm/strip-vision.d.ts +32 -0
  120. package/dist/llm/strip-vision.js +94 -0
  121. package/dist/llm/types.d.ts +5 -6
  122. package/dist/logging/logger.js +18 -4
  123. package/dist/logging/sanitize-messages.d.ts +10 -0
  124. package/dist/logging/sanitize-messages.js +90 -0
  125. package/dist/lsp/client.js +28 -8
  126. package/dist/lsp/manager.js +2 -1
  127. package/dist/lsp/root-path.d.ts +9 -0
  128. package/dist/lsp/root-path.js +12 -0
  129. package/dist/onboarding.js +18 -11
  130. package/dist/plugins/gitOps.d.ts +34 -0
  131. package/dist/plugins/gitOps.js +59 -3
  132. package/dist/plugins/installer/codex/convertAgents.d.ts +7 -0
  133. package/dist/plugins/installer/codex/convertAgents.js +55 -0
  134. package/dist/plugins/installer/codex/convertMcp.d.ts +8 -0
  135. package/dist/plugins/installer/codex/convertMcp.js +45 -0
  136. package/dist/plugins/installer/codex/convertSkills.d.ts +12 -0
  137. package/dist/plugins/installer/codex/convertSkills.js +33 -0
  138. package/dist/plugins/installer/detectFormat.d.ts +2 -0
  139. package/dist/plugins/installer/detectFormat.js +6 -0
  140. package/dist/plugins/installer/install.d.ts +7 -0
  141. package/dist/plugins/installer/install.js +99 -0
  142. package/dist/plugins/installer/installFromSource.d.ts +13 -0
  143. package/dist/plugins/installer/installFromSource.js +45 -0
  144. package/dist/plugins/installer/list.d.ts +9 -0
  145. package/dist/plugins/installer/list.js +30 -0
  146. package/dist/plugins/installer/loadPluginAgents.d.ts +3 -0
  147. package/dist/plugins/installer/loadPluginAgents.js +23 -0
  148. package/dist/plugins/installer/loadPluginMcp.d.ts +7 -0
  149. package/dist/plugins/installer/loadPluginMcp.js +74 -0
  150. package/dist/plugins/installer/parseSource.d.ts +20 -0
  151. package/dist/plugins/installer/parseSource.js +74 -0
  152. package/dist/plugins/installer/paths.d.ts +5 -0
  153. package/dist/plugins/installer/paths.js +25 -0
  154. package/dist/plugins/installer/types.d.ts +49 -0
  155. package/dist/plugins/installer/types.js +27 -0
  156. package/dist/plugins/installer/uninstall.d.ts +2 -0
  157. package/dist/plugins/installer/uninstall.js +14 -0
  158. package/dist/plugins/installer/update.d.ts +14 -0
  159. package/dist/plugins/installer/update.js +65 -0
  160. package/dist/plugins/loadPluginHooks.d.ts +8 -1
  161. package/dist/plugins/loadPluginHooks.js +11 -1
  162. package/dist/plugins/marketplaceManager.d.ts +8 -1
  163. package/dist/plugins/marketplaceManager.js +38 -4
  164. package/dist/plugins/pluginCommandHook.js +34 -0
  165. package/dist/plugins/pluginInstaller.d.ts +21 -0
  166. package/dist/plugins/pluginInstaller.js +128 -29
  167. package/dist/plugins/schemas.js +40 -6
  168. package/dist/plugins/types.d.ts +4 -0
  169. package/dist/preset/index.js +16 -0
  170. package/dist/prompt/composer.d.ts +4 -0
  171. package/dist/prompt/composer.js +28 -4
  172. package/dist/prompt/sections/orchestration.md +8 -0
  173. package/dist/protocol/chat-session-manager.d.ts +8 -1
  174. package/dist/protocol/chat-session-manager.js +10 -0
  175. package/dist/protocol/chat-session.d.ts +17 -0
  176. package/dist/protocol/chat-session.js +28 -0
  177. package/dist/protocol/redact.d.ts +50 -0
  178. package/dist/protocol/redact.js +71 -0
  179. package/dist/protocol/server.d.ts +41 -2
  180. package/dist/protocol/server.js +231 -33
  181. package/dist/protocol/tcp-transport.d.ts +45 -0
  182. package/dist/protocol/tcp-transport.js +74 -0
  183. package/dist/protocol/types.d.ts +23 -0
  184. package/dist/protocol/types.js +6 -0
  185. package/dist/remote/bridge.d.ts +11 -2
  186. package/dist/remote/bridge.js +61 -33
  187. package/dist/run/ArtifactTracker.js +5 -4
  188. package/dist/run/EngineRunner.d.ts +27 -1
  189. package/dist/run/EngineRunner.js +46 -8
  190. package/dist/run/FileRunStore.js +32 -8
  191. package/dist/run/RunLock.d.ts +28 -2
  192. package/dist/run/RunLock.js +49 -7
  193. package/dist/run/RunManager.js +51 -3
  194. package/dist/run/RunQueue.d.ts +1 -0
  195. package/dist/run/RunQueue.js +8 -2
  196. package/dist/run/factory.d.ts +7 -0
  197. package/dist/run/factory.js +1 -0
  198. package/dist/run/index.d.ts +2 -2
  199. package/dist/run/index.js +1 -1
  200. package/dist/run/redirect-target.d.ts +7 -0
  201. package/dist/run/redirect-target.js +13 -0
  202. package/dist/run/types.js +1 -1
  203. package/dist/services/browser-open.d.ts +13 -0
  204. package/dist/services/browser-open.js +16 -0
  205. package/dist/services/dream-consolidation.d.ts +57 -0
  206. package/dist/services/dream-consolidation.js +151 -0
  207. package/dist/services/memory-orchestrator.js +18 -0
  208. package/dist/services/notifier.d.ts +8 -0
  209. package/dist/services/notifier.js +39 -25
  210. package/dist/services/oauth.js +5 -7
  211. package/dist/services/session-memory-sort.d.ts +8 -0
  212. package/dist/services/session-memory-sort.js +9 -0
  213. package/dist/services/session-memory.js +8 -9
  214. package/dist/session/file-history.js +10 -3
  215. package/dist/session/session-manager.d.ts +23 -1
  216. package/dist/session/session-manager.js +73 -2
  217. package/dist/settings/disk-defaults.d.ts +35 -0
  218. package/dist/settings/disk-defaults.js +24 -0
  219. package/dist/settings/manager.d.ts +33 -0
  220. package/dist/settings/manager.js +94 -1
  221. package/dist/settings/personalization.d.ts +19 -0
  222. package/dist/settings/personalization.js +7 -0
  223. package/dist/settings/schema.d.ts +1142 -126
  224. package/dist/settings/schema.js +119 -10
  225. package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
  226. package/dist/tool-system/builtin/add-marketplace.js +76 -0
  227. package/dist/tool-system/builtin/agent-registry.d.ts +11 -0
  228. package/dist/tool-system/builtin/agent-registry.js +8 -4
  229. package/dist/tool-system/builtin/agent.d.ts +29 -10
  230. package/dist/tool-system/builtin/agent.js +108 -52
  231. package/dist/tool-system/builtin/apply-patch/index.js +22 -3
  232. package/dist/tool-system/builtin/arena.js +6 -7
  233. package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
  234. package/dist/tool-system/builtin/complete-goal.js +45 -0
  235. package/dist/tool-system/builtin/cron.js +53 -9
  236. package/dist/tool-system/builtin/edit.d.ts +2 -1
  237. package/dist/tool-system/builtin/edit.js +6 -1
  238. package/dist/tool-system/builtin/generate-image.d.ts +25 -0
  239. package/dist/tool-system/builtin/generate-image.js +146 -0
  240. package/dist/tool-system/builtin/glob.js +7 -0
  241. package/dist/tool-system/builtin/grep.js +6 -0
  242. package/dist/tool-system/builtin/index.d.ts +18 -1
  243. package/dist/tool-system/builtin/index.js +62 -1
  244. package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
  245. package/dist/tool-system/builtin/notebook-edit.js +8 -1
  246. package/dist/tool-system/builtin/read.d.ts +2 -1
  247. package/dist/tool-system/builtin/read.js +9 -1
  248. package/dist/tool-system/builtin/sleep.js +9 -3
  249. package/dist/tool-system/builtin/task.js +4 -1
  250. package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
  251. package/dist/tool-system/builtin/update-automation-memory.js +60 -0
  252. package/dist/tool-system/builtin/view-image.d.ts +18 -0
  253. package/dist/tool-system/builtin/view-image.js +96 -0
  254. package/dist/tool-system/builtin/web-search.d.ts +4 -1
  255. package/dist/tool-system/builtin/web-search.js +36 -3
  256. package/dist/tool-system/builtin/write.d.ts +2 -1
  257. package/dist/tool-system/builtin/write.js +7 -1
  258. package/dist/tool-system/context.d.ts +12 -0
  259. package/dist/tool-system/executor.d.ts +0 -1
  260. package/dist/tool-system/executor.js +34 -40
  261. package/dist/tool-system/investigation-guard.d.ts +4 -1
  262. package/dist/tool-system/investigation-guard.js +19 -3
  263. package/dist/tool-system/mcp-manager.d.ts +36 -12
  264. package/dist/tool-system/mcp-manager.js +173 -10
  265. package/dist/tool-system/path-policy.d.ts +94 -0
  266. package/dist/tool-system/path-policy.js +279 -0
  267. package/dist/tool-system/permission.js +43 -50
  268. package/dist/tool-system/plan-mode-allowlist.d.ts +21 -0
  269. package/dist/tool-system/plan-mode-allowlist.js +43 -0
  270. package/dist/tool-system/registry.js +12 -1
  271. package/dist/tool-system/validation.d.ts +10 -0
  272. package/dist/tool-system/validation.js +16 -3
  273. package/dist/types.d.ts +90 -15
  274. package/dist/utils/format.js +4 -2
  275. package/dist/utils/lockfile.js +9 -2
  276. package/dist/utils/theme.d.ts +6 -0
  277. package/dist/utils/theme.js +4 -2
  278. package/package.json +2 -1
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ /** Codex `.codex-plugin/plugin.json`. v1 reads required fields; unknowns pass through. */
3
+ export declare const CodexPluginManifest: z.ZodObject<{
4
+ name: z.ZodString;
5
+ version: z.ZodString;
6
+ description: z.ZodOptional<z.ZodString>;
7
+ mcpServers: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodAny>]>>;
8
+ skills: z.ZodOptional<z.ZodString>;
9
+ agents: z.ZodOptional<z.ZodString>;
10
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
11
+ name: z.ZodString;
12
+ version: z.ZodString;
13
+ description: z.ZodOptional<z.ZodString>;
14
+ mcpServers: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodAny>]>>;
15
+ skills: z.ZodOptional<z.ZodString>;
16
+ agents: z.ZodOptional<z.ZodString>;
17
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
18
+ name: z.ZodString;
19
+ version: z.ZodString;
20
+ description: z.ZodOptional<z.ZodString>;
21
+ mcpServers: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodAny>]>>;
22
+ skills: z.ZodOptional<z.ZodString>;
23
+ agents: z.ZodOptional<z.ZodString>;
24
+ }, z.ZodTypeAny, "passthrough">>;
25
+ export type CodexPluginManifest = z.infer<typeof CodexPluginManifest>;
26
+ /** `.cs-meta.json` written into every installed plugin dir. */
27
+ export declare const CSMeta: z.ZodObject<{
28
+ name: z.ZodString;
29
+ format: z.ZodEnum<["cc", "codex"]>;
30
+ version: z.ZodOptional<z.ZodString>;
31
+ source: z.ZodString;
32
+ installedAt: z.ZodString;
33
+ }, "strip", z.ZodTypeAny, {
34
+ source: string;
35
+ name: string;
36
+ format: "codex" | "cc";
37
+ installedAt: string;
38
+ version?: string | undefined;
39
+ }, {
40
+ source: string;
41
+ name: string;
42
+ format: "codex" | "cc";
43
+ installedAt: string;
44
+ version?: string | undefined;
45
+ }>;
46
+ export type CSMeta = z.infer<typeof CSMeta>;
47
+ export declare class PluginInstallError extends Error {
48
+ constructor(message: string);
49
+ }
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ /** Codex `.codex-plugin/plugin.json`. v1 reads required fields; unknowns pass through. */
3
+ export const CodexPluginManifest = z
4
+ .object({
5
+ name: z.string(),
6
+ version: z.string(),
7
+ description: z.string().optional(),
8
+ // string → relative path to a .mcp.json; object → inline mcpServers map
9
+ mcpServers: z.union([z.string(), z.record(z.any())]).optional(),
10
+ skills: z.string().optional(),
11
+ agents: z.string().optional(),
12
+ })
13
+ .passthrough();
14
+ /** `.cs-meta.json` written into every installed plugin dir. */
15
+ export const CSMeta = z.object({
16
+ name: z.string(),
17
+ format: z.enum(["cc", "codex"]),
18
+ version: z.string().optional(),
19
+ source: z.string(),
20
+ installedAt: z.string(),
21
+ });
22
+ export class PluginInstallError extends Error {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = "PluginInstallError";
26
+ }
27
+ }
@@ -0,0 +1,2 @@
1
+ /** Remove a locally-installed plugin dir + its installed_plugins.json entry. */
2
+ export declare function uninstallPluginByName(name: string): void;
@@ -0,0 +1,14 @@
1
+ import { existsSync, rmSync } from "node:fs";
2
+ import { pluginInstallDir, assertSafePluginName } from "./paths.js";
3
+ import { removeInstallEntries, pluginInstallKey } from "../installedPlugins.js";
4
+ import { PluginInstallError } from "./types.js";
5
+ /** Remove a locally-installed plugin dir + its installed_plugins.json entry. */
6
+ export function uninstallPluginByName(name) {
7
+ assertSafePluginName(name);
8
+ const dir = pluginInstallDir(name);
9
+ if (!existsSync(dir)) {
10
+ throw new PluginInstallError(`no plugin named '${name}'`);
11
+ }
12
+ rmSync(dir, { recursive: true, force: true });
13
+ removeInstallEntries(pluginInstallKey(name, "local"));
14
+ }
@@ -0,0 +1,14 @@
1
+ export interface UpdateResult {
2
+ updated: boolean;
3
+ reason: string;
4
+ }
5
+ /**
6
+ * Reinstall a plugin from its recorded source.
7
+ *
8
+ * - Local source: reinstall when the source version changed, or when `force`.
9
+ * CC plugins have no version → only `force` updates them.
10
+ * - Remote (git) source: re-clone and reinstall every time — git sources carry
11
+ * no local version file to compare, so update is always a fresh pull
12
+ * (equivalent to `--force`; cheap and reliable). See spec §9.
13
+ */
14
+ export declare function updatePluginByName(name: string, installedAt: string, force: boolean): Promise<UpdateResult>;
@@ -0,0 +1,65 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { detectPluginFormat } from "./detectFormat.js";
4
+ import { pluginInstallDir } from "./paths.js";
5
+ import { uninstallPluginByName } from "./uninstall.js";
6
+ import { installPluginFromPath } from "./install.js";
7
+ import { installPluginFromSource } from "./installFromSource.js";
8
+ import { parseSource } from "./parseSource.js";
9
+ import { CodexPluginManifest, CSMeta, PluginInstallError } from "./types.js";
10
+ /**
11
+ * Reinstall a plugin from its recorded source.
12
+ *
13
+ * - Local source: reinstall when the source version changed, or when `force`.
14
+ * CC plugins have no version → only `force` updates them.
15
+ * - Remote (git) source: re-clone and reinstall every time — git sources carry
16
+ * no local version file to compare, so update is always a fresh pull
17
+ * (equivalent to `--force`; cheap and reliable). See spec §9.
18
+ */
19
+ export async function updatePluginByName(name, installedAt, force) {
20
+ const dir = pluginInstallDir(name);
21
+ const metaPath = join(dir, ".cs-meta.json");
22
+ if (!existsSync(metaPath))
23
+ throw new PluginInstallError(`no plugin named '${name}'`);
24
+ const meta = CSMeta.parse(JSON.parse(readFileSync(metaPath, "utf-8")));
25
+ const parsed = parseSource(meta.source);
26
+ if (parsed.kind === "remote") {
27
+ // No local version to diff against — always re-clone and reinstall.
28
+ // uninstall-then-install isn't atomic: if the reinstall fails (clone
29
+ // error, bad plugin) the old copy is already gone. We can't roll back the
30
+ // removal, but we surface a clear error instead of leaving silent
31
+ // inconsistency.
32
+ uninstallPluginByName(name);
33
+ try {
34
+ await installPluginFromSource(parsed, name, installedAt);
35
+ }
36
+ catch (err) {
37
+ throw new PluginInstallError(`update failed and '${name}' was removed during reinstall: ` +
38
+ `${err instanceof Error ? err.message : String(err)}. Reinstall it from ${meta.source}.`);
39
+ }
40
+ return { updated: true, reason: "reinstalled from git source" };
41
+ }
42
+ if (!existsSync(meta.source)) {
43
+ throw new PluginInstallError(`source no longer exists: ${meta.source}`);
44
+ }
45
+ if (!force) {
46
+ if (detectPluginFormat(meta.source) === "codex") {
47
+ const manifest = CodexPluginManifest.parse(JSON.parse(readFileSync(join(meta.source, ".codex-plugin", "plugin.json"), "utf-8")));
48
+ if (manifest.version === meta.version) {
49
+ return { updated: false, reason: "already up to date" };
50
+ }
51
+ }
52
+ else {
53
+ return { updated: false, reason: "CC plugin needs --force to reinstall" };
54
+ }
55
+ }
56
+ uninstallPluginByName(name);
57
+ try {
58
+ await installPluginFromPath(meta.source, name, installedAt);
59
+ }
60
+ catch (err) {
61
+ throw new PluginInstallError(`update failed and '${name}' was removed during reinstall: ` +
62
+ `${err instanceof Error ? err.message : String(err)}. Reinstall it from ${meta.source}.`);
63
+ }
64
+ return { updated: true, reason: "reinstalled" };
65
+ }
@@ -48,5 +48,12 @@ import type { HookRegistry } from "../hooks/registry.js";
48
48
  * multiple times — the caller is responsible for not double-registering
49
49
  * (HookRegistry has no de-dup; the engine constructor calls this exactly
50
50
  * once after creating the registry).
51
+ *
52
+ * `disabledPlugins` is the coarse "plugin total switch" — bare plugin names
53
+ * (no `@marketplace`, no `:` suffix), matching scanSkills' semantics. A
54
+ * disabled plugin contributes NO hooks, so e.g. disabling "superpowers"
55
+ * also suppresses its SessionStart injection — not just its Skill-tool
56
+ * entries. Without this, `disabledPlugins` only filtered the skill list and
57
+ * the plugin's hooks still fired regardless.
51
58
  */
52
- export declare function loadPluginHooks(registry: HookRegistry): void;
59
+ export declare function loadPluginHooks(registry: HookRegistry, disabledPlugins?: string[]): void;
@@ -114,10 +114,20 @@ function pluginNameFromKey(key) {
114
114
  * multiple times — the caller is responsible for not double-registering
115
115
  * (HookRegistry has no de-dup; the engine constructor calls this exactly
116
116
  * once after creating the registry).
117
+ *
118
+ * `disabledPlugins` is the coarse "plugin total switch" — bare plugin names
119
+ * (no `@marketplace`, no `:` suffix), matching scanSkills' semantics. A
120
+ * disabled plugin contributes NO hooks, so e.g. disabling "superpowers"
121
+ * also suppresses its SessionStart injection — not just its Skill-tool
122
+ * entries. Without this, `disabledPlugins` only filtered the skill list and
123
+ * the plugin's hooks still fired regardless.
117
124
  */
118
- export function loadPluginHooks(registry) {
125
+ export function loadPluginHooks(registry, disabledPlugins = []) {
119
126
  const data = readInstalledPlugins();
127
+ const disabledSet = new Set(disabledPlugins);
120
128
  for (const [key, entries] of Object.entries(data.plugins)) {
129
+ if (disabledSet.has(pluginNameFromKey(key)))
130
+ continue;
121
131
  for (const entry of entries) {
122
132
  const installPath = entry.installPath;
123
133
  if (!installPath || !existsSync(installPath))
@@ -5,9 +5,15 @@
5
5
  * at the MVP subset (github + git sources only, no auto-update,
6
6
  * no policy blocking, no GCS mirror).
7
7
  */
8
- import type { MarketplaceSource, PluginMarketplace } from "./types.js";
8
+ import type { MarketplaceFormat, MarketplaceSource, PluginMarketplace } from "./types.js";
9
+ export type { MarketplaceFormat } from "./types.js";
9
10
  export declare function marketplacesRoot(): string;
10
11
  export declare function marketplaceDir(name: string): string;
12
+ /**
13
+ * Classify a cloned marketplace by which manifest files it ships:
14
+ * both → universal, only .agents/plugins → codex, otherwise claude-code.
15
+ */
16
+ export declare function detectMarketplaceFormat(dir: string): MarketplaceFormat;
11
17
  export type AddMarketplaceResult = {
12
18
  ok: true;
13
19
  name: string;
@@ -40,6 +46,7 @@ export interface ListedMarketplace {
40
46
  installLocation: string;
41
47
  lastUpdated: string;
42
48
  pluginCount: number;
49
+ format: MarketplaceFormat;
43
50
  }
44
51
  /**
45
52
  * Lists all known marketplaces with a quick plugin count read from each
@@ -20,8 +20,39 @@ export function marketplacesRoot() {
20
20
  export function marketplaceDir(name) {
21
21
  return join(marketplacesRoot(), name);
22
22
  }
23
+ const CC_MANIFEST_REL = [".claude-plugin", "marketplace.json"];
24
+ const CODEX_MANIFEST_REL = [".agents", "plugins", "marketplace.json"];
25
+ /**
26
+ * Resolve the marketplace manifest inside a cloned repo. Claude Code's format
27
+ * lives at .claude-plugin/marketplace.json; the Codex / agents format lives at
28
+ * .agents/plugins/marketplace.json. Prefer the CC manifest when present (it is
29
+ * our canonical shape), else fall back to the Codex one. Returns null when
30
+ * neither exists.
31
+ */
32
+ function resolveManifestPath(dir) {
33
+ const cc = join(dir, ...CC_MANIFEST_REL);
34
+ if (existsSync(cc))
35
+ return cc;
36
+ const codex = join(dir, ...CODEX_MANIFEST_REL);
37
+ if (existsSync(codex))
38
+ return codex;
39
+ return null;
40
+ }
23
41
  function marketplaceJsonPath(name) {
24
- return join(marketplaceDir(name), ".claude-plugin", "marketplace.json");
42
+ return resolveManifestPath(marketplaceDir(name));
43
+ }
44
+ /**
45
+ * Classify a cloned marketplace by which manifest files it ships:
46
+ * both → universal, only .agents/plugins → codex, otherwise claude-code.
47
+ */
48
+ export function detectMarketplaceFormat(dir) {
49
+ const hasCc = existsSync(join(dir, ...CC_MANIFEST_REL));
50
+ const hasCodex = existsSync(join(dir, ...CODEX_MANIFEST_REL));
51
+ if (hasCc && hasCodex)
52
+ return "universal";
53
+ if (hasCodex)
54
+ return "codex";
55
+ return "claude-code";
25
56
  }
26
57
  function sourceToCloneUrl(source) {
27
58
  return source.source === "github" ? githubRepoToCloneUrl(source.repo) : source.url;
@@ -55,11 +86,11 @@ export async function addMarketplace(name, source) {
55
86
  }
56
87
  }
57
88
  const manifestPath = marketplaceJsonPath(name);
58
- if (!existsSync(manifestPath)) {
89
+ if (!manifestPath) {
59
90
  rmSync(dir, { recursive: true, force: true });
60
91
  return {
61
92
  ok: false,
62
- error: `Marketplace ${name}: .claude-plugin/marketplace.json not found in the cloned repository.`,
93
+ error: `Marketplace ${name}: no marketplace.json found (looked in .claude-plugin/ and .agents/plugins/).`,
63
94
  };
64
95
  }
65
96
  let raw;
@@ -82,6 +113,7 @@ export async function addMarketplace(name, source) {
82
113
  source,
83
114
  installLocation: dir,
84
115
  lastUpdated: new Date().toISOString(),
116
+ format: detectMarketplaceFormat(dir),
85
117
  };
86
118
  upsertKnownMarketplace(name, entry);
87
119
  return { ok: true, name, marketplace: v.value, replaced: Boolean(existing) };
@@ -108,7 +140,7 @@ export function loadMarketplace(name) {
108
140
  if (!known[name])
109
141
  return null;
110
142
  const manifestPath = marketplaceJsonPath(name);
111
- if (!existsSync(manifestPath))
143
+ if (!manifestPath)
112
144
  return null;
113
145
  let raw;
114
146
  try {
@@ -136,6 +168,8 @@ export function listMarketplaces() {
136
168
  installLocation: entry.installLocation,
137
169
  lastUpdated: entry.lastUpdated,
138
170
  pluginCount: mp ? mp.plugins.length : -1,
171
+ // Re-detect from disk when the stored entry predates the format field.
172
+ format: entry.format ?? detectMarketplaceFormat(entry.installLocation),
139
173
  });
140
174
  }
141
175
  return out.sort((a, b) => a.name.localeCompare(b.name));
@@ -31,6 +31,7 @@
31
31
  * branch — not the CC one.
32
32
  */
33
33
  import { spawn } from "node:child_process";
34
+ import { MAX_HOOK_OUTPUT_BYTES } from "../hooks/hook-output.js";
34
35
  const DEFAULT_TIMEOUT_MS = 60_000;
35
36
  /**
36
37
  * Extract the user-facing context string from a CC plugin's stdout JSON.
@@ -99,6 +100,13 @@ export async function runPluginCommandHook(spec, ctx) {
99
100
  let stdout = "";
100
101
  let stderr = "";
101
102
  let settled = false;
103
+ // Output byte caps mirror src/hooks/shell-runner.ts so a chatty plugin
104
+ // hook can't hold engine memory hostage. Past the cap we SIGTERM the
105
+ // child and treat the hook as failed; stderr cap truncates with a
106
+ // marker instead of failing the hook.
107
+ let stdoutBytes = 0;
108
+ let stdoutCapped = false;
109
+ let stderrCapped = false;
102
110
  const settle = (value) => {
103
111
  if (settled)
104
112
  return;
@@ -125,9 +133,29 @@ export async function runPluginCommandHook(spec, ctx) {
125
133
  settle({});
126
134
  }, timeoutMs);
127
135
  child.stdout?.on("data", (chunk) => {
136
+ stdoutBytes += chunk.length;
137
+ if (stdoutBytes > MAX_HOOK_OUTPUT_BYTES) {
138
+ if (!stdoutCapped) {
139
+ stdoutCapped = true;
140
+ // eslint-disable-next-line no-console
141
+ console.warn(`[plugin-hook] ${spec.pluginKey} ${ctx.eventName} stdout exceeded ${MAX_HOOK_OUTPUT_BYTES} bytes — killing`);
142
+ try {
143
+ child.kill("SIGTERM");
144
+ }
145
+ catch { /* already exited */ }
146
+ }
147
+ return;
148
+ }
128
149
  stdout += chunk.toString("utf8");
129
150
  });
130
151
  child.stderr?.on("data", (chunk) => {
152
+ if (stderr.length + chunk.length > MAX_HOOK_OUTPUT_BYTES) {
153
+ if (!stderrCapped) {
154
+ stderrCapped = true;
155
+ stderr += "\n…[stderr truncated]";
156
+ }
157
+ return;
158
+ }
131
159
  stderr += chunk.toString("utf8");
132
160
  });
133
161
  child.on("error", (err) => {
@@ -138,6 +166,12 @@ export async function runPluginCommandHook(spec, ctx) {
138
166
  });
139
167
  child.on("close", (code) => {
140
168
  clearTimeout(timer);
169
+ if (stdoutCapped) {
170
+ // eslint-disable-next-line no-console
171
+ console.error(`[plugin-hook] ${spec.pluginKey} ${ctx.eventName} killed due to oversized stdout (> ${MAX_HOOK_OUTPUT_BYTES} bytes)`);
172
+ settle({});
173
+ return;
174
+ }
141
175
  if (code !== 0) {
142
176
  // eslint-disable-next-line no-console
143
177
  console.warn(`[plugin-hook] ${spec.pluginKey} ${ctx.eventName} exited ${code}; stderr:`, stderr.slice(0, 500));
@@ -5,6 +5,17 @@
5
5
  * sparse-checkout, no npm/pip.
6
6
  */
7
7
  import type { PluginInstallEntry } from "./types.js";
8
+ /**
9
+ * Resolve a candidate `installPath` to a realpath and verify it lives strictly
10
+ * underneath the plugin cache root. Returns the resolved path on success, or
11
+ * null when the path is missing, escapes the cache, equals the cache root
12
+ * itself, or is otherwise unsafe to remove.
13
+ *
14
+ * Exported so tests can exercise the safety predicate directly without
15
+ * arranging a full uninstall — the contract this defends (no rmSync outside
16
+ * the plugin cache) is the entire point of T2 / Workstream A2.
17
+ */
18
+ export declare function resolveSafePluginPath(installPath: string, cacheRoot: string): string | null;
8
19
  export interface VarRewriteReport {
9
20
  filesScanned: number;
10
21
  filesRewritten: number;
@@ -18,6 +29,16 @@ export type InstallResult = {
18
29
  ok: false;
19
30
  error: string;
20
31
  };
32
+ /**
33
+ * Compare a marketplace-declared SHA against the cloned HEAD. The
34
+ * declaration is allowed to be a short prefix (>= 7 chars, standard git
35
+ * abbreviation length); for stricter integrity guarantees marketplaces
36
+ * should pin the full 40-char hash. Case-insensitive.
37
+ *
38
+ * Exported so a unit test can pin the policy without spinning up a real
39
+ * clone.
40
+ */
41
+ export declare function shaMatches(declared: string, actual: string): boolean;
21
42
  /**
22
43
  * Install a plugin from a previously-added marketplace into the user
23
44
  * cache. Idempotent within a process: re-installing replaces the