@gajae-code/coding-agent 0.16.7 → 0.17.1

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 (321) hide show
  1. package/CHANGELOG.md +180 -1
  2. package/dist/types/capability/fs.d.ts +37 -4
  3. package/dist/types/capability/index.d.ts +19 -0
  4. package/dist/types/capability/types.d.ts +9 -0
  5. package/dist/types/cli/doctor/args.d.ts +36 -0
  6. package/dist/types/cli/doctor/checks.d.ts +18 -0
  7. package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
  8. package/dist/types/cli/doctor/context.d.ts +89 -0
  9. package/dist/types/cli/doctor/files.d.ts +27 -0
  10. package/dist/types/cli/doctor/ids.d.ts +20 -0
  11. package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
  12. package/dist/types/cli/doctor/journal.d.ts +43 -0
  13. package/dist/types/cli/doctor/managed-link.d.ts +39 -0
  14. package/dist/types/cli/doctor/native-probe.d.ts +2 -0
  15. package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
  16. package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
  17. package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
  18. package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
  19. package/dist/types/cli/doctor/probe-client.d.ts +9 -0
  20. package/dist/types/cli/doctor/probe-types.d.ts +18 -0
  21. package/dist/types/cli/doctor/probe.d.ts +3 -0
  22. package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
  23. package/dist/types/cli/doctor/repairs.d.ts +28 -0
  24. package/dist/types/cli/doctor/report.d.ts +27 -0
  25. package/dist/types/cli/doctor/runner.d.ts +4 -0
  26. package/dist/types/cli/doctor/safety.d.ts +10 -0
  27. package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
  28. package/dist/types/cli/doctor/service-targets.d.ts +41 -0
  29. package/dist/types/cli/doctor/types.d.ts +145 -0
  30. package/dist/types/cli/doctor-cli.d.ts +7 -0
  31. package/dist/types/cli/doctor-supervisor.d.ts +121 -0
  32. package/dist/types/cli/doctor-worker.d.ts +29 -0
  33. package/dist/types/cli/install-activation.d.ts +158 -0
  34. package/dist/types/cli/macos-community-app.d.ts +41 -0
  35. package/dist/types/cli/mcp-cli.d.ts +0 -11
  36. package/dist/types/cli/update-cli.d.ts +41 -4
  37. package/dist/types/cli-main.d.ts +174 -0
  38. package/dist/types/cli.d.ts +1 -171
  39. package/dist/types/commands/doctor.d.ts +7 -0
  40. package/dist/types/commands/sdk.d.ts +17 -8
  41. package/dist/types/config/autorouting-tier-map.d.ts +19 -0
  42. package/dist/types/config/file-lock.d.ts +27 -3
  43. package/dist/types/config/model-preset-registry.d.ts +1 -0
  44. package/dist/types/config/model-registry.d.ts +12 -5
  45. package/dist/types/config/model-resolver.d.ts +16 -3
  46. package/dist/types/config/models-config-schema.d.ts +2 -0
  47. package/dist/types/config/settings-schema.d.ts +1 -1
  48. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
  49. package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
  50. package/dist/types/cursor.d.ts +9 -9
  51. package/dist/types/discovery/agents-md.d.ts +6 -1
  52. package/dist/types/discovery/helpers.d.ts +36 -7
  53. package/dist/types/discovery/index.d.ts +1 -1
  54. package/dist/types/discovery/mcp-json.d.ts +2 -0
  55. package/dist/types/extensibility/extensions/loader.d.ts +22 -1
  56. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
  57. package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
  58. package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
  59. package/dist/types/extensibility/plugins/manager.d.ts +33 -4
  60. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
  61. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
  62. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
  63. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
  64. package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
  65. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
  66. package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
  67. package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
  68. package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
  69. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
  70. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
  71. package/dist/types/main.d.ts +19 -1
  72. package/dist/types/modes/acp/acp-agent.d.ts +40 -0
  73. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  74. package/dist/types/modes/components/model-selector.d.ts +2 -0
  75. package/dist/types/modes/interactive-mode.d.ts +1 -1
  76. package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
  77. package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
  78. package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
  79. package/dist/types/runtime-mcp/types.d.ts +2 -2
  80. package/dist/types/sdk/acp/adapter.d.ts +5 -1
  81. package/dist/types/sdk/broker/broker.d.ts +51 -0
  82. package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
  83. package/dist/types/sdk/broker/discovery.d.ts +38 -0
  84. package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
  85. package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
  86. package/dist/types/sdk/broker/ensure.d.ts +14 -0
  87. package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
  88. package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
  89. package/dist/types/sdk/broker/runtime.d.ts +26 -0
  90. package/dist/types/sdk/broker/session-index.d.ts +13 -4
  91. package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
  95. package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
  96. package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
  97. package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
  98. package/dist/types/sdk/bus/index.d.ts +2 -0
  99. package/dist/types/sdk/bus/notification-service.d.ts +3 -0
  100. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
  101. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  102. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
  103. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
  104. package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
  105. package/dist/types/sdk/cli/session-cli.d.ts +1 -0
  106. package/dist/types/sdk/host/session-runtime.d.ts +4 -0
  107. package/dist/types/sdk/host/surface-policy.d.ts +3 -1
  108. package/dist/types/sdk/lifecycle/service.d.ts +44 -10
  109. package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
  110. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
  111. package/dist/types/sdk/prompt-failure.d.ts +47 -0
  112. package/dist/types/sdk/prompt-status.d.ts +19 -0
  113. package/dist/types/sdk/router/session-router.d.ts +3 -4
  114. package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
  115. package/dist/types/sdk/session-authority.d.ts +9 -0
  116. package/dist/types/sdk/session.d.ts +3 -1
  117. package/dist/types/session/agent-session.d.ts +1 -1
  118. package/dist/types/session/blob-store.d.ts +1 -1
  119. package/dist/types/session/fallback-chain-controller.d.ts +3 -6
  120. package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
  121. package/dist/types/session/primary-control-surface.d.ts +4 -0
  122. package/dist/types/session/session-manager.d.ts +6 -0
  123. package/dist/types/system-prompt.d.ts +6 -0
  124. package/dist/types/tools/ask.d.ts +25 -0
  125. package/dist/types/tools/image-gen.d.ts +0 -4
  126. package/dist/types/tools/skill-discovery.d.ts +7 -5
  127. package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
  128. package/dist/types/utils/changelog.d.ts +0 -9
  129. package/dist/types/utils/mupdf-wasm.d.ts +1 -0
  130. package/package.json +9 -8
  131. package/scripts/compile-args.ts +8 -4
  132. package/src/capability/fs.ts +395 -17
  133. package/src/capability/index.ts +273 -10
  134. package/src/capability/types.ts +9 -0
  135. package/src/cli/customize-doctor.ts +18 -12
  136. package/src/cli/doctor/args.ts +236 -0
  137. package/src/cli/doctor/checks.ts +431 -0
  138. package/src/cli/doctor/config-repairs.ts +517 -0
  139. package/src/cli/doctor/context.ts +149 -0
  140. package/src/cli/doctor/files.ts +149 -0
  141. package/src/cli/doctor/ids.ts +115 -0
  142. package/src/cli/doctor/install-repairs.ts +335 -0
  143. package/src/cli/doctor/journal.ts +423 -0
  144. package/src/cli/doctor/managed-link.ts +514 -0
  145. package/src/cli/doctor/native-probe.ts +13 -0
  146. package/src/cli/doctor/permission-repairs.ts +242 -0
  147. package/src/cli/doctor/plugin-quarantine.ts +377 -0
  148. package/src/cli/doctor/plugin-restore.ts +59 -0
  149. package/src/cli/doctor/plugin-targets.ts +373 -0
  150. package/src/cli/doctor/probe-client.ts +195 -0
  151. package/src/cli/doctor/probe-types.ts +21 -0
  152. package/src/cli/doctor/probe.ts +42 -0
  153. package/src/cli/doctor/projection-probe.ts +249 -0
  154. package/src/cli/doctor/repairs.ts +1157 -0
  155. package/src/cli/doctor/report.ts +176 -0
  156. package/src/cli/doctor/runner.ts +342 -0
  157. package/src/cli/doctor/safety.ts +40 -0
  158. package/src/cli/doctor/service-repairs.ts +452 -0
  159. package/src/cli/doctor/service-targets.ts +274 -0
  160. package/src/cli/doctor/types.ts +164 -0
  161. package/src/cli/doctor-cli.ts +62 -0
  162. package/src/cli/doctor-supervisor.ts +571 -0
  163. package/src/cli/doctor-worker.ts +181 -0
  164. package/src/cli/install-activation.ts +666 -0
  165. package/src/cli/macos-community-app.ts +1449 -0
  166. package/src/cli/mcp-cli.ts +11 -21
  167. package/src/cli/nofile-limit.ts +5 -1
  168. package/src/cli/plugin-cli.ts +6 -1
  169. package/src/cli/update-cli.ts +362 -264
  170. package/src/cli-main.ts +517 -0
  171. package/src/cli.ts +64 -433
  172. package/src/commands/autoresearch.ts +11 -5
  173. package/src/commands/completion.ts +1 -1
  174. package/src/commands/doctor.ts +13 -0
  175. package/src/commands/sdk.ts +58 -10
  176. package/src/commands/ultragoal.ts +11 -5
  177. package/src/config/autorouting-tier-map.ts +7 -0
  178. package/src/config/file-lock.ts +736 -71
  179. package/src/config/mcp-schema.json +3 -3
  180. package/src/config/model-preset-registry.ts +1 -0
  181. package/src/config/model-registry.ts +80 -27
  182. package/src/config/model-resolver.ts +33 -4
  183. package/src/config/models-config-schema.ts +2 -0
  184. package/src/config/settings-schema.ts +6 -2
  185. package/src/coordinator-mcp/question-gate-codec.ts +1 -0
  186. package/src/coordinator-mcp/server.ts +534 -51
  187. package/src/coordinator-mcp/session-reaper.ts +64 -8
  188. package/src/cursor.ts +223 -53
  189. package/src/discovery/agents-md.ts +74 -8
  190. package/src/discovery/agents.ts +32 -7
  191. package/src/discovery/builtin.ts +184 -75
  192. package/src/discovery/claude-plugins.ts +85 -17
  193. package/src/discovery/cline.ts +38 -10
  194. package/src/discovery/cursor.ts +19 -6
  195. package/src/discovery/gemini.ts +62 -22
  196. package/src/discovery/github.ts +13 -3
  197. package/src/discovery/helpers.ts +483 -89
  198. package/src/discovery/index.ts +1 -0
  199. package/src/discovery/mcp-json.ts +36 -10
  200. package/src/discovery/opencode.ts +36 -19
  201. package/src/discovery/ssh.ts +11 -8
  202. package/src/discovery/windsurf.ts +12 -3
  203. package/src/exec/bash-executor.ts +10 -3
  204. package/src/exec/isolated-shell.ts +15 -2
  205. package/src/extensibility/extensions/loader.ts +88 -26
  206. package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
  207. package/src/extensibility/gjc-plugins/paths.ts +4 -1
  208. package/src/extensibility/gjc-plugins/types.ts +27 -0
  209. package/src/extensibility/plugins/manager.ts +200 -22
  210. package/src/extensibility/plugins/marketplace/cache.ts +55 -2
  211. package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
  212. package/src/extensibility/plugins/marketplace/registry.ts +153 -0
  213. package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
  214. package/src/extensibility/runtime-skill-discovery.ts +61 -9
  215. package/src/extensibility/skill-management.ts +7 -1
  216. package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
  217. package/src/gjc-runtime/launch-worktree.test.ts +248 -0
  218. package/src/gjc-runtime/launch-worktree.ts +275 -38
  219. package/src/gjc-runtime/repository-binding.ts +26 -1
  220. package/src/gjc-runtime/session-layout.ts +10 -0
  221. package/src/gjc-runtime/session-state-lock.ts +330 -23
  222. package/src/gjc-runtime/session-state-sidecar.ts +328 -80
  223. package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
  224. package/src/harness-control-plane/session-lease.ts +2 -2
  225. package/src/internal-urls/docs-index.generated.ts +28 -26
  226. package/src/main.ts +150 -29
  227. package/src/memories/index.ts +24 -2
  228. package/src/modes/acp/acp-agent.ts +522 -68
  229. package/src/modes/components/agent-dashboard.ts +3 -1
  230. package/src/modes/components/model-selector.ts +28 -19
  231. package/src/modes/components/plugin-settings.ts +2 -1
  232. package/src/modes/controllers/selector-controller.ts +15 -9
  233. package/src/modes/interactive-mode.ts +21 -3
  234. package/src/prompts/system/system-prompt.md +5 -1
  235. package/src/prompts/tools/browser.md +1 -1
  236. package/src/prompts/tools/move-session.md +4 -0
  237. package/src/prompts/tools/read.md +2 -1
  238. package/src/prompts/tools/skill-discovery.md +6 -5
  239. package/src/prompts/tools/task.md +1 -0
  240. package/src/runtime-mcp/config-writer.ts +228 -0
  241. package/src/runtime-mcp/oauth-discovery.ts +114 -14
  242. package/src/runtime-mcp/policy-json-edit.ts +129 -0
  243. package/src/runtime-mcp/startup-policy.ts +14 -0
  244. package/src/runtime-mcp/types.ts +2 -2
  245. package/src/sdk/acp/adapter.ts +27 -12
  246. package/src/sdk/broker/broker.ts +273 -44
  247. package/src/sdk/broker/daemon-entry.ts +119 -0
  248. package/src/sdk/broker/discovery.ts +173 -20
  249. package/src/sdk/broker/doctor-restart.ts +206 -0
  250. package/src/sdk/broker/endpoint-authority.ts +36 -0
  251. package/src/sdk/broker/ensure.ts +49 -14
  252. package/src/sdk/broker/lifecycle.ts +174 -42
  253. package/src/sdk/broker/process-incarnation.ts +86 -2
  254. package/src/sdk/broker/runtime.ts +145 -21
  255. package/src/sdk/broker/session-index.ts +136 -22
  256. package/src/sdk/broker/spawn-substrate.ts +4 -1
  257. package/src/sdk/broker/transport.ts +5 -0
  258. package/src/sdk/broker/worktree-occupancy.ts +21 -1
  259. package/src/sdk/bus/chat-daemon-cli.ts +63 -0
  260. package/src/sdk/bus/chat-daemon-control.ts +260 -64
  261. package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
  262. package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
  263. package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
  264. package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
  265. package/src/sdk/bus/index.ts +252 -51
  266. package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
  267. package/src/sdk/bus/notification-service.ts +21 -3
  268. package/src/sdk/bus/reconciliation-store.ts +17 -11
  269. package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
  270. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  271. package/src/sdk/bus/telegram-daemon-control.ts +47 -0
  272. package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
  273. package/src/sdk/bus/telegram-daemon.ts +178 -13
  274. package/src/sdk/cli/session-cli.ts +100 -12
  275. package/src/sdk/host/host.ts +2 -7
  276. package/src/sdk/host/session-runtime.test.ts +329 -8
  277. package/src/sdk/host/session-runtime.ts +202 -50
  278. package/src/sdk/host/surface-policy.ts +8 -1
  279. package/src/sdk/lifecycle/service.ts +199 -22
  280. package/src/sdk/mcp/server.ts +1 -1
  281. package/src/sdk/prompt-deadline-lease.ts +12 -4
  282. package/src/sdk/prompt-deadline-manager.ts +5 -7
  283. package/src/sdk/prompt-failure.ts +148 -0
  284. package/src/sdk/prompt-status.ts +30 -1
  285. package/src/sdk/prompt-watchdog.ts +11 -3
  286. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  287. package/src/sdk/protocol/operation-registry.ts +20 -8
  288. package/src/sdk/router/session-router.ts +8 -3
  289. package/src/sdk/service-artifact-paths.ts +26 -0
  290. package/src/sdk/session-authority.ts +10 -0
  291. package/src/sdk/session.ts +361 -194
  292. package/src/session/agent-session.ts +398 -93
  293. package/src/session/blob-store.ts +9 -9
  294. package/src/session/fallback-chain-controller.ts +3 -7
  295. package/src/session/internal/managed-session-scope.ts +445 -29
  296. package/src/session/internal/managed-session-storage.ts +38 -6
  297. package/src/session/primary-control-surface.ts +12 -0
  298. package/src/session/session-manager.ts +11 -3
  299. package/src/session/session-storage.ts +1 -1
  300. package/src/session-import/codex.ts +6 -1
  301. package/src/session-import/redact.ts +7 -0
  302. package/src/skill-state/workflow-mutation-guard.ts +645 -39
  303. package/src/slash-commands/builtin-registry.ts +7 -3
  304. package/src/system-prompt.ts +8 -0
  305. package/src/task/executor.ts +36 -3
  306. package/src/task/types.ts +27 -5
  307. package/src/tools/ask.ts +114 -34
  308. package/src/tools/browser/actions.ts +2 -2
  309. package/src/tools/browser/tab-worker.ts +11 -8
  310. package/src/tools/descriptors.ts +6 -1
  311. package/src/tools/fetch.ts +7 -2
  312. package/src/tools/image-gen.ts +33 -34
  313. package/src/tools/read.ts +78 -32
  314. package/src/tools/skill-discovery.ts +17 -7
  315. package/src/tools/tool-catalog.generated.ts +8 -8
  316. package/src/tools/ultragoal-ask-guard.ts +16 -26
  317. package/src/utils/changelog.ts +7 -1
  318. package/src/utils/git.ts +3 -1
  319. package/src/utils/markit.ts +24 -2
  320. package/src/utils/mupdf-wasm.ts +26 -0
  321. package/src/web/search/providers/openai-compatible.ts +191 -14
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Idle reaper for coordinator-managed GJC worker sessions.
3
3
  *
4
- * Every `gjc_delegate_*` call that omits `session_id` starts a fresh tmux worker
5
- * session. Nothing in the coordinator ever tore those down, so completed/crashed
6
- * sessions accumulated (RAM + worktrees) until something killed them by hand.
4
+ * New coordinator-owned sessions created by `gjc_coordinator_start_session` or by a
5
+ * `gjc_delegate_*` call that omits `session_id` are ephemeral. Nothing in the
6
+ * coordinator ever tore those down, so completed/crashed sessions accumulated
7
+ * (RAM + worktrees) until something killed them by hand.
7
8
  *
8
9
  * This is the automatic backstop (defense-in-depth): a periodic sweep force-closes
9
- * sessions that are (a) ephemeral — coordinator delegate-created, never a user's
10
+ * sessions that are (a) ephemeral — coordinator-created, never a user's
10
11
  * registered resident session, (b) not mid-turn, and (c) idle past a TTL.
11
12
  *
12
13
  * The controller is pure + fully injectable (clock / list / reap side-effects) so
@@ -18,10 +19,12 @@ export declare const DEFAULT_SESSION_IDLE_TTL_MS: number;
18
19
  export declare const DEFAULT_SESSION_SWEEP_INTERVAL_MS: number;
19
20
  export declare const MIN_SESSION_IDLE_TTL_MS = 60000;
20
21
  export declare const MIN_SESSION_SWEEP_INTERVAL_MS = 30000;
22
+ /** After this many consecutive reap failures the session is force-evicted from the index. */
23
+ export declare const MAX_REAP_FAILURES = 3;
21
24
  /** Minimal projection of a coordinator session the reaper needs to decide. */
22
25
  export interface ReapableSession {
23
26
  sessionId: string;
24
- /** True only for coordinator delegate-created sessions. User-registered resident sessions are false and never reaped. */
27
+ /** True for newly coordinator-created sessions. User-registered resident sessions are false and never reaped. */
25
28
  ephemeral: boolean;
26
29
  /** Epoch ms of last observed activity (turn update / session-state write / session creation). */
27
30
  lastActivityMs: number;
@@ -41,6 +44,13 @@ export declare function selectReapableSessions(sessions: readonly ReapableSessio
41
44
  export interface SessionReaperDeps {
42
45
  listSessions: () => Promise<ReapableSession[]>;
43
46
  reapSession: (sessionId: string) => Promise<void>;
47
+ /**
48
+ * Force-evict a session from the coordinator index when it has exceeded the
49
+ * consecutive-failure limit and cannot be reaped normally (e.g. endpoint_stale).
50
+ * Called exactly once per session-id at the eviction boundary; the session must
51
+ * not appear in future listSessions() results after this resolves.
52
+ */
53
+ markSessionDead: (sessionId: string) => Promise<void>;
44
54
  now: () => number;
45
55
  }
46
56
  export interface SessionReaper {
@@ -27,13 +27,13 @@ export declare class CursorExecHandlers implements ICursorExecHandlers {
27
27
  #private;
28
28
  private options;
29
29
  constructor(options: CursorExecBridgeOptions);
30
- read(args: Parameters<NonNullable<ICursorExecHandlers["read"]>>[0]): Promise<ToolResultMessage<any>>;
31
- ls(args: Parameters<NonNullable<ICursorExecHandlers["ls"]>>[0]): Promise<ToolResultMessage<any>>;
32
- grep(args: Parameters<NonNullable<ICursorExecHandlers["grep"]>>[0]): Promise<ToolResultMessage<any>>;
33
- write(args: Parameters<NonNullable<ICursorExecHandlers["write"]>>[0]): Promise<ToolResultMessage<any>>;
34
- delete(args: Parameters<NonNullable<ICursorExecHandlers["delete"]>>[0]): Promise<ToolResultMessage<any>>;
35
- shell(args: Parameters<NonNullable<ICursorExecHandlers["shell"]>>[0]): Promise<ToolResultMessage<any>>;
36
- shellStream(args: Parameters<NonNullable<ICursorExecHandlers["shellStream"]>>[0], callbacks: CursorShellStreamCallbacks): Promise<ToolResultMessage<any>>;
30
+ read(args: Parameters<NonNullable<ICursorExecHandlers["read"]>>[0], signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
31
+ ls(args: Parameters<NonNullable<ICursorExecHandlers["ls"]>>[0], signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
32
+ grep(args: Parameters<NonNullable<ICursorExecHandlers["grep"]>>[0], signal?: AbortSignal): Promise<ToolResultMessage<any>>;
33
+ write(args: Parameters<NonNullable<ICursorExecHandlers["write"]>>[0], signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
34
+ delete(args: Parameters<NonNullable<ICursorExecHandlers["delete"]>>[0], signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
35
+ shell(args: Parameters<NonNullable<ICursorExecHandlers["shell"]>>[0], signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
36
+ shellStream(args: Parameters<NonNullable<ICursorExecHandlers["shellStream"]>>[0], callbacks: CursorShellStreamCallbacks, signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
37
37
  piRead(call: Parameters<NonNullable<ICursorExecHandlers["piRead"]>>[0]): Promise<ToolResultMessage<any>>;
38
38
  piBash(call: Parameters<NonNullable<ICursorExecHandlers["piBash"]>>[0]): Promise<ToolResultMessage<any>>;
39
39
  piEdit(call: Parameters<NonNullable<ICursorExecHandlers["piEdit"]>>[0]): Promise<ToolResultMessage<any>>;
@@ -41,7 +41,7 @@ export declare class CursorExecHandlers implements ICursorExecHandlers {
41
41
  piGrep(call: Parameters<NonNullable<ICursorExecHandlers["piGrep"]>>[0]): Promise<ToolResultMessage<any>>;
42
42
  piFind(call: Parameters<NonNullable<ICursorExecHandlers["piFind"]>>[0]): Promise<ToolResultMessage<any>>;
43
43
  piLs(call: Parameters<NonNullable<ICursorExecHandlers["piLs"]>>[0]): Promise<ToolResultMessage<any>>;
44
- diagnostics(args: Parameters<NonNullable<ICursorExecHandlers["diagnostics"]>>[0]): Promise<ToolResultMessage<any>>;
45
- mcp(call: CursorMcpCall): Promise<ToolResultMessage<any>>;
44
+ diagnostics(args: Parameters<NonNullable<ICursorExecHandlers["diagnostics"]>>[0], signal?: AbortSignal): Promise<ToolResultMessage<any>>;
45
+ mcp(call: CursorMcpCall, signal?: AbortSignal, markNonAbortable?: () => void): Promise<ToolResultMessage<any>>;
46
46
  }
47
47
  export {};
@@ -1,6 +1,11 @@
1
1
  import { type ContextFile } from "../capability/context-file";
2
+ import type { FileIdentity } from "../capability/fs";
2
3
  import type { LoadContext, LoadResult } from "../capability/types";
3
- export type AgentsMdReader = (filePath: string, maxBytes: number) => Promise<{
4
+ export type AgentsMdReader = (filePath: string, maxBytes: number, options?: {
5
+ noFollow?: boolean;
6
+ home?: string;
7
+ homeIdentity?: FileIdentity;
8
+ }) => Promise<{
4
9
  content: string | null;
5
10
  byteLength: number;
6
11
  tooLarge: boolean;
@@ -1,5 +1,6 @@
1
1
  import type { ThinkingLevel } from "@gajae-code/agent-core";
2
2
  import type { ExtensionModule } from "../capability/extension-module";
3
+ import { type FileIdentity, type ReadFileOptions, type ReadScope } from "../capability/fs";
3
4
  import { type Rule } from "../capability/rule";
4
5
  import type { Skill } from "../capability/skill";
5
6
  import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
@@ -91,6 +92,9 @@ export declare function getUserSkillScanDirs(home: string, userAgentDir?: string
91
92
  * Get project-level path for a source (cwd only).
92
93
  */
93
94
  export declare function getProjectPath(ctx: LoadContext, source: SourceId, subpath: string): string | null;
95
+ /** Build the filesystem authority for a provider read. */
96
+ export declare function getReadOptions(ctx: Pick<LoadContext, "home" | "isolatedHome" | "userAgentDir" | "homeIdentity" | "userAgentIdentity">, scope: ReadScope): ReadFileOptions | undefined;
97
+ export declare function getReadOptionsForContainment(ctx: Pick<LoadContext, "home" | "isolatedHome" | "userAgentDir" | "homeIdentity" | "userAgentIdentity">, scope: ReadScope, containmentRoot?: string): Promise<ReadFileOptions | undefined>;
94
98
  /**
95
99
  * Create source metadata for an item.
96
100
  */
@@ -143,6 +147,12 @@ export interface ScanSkillsFromDirOptions {
143
147
  providerId: string;
144
148
  level: "user" | "project";
145
149
  requireDescription?: boolean;
150
+ /** Optional physical root that every discovered skill must remain within. */
151
+ containmentRoot?: string;
152
+ /** Physical repository root permitting the project scan directory itself to be a symlink. */
153
+ linkContainmentRoot?: string;
154
+ /** Filesystem authority for explicit-home reads. */
155
+ scope?: ReadScope;
146
156
  }
147
157
  export declare function compareSkillOrder(aName: string, aPath: string, bName: string, bPath: string): number;
148
158
  /** Maximum bytes read per incremental frontmatter scan chunk. */
@@ -154,10 +164,11 @@ export declare const SkillDiscoveryTestHooks: {
154
164
  afterAuthorityRootValidated?: (root: string) => void | Promise<void>;
155
165
  afterAuthorityRootMissing?: (root: string) => void | Promise<void>;
156
166
  afterContainedRootValidated?: (root: string) => void | Promise<void>;
167
+ afterScanRootValidated?: (root: string) => void | Promise<void>;
157
168
  };
158
169
  export declare function scanSkillsFromDir(_ctx: LoadContext, options: ScanSkillsFromDirOptions): Promise<LoadResult<Skill>>;
159
- /** Read a regular single-link file that remains contained by its configured root. */
160
- export declare function readContainedFile(root: string, filePath: string): Promise<string | null>;
170
+ /** Read a regular file that remains contained by its configured root. */
171
+ export declare function readContainedFile(root: string, filePath: string, expectedRootIdentity?: FileIdentity | null): Promise<string | null>;
161
172
  /**
162
173
  * Recursively expand environment variables in an object.
163
174
  */
@@ -173,6 +184,10 @@ export declare function loadFilesFromDir<T>(_ctx: LoadContext, dir: string, prov
173
184
  transform: (name: string, content: string, path: string, source: SourceMeta) => T | null;
174
185
  /** Whether to recurse into subdirectories (default: false) */
175
186
  recursive?: boolean;
187
+ /** Optional physical root that every discovered file must remain within. */
188
+ containmentRoot?: string;
189
+ /** Filesystem authority for explicit-home reads. */
190
+ scope?: ReadScope;
176
191
  }): Promise<LoadResult<T>>;
177
192
  /**
178
193
  * Calculate depth of target directory relative to current working directory.
@@ -193,7 +208,9 @@ export declare function calculateDepth(cwd: string, targetDir: string, separator
193
208
  * No recursion beyond one level. Complex packages must use package.json manifest.
194
209
  * Uses native glob for fast filesystem scanning with gitignore support.
195
210
  */
196
- export declare function discoverExtensionModulePaths(_ctx: LoadContext, dir: string): Promise<string[]>;
211
+ export declare function discoverExtensionModulePaths(ctx: LoadContext, dir: string, options?: {
212
+ scope?: ReadScope;
213
+ }): Promise<string[]>;
197
214
  /**
198
215
  * Derive a stable extension name from a path.
199
216
  */
@@ -256,7 +273,7 @@ export declare function parseClaudePluginsRegistry(content: string): ClaudePlugi
256
273
  * This is the single source of truth for "active project root" used by install,
257
274
  * uninstall, list, upgrade, discovery, and doctor. Deterministic for a given `cwd`.
258
275
  */
259
- export declare function resolveActiveProjectRegistryPath(cwd: string): Promise<string | null>;
276
+ export declare function resolveActiveProjectRegistryPath(cwd: string, homeDir?: string, isolatedHome?: boolean): Promise<string | null>;
260
277
  /**
261
278
  * Like resolveActiveProjectRegistryPath, but falls back to `<cwd>/.gjc/plugins/installed_plugins.json`
262
279
  * when no project anchor (.gjc/ or .git/) is found.
@@ -270,14 +287,26 @@ export declare function resolveActiveProjectRegistryPath(cwd: string): Promise<s
270
287
  */
271
288
  export declare function resolveOrDefaultProjectRegistryPath(cwd: string): Promise<string | undefined>;
272
289
  /** Invalidate the exact user/project registry pair and their resolved-root cache entry. */
273
- export declare function invalidateClaudePluginRoots(home: string, cwd?: string): Promise<void>;
290
+ export declare function invalidateClaudePluginRoots(home: string, cwd?: string, isolatedHome?: boolean): Promise<void>;
291
+ /**
292
+ * Resolve a configured path through existing symlinks when an explicit-home
293
+ * load is active. Ordinary discovery keeps its historical lexical path
294
+ * handling; isolated discovery must reject paths that leave the supplied
295
+ * physical home (or an explicitly selected agent directory), including paths
296
+ * that escape through an existing symlink. When provided, containmentRoot is
297
+ * an additional physical boundary, such as a plugin root.
298
+ */
299
+ export declare function canonicalizePathWithinHome(ctx: Pick<LoadContext, "home" | "isolatedHome" | "userAgentDir" | "homeIdentity">, target: string, containmentRoot?: string, scope?: ReadScope): Promise<string | undefined>;
274
300
  /**
275
301
  * List installed GJC plugin roots from the GJC plugin registry and, when present,
276
302
  * the nearest project-scoped registry resolved from `cwd`.
277
303
  *
278
- * Results are cached per `home:resolvedProjectPath` key to avoid repeated parsing.
304
+ * Ordinary results are cached per `home:resolvedProjectPath` key to avoid
305
+ * repeated parsing. Isolated results intentionally bypass the shared cache:
306
+ * an ordinary load may contain external install roots that an isolated load
307
+ * must reject, and reusing that result would cross the home boundary.
279
308
  */
280
- export declare function listClaudePluginRoots(home: string, cwd?: string): Promise<{
309
+ export declare function listClaudePluginRoots(home: string, cwd?: string, isolatedHome?: boolean, homeIdentity?: FileIdentity): Promise<{
281
310
  roots: ClaudePluginRoot[];
282
311
  warnings: string[];
283
312
  }>;
@@ -32,7 +32,7 @@ import "./github";
32
32
  import "./mcp-json";
33
33
  import "./ssh";
34
34
  import "./windsurf";
35
- export { cacheStats, disableProvider, enableProvider, getAllCapabilitiesInfo, getAllProvidersInfo, getCapability, getCapabilityInfo, getDisabledProviders, getProviderInfo, initializeWithSettings, invalidate, isProviderEnabled, listCapabilities, loadCapability, releaseSettingsScope, reset, setDisabledProviders, } from "../capability";
35
+ export { cacheStats, disableProvider, enableProvider, getAllCapabilitiesInfo, getAllProvidersInfo, getCapability, getCapabilityInfo, getDisabledProviders, getProviderInfo, initializeWithSettings, invalidate, isProviderEnabled, listCapabilities, loadCapability, loadCapabilityForHome, releaseSettingsScope, reset, setDisabledProviders, } from "../capability";
36
36
  export type { ContextFile } from "../capability/context-file";
37
37
  export type { Extension, ExtensionManifest } from "../capability/extension";
38
38
  export type { ExtensionModule } from "../capability/extension-module";
@@ -1,3 +1,4 @@
1
+ import { type ReadFileOptions } from "../capability/fs";
1
2
  import { type MCPServer } from "../capability/mcp";
2
3
  import type { LoadResult } from "../capability/types";
3
4
  export interface MCPJsonLoadResult extends LoadResult<MCPServer> {
@@ -9,4 +10,5 @@ export interface MCPJsonLoadResult extends LoadResult<MCPServer> {
9
10
  export declare function loadMCPJsonFile(filePath: string, level: "user" | "project", options?: {
10
11
  quiet?: boolean;
11
12
  useCache?: boolean;
13
+ readOptions?: ReadFileOptions;
12
14
  }): Promise<MCPJsonLoadResult>;
@@ -1,5 +1,6 @@
1
1
  import type { ThinkingLevel } from "@gajae-code/agent-core";
2
2
  import type { Tool, UsageReport } from "@gajae-code/ai/core";
3
+ import type { Settings } from "../../config/settings";
3
4
  import { EventBus } from "../../utils/event-bus";
4
5
  import type { Extension, ExtensionFactory, ExtensionRuntime as IExtensionRuntime, LoadExtensionsResult } from "./types";
5
6
  export declare class ExtensionRuntimeNotInitializedError extends Error {
@@ -79,7 +80,27 @@ export declare function loadExtensionFromFactory(factory: ExtensionFactory, cwd:
79
80
  * Load extensions from paths.
80
81
  */
81
82
  export declare function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult>;
83
+ /**
84
+ * Session-scoped discovery inputs.
85
+ *
86
+ * A session's selected agent directory is not necessarily the process-global
87
+ * one (`createAgentSession({ agentDir })`), so user-scope extension modules and
88
+ * provider policy must resolve against the caller's profile rather than
89
+ * `getAgentDir()`.
90
+ */
91
+ export interface DiscoverExtensionsOptions {
92
+ /**
93
+ * Agent directory backing user-scope discovery. Default: `getAgentDir()`.
94
+ * Only the native capability provider is scoped this way; installed
95
+ * plugin-bundle extension paths stay home-scoped by design.
96
+ */
97
+ agentDir?: string;
98
+ /** Resolver-owned classification for `agentDir`. */
99
+ profileAuthority?: "default" | "custom";
100
+ /** Session settings whose provider policy applies to this load. */
101
+ settings?: Settings;
102
+ }
82
103
  /**
83
104
  * Discover and load extensions from standard locations.
84
105
  */
85
- export declare function discoverAndLoadExtensions(configuredPaths: string[], cwd: string, eventBus?: EventBus, disabledExtensionIds?: string[]): Promise<LoadExtensionsResult>;
106
+ export declare function discoverAndLoadExtensions(configuredPaths: string[], cwd: string, eventBus?: EventBus, disabledExtensionIds?: string[], options?: DiscoverExtensionsOptions): Promise<LoadExtensionsResult>;
@@ -1,4 +1,4 @@
1
- import type { GjcBundleIdentity, GjcBundleSummary, GjcInstallResult, GjcLifecycleResult, GjcPluginRegistryEntry, GjcPluginRegistrySource, GjcPluginScope, GjcReviewedUpdateToken, GjcToggleResult, GjcUninstallPreview, GjcUpdateApplyResult, GjcUpdatePreview } from "./types";
1
+ import type { GjcBundleIdentity, GjcBundleSummary, GjcInstallResult, GjcLifecycleResult, GjcPluginRegistryEntry, GjcPluginRegistrySource, GjcPluginScope, GjcReviewedUpdateToken, GjcToggleResult, GjcUninstallPreview, GjcUpdateApplyResult, GjcUpdatePreview, LocalRestorePlanV1, ReviewedRestoreTokenV1 } from "./types";
2
2
  /**
3
3
  * GJC bundle lifecycle service.
4
4
  *
@@ -72,6 +72,19 @@ export declare function previewGjcBundleUpdate(ctx: GjcLifecycleContext, identit
72
72
  * zero mutation.
73
73
  */
74
74
  export declare function applyGjcBundleUpdate(ctx: GjcLifecycleContext, token: GjcReviewedUpdateToken): Promise<GjcLifecycleResult<GjcUpdateApplyResult>>;
75
+ export declare function previewGjcBundleRestore(ctx: GjcLifecycleContext, identity: GjcBundleIdentity): Promise<GjcLifecycleResult<LocalRestorePlanV1>>;
76
+ export declare function authorizeGjcBundleRestore(ctx: GjcLifecycleContext, plan: LocalRestorePlanV1, authorizations: readonly string[]): Promise<GjcLifecycleResult<ReviewedRestoreTokenV1>>;
77
+ export declare function applyGjcBundleRestore(ctx: GjcLifecycleContext, token: ReviewedRestoreTokenV1): Promise<GjcLifecycleResult<GjcUpdateApplyResult>>;
78
+ /**
79
+ * Doctor-only quarantine primitive. The expected baseline is compared while
80
+ * holding the ordinary registry writer lock, so concurrent enable/disable or
81
+ * update cannot be clobbered.
82
+ */
83
+ export declare function setGjcBundleQuarantineExpectedBaseline(ctx: GjcLifecycleContext, identity: GjcBundleIdentity, enabled: boolean, expectedBaseline: string): Promise<GjcLifecycleResult<GjcToggleResult>>;
84
+ export declare function getGjcBundleEnablementState(ctx: GjcLifecycleContext, identity: GjcBundleIdentity): Promise<GjcLifecycleResult<{
85
+ enabled: boolean;
86
+ baseline: string;
87
+ }>>;
75
88
  /**
76
89
  * Enable or disable a whole bundle. Deterministic quarantine blocks enabling;
77
90
  * disabling is always allowed so operators can always de-escalate.
@@ -1,8 +1,9 @@
1
+ import type { ReadFileOptions } from "../../capability/fs";
1
2
  export declare function gjcPluginUserRoot(): string;
2
3
  export declare function gjcPluginProjectRoot(cwd: string): string;
3
4
  export declare function gjcPluginSafeDirectoryName(name: string): string;
4
5
  export declare function gjcPluginInstallRoot(scope: "user" | "project", cwd: string, name: string): string;
5
- export declare function rootContainsGjcManifest(dir: string): Promise<boolean>;
6
+ export declare function rootContainsGjcManifest(dir: string, options?: ReadFileOptions): Promise<boolean>;
6
7
  export declare function discoverGjcPluginRoots({ cwd }: {
7
8
  cwd: string;
8
9
  home?: string;
@@ -358,6 +358,31 @@ export interface GjcReviewedUpdateToken {
358
358
  decisionContextFingerprint: string;
359
359
  reviewedAt: string;
360
360
  }
361
+ export interface LocalRestorePlanV1 {
362
+ schemaVersion: 1;
363
+ kind: "gjc-plugin.restore-artifact";
364
+ identity: GjcBundleIdentity;
365
+ baselineFingerprint: string;
366
+ decisionContextFingerprint: string;
367
+ artifact: {
368
+ status: "present" | "absent" | "unreadable";
369
+ digest?: string;
370
+ };
371
+ writes: false;
372
+ fetch: false;
373
+ locks: false;
374
+ }
375
+ export interface ReviewedRestoreTokenV1 {
376
+ schemaVersion: 1;
377
+ kind: "gjc-plugin.restore-artifact";
378
+ purpose: "restore-artifact";
379
+ identity: GjcBundleIdentity;
380
+ candidateFingerprint: string;
381
+ baselineFingerprint: string;
382
+ decisionContextFingerprint: string;
383
+ artifactFingerprint: string;
384
+ reviewedAt: string;
385
+ }
361
386
  export type GjcLifecycleErrorCode = "already_installed_use_upgrade" | "not_installed" | "registry_unreadable" | "identity_mismatch" | "stale_candidate" | "stale_baseline" | "stale_decision_context" | "source_unsupported" | "source_unavailable" | "quarantined" | "surface_unknown" | "invalid_target";
362
387
  export interface GjcLifecycleError {
363
388
  code: GjcLifecycleErrorCode;
@@ -1,7 +1,40 @@
1
1
  import type { DoctorCheck, DoctorOptions, InstalledPlugin, InstallOptions, PluginSettingSchema } from "./types";
2
+ export type PluginEnablementState = {
3
+ status: "ok";
4
+ enabled: boolean;
5
+ baseline: string;
6
+ } | {
7
+ status: "not_installed";
8
+ } | {
9
+ status: "malformed";
10
+ };
2
11
  export declare class PluginManager {
3
12
  #private;
4
13
  constructor(cwd?: string);
14
+ /**
15
+ * Read-only durable-enablement snapshot for one npm plugin, scope-qualified.
16
+ * `"user"` reads the shared runtime lock file (~/.gjc/plugins/gjc-plugins.lock.json);
17
+ * `"project"` reads this project's `.gjc/plugin-overrides.json` disabled list.
18
+ * A malformed underlying file is reported distinctly from "not installed" —
19
+ * neither is silently treated as an empty/enabled state.
20
+ */
21
+ getEnablementState(name: string, scope: "user" | "project"): Promise<PluginEnablementState>;
22
+ /**
23
+ * Durable enablement toggle used by doctor quarantine and the plugin CLI.
24
+ * No install/fetch/reinstall occurs — this only flips the durable enabled
25
+ * flag a future session-startup load (`getEnabledPlugins`) consults: the
26
+ * user-scope runtime lock file, or the project's disabled-list override.
27
+ * Serialized under the canonical native-identity-bound file lock shared
28
+ * with every other writer of the same file (bounded retry/timeout,
29
+ * owner-safe release — never an unbounded wait, never a blind `rm`).
30
+ * `expectedBaseline` is required: a caller with no prior
31
+ * {@link getEnablementState} read has no CAS authority to mutate.
32
+ */
33
+ setEnabled(name: string, enabled: boolean, scope: "user" | "project", expectedBaseline: string): Promise<{
34
+ status: "updated" | "not_needed";
35
+ enabled: boolean;
36
+ version?: string;
37
+ }>;
5
38
  /**
6
39
  * Install a plugin from npm with optional feature selection.
7
40
  *
@@ -30,10 +63,6 @@ export declare class PluginManager {
30
63
  * Link a local plugin for development.
31
64
  */
32
65
  link(localPath: string): Promise<InstalledPlugin>;
33
- /**
34
- * Enable or disable a plugin globally.
35
- */
36
- setEnabled(name: string, enabled: boolean): Promise<void>;
37
66
  /**
38
67
  * Get enabled features for a plugin.
39
68
  */
@@ -23,6 +23,12 @@ export declare function getCachedPluginPath(cacheDir: string, marketplace: strin
23
23
  * so a partial previous cache is never silently reused.
24
24
  */
25
25
  export declare function cachePlugin(sourcePath: string, cacheDir: string, marketplace: string, pluginName: string, version: string): Promise<string>;
26
+ export declare function stageCachedPlugin(sourcePath: string, stagingPath: string): Promise<string>;
27
+ export declare function digestCachedPlugin(targetPath: string): Promise<string | undefined>;
28
+ export declare function inspectCachedPlugin(targetPath: string): Promise<{
29
+ status: "present" | "absent" | "unreadable";
30
+ digest?: string;
31
+ }>;
26
32
  /**
27
33
  * Synchronous check — true when the cache directory exists on disk.
28
34
  * Uses `existsSync` because callers may need to run this check inline without async.
@@ -21,7 +21,165 @@ export interface MarketplaceManagerOptions {
21
21
  * Receives any additional file paths that should also be invalidated from the fs cache.
22
22
  */
23
23
  clearPluginRootsCache?: (extraPaths?: readonly string[]) => void;
24
+ /**
25
+ * Test seam ONLY: injected immediately after {@link MarketplaceManager.applyPluginRestore}
26
+ * renames the staged candidate onto `finalPath` and captures its own
27
+ * published identity, before any further verification. Production callers
28
+ * never set this — default behavior is a no-op. Exists so a test can
29
+ * deterministically simulate a concurrent second writer republishing
30
+ * `finalPath` with a different inode inside the real race window, to
31
+ * exercise the `foreign_owner_conflict` rollback branch without a second
32
+ * process. Never used to bypass or weaken the identity re-check itself.
33
+ */
34
+ afterRestorePublish?: (finalPath: string) => Promise<void>;
35
+ }
36
+ export type MarketplaceRestoreRiskClass = "plugin-change" | "install-replace" | "network" | "external-execution";
37
+ /**
38
+ * Pure, read-only restoration descriptor. Every field is an observation of
39
+ * already-stored registry/catalog/local-artifact state; nothing here resolves
40
+ * a source, touches the network, or stages anything. `installPath` names the
41
+ * artifact this plan is ABOUT (the thing that would be repaired), never a
42
+ * staged candidate — the plan carries no writable authority.
43
+ */
44
+ export interface MarketplaceRestorePlanV1 {
45
+ schemaVersion: 1;
46
+ kind: "marketplace-plugin.restore-artifact";
47
+ pluginId: string;
48
+ scope: "user" | "project";
49
+ version: string;
50
+ installPath: string;
51
+ enabled: boolean;
52
+ /** Pinned SHA already recorded for this install, when known. */
53
+ gitCommitSha?: string;
54
+ /** Covers every entry recorded for this pluginId (all scopes) plus the local artifact observation. */
55
+ baselineFingerprint: string;
56
+ catalogFingerprint: string;
57
+ source: MarketplacePluginEntry["source"];
58
+ artifact: {
59
+ status: "present" | "absent" | "unreadable";
60
+ digest?: string;
61
+ };
62
+ riskClasses: readonly MarketplaceRestoreRiskClass[];
63
+ writes: false;
64
+ fetch: false;
65
+ execute: false;
66
+ }
67
+ /**
68
+ * Materialized after explicit risk authorization: a verified, staged,
69
+ * pinned-SHA candidate bound to the exact baseline/catalog it was reviewed
70
+ * against. `originalInstallPath` (what apply repairs) and `stagedArtifactPath`
71
+ * (the verified candidate bytes) are always distinct paths — apply never
72
+ * confuses the target it is replacing with the replacement.
73
+ */
74
+ export interface MarketplaceReviewedRestoreTokenV1 {
75
+ schemaVersion: 1;
76
+ kind: "marketplace-plugin.restore-artifact";
77
+ purpose: "restore-artifact";
78
+ pluginId: string;
79
+ scope: "user" | "project";
80
+ version: string;
81
+ originalInstallPath: string;
82
+ stagedArtifactPath: string;
83
+ enabled: boolean;
84
+ pinnedSha: string;
85
+ baselineFingerprint: string;
86
+ catalogFingerprint: string;
87
+ candidateFingerprint: string;
88
+ candidateArtifact: {
89
+ status: "present";
90
+ digest: string;
91
+ };
92
+ riskClasses: readonly MarketplaceRestoreRiskClass[];
93
+ reviewedAt: string;
24
94
  }
95
+ /**
96
+ * `refused` — nothing was mutated; safe to retry after fixing the cause.
97
+ * `conflict` — a filesystem mutation was attempted and then fully, verifiably
98
+ * rolled back to OUR exact prior artifact; the installed state is unchanged
99
+ * from before this apply ran.
100
+ * `foreign_owner_conflict` — a filesystem mutation was attempted, but the
101
+ * publish target now belongs to a different, concurrently-completed owner.
102
+ * Neither the foreign publication nor our own retained backup is touched;
103
+ * `retainedBackupPath` on the error names exactly where our pre-swap artifact
104
+ * is preserved for inspection/manual reconciliation.
105
+ * `uncertain` — a filesystem mutation was attempted and rollback to OUR prior
106
+ * artifact could not be verified; the installed state may not match either
107
+ * the old or new artifact and requires manual inspection.
108
+ * A caller (doctor journal) MUST record all four distinctly and MUST NOT
109
+ * treat any of the non-`refused` outcomes as a clean no-op.
110
+ */
111
+ export type MarketplaceRestoreOutcome = "refused" | "conflict" | "foreign_owner_conflict" | "uncertain";
112
+ /**
113
+ * Typed refusal/failure for the restore lane. Every throw site in
114
+ * previewPluginRestore/authorizePluginRestore/applyPluginRestore uses this
115
+ * class (never a bare `Error`) so a caller (the doctor journal) can
116
+ * distinguish a clean pre-mutation refusal from a filesystem mutation that
117
+ * was attempted and either rolled back, lost to a foreign owner, or left
118
+ * uncertain.
119
+ */
120
+ export declare class MarketplaceRestoreError extends Error {
121
+ readonly reasonCode: MarketplaceRestoreReasonCode;
122
+ readonly sideEffectStarted: boolean;
123
+ readonly outcome: MarketplaceRestoreOutcome;
124
+ /** Set whenever a pre-swap backup survives this call untouched: `foreign_owner_conflict` and every `uncertain` outcome that retains it. */
125
+ readonly retainedBackupPath?: string;
126
+ /**
127
+ * Private, non-reported free-text context (e.g. a wrapped underlying error
128
+ * message). NEVER surfaced as `reasonCode` — `reasonCode` reaches redacted
129
+ * external reports and must stay a fixed enum member.
130
+ */
131
+ readonly detail?: string;
132
+ constructor(reasonCode: MarketplaceRestoreReasonCode, options?: {
133
+ sideEffectStarted?: boolean;
134
+ outcome?: MarketplaceRestoreOutcome;
135
+ retainedBackupPath?: string;
136
+ detail?: string;
137
+ });
138
+ }
139
+ /**
140
+ * Fixed enum of every `MarketplaceRestoreError.reasonCode` produced by
141
+ * previewPluginRestore/authorizePluginRestore/applyPluginRestore. `reasonCode`
142
+ * reaches redacted external reports, so it MUST stay a member of this exact
143
+ * set — never an interpolated raw Error message (that goes into `detail`,
144
+ * a private, non-reported field on the error).
145
+ */
146
+ export declare const MARKETPLACE_RESTORE_REASON_CODES: readonly ["invalid_plugin_id", "not_installed", "marketplace_missing", "catalog_entry_missing", "catalog_changed", "baseline_changed", "original_path_not_canonical_private_layout", "candidate_changed", "unpinned_source", "unsupported_shared_layout", "install_path_not_canonical_private_layout", "resolved_provenance_mismatch", "unsafe_candidate_artifact", "authorization_missing", "staged_artifact_inside_cache_root", "final_path_outside_private_cache_root", "invalid_restore_token", "staged_snapshot_unavailable", "private_cache_root_missing", "private_cache_root_changed", "final_path_snapshot_unavailable", "final_path_is_symlink", "backup_detach_failed", "final_path_changed_before_backup", "backup_detach_unverified", "backup_publish_failed", "final_path_claimed_by_new_owner", "post_publish_identity_unconfirmed", "post_publish_digest_mismatch", "registry_write_failed", "post_publish_registry_verification_failed", "unexpected_occupant_before_our_publish", "rollback_rename_failed", "rollback_digest_mismatch", "restore_publish_failed"];
147
+ export type MarketplaceRestoreReasonCode = (typeof MARKETPLACE_RESTORE_REASON_CODES)[number];
148
+ export type MarketplaceRestoreApplyStatus = "verified" | "not_needed";
149
+ /**
150
+ * Discriminated success result for {@link MarketplaceManager.applyPluginRestore}.
151
+ * A TypeScript discriminated union (not one interface with optional fields):
152
+ * `not_needed` structurally has ONLY `staleStagedArtifactPath` and can never
153
+ * carry a `retainedBackupPath` field — there is no backup rollback state in
154
+ * a branch that made zero mutations. `verified` carries neither field, since
155
+ * a fully committed apply has nothing stale or retained to report.
156
+ *
157
+ * `sideEffectStarted` is explicit and MUST be `false` for `not_needed` (zero
158
+ * filesystem or registry mutation of any kind is attempted — the token is not
159
+ * consumed and can be safely retried or discarded) and `true` for `verified`
160
+ * (the cache directory was swapped and the registry written). `entry` for
161
+ * `verified` is re-read from disk after the write, not the in-memory value
162
+ * that was written, so it is independent observation rather than an echo of
163
+ * the input.
164
+ *
165
+ * `not_needed.staleStagedArtifactPath` names the token's now-redundant staged
166
+ * scratch directory for the CALLER to dispose of; this function does not
167
+ * delete it (doing so would itself be a write inside a branch that must
168
+ * remain a true zero-effect no-op), and it is populated ONLY with the exact
169
+ * path this same call's precheck confirmed still exists and still matches
170
+ * the token — never a path this call did not itself verify.
171
+ */
172
+ export type MarketplaceRestoreApplyResult = {
173
+ status: "verified";
174
+ sideEffectStarted: true;
175
+ entry: InstalledPluginEntry;
176
+ } | {
177
+ status: "not_needed";
178
+ sideEffectStarted: false;
179
+ entry: InstalledPluginEntry;
180
+ /** Present only when this call itself verified the staged directory still exists. */
181
+ staleStagedArtifactPath?: string;
182
+ };
25
183
  export declare class MarketplaceManager {
26
184
  #private;
27
185
  constructor(options: MarketplaceManagerOptions);
@@ -32,6 +190,34 @@ export declare class MarketplaceManager {
32
190
  listMarketplaces(): Promise<MarketplaceRegistryEntry[]>;
33
191
  listAvailablePlugins(marketplace?: string): Promise<MarketplacePluginEntry[]>;
34
192
  getPluginInfo(name: string, marketplace: string): Promise<MarketplacePluginEntry | null>;
193
+ /**
194
+ * Pure, read-only restoration observation. Reads the installed registry
195
+ * entry, the marketplace catalog entry, and the local cache artifact only.
196
+ * Never resolves the plugin source, never touches the network, never stages
197
+ * or writes anything.
198
+ */
199
+ previewPluginRestore(pluginId: string, scope: "user" | "project"): Promise<MarketplaceRestorePlanV1>;
200
+ /**
201
+ * Materialize a verified, pinned-SHA candidate after explicit risk
202
+ * authorization. Re-derives every fact from live state instead of trusting
203
+ * the caller-supplied plan: risk classes are recomputed (never taken from
204
+ * `plan.riskClasses`), the source is re-read from the current catalog entry
205
+ * (never from `plan.source`), and the resolved checkout's HEAD is
206
+ * independently re-verified against the pinned SHA before anything is
207
+ * staged. The plan itself confers no authority — only an explicit,
208
+ * risk-complete `authorizations` set does.
209
+ */
210
+ authorizePluginRestore(plan: MarketplaceRestorePlanV1, authorizations: readonly string[]): Promise<MarketplaceReviewedRestoreTokenV1>;
211
+ /**
212
+ * Publish a verified restore candidate. Re-verifies catalog/baseline/
213
+ * candidate CAS against live state (the token confers no authority by
214
+ * itself), swaps the private per-version cache directory atomically with a
215
+ * randomized backup name, and mutates ONLY the matched (pluginId, scope)
216
+ * registry entry — every sibling entry, every other pluginId, and the
217
+ * opposite scope's registry file are left untouched. On any failure after
218
+ * the filesystem swap the exact old artifact/registry pair is restored.
219
+ */
220
+ applyPluginRestore(token: MarketplaceReviewedRestoreTokenV1): Promise<MarketplaceRestoreApplyResult>;
35
221
  installPlugin(name: string, marketplace: string, options?: {
36
222
  force?: boolean;
37
223
  scope?: "user" | "project";
@@ -20,6 +20,33 @@ export declare function readMarketplacesRegistry(filePath: string): Promise<Mark
20
20
  export declare function writeMarketplacesRegistry(filePath: string, reg: MarketplacesRegistry): Promise<void>;
21
21
  export declare function readInstalledPluginsRegistry(filePath: string): Promise<InstalledPluginsRegistry>;
22
22
  export declare function writeInstalledPluginsRegistry(filePath: string, reg: InstalledPluginsRegistry): Promise<void>;
23
+ export type InstalledPluginEnablementState = {
24
+ status: "ok";
25
+ enabled: boolean;
26
+ baseline: string;
27
+ } | {
28
+ status: "not_installed";
29
+ } | {
30
+ status: "malformed";
31
+ } | {
32
+ status: "unsafe_link";
33
+ };
34
+ /**
35
+ * Pure read-only snapshot of one (id, scope) entry's durable enablement plus
36
+ * an exact file+parent CAS baseline. Never touches the cached artifact at
37
+ * `installPath` — presence/absence of that artifact is a D6 concern, not D7's.
38
+ * A symlinked or hard-linked registry file is refused distinctly from an
39
+ * absent ("not_installed"-eligible) or malformed one.
40
+ */
41
+ export declare function getInstalledPluginEnablementState(filePath: string, id: string, scope: "user" | "project"): Promise<InstalledPluginEnablementState>;
42
+ /**
43
+ * Update durable marketplace enablement without touching cached artifacts.
44
+ * Serialized under the canonical native-identity-bound file lock ordinary
45
+ * marketplace writers use (bounded retries, no blind directory removal).
46
+ * `expectedBaseline` is required: a caller with no prior read has no CAS
47
+ * authority and must call {@link getInstalledPluginEnablementState} first.
48
+ */
49
+ export declare function setInstalledPluginEnabled(filePath: string, id: string, scope: "user" | "project", enabled: boolean, expectedBaseline: string): Promise<"updated" | "not_needed">;
23
50
  export declare function addMarketplaceEntry(reg: MarketplacesRegistry, entry: MarketplaceRegistryEntry): MarketplacesRegistry;
24
51
  export declare function removeMarketplaceEntry(reg: MarketplacesRegistry, name: string): MarketplacesRegistry;
25
52
  export declare function getMarketplaceEntry(reg: MarketplacesRegistry, name: string): MarketplaceRegistryEntry | undefined;