comisai 1.0.36 → 1.0.37

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 (239) hide show
  1. package/node_modules/@comis/agent/dist/background/auto-background-middleware.js +9 -0
  2. package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +22 -2
  3. package/node_modules/@comis/agent/dist/background/background-task-manager.js +48 -41
  4. package/node_modules/@comis/agent/dist/background/background-task-persistence.js +28 -5
  5. package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +49 -0
  6. package/node_modules/@comis/agent/dist/background/completion-dispatcher.d.ts +130 -0
  7. package/node_modules/@comis/agent/dist/background/completion-dispatcher.js +215 -0
  8. package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +10 -1
  9. package/node_modules/@comis/agent/dist/background/completion-runner.js +98 -15
  10. package/node_modules/@comis/agent/dist/background/index.d.ts +6 -1
  11. package/node_modules/@comis/agent/dist/background/index.js +2 -0
  12. package/node_modules/@comis/agent/dist/background/session-resolver.d.ts +85 -0
  13. package/node_modules/@comis/agent/dist/background/session-resolver.js +78 -0
  14. package/node_modules/@comis/agent/dist/bootstrap/sections/messaging-sections.js +1 -0
  15. package/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +3 -3
  16. package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.d.ts +30 -2
  17. package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +51 -2
  18. package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.d.ts +22 -0
  19. package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.js +2 -2
  20. package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.d.ts +1 -5
  21. package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.js +2 -14
  22. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +26 -0
  23. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +3 -0
  24. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +9 -0
  25. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +73 -2
  26. package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.d.ts +10 -10
  27. package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.js +14 -14
  28. package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.d.ts +11 -13
  29. package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.js +14 -15
  30. package/node_modules/@comis/agent/dist/executor/capability-index-context.d.ts +72 -0
  31. package/node_modules/@comis/agent/dist/executor/capability-index-context.js +329 -0
  32. package/node_modules/@comis/agent/dist/executor/drain-helper.d.ts +122 -0
  33. package/node_modules/@comis/agent/dist/executor/drain-helper.js +173 -0
  34. package/node_modules/@comis/agent/dist/executor/error-classifier.js +2 -2
  35. package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +48 -4
  36. package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +134 -31
  37. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +7 -0
  38. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +25 -4
  39. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.d.ts +18 -1
  40. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +19 -16
  41. package/node_modules/@comis/agent/dist/executor/jit-guide-injector.d.ts +11 -2
  42. package/node_modules/@comis/agent/dist/executor/jit-guide-injector.js +16 -2
  43. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +8 -2
  44. package/node_modules/@comis/agent/dist/executor/pi-executor.js +25 -12
  45. package/node_modules/@comis/agent/dist/executor/prompt-assembly.d.ts +9 -1
  46. package/node_modules/@comis/agent/dist/executor/prompt-assembly.js +15 -1
  47. package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +18 -27
  48. package/node_modules/@comis/agent/dist/executor/tool-deferral.js +29 -38
  49. package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +1 -1
  50. package/node_modules/@comis/agent/dist/model/model-scanner.js +1 -1
  51. package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.d.ts +11 -1
  52. package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.js +19 -22
  53. package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +16 -2
  54. package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.d.ts +1 -1
  55. package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.js +5 -5
  56. package/node_modules/@comis/agent/dist/workspace/data-env.d.ts +38 -0
  57. package/node_modules/@comis/agent/dist/workspace/data-env.js +56 -0
  58. package/node_modules/@comis/agent/dist/workspace/index.d.ts +1 -0
  59. package/node_modules/@comis/agent/dist/workspace/index.js +1 -0
  60. package/node_modules/@comis/agent/dist/workspace/templates.js +5 -1
  61. package/node_modules/@comis/agent/package.json +1 -1
  62. package/node_modules/@comis/channels/dist/index.d.ts +1 -1
  63. package/node_modules/@comis/channels/dist/index.js +1 -1
  64. package/node_modules/@comis/channels/dist/shared/channel-manager.d.ts +9 -3
  65. package/node_modules/@comis/channels/dist/shared/inbound-gate.d.ts +1 -1
  66. package/node_modules/@comis/channels/dist/shared/inbound-gate.js +22 -7
  67. package/node_modules/@comis/channels/dist/shared/inbound-pipeline.d.ts +10 -3
  68. package/node_modules/@comis/channels/dist/shared/inbound-route.d.ts +1 -1
  69. package/node_modules/@comis/channels/dist/shared/inbound-route.js +13 -2
  70. package/node_modules/@comis/channels/dist/shared/response-filter.d.ts +11 -24
  71. package/node_modules/@comis/channels/dist/shared/response-filter.js +25 -53
  72. package/node_modules/@comis/channels/package.json +1 -1
  73. package/node_modules/@comis/cli/dist/commands/providers.d.ts +1 -2
  74. package/node_modules/@comis/cli/dist/commands/providers.js +5 -6
  75. package/node_modules/@comis/cli/package.json +1 -1
  76. package/node_modules/@comis/core/dist/config/field-metadata.js +2 -0
  77. package/node_modules/@comis/core/dist/config/immutable-keys.js +4 -1
  78. package/node_modules/@comis/core/dist/config/index.d.ts +4 -0
  79. package/node_modules/@comis/core/dist/config/index.js +2 -0
  80. package/node_modules/@comis/core/dist/config/schema-agent.d.ts +0 -792
  81. package/node_modules/@comis/core/dist/config/schema-approvals.d.ts +0 -14
  82. package/node_modules/@comis/core/dist/config/schema-auto-reply-engine.d.ts +0 -6
  83. package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +0 -12
  84. package/node_modules/@comis/core/dist/config/schema-browser.d.ts +0 -18
  85. package/node_modules/@comis/core/dist/config/schema-channel.d.ts +0 -158
  86. package/node_modules/@comis/core/dist/config/schema-coalescer.d.ts +0 -5
  87. package/node_modules/@comis/core/dist/config/schema-daemon.d.ts +0 -32
  88. package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +0 -18
  89. package/node_modules/@comis/core/dist/config/schema-documentation.d.ts +0 -12
  90. package/node_modules/@comis/core/dist/config/schema-embedding.d.ts +0 -20
  91. package/node_modules/@comis/core/dist/config/schema-envelope.d.ts +0 -15
  92. package/node_modules/@comis/core/dist/config/schema-gateway.d.ts +0 -37
  93. package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
  94. package/node_modules/@comis/core/dist/config/schema-integrations.d.ts +0 -318
  95. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.d.ts +0 -18
  96. package/node_modules/@comis/core/dist/config/schema-memory-review.d.ts +0 -7
  97. package/node_modules/@comis/core/dist/config/schema-memory.d.ts +0 -16
  98. package/node_modules/@comis/core/dist/config/schema-messages.d.ts +0 -8
  99. package/node_modules/@comis/core/dist/config/schema-models.d.ts +0 -15
  100. package/node_modules/@comis/core/dist/config/schema-notification.d.ts +0 -5
  101. package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +0 -5
  102. package/node_modules/@comis/core/dist/config/schema-observability.d.ts +0 -38
  103. package/node_modules/@comis/core/dist/config/schema-output-retention.d.ts +34 -0
  104. package/node_modules/@comis/core/dist/config/schema-output-retention.js +48 -0
  105. package/node_modules/@comis/core/dist/config/schema-plugins.d.ts +0 -8
  106. package/node_modules/@comis/core/dist/config/schema-providers.d.ts +0 -64
  107. package/node_modules/@comis/core/dist/config/schema-queue.d.ts +0 -58
  108. package/node_modules/@comis/core/dist/config/schema-response-prefix.d.ts +0 -2
  109. package/node_modules/@comis/core/dist/config/schema-retry.d.ts +0 -6
  110. package/node_modules/@comis/core/dist/config/schema-scheduler.d.ts +0 -39
  111. package/node_modules/@comis/core/dist/config/schema-secrets.d.ts +0 -3
  112. package/node_modules/@comis/core/dist/config/schema-security.d.ts +0 -18
  113. package/node_modules/@comis/core/dist/config/schema-send-policy.d.ts +0 -13
  114. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.d.ts +0 -5
  115. package/node_modules/@comis/core/dist/config/schema-serializer.js +2 -0
  116. package/node_modules/@comis/core/dist/config/schema-skills.d.ts +0 -61
  117. package/node_modules/@comis/core/dist/config/schema-streaming.d.ts +0 -38
  118. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.d.ts +0 -3
  119. package/node_modules/@comis/core/dist/config/schema-tooling.d.ts +87 -0
  120. package/node_modules/@comis/core/dist/config/schema-tooling.js +152 -0
  121. package/node_modules/@comis/core/dist/config/schema-verbosity.d.ts +0 -12
  122. package/node_modules/@comis/core/dist/config/schema-webhooks.d.ts +0 -40
  123. package/node_modules/@comis/core/dist/config/schema.d.ts +41 -38
  124. package/node_modules/@comis/core/dist/config/schema.js +6 -0
  125. package/node_modules/@comis/core/dist/context/context.d.ts +0 -4
  126. package/node_modules/@comis/core/dist/domain/approval-request.d.ts +0 -17
  127. package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +0 -10
  128. package/node_modules/@comis/core/dist/domain/delivery-origin.d.ts +0 -5
  129. package/node_modules/@comis/core/dist/domain/execution-graph.d.ts +0 -48
  130. package/node_modules/@comis/core/dist/domain/memory-entry.d.ts +0 -3
  131. package/node_modules/@comis/core/dist/domain/model-compat.d.ts +0 -4
  132. package/node_modules/@comis/core/dist/domain/normalized-message.d.ts +0 -15
  133. package/node_modules/@comis/core/dist/domain/provider-capabilities.d.ts +0 -6
  134. package/node_modules/@comis/core/dist/domain/rich-message.d.ts +0 -14
  135. package/node_modules/@comis/core/dist/domain/subagent-context-config.d.ts +0 -22
  136. package/node_modules/@comis/core/dist/domain/subagent-context-types.d.ts +0 -8
  137. package/node_modules/@comis/core/dist/event-bus/events-agent.d.ts +31 -0
  138. package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +5 -0
  139. package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
  140. package/node_modules/@comis/core/dist/exports/config.js +3 -1
  141. package/node_modules/@comis/core/dist/exports/hooks.d.ts +1 -1
  142. package/node_modules/@comis/core/dist/exports/ports.d.ts +2 -2
  143. package/node_modules/@comis/core/dist/exports/ports.js +1 -1
  144. package/node_modules/@comis/core/dist/ports/channel-plugin.d.ts +0 -13
  145. package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
  146. package/node_modules/@comis/core/dist/ports/index.js +4 -0
  147. package/node_modules/@comis/core/dist/ports/no-op-tool-capability.d.ts +30 -0
  148. package/node_modules/@comis/core/dist/ports/no-op-tool-capability.js +47 -0
  149. package/node_modules/@comis/core/dist/ports/tool-capability.d.ts +165 -0
  150. package/node_modules/@comis/core/dist/ports/tool-capability.js +15 -0
  151. package/node_modules/@comis/core/dist/security/audit.d.ts +0 -11
  152. package/node_modules/@comis/core/dist/tool-metadata.d.ts +21 -1
  153. package/node_modules/@comis/core/dist/tool-metadata.js +1 -1
  154. package/node_modules/@comis/core/package.json +1 -1
  155. package/node_modules/@comis/daemon/bundled-skills/skill-creator/scripts/validate-skill.py +1 -1
  156. package/node_modules/@comis/daemon/dist/daemon.js +89 -14
  157. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.d.ts +1 -1
  158. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +1 -1
  159. package/node_modules/@comis/daemon/dist/rpc/builtin-provider-guard.js +2 -2
  160. package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +1 -1
  161. package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +1 -1
  162. package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +2 -2
  163. package/node_modules/@comis/daemon/dist/sub-agent-runner.d.ts +18 -0
  164. package/node_modules/@comis/daemon/dist/sub-agent-runner.js +41 -9
  165. package/node_modules/@comis/daemon/dist/wiring/index.d.ts +2 -0
  166. package/node_modules/@comis/daemon/dist/wiring/index.js +1 -0
  167. package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +36 -2
  168. package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +45 -8
  169. package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +28 -9
  170. package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +36 -9
  171. package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +2 -2
  172. package/node_modules/@comis/daemon/dist/wiring/setup-channels.d.ts +9 -2
  173. package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +15 -9
  174. package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.d.ts +20 -5
  175. package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +20 -15
  176. package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +14 -2
  177. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.d.ts +4 -6
  178. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +3 -5
  179. package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.d.ts +20 -5
  180. package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.js +11 -2
  181. package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.d.ts +89 -0
  182. package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.js +212 -0
  183. package/node_modules/@comis/daemon/dist/wiring/setup-tools.d.ts +18 -4
  184. package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +29 -10
  185. package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.d.ts +75 -0
  186. package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.js +253 -0
  187. package/node_modules/@comis/daemon/package.json +1 -1
  188. package/node_modules/@comis/gateway/dist/webhook/webhook-endpoint.d.ts +0 -4
  189. package/node_modules/@comis/gateway/package.json +1 -1
  190. package/node_modules/@comis/infra/package.json +1 -1
  191. package/node_modules/@comis/memory/package.json +1 -1
  192. package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +0 -42
  193. package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.d.ts +29 -8
  194. package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +19 -7
  195. package/node_modules/@comis/scheduler/dist/system-events/system-event-types.d.ts +0 -3
  196. package/node_modules/@comis/scheduler/dist/tasks/task-types.d.ts +0 -17
  197. package/node_modules/@comis/scheduler/package.json +1 -1
  198. package/node_modules/@comis/shared/dist/index.d.ts +3 -0
  199. package/node_modules/@comis/shared/dist/index.js +4 -0
  200. package/node_modules/@comis/shared/dist/mcp-tool-name.d.ts +78 -0
  201. package/node_modules/@comis/shared/dist/mcp-tool-name.js +92 -0
  202. package/node_modules/@comis/shared/dist/silent-tokens.d.ts +38 -0
  203. package/node_modules/@comis/shared/dist/silent-tokens.js +51 -0
  204. package/node_modules/@comis/shared/dist/visible-delivery.d.ts +28 -0
  205. package/node_modules/@comis/shared/dist/visible-delivery.js +16 -0
  206. package/node_modules/@comis/shared/package.json +1 -1
  207. package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.d.ts +2 -13
  208. package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.js +3 -21
  209. package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +1 -1
  210. package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +4 -4
  211. package/node_modules/@comis/skills/dist/builtin/exec-tool.d.ts +55 -9
  212. package/node_modules/@comis/skills/dist/builtin/exec-tool.js +383 -19
  213. package/node_modules/@comis/skills/dist/builtin/install-detour.d.ts +67 -0
  214. package/node_modules/@comis/skills/dist/builtin/install-detour.js +342 -0
  215. package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.js +5 -5
  216. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +2 -2
  217. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +2 -2
  218. package/node_modules/@comis/skills/dist/builtin/platform/message-tool.js +18 -0
  219. package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.d.ts +18 -1
  220. package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.js +18 -2
  221. package/node_modules/@comis/skills/dist/builtin/platform/models-manage-tool.js +3 -3
  222. package/node_modules/@comis/skills/dist/builtin/process-registry.d.ts +14 -0
  223. package/node_modules/@comis/skills/dist/builtin/process-tool.d.ts +24 -4
  224. package/node_modules/@comis/skills/dist/builtin/process-tool.js +25 -7
  225. package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +1 -1
  226. package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +9 -0
  227. package/node_modules/@comis/skills/dist/index.d.ts +4 -1
  228. package/node_modules/@comis/skills/dist/index.js +3 -1
  229. package/node_modules/@comis/skills/dist/manifest/capability-parser.d.ts +44 -0
  230. package/node_modules/@comis/skills/dist/manifest/capability-parser.js +68 -0
  231. package/node_modules/@comis/skills/dist/manifest/schema.d.ts +44 -37
  232. package/node_modules/@comis/skills/dist/manifest/schema.js +35 -0
  233. package/node_modules/@comis/skills/dist/registry/discovery.d.ts +8 -0
  234. package/node_modules/@comis/skills/dist/registry/discovery.js +10 -3
  235. package/node_modules/@comis/skills/dist/registry/skill-registry.d.ts +45 -1
  236. package/node_modules/@comis/skills/dist/registry/skill-registry.js +70 -7
  237. package/node_modules/@comis/skills/package.json +1 -1
  238. package/node_modules/@comis/web/package.json +1 -1
  239. package/package.json +21 -21
@@ -14,6 +14,10 @@
14
14
  */
15
15
  import { Type } from "typebox";
16
16
  import { jsonResult, throwToolError, readEnumParam, readStringParam, readNumberParam, } from "./platform/tool-helpers.js";
17
+ import { buildInstallDetourHint } from "./exec-tool.js";
18
+ // `InstallDetourDecision` is imported transitively via
19
+ // ProcessSession.installDetourDecision (process-registry.ts type-only import);
20
+ // no direct import here — never re-derive at status-query time.
17
21
  // ---------------------------------------------------------------------------
18
22
  // Parameter schema
19
23
  // ---------------------------------------------------------------------------
@@ -30,17 +34,19 @@ const ProcessParams = Type.Object({
30
34
  offset: Type.Optional(Type.Integer({ description: "Line offset for log pagination (0-indexed)" })),
31
35
  limit: Type.Optional(Type.Integer({ description: "Max lines to return for log (default 200)" })),
32
36
  });
33
- // ---------------------------------------------------------------------------
34
- // Factory
35
- // ---------------------------------------------------------------------------
36
37
  /**
37
38
  * Create a process management tool that delegates to a ProcessRegistry.
38
39
  *
39
- * @param registry - ProcessRegistry for session CRUD operations
40
- * @param logger - Optional structured logger for DEBUG-level operation logging
41
- * @returns AgentTool implementing the process management interface
40
+ * Uses a deps-object signature; backward compat with the prior positional
41
+ * `(registry, logger?)` shape is NOT preserved.
42
+ *
43
+ * @param deps - Dependencies bundle. See `ProcessToolDeps` for field semantics.
44
+ * @returns AgentTool implementing the process management interface.
42
45
  */
43
- export function createProcessTool(registry, logger) {
46
+ export function createProcessTool(deps) {
47
+ const { registry, logger,
48
+ // toolCapabilityPort is read inside execute(...) below
49
+ } = deps;
44
50
  return {
45
51
  name: "process",
46
52
  label: "Process",
@@ -76,6 +82,18 @@ export function createProcessTool(registry, logger) {
76
82
  if (!details) {
77
83
  throwToolError("not_found", `Process session not found: ${sessionId}`);
78
84
  }
85
+ // Retroactive advise-mode hint augmentation. Read the spawn-time
86
+ // decision back from the session rather than re-deriving from current
87
+ // connected-server state (the connected set may have drifted since
88
+ // spawn, producing an inconsistent hint vs the spawn-time event).
89
+ // No current-mode check — operators can switch modes mid-session via
90
+ // daemon restart; advise-spawned sessions keep their hint.
91
+ const session = registry.get(sessionId);
92
+ if (session?.installDetourDecision &&
93
+ session.installDetourDecision.overlaps.length > 0) {
94
+ const hint = buildInstallDetourHint(session.installDetourDecision);
95
+ return jsonResult({ ...details, installDetourHint: hint.installDetourHint });
96
+ }
79
97
  return jsonResult(details);
80
98
  }
81
99
  case "log": {
@@ -17,7 +17,7 @@ import type { SandboxOptions, SandboxProvider } from "./types.js";
17
17
  * → /bin/true's dynamic linker unreachable → smoke EPERMs while the
18
18
  * production sandbox actually works fine).
19
19
  */
20
- export declare const SYSTEM_RO_PATHS: readonly ["/usr", "/bin", "/sbin", "/lib", "/lib64", "/lib32", "/etc/resolv.conf", "/etc/hosts", "/etc/hostname", "/etc/ssl", "/etc/ca-certificates", "/etc/pki", "/etc/ld.so.cache", "/etc/ld.so.conf", "/etc/ld.so.conf.d", "/etc/alternatives", "/etc/localtime", "/etc/passwd", "/etc/group", "/etc/nsswitch.conf"];
20
+ export declare const SYSTEM_RO_PATHS: readonly ["/usr", "/bin", "/sbin", "/lib", "/lib64", "/lib32", "/etc/resolv.conf", "/etc/hosts", "/etc/hostname", "/etc/ssl", "/etc/ca-certificates", "/etc/pki", "/etc/ld.so.cache", "/etc/ld.so.conf", "/etc/ld.so.conf.d", "/etc/alternatives", "/etc/localtime", "/etc/passwd", "/etc/group", "/etc/nsswitch.conf", "/etc/fonts"];
21
21
  export declare class BwrapProvider implements SandboxProvider {
22
22
  readonly name = "bwrap";
23
23
  private bwrapPath;
@@ -42,6 +42,15 @@ export const SYSTEM_RO_PATHS = [
42
42
  "/etc/passwd",
43
43
  "/etc/group",
44
44
  "/etc/nsswitch.conf",
45
+ // fontconfig config (font.conf, conf.d/). Without this, libfontconfig prints
46
+ // "Cannot load default config file" to stderr on every text-rendering call
47
+ // (matplotlib, Pango, Pillow TTF, ImageMagick, headless Chromium, weasyprint,
48
+ // ffmpeg drawtext, LibreOffice headless) and falls back to a minimal compiled-in
49
+ // config — which silently breaks the substitution chain for non-Latin scripts
50
+ // (CJK/Arabic/devanagari render as Tofu boxes even when the fonts are present
51
+ // under /usr/share/fonts). Per-user cache lives in XDG_CACHE_HOME/fontconfig,
52
+ // which is already RW via the workspace .cache bind in wrapEnv().
53
+ "/etc/fonts",
45
54
  ];
46
55
  /**
47
56
  * Per-user config paths to bind read-only. Resolved against the daemon
@@ -17,6 +17,8 @@ export { createExecTool } from "./builtin/exec-tool.js";
17
17
  export { createProcessTool } from "./builtin/process-tool.js";
18
18
  export { createProcessRegistry } from "./builtin/process-registry.js";
19
19
  export type { ProcessRegistry } from "./builtin/process-registry.js";
20
+ export type { InstallDetourDecision, DetourOverlap } from "./builtin/install-detour.js";
21
+ export { parseInstallDetour } from "./builtin/install-detour.js";
20
22
  export type { SandboxProvider, SandboxOptions, ExecSandboxConfig } from "./builtin/sandbox/types.js";
21
23
  export { detectSandboxProvider } from "./builtin/sandbox/detect-provider.js";
22
24
  export type { DetectLogger } from "./builtin/sandbox/detect-provider.js";
@@ -44,7 +46,8 @@ export { createLinkRunner } from "./integrations/link/link-runner.js";
44
46
  export type { LinkRunner } from "./integrations/link/link-runner.js";
45
47
  export { createMcpClientManager, qualifyToolName, parseQualifiedName } from "./integrations/mcp-client.js";
46
48
  export type { McpClientManager, McpClientManagerDeps, McpServerConfig, McpConnection, McpConnectionStatus, McpToolDefinition, McpToolCallResult, McpToolCallContent, } from "./integrations/mcp-client.js";
47
- export { mcpToolsToAgentTools, jsonSchemaToTypeBox, sanitizeMcpToolName, extractMcpServerName, classifyMcpErrorType } from "./bridge/mcp-tool-bridge.js";
49
+ export { mcpToolsToAgentTools, jsonSchemaToTypeBox, sanitizeMcpToolName, classifyMcpErrorType } from "./bridge/mcp-tool-bridge.js";
50
+ export { extractMcpServerName } from "@comis/shared";
48
51
  export { createVisionProviderRegistry, selectVisionProvider } from "./integrations/vision/vision-provider-registry.js";
49
52
  export { resolveVisionScope } from "./integrations/vision/scope-resolver.js";
50
53
  export { detectFfmpeg, createAudioConverter, createMediaTempManager, createMediaSemaphore, createSsrfGuardedFetcher, createCompositeResolver, createMediaPersistenceService, } from "./media/index.js";
@@ -22,6 +22,7 @@ export { createApplyPatchTool } from "./builtin/file/apply-patch-tool.js";
22
22
  export { createExecTool } from "./builtin/exec-tool.js";
23
23
  export { createProcessTool } from "./builtin/process-tool.js";
24
24
  export { createProcessRegistry } from "./builtin/process-registry.js";
25
+ export { parseInstallDetour } from "./builtin/install-detour.js";
25
26
  // Built-in tools -- Exec sandbox detection
26
27
  export { detectSandboxProvider } from "./builtin/sandbox/detect-provider.js";
27
28
  // Registry
@@ -89,7 +90,8 @@ export { createLinkRunner } from "./integrations/link/link-runner.js";
89
90
  // Integrations -- MCP client manager
90
91
  export { createMcpClientManager, qualifyToolName, parseQualifiedName } from "./integrations/mcp-client.js";
91
92
  // Bridge -- MCP tool bridge
92
- export { mcpToolsToAgentTools, jsonSchemaToTypeBox, sanitizeMcpToolName, extractMcpServerName, classifyMcpErrorType } from "./bridge/mcp-tool-bridge.js";
93
+ export { mcpToolsToAgentTools, jsonSchemaToTypeBox, sanitizeMcpToolName, classifyMcpErrorType } from "./bridge/mcp-tool-bridge.js";
94
+ export { extractMcpServerName } from "@comis/shared";
93
95
  // Integrations -- Vision
94
96
  export { createVisionProviderRegistry, selectVisionProvider } from "./integrations/vision/vision-provider-registry.js";
95
97
  export { resolveVisionScope } from "./integrations/vision/scope-resolver.js";
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Defensive parser for `comis.capability` skill manifest blocks.
3
+ *
4
+ * The outer `ComisNamespaceSchema` is z.strictObject -- a typo'd nested
5
+ * capability key (`replacePackages` missing `s`) would normally cause the
6
+ * whole `comis:` block to fail parse and the skill to become invisible.
7
+ * This function parses the capability sub-block separately with try/recover
8
+ * semantics: on any validation failure (typo, type mismatch, empty string),
9
+ * log a Pino WARN with `errorKind: "config"` and return undefined. The skill
10
+ * renders under the fallback `prompt-skills` cluster.
11
+ *
12
+ * Capability metadata is enrichment, not a gate. The skill itself is NEVER
13
+ * hidden solely because optional capability metadata is invalid.
14
+ *
15
+ * Caller pattern:
16
+ * const ns = (typeof obj["comis"] === "object" && ...) ? ... : undefined;
17
+ * const capability = parseComisCapabilityDefensively(ns?.["capability"], skillName, logger);
18
+ * // ... include `capability` in SkillMetadata; downstream filters tolerate undefined.
19
+ *
20
+ * @module
21
+ */
22
+ import type { ToolCapabilityMetadata } from "@comis/core";
23
+ export type { ToolCapabilityMetadata };
24
+ /** Pino-compatible logger interface. The skills package already uses this shape; reuse here. */
25
+ interface DiscoveryLogger {
26
+ warn(obj: Record<string, unknown>, msg: string): void;
27
+ }
28
+ /**
29
+ * Defensively parse a `comis.capability` block.
30
+ *
31
+ * On success: returns the parsed shape (with defaults applied).
32
+ * On failure: logs a Pino WARN with `errorKind: "config"`, the skillName,
33
+ * the Zod issue paths, and an operator-actionable hint, then returns
34
+ * undefined. NEVER throws.
35
+ *
36
+ * @param raw - The raw `capability` value from `manifest.comis.capability`
37
+ * (may be undefined or null).
38
+ * @param skillName - Used in the WARN log payload for operator context.
39
+ * @param logger - Optional Pino logger. When omitted, parse failures fall
40
+ * through silently (the function still returns undefined;
41
+ * the caller may emit its own log).
42
+ * @returns Parsed capability metadata, or undefined if absent / malformed.
43
+ */
44
+ export declare function parseComisCapabilityDefensively(raw: unknown, skillName: string, logger: DiscoveryLogger | undefined): ToolCapabilityMetadata | undefined;
@@ -0,0 +1,68 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Defensive parser for `comis.capability` skill manifest blocks.
4
+ *
5
+ * The outer `ComisNamespaceSchema` is z.strictObject -- a typo'd nested
6
+ * capability key (`replacePackages` missing `s`) would normally cause the
7
+ * whole `comis:` block to fail parse and the skill to become invisible.
8
+ * This function parses the capability sub-block separately with try/recover
9
+ * semantics: on any validation failure (typo, type mismatch, empty string),
10
+ * log a Pino WARN with `errorKind: "config"` and return undefined. The skill
11
+ * renders under the fallback `prompt-skills` cluster.
12
+ *
13
+ * Capability metadata is enrichment, not a gate. The skill itself is NEVER
14
+ * hidden solely because optional capability metadata is invalid.
15
+ *
16
+ * Caller pattern:
17
+ * const ns = (typeof obj["comis"] === "object" && ...) ? ... : undefined;
18
+ * const capability = parseComisCapabilityDefensively(ns?.["capability"], skillName, logger);
19
+ * // ... include `capability` in SkillMetadata; downstream filters tolerate undefined.
20
+ *
21
+ * @module
22
+ */
23
+ import { ComisCapabilityBlockSchema } from "./schema.js";
24
+ /**
25
+ * Defensively parse a `comis.capability` block.
26
+ *
27
+ * On success: returns the parsed shape (with defaults applied).
28
+ * On failure: logs a Pino WARN with `errorKind: "config"`, the skillName,
29
+ * the Zod issue paths, and an operator-actionable hint, then returns
30
+ * undefined. NEVER throws.
31
+ *
32
+ * @param raw - The raw `capability` value from `manifest.comis.capability`
33
+ * (may be undefined or null).
34
+ * @param skillName - Used in the WARN log payload for operator context.
35
+ * @param logger - Optional Pino logger. When omitted, parse failures fall
36
+ * through silently (the function still returns undefined;
37
+ * the caller may emit its own log).
38
+ * @returns Parsed capability metadata, or undefined if absent / malformed.
39
+ */
40
+ export function parseComisCapabilityDefensively(raw, skillName, logger) {
41
+ // Fast path: no capability block declared -> no log, no work.
42
+ if (raw === undefined)
43
+ return undefined;
44
+ const result = ComisCapabilityBlockSchema.safeParse(raw);
45
+ if (result.success) {
46
+ // Coerce the Zod-inferred shape into ToolCapabilityMetadata
47
+ // (compatible by structure).
48
+ return {
49
+ cluster: result.data.cluster,
50
+ summary: result.data.summary,
51
+ replacesPackages: result.data.replacesPackages,
52
+ };
53
+ }
54
+ // Malformed -- log WARN and fall back. This path NEVER raises an exception.
55
+ const issues = result.error.issues.map((issue) => ({
56
+ path: issue.path.join("."),
57
+ code: issue.code,
58
+ message: issue.message,
59
+ }));
60
+ logger?.warn({
61
+ errorKind: "config",
62
+ skillName,
63
+ issues,
64
+ hint: "Fix the comis.capability block in the skill manifest, or remove it. " +
65
+ "The skill will render under the fallback 'prompt-skills' cluster until corrected.",
66
+ }, "Malformed comis.capability metadata; skill renders under fallback cluster.");
67
+ return undefined;
68
+ }
@@ -10,13 +10,9 @@ export declare const SkillNameSchema: z.ZodString;
10
10
  * All fields default to empty arrays (no permissions).
11
11
  */
12
12
  export declare const SkillPermissionsSchema: z.ZodObject<{
13
- /** Filesystem read access paths (e.g. ["/tmp/skill-data"]) */
14
13
  fsRead: z.ZodDefault<z.ZodArray<z.ZodString>>;
15
- /** Filesystem write access paths */
16
14
  fsWrite: z.ZodDefault<z.ZodArray<z.ZodString>>;
17
- /** Network access domains (e.g. ["api.example.com"]) */
18
15
  net: z.ZodDefault<z.ZodArray<z.ZodString>>;
19
- /** Environment variable access (read-only, specific keys) */
20
16
  env: z.ZodDefault<z.ZodArray<z.ZodString>>;
21
17
  }, z.core.$strict>;
22
18
  /**
@@ -24,7 +20,7 @@ export declare const SkillPermissionsSchema: z.ZodObject<{
24
20
  * Accepts a single string (wraps in array, lowercases) or an array of strings (lowercases each).
25
21
  * No enum restriction -- any OS string is valid (e.g., "playstation").
26
22
  */
27
- export declare const OsFieldSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodArray<z.ZodString>>>;
23
+ export declare const OsFieldSchema: z.ZodPreprocess<z.ZodOptional<z.ZodArray<z.ZodString>>>;
28
24
  /**
29
25
  * Skill prerequisites schema (strict: only bins and env keys accepted).
30
26
  * Undefined means no prerequisites; present means the skill declares external dependencies.
@@ -37,7 +33,35 @@ export declare const SkillRequiresSchema: z.ZodObject<{
37
33
  * Skill key schema with preprocess coercion to slug format.
38
34
  * Lowercases, replaces spaces with hyphens, strips non-alphanumeric-hyphen chars.
39
35
  */
40
- export declare const SkillKeySchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>;
36
+ export declare const SkillKeySchema: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
37
+ /**
38
+ * Capability metadata block for v1.1 capability layer.
39
+ *
40
+ * Optional sub-block of `comis:` namespace. All inner fields optional. The
41
+ * block is z.strictObject -- unknown nested keys (typos like
42
+ * `replacePackages` missing `s`) are rejected when used in a strict-parse
43
+ * context.
44
+ *
45
+ * IMPORTANT -- defensive parse at registry-side:
46
+ * The outer ComisNamespaceSchema is strict, so a malformed `capability` block
47
+ * would normally cause the whole `comis:` block to fail parse and the skill
48
+ * to become invisible. The registry's discovery enrichment extracts
49
+ * `comis.capability` SEPARATELY via `parseComisCapabilityDefensively`, which
50
+ * logs a WARN and returns undefined on failure -- letting the skill render
51
+ * under the fallback `prompt-skills` cluster. The strict schema here is the
52
+ * declaration of the contract; the defensive parser is the recovery
53
+ * mechanism.
54
+ *
55
+ * The skill itself is never hidden solely because optional capability
56
+ * metadata is invalid.
57
+ */
58
+ export declare const ComisCapabilityBlockSchema: z.ZodObject<{
59
+ cluster: z.ZodOptional<z.ZodString>;
60
+ summary: z.ZodOptional<z.ZodString>;
61
+ replacesPackages: z.ZodDefault<z.ZodArray<z.ZodString>>;
62
+ }, z.core.$strict>;
63
+ /** Parsed `comis.capability` block (Zod-inferred, defaults applied). */
64
+ export type ComisCapabilityBlockParsed = z.infer<typeof ComisCapabilityBlockSchema>;
41
65
  /**
42
66
  * Comis-specific namespace schema for fields that only apply within the
43
67
  * Comis platform. Other pi-coding-agent hosts will simply ignore this block.
@@ -45,19 +69,19 @@ export declare const SkillKeySchema: z.ZodPipe<z.ZodTransform<unknown, unknown>,
45
69
  * Skills place these fields under `comis:` in frontmatter.
46
70
  */
47
71
  export declare const ComisNamespaceSchema: z.ZodOptional<z.ZodObject<{
48
- /** Target operating systems (coerced: string -> [string], lowercased) */
49
- os: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodArray<z.ZodString>>>;
50
- /** External prerequisites: binary executables and environment variables */
72
+ os: z.ZodPreprocess<z.ZodOptional<z.ZodArray<z.ZodString>>>;
51
73
  requires: z.ZodOptional<z.ZodObject<{
52
74
  bins: z.ZodDefault<z.ZodArray<z.ZodString>>;
53
75
  env: z.ZodDefault<z.ZodArray<z.ZodString>>;
54
76
  }, z.core.$strict>>;
55
- /** Explicit skill key override (coerced to slug format) */
56
- "skill-key": z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>;
57
- /** Display/grouping hint for primary environment (e.g., "discord", "telegram") */
77
+ "skill-key": z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
58
78
  "primary-env": z.ZodOptional<z.ZodString>;
59
- /** Metadata-only dispatch tag for command routing */
60
79
  "command-dispatch": z.ZodOptional<z.ZodString>;
80
+ capability: z.ZodOptional<z.ZodObject<{
81
+ cluster: z.ZodOptional<z.ZodString>;
82
+ summary: z.ZodOptional<z.ZodString>;
83
+ replacesPackages: z.ZodDefault<z.ZodArray<z.ZodString>>;
84
+ }, z.core.$strict>>;
61
85
  }, z.core.$strict>>;
62
86
  /** Parsed Comis namespace block type. */
63
87
  export type ComisNamespaceParsed = z.infer<typeof ComisNamespaceSchema>;
@@ -69,54 +93,37 @@ export type ComisNamespaceParsed = z.infer<typeof ComisNamespaceSchema>;
69
93
  * exclusively under the `comis:` namespace block.
70
94
  */
71
95
  export declare const SkillManifestSchema: z.ZodObject<{
72
- /** Unique skill name (lowercase alphanumeric with hyphens) */
73
96
  name: z.ZodString;
74
- /** Human-readable description (1-1024 chars) */
75
97
  description: z.ZodString;
76
- /** Skill type: always "prompt" for Markdown instruction skills. */
77
98
  type: z.ZodDefault<z.ZodLiteral<"prompt">>;
78
- /** Semver version string */
79
99
  version: z.ZodOptional<z.ZodString>;
80
- /** SPDX license identifier */
81
100
  license: z.ZodOptional<z.ZodString>;
82
- /** Whether users can invoke this skill via /skill:name (default true) */
83
101
  userInvocable: z.ZodDefault<z.ZodBoolean>;
84
- /** When true, skill is hidden from model's available skills listing (default false) */
85
102
  disableModelInvocation: z.ZodDefault<z.ZodBoolean>;
86
- /** Tool restrictions when skill is active; empty array means no restriction (default []) */
87
103
  allowedTools: z.ZodDefault<z.ZodArray<z.ZodString>>;
88
- /** Optional hint text shown to users (e.g., "[name]") */
89
104
  argumentHint: z.ZodOptional<z.ZodString>;
90
- /** Required permissions */
91
105
  permissions: z.ZodDefault<z.ZodObject<{
92
- /** Filesystem read access paths (e.g. ["/tmp/skill-data"]) */
93
106
  fsRead: z.ZodDefault<z.ZodArray<z.ZodString>>;
94
- /** Filesystem write access paths */
95
107
  fsWrite: z.ZodDefault<z.ZodArray<z.ZodString>>;
96
- /** Network access domains (e.g. ["api.example.com"]) */
97
108
  net: z.ZodDefault<z.ZodArray<z.ZodString>>;
98
- /** Environment variable access (read-only, specific keys) */
99
109
  env: z.ZodDefault<z.ZodArray<z.ZodString>>;
100
110
  }, z.core.$strict>>;
101
- /** JSON Schema describing the skill's input parameters */
102
111
  inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
103
- /** Arbitrary key-value metadata */
104
112
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
105
- /** Comis-specific namespace block for platform-only fields */
106
113
  comis: z.ZodOptional<z.ZodObject<{
107
- /** Target operating systems (coerced: string -> [string], lowercased) */
108
- os: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodArray<z.ZodString>>>;
109
- /** External prerequisites: binary executables and environment variables */
114
+ os: z.ZodPreprocess<z.ZodOptional<z.ZodArray<z.ZodString>>>;
110
115
  requires: z.ZodOptional<z.ZodObject<{
111
116
  bins: z.ZodDefault<z.ZodArray<z.ZodString>>;
112
117
  env: z.ZodDefault<z.ZodArray<z.ZodString>>;
113
118
  }, z.core.$strict>>;
114
- /** Explicit skill key override (coerced to slug format) */
115
- "skill-key": z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>;
116
- /** Display/grouping hint for primary environment (e.g., "discord", "telegram") */
119
+ "skill-key": z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
117
120
  "primary-env": z.ZodOptional<z.ZodString>;
118
- /** Metadata-only dispatch tag for command routing */
119
121
  "command-dispatch": z.ZodOptional<z.ZodString>;
122
+ capability: z.ZodOptional<z.ZodObject<{
123
+ cluster: z.ZodOptional<z.ZodString>;
124
+ summary: z.ZodOptional<z.ZodString>;
125
+ replacesPackages: z.ZodDefault<z.ZodArray<z.ZodString>>;
126
+ }, z.core.$strict>>;
120
127
  }, z.core.$strict>>;
121
128
  }, z.core.$strict>;
122
129
  /** Parsed and validated skill manifest. */
@@ -58,6 +58,35 @@ export const SkillKeySchema = z.preprocess((val) => {
58
58
  }
59
59
  return val;
60
60
  }, z.string().regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "skill-key must be a valid slug").optional());
61
+ /**
62
+ * Capability metadata block for v1.1 capability layer.
63
+ *
64
+ * Optional sub-block of `comis:` namespace. All inner fields optional. The
65
+ * block is z.strictObject -- unknown nested keys (typos like
66
+ * `replacePackages` missing `s`) are rejected when used in a strict-parse
67
+ * context.
68
+ *
69
+ * IMPORTANT -- defensive parse at registry-side:
70
+ * The outer ComisNamespaceSchema is strict, so a malformed `capability` block
71
+ * would normally cause the whole `comis:` block to fail parse and the skill
72
+ * to become invisible. The registry's discovery enrichment extracts
73
+ * `comis.capability` SEPARATELY via `parseComisCapabilityDefensively`, which
74
+ * logs a WARN and returns undefined on failure -- letting the skill render
75
+ * under the fallback `prompt-skills` cluster. The strict schema here is the
76
+ * declaration of the contract; the defensive parser is the recovery
77
+ * mechanism.
78
+ *
79
+ * The skill itself is never hidden solely because optional capability
80
+ * metadata is invalid.
81
+ */
82
+ export const ComisCapabilityBlockSchema = z.strictObject({
83
+ /** Cluster ID this skill belongs to (operator may override via tooling.skills.capabilityHints). */
84
+ cluster: z.string().min(1).optional(),
85
+ /** Operator-tunable display summary; falls back to skill description if absent. */
86
+ summary: z.string().min(1).optional(),
87
+ /** Package names this skill replaces (for install-detour overlap detection). */
88
+ replacesPackages: z.array(z.string().min(1)).default([]),
89
+ });
61
90
  /**
62
91
  * Comis-specific namespace schema for fields that only apply within the
63
92
  * Comis platform. Other pi-coding-agent hosts will simply ignore this block.
@@ -75,6 +104,12 @@ export const ComisNamespaceSchema = z.strictObject({
75
104
  "primary-env": z.string().optional(),
76
105
  /** Metadata-only dispatch tag for command routing */
77
106
  "command-dispatch": z.string().optional(),
107
+ /**
108
+ * v1.1 capability layer -- optional metadata for cluster, summary,
109
+ * package aliases. Defensively parsed at registry-side; a typo here will
110
+ * NOT hide the skill.
111
+ */
112
+ capability: ComisCapabilityBlockSchema.optional(),
78
113
  }).optional();
79
114
  /**
80
115
  * Full SKILL.md manifest schema.
@@ -17,6 +17,7 @@
17
17
  *
18
18
  * @module
19
19
  */
20
+ import type { ToolCapabilityMetadata } from "@comis/core";
20
21
  import type { ResourceDiagnostic } from "./diagnostics.js";
21
22
  /** Minimal pino-compatible logger for discovery warnings. */
22
23
  export interface DiscoveryLogger {
@@ -63,6 +64,13 @@ export interface SkillMetadata {
63
64
  readonly primaryEnv?: string;
64
65
  /** Dispatch mode tag (metadata-only in this phase). */
65
66
  readonly commandDispatch?: string;
67
+ /**
68
+ * Capability layer -- extracted from `comis.capability` via defensive
69
+ * parse. Malformed metadata -> undefined + WARN log. The skill still
70
+ * renders under the fallback `prompt-skills` cluster when this is
71
+ * undefined; metadata absence never hides the skill.
72
+ */
73
+ readonly capability?: ToolCapabilityMetadata;
66
74
  }
67
75
  /** Result of skill discovery: skills found plus any diagnostics (collisions, warnings). */
68
76
  export interface DiscoveryResult {
@@ -22,6 +22,7 @@ import * as fs from "node:fs";
22
22
  import * as path from "node:path";
23
23
  import ignore from "ignore";
24
24
  import { parseFrontmatter } from "../manifest/parser.js";
25
+ import { parseComisCapabilityDefensively } from "../manifest/capability-parser.js";
25
26
  // ---------------------------------------------------------------------------
26
27
  // Ignore helpers
27
28
  // ---------------------------------------------------------------------------
@@ -108,7 +109,7 @@ function resolveSource(pathIndex, totalPaths) {
108
109
  * Only parses the frontmatter block -- does not validate the full manifest schema.
109
110
  * This keeps discovery fast and lightweight (Level 1 progressive disclosure).
110
111
  */
111
- function extractMetadataFromSkillMd(skillMdPath) {
112
+ function extractMetadataFromSkillMd(skillMdPath, logger) {
112
113
  let content;
113
114
  try {
114
115
  content = fs.readFileSync(skillMdPath, "utf-8");
@@ -163,7 +164,12 @@ function extractMetadataFromSkillMd(skillMdPath) {
163
164
  // command-dispatch field
164
165
  const rawCommandDispatch = ns?.["command-dispatch"];
165
166
  const commandDispatch = typeof rawCommandDispatch === "string" ? rawCommandDispatch : undefined;
166
- return { name: obj["name"], description: obj["description"], type, userInvocable, disableModelInvocation, argumentHint, os, requires, skillKey, primaryEnv, commandDispatch };
167
+ // Capability layer -- defensive parse. A typo or type mismatch in
168
+ // `comis.capability` returns undefined + emits a WARN; the skill itself
169
+ // remains visible (renders under the fallback "prompt-skills" cluster
170
+ // downstream).
171
+ const capability = parseComisCapabilityDefensively(ns?.["capability"], obj["name"], logger);
172
+ return { name: obj["name"], description: obj["description"], type, userInvocable, disableModelInvocation, argumentHint, os, requires, skillKey, primaryEnv, commandDispatch, capability };
167
173
  }
168
174
  /**
169
175
  * Recursive internal helper for discovering skills within a directory tree.
@@ -237,7 +243,7 @@ function discoverSkillsFromDir(dir, source, includeRootFiles, skillMap, diagnost
237
243
  // Silent skip if same real file already loaded (same file via different symlink)
238
244
  if (realPathSet.has(realPath))
239
245
  continue;
240
- const metadata = extractMetadataFromSkillMd(fullPath);
246
+ const metadata = extractMetadataFromSkillMd(fullPath, logger);
241
247
  if (metadata === null) {
242
248
  logger?.warn({ skillPath: fullPath, hint: "Check skill file has valid YAML frontmatter with name and description fields", errorKind: "validation" }, "Skipping malformed skill file");
243
249
  continue;
@@ -278,6 +284,7 @@ function discoverSkillsFromDir(dir, source, includeRootFiles, skillMap, diagnost
278
284
  skillKey: metadata.skillKey,
279
285
  primaryEnv: metadata.primaryEnv,
280
286
  commandDispatch: metadata.commandDispatch,
287
+ capability: metadata.capability,
281
288
  };
282
289
  skillMap.set(metadata.name, skillMeta);
283
290
  realPathSet.add(realPath);
@@ -10,12 +10,25 @@
10
10
  *
11
11
  * @module
12
12
  */
13
- import type { SkillsConfig, TypedEventBus } from "@comis/core";
13
+ import type { PromptSkillCapability, SkillsConfig, TypedEventBus } from "@comis/core";
14
14
  import type { Result } from "@comis/shared";
15
15
  import { type PromptSkillDescription } from "../prompt/processor.js";
16
16
  import { type SkillMetadata, type SkillSource } from "./discovery.js";
17
17
  import { type RuntimeEligibilityContext } from "./eligibility.js";
18
18
  import { type SkillWatcherHandle } from "./skill-watcher.js";
19
+ /**
20
+ * Operator hint shape consumed by `getPromptSkillCapabilities`.
21
+ *
22
+ * Mirrors the return shape of `ToolCapabilityPort.getSkillHint` in
23
+ * `@comis/core/ports/tool-capability.ts`. The registry stays decoupled from
24
+ * the port itself -- daemon-side wiring passes the port's `getSkillHint`
25
+ * method as the callback.
26
+ */
27
+ type OperatorSkillHint = {
28
+ readonly cluster: string;
29
+ readonly description?: string;
30
+ readonly replacesPackages: readonly string[];
31
+ };
19
32
  /** Minimal pino-compatible logger interface for skills subsystem logging. */
20
33
  interface SkillsLogger {
21
34
  info(obj: Record<string, unknown>, msg: string): void;
@@ -101,6 +114,37 @@ export interface SkillRegistry {
101
114
  * Acts as the Comis eligibility gate for SDK discovery.
102
115
  */
103
116
  getEligibleSkillNames(): Set<string>;
117
+ /**
118
+ * Return all visible eligible prompt skills with merged capability metadata.
119
+ *
120
+ * Applies the same `allowedSkills`/`deniedSkills` and runtime-eligibility
121
+ * filters as `getPromptSkillDescriptions`, PLUS an extra
122
+ * `disableModelInvocation !== true` filter -- skills hidden from the model
123
+ * are not surfaced as capability index entries.
124
+ *
125
+ * Capability merge precedence:
126
+ * 1. operator hint by `skillKey` (when the skill declares one)
127
+ * 2. operator hint by skill name (always available as fallback)
128
+ * 3. `comis.capability` from the skill manifest (already in
129
+ * `metadata.capability`)
130
+ * 4. Fallback: `cluster` undefined (renderer falls back to the literal
131
+ * `"prompt-skills"` cluster); `summary` = `description`;
132
+ * `replacesPackages` = `[]`.
133
+ *
134
+ * The `getOperatorHint` callback keeps the registry decoupled from
135
+ * `ToolCapabilityPort` -- daemon-side adapters pass the port's
136
+ * `getSkillHint` method here.
137
+ *
138
+ * Fresh-per-call (no memoization). Returns a frozen array of frozen entries.
139
+ *
140
+ * IMPORTANT -- cache fence:
141
+ * This method MUST NOT be consumed by `assembleRichSystemPrompt`'s
142
+ * `assemblerParams` in `packages/agent/src/executor/prompt-assembly.ts`.
143
+ * If a skill discovery sweep runs between turns, the cached system-prompt
144
+ * prefix MUST stay byte-identical. An architecture-grep test enforces this
145
+ * invariant.
146
+ */
147
+ getPromptSkillCapabilities(getOperatorHint: (skillName: string, skillKey?: string) => OperatorSkillHint | undefined): readonly PromptSkillCapability[];
104
148
  /**
105
149
  * Populate the registry from SDK-discovered skills instead of filesystem discovery.
106
150
  * Clears existing metadata, maps SDK Skill fields to Comis SkillMetadata,