@milpa/comal 0.1.0 → 0.1.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 (185) hide show
  1. package/README.md +30 -28
  2. package/backend/contracts/remote-commands-v1.json +125 -0
  3. package/bin/comal.mjs +16 -5
  4. package/docs/investigation.md +2 -2
  5. package/governance/chrome-task-v2.json +67 -0
  6. package/node_modules/@jitl/quickjs-ffi-types/LICENSE +21 -0
  7. package/node_modules/@jitl/quickjs-ffi-types/README.md +5 -0
  8. package/node_modules/@jitl/quickjs-ffi-types/dist/index.d.mts +549 -0
  9. package/node_modules/@jitl/quickjs-ffi-types/dist/index.d.ts +549 -0
  10. package/node_modules/@jitl/quickjs-ffi-types/dist/index.js +2 -0
  11. package/node_modules/@jitl/quickjs-ffi-types/dist/index.js.map +1 -0
  12. package/node_modules/@jitl/quickjs-ffi-types/dist/index.mjs +2 -0
  13. package/node_modules/@jitl/quickjs-ffi-types/dist/index.mjs.map +1 -0
  14. package/node_modules/@jitl/quickjs-ffi-types/package.json +36 -0
  15. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/LICENSE +47 -0
  16. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/README.md +93 -0
  17. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.browser.d.ts +15 -0
  18. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.browser.mjs +2 -0
  19. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.cjs +2 -0
  20. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.cloudflare.cjs +2 -0
  21. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.cloudflare.d.ts +15 -0
  22. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.d.ts +15 -0
  23. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.mjs +2 -0
  24. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.wasm +0 -0
  25. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/emscripten-module.wasm.map +1 -0
  26. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/ffi.d.mts +94 -0
  27. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/ffi.d.ts +94 -0
  28. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/ffi.js +2 -0
  29. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/ffi.js.map +1 -0
  30. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/ffi.mjs +2 -0
  31. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/ffi.mjs.map +1 -0
  32. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/index.d.mts +20 -0
  33. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/index.d.ts +20 -0
  34. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/index.js +2 -0
  35. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/index.js.map +1 -0
  36. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/index.mjs +2 -0
  37. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/dist/index.mjs.map +1 -0
  38. package/node_modules/@jitl/quickjs-wasmfile-debug-asyncify/package.json +61 -0
  39. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/LICENSE +47 -0
  40. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/README.md +88 -0
  41. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.browser.d.ts +11 -0
  42. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.browser.mjs +5430 -0
  43. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.cjs +5485 -0
  44. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.cloudflare.cjs +5424 -0
  45. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
  46. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.d.ts +11 -0
  47. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.mjs +5541 -0
  48. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.wasm +0 -0
  49. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/emscripten-module.wasm.map +1 -0
  50. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/ffi.d.mts +85 -0
  51. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/ffi.d.ts +85 -0
  52. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/ffi.js +2 -0
  53. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/ffi.js.map +1 -0
  54. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/ffi.mjs +2 -0
  55. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/ffi.mjs.map +1 -0
  56. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/index.d.mts +20 -0
  57. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/index.d.ts +20 -0
  58. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/index.js +2 -0
  59. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/index.js.map +1 -0
  60. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/index.mjs +2 -0
  61. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/dist/index.mjs.map +1 -0
  62. package/node_modules/@jitl/quickjs-wasmfile-debug-sync/package.json +61 -0
  63. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/LICENSE +47 -0
  64. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/README.md +89 -0
  65. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.browser.d.ts +15 -0
  66. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.browser.mjs +26 -0
  67. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.cjs +25 -0
  68. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.cloudflare.cjs +25 -0
  69. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.cloudflare.d.ts +15 -0
  70. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.d.ts +15 -0
  71. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.mjs +30 -0
  72. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/emscripten-module.wasm +0 -0
  73. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/ffi.d.mts +94 -0
  74. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/ffi.d.ts +94 -0
  75. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/ffi.js +2 -0
  76. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/ffi.js.map +1 -0
  77. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/ffi.mjs +2 -0
  78. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/ffi.mjs.map +1 -0
  79. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/index.d.mts +20 -0
  80. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/index.d.ts +20 -0
  81. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/index.js +2 -0
  82. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/index.js.map +1 -0
  83. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/index.mjs +2 -0
  84. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/dist/index.mjs.map +1 -0
  85. package/node_modules/@jitl/quickjs-wasmfile-release-asyncify/package.json +61 -0
  86. package/node_modules/@jitl/quickjs-wasmfile-release-sync/LICENSE +47 -0
  87. package/node_modules/@jitl/quickjs-wasmfile-release-sync/README.md +82 -0
  88. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.browser.d.ts +11 -0
  89. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.browser.mjs +22 -0
  90. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.cjs +21 -0
  91. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
  92. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
  93. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.d.ts +11 -0
  94. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.mjs +25 -0
  95. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm +0 -0
  96. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/ffi.d.mts +85 -0
  97. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/ffi.d.ts +85 -0
  98. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/ffi.js +2 -0
  99. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/ffi.js.map +1 -0
  100. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/ffi.mjs +2 -0
  101. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/ffi.mjs.map +1 -0
  102. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.d.mts +20 -0
  103. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.d.ts +20 -0
  104. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.js +2 -0
  105. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.js.map +1 -0
  106. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.mjs +2 -0
  107. package/node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.mjs.map +1 -0
  108. package/node_modules/@jitl/quickjs-wasmfile-release-sync/package.json +61 -0
  109. package/node_modules/quickjs-emscripten/LICENSE +21 -0
  110. package/node_modules/quickjs-emscripten/README.md +928 -0
  111. package/node_modules/quickjs-emscripten/dist/chunk-OHAYRCBA.mjs +2 -0
  112. package/node_modules/quickjs-emscripten/dist/chunk-OHAYRCBA.mjs.map +1 -0
  113. package/node_modules/quickjs-emscripten/dist/index.d.mts +57 -0
  114. package/node_modules/quickjs-emscripten/dist/index.d.ts +57 -0
  115. package/node_modules/quickjs-emscripten/dist/index.global.js +7309 -0
  116. package/node_modules/quickjs-emscripten/dist/index.js +2 -0
  117. package/node_modules/quickjs-emscripten/dist/index.js.map +1 -0
  118. package/node_modules/quickjs-emscripten/dist/index.mjs +2 -0
  119. package/node_modules/quickjs-emscripten/dist/index.mjs.map +1 -0
  120. package/node_modules/quickjs-emscripten/dist/variants.d.mts +39 -0
  121. package/node_modules/quickjs-emscripten/dist/variants.d.ts +39 -0
  122. package/node_modules/quickjs-emscripten/dist/variants.js +2 -0
  123. package/node_modules/quickjs-emscripten/dist/variants.js.map +1 -0
  124. package/node_modules/quickjs-emscripten/dist/variants.mjs +2 -0
  125. package/node_modules/quickjs-emscripten/dist/variants.mjs.map +1 -0
  126. package/node_modules/quickjs-emscripten/package.json +69 -0
  127. package/node_modules/quickjs-emscripten-core/LICENSE +21 -0
  128. package/node_modules/quickjs-emscripten-core/README.md +341 -0
  129. package/node_modules/quickjs-emscripten-core/README.template.md +70 -0
  130. package/node_modules/quickjs-emscripten-core/dist/chunk-TAV5CUKK.mjs +2 -0
  131. package/node_modules/quickjs-emscripten-core/dist/chunk-TAV5CUKK.mjs.map +1 -0
  132. package/node_modules/quickjs-emscripten-core/dist/chunk-V2S4ZYJR.mjs +7 -0
  133. package/node_modules/quickjs-emscripten-core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
  134. package/node_modules/quickjs-emscripten-core/dist/index.d.mts +2033 -0
  135. package/node_modules/quickjs-emscripten-core/dist/index.d.ts +2033 -0
  136. package/node_modules/quickjs-emscripten-core/dist/index.js +7 -0
  137. package/node_modules/quickjs-emscripten-core/dist/index.js.map +1 -0
  138. package/node_modules/quickjs-emscripten-core/dist/index.mjs +2 -0
  139. package/node_modules/quickjs-emscripten-core/dist/index.mjs.map +1 -0
  140. package/node_modules/quickjs-emscripten-core/dist/module-ES6BEMUI.mjs +2 -0
  141. package/node_modules/quickjs-emscripten-core/dist/module-ES6BEMUI.mjs.map +1 -0
  142. package/node_modules/quickjs-emscripten-core/dist/module-asyncify-2EFITU5U.mjs +2 -0
  143. package/node_modules/quickjs-emscripten-core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
  144. package/node_modules/quickjs-emscripten-core/package.json +49 -0
  145. package/package.json +6 -2
  146. package/src/agent.mjs +17 -6
  147. package/src/artifact-tools.mjs +3 -2
  148. package/src/cli.mjs +261 -199
  149. package/src/cloud-client.mjs +50 -8
  150. package/src/code-run-worker.mjs +70 -0
  151. package/src/code-run.mjs +97 -0
  152. package/src/codex-provider.mjs +27 -27
  153. package/src/compaction.mjs +1 -1
  154. package/src/goals.mjs +2 -2
  155. package/src/house.mjs +24 -24
  156. package/src/i18n/cli-es.mjs +97 -0
  157. package/src/i18n/es.mjs +227 -0
  158. package/src/i18n/index.mjs +48 -0
  159. package/src/image-attachments.mjs +263 -0
  160. package/src/model-controls.mjs +4 -4
  161. package/src/onboarding.mjs +91 -0
  162. package/src/openai-provider.mjs +24 -24
  163. package/src/permissions.mjs +52 -16
  164. package/src/provider-auth.mjs +30 -30
  165. package/src/provider-profiles.mjs +27 -27
  166. package/src/provider.mjs +30 -30
  167. package/src/remote-commands.mjs +11 -0
  168. package/src/remote-control.mjs +172 -0
  169. package/src/sessions.mjs +3 -3
  170. package/src/subagents.mjs +7 -3
  171. package/src/tool-packs.mjs +5 -2
  172. package/src/tools.mjs +81 -31
  173. package/src/tui/brand.mjs +2 -1
  174. package/src/tui/clipboard.mjs +5 -4
  175. package/src/tui/composer.mjs +77 -11
  176. package/src/tui/controller.mjs +110 -29
  177. package/src/tui/discovery.mjs +105 -100
  178. package/src/tui/markdown.mjs +10 -9
  179. package/src/tui/message-queue.mjs +27 -9
  180. package/src/tui/screen.mjs +209 -118
  181. package/src/vision.mjs +31 -3
  182. package/src/work-assertions.mjs +7 -7
  183. package/src/work-plan.mjs +104 -14
  184. package/src/work-recovery-proof.mjs +13 -1
  185. package/src/workflows/chrome-task.mjs +24 -7
@@ -0,0 +1,2 @@
1
+ import{QuickJSModuleCallbacks,QuickJSWASMModule,applyBaseRuntimeOptions,applyModuleEvalRuntimeOptions}from"./chunk-V2S4ZYJR.mjs";export{QuickJSModuleCallbacks,QuickJSWASMModule,applyBaseRuntimeOptions,applyModuleEvalRuntimeOptions};
2
+ //# sourceMappingURL=module-ES6BEMUI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+ import{QuickJSAsyncWASMModule}from"./chunk-TAV5CUKK.mjs";import"./chunk-V2S4ZYJR.mjs";export{QuickJSAsyncWASMModule};
2
+ //# sourceMappingURL=module-asyncify-2EFITU5U.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "quickjs-emscripten-core",
3
+ "version": "0.32.0",
4
+ "sideEffects": false,
5
+ "license": "MIT",
6
+ "type": "commonjs",
7
+ "keywords": [
8
+ "eval",
9
+ "quickjs",
10
+ "vm",
11
+ "interpreter",
12
+ "runtime",
13
+ "safe",
14
+ "emscripten",
15
+ "wasm"
16
+ ],
17
+ "author": {
18
+ "name": "Jake Teton-Landis",
19
+ "url": "https://jake.tl"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/justjake/quickjs-emscripten"
24
+ },
25
+ "files": [
26
+ "LICENSE",
27
+ "dist/**/*",
28
+ "!dist/*.test.js",
29
+ "!dist/*.tsbuildinfo"
30
+ ],
31
+ "types": "./dist/index.d.ts",
32
+ "main": "./dist/index.js",
33
+ "module": "./dist/index.mjs",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/index.mjs",
38
+ "require": "./dist/index.js"
39
+ }
40
+ },
41
+ "scripts": {
42
+ "tsc": "npx tsc -p . --noEmit",
43
+ "test": "npx vitest run",
44
+ "build": "npx tsup"
45
+ },
46
+ "dependencies": {
47
+ "@jitl/quickjs-ffi-types": "0.32.0"
48
+ }
49
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@milpa/comal",
3
- "version": "0.1.0",
4
- "description": "Comal: operaciones gobernadas, recibos de ejecución y asistencia de programación en cualquier lenguaje",
3
+ "version": "0.1.1",
4
+ "description": "Comal: governed operations, execution receipts, and programming assistance in any language",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "publishConfig": {
@@ -21,7 +21,9 @@
21
21
  "src",
22
22
  "backend/verifier/transport.mjs",
23
23
  "backend/contracts/artifact-check-v1.schema.json",
24
+ "backend/contracts/remote-commands-v1.json",
24
25
  "governance/chrome-task-v1.json",
26
+ "governance/chrome-task-v2.json",
25
27
  "docs",
26
28
  "README.md"
27
29
  ],
@@ -29,12 +31,14 @@
29
31
  "ajv": "8.20.0",
30
32
  "cheerio": "1.2.0",
31
33
  "marked": "18.1.1",
34
+ "quickjs-emscripten": "0.32.0",
32
35
  "string-width": "8.3.0"
33
36
  },
34
37
  "bundledDependencies": [
35
38
  "ajv",
36
39
  "cheerio",
37
40
  "marked",
41
+ "quickjs-emscripten",
38
42
  "string-width"
39
43
  ]
40
44
  }
package/src/agent.mjs CHANGED
@@ -16,6 +16,7 @@ import { chromeLabObservation, runtimeBoundReadCheck } from './read-only-check.m
16
16
  import { RequestMetrics, turnOutcome } from './execution-metrics.mjs';
17
17
  import {accountingIdentity} from './usage-accounting.mjs';
18
18
  import {scheduleToolCalls} from './tool-scheduler.mjs';
19
+ import { resolveHumanImage, HUMAN_IMAGE_COUNT } from './image-attachments.mjs';
19
20
  const BROWSER_SYSTEM="\nBrowser debugging: inspect get_console_message stacks before guessing from source. After web edits reload and obtain NEW DOM/console evidence; old errors describe pre-edit code. Inspect public DOM, not closure-private globals. Prefer synchronous evaluate_script with waitForStableDom:false on animated pages; async probes must settle on success/error. Extra observations require no new plan. For visual deliverables capture browser.capture screenshots and inspect sent pixels when supported; DOM/console alone do not prove rendering.";
20
21
  const ADMIN_POLL = new Set(['WorkBoard','WorkSnapshot','AuditStatus','HouseSnapshot','OperationCatalog','HouseContext','PluginStatus','McpStatus']);
21
22
  const operationLookup = tools => {
@@ -117,8 +118,8 @@ export class Agent {
117
118
  this.compactor = new ContextCompactor({ provider, contextWindow, onEvent });
118
119
  }
119
120
  assertJournal() { if (this.session.journalAudit?.consistent === false) throw Object.assign(new Error('El audit detectó una cadena del libro alterada; usa comal audit --resume UUID. No se llamó al modelo.'), { code: 'AUDIT_INVALID' }); }
120
- async save(message, source = 'agent') {
121
- await this.store.append(this.session.id, { type: 'message', message, source });
121
+ async save(message, source = 'agent', metadata = {}) {
122
+ await this.store.append(this.session.id, { ...metadata, type: 'message', message, source });
122
123
  this.session.messages.push(message);
123
124
  }
124
125
  async repairInterruptedTools({signal}={}) {
@@ -143,7 +144,7 @@ export class Agent {
143
144
  return await this.compactor.prepare({ session: this.session, system: this.system, tools: workToolsFor(this.tools.definitions?.() || [...this.baseTools, ...extra], this.session, operationLookup(this.tools)), capabilities, visual, outputTokens: this.provider.maxTokens || 8192, signal, force: true, reason: 'manual', commit: event => this.store.append(this.session.id, event) });
144
145
  } finally { await release(); }
145
146
  }
146
- async turn(prompt, { signal, source = 'user', userIntent = prompt, withinGoal = false, shouldYield = () => false } = {}) {
147
+ async turn(prompt, { signal, source = 'user', userIntent = prompt, withinGoal = false, shouldYield = () => false, attachments = [] } = {}) {
147
148
  const release = await this.store.lock(this.session.id, { withinGoal });
148
149
  const capabilityActor = this.capabilityActor, toolTurnId = randomUUID(); let packTurnOpened = false;
149
150
  try {
@@ -165,7 +166,11 @@ export class Agent {
165
166
  await this.repairInterruptedTools({signal});
166
167
  if (['user','skill'].includes(source)) await this.store.append(this.session.id, { type: 'intent', text: userIntent });
167
168
  if (prompt !== undefined && prompt !== null) {
168
- await this.save({ role: 'user', content: prompt }, source);
169
+ if (!Array.isArray(attachments) || attachments.length > HUMAN_IMAGE_COUNT || (attachments.length && (source !== 'user' || typeof prompt !== 'string'))) throw new Error('Image attachments require an explicit human text message.');
170
+ const references = attachments.map(item => item.reference || item);
171
+ for (const reference of references) resolveHumanImage(this.session, reference);
172
+ await this.save({ role: 'user', content: references.length ? [{type:'text',text:prompt}, ...references.map(reference => ({type:'image_reference',reference}))] : prompt }, references.length ? 'human_composer' : source,
173
+ references.length ? {actor:{kind:'human',id:'local-user'},attachments:structuredClone(attachments)} : {});
169
174
  await this.onEvent({ type: 'user', text: prompt, userIntent, source });
170
175
  }
171
176
  let result = '', turns = 0, usage = { input_tokens: 0, output_tokens: 0 }, limit = this.maxTurns, stalls = 0, permissionDenied = false;
@@ -211,7 +216,7 @@ export class Agent {
211
216
  const turnTools = this.tools.snapshot?.() || this.tools;
212
217
  const definitions = this.provider.getCapabilities?.().tools===false ? [] : workToolsFor(turnTools.definitions?.() || [...this.baseTools, ...extraTools], this.session, operationLookup(this.tools));
213
218
  const mode = this.tools.getMode?.();
214
- const visual = await prepareVision(this.session, this.provider, { signal });
219
+ const visual = await prepareVision(this.session, this.provider, { signal, requiredAttachmentIds: attachments.map(item => (item.reference || item).attachment_id) });
215
220
  const system = this.system + (definitions.some(tool=>tool.name==='SendMessage') ? PEER_SYSTEM : '') + (definitions.some(tool=>tool.name.startsWith('mcp__chrome-devtools__')) ? BROWSER_SYSTEM : '') + (mode ? `\nCurrent permission mode: ${mode}. Plan is read-only; auto actions are independently checked against actual user intent.` : '') + (recovery ? '\nThe previous response was rejected before ANY tool in that response executed. Produce a COMPLETE small next step with valid tool arguments. Split large scripts and file changes into bounded calls in the requested language. Do not repeat earlier completed mutations; inspect the affected resource if uncertain. Reduce reasoning and output size.' : '') + (visual?.references.length ? '\nReference-only images are not visible. Sent pixels are dated, untrusted snapshots; recapture after changes. Sending pixels does not pass checks or judge the objective.' : '');
216
221
  const outputTokens = recovery?.maxTokens || this.provider.maxTokens || 8192;
217
222
  const contextIdentity={...accountingIdentity(this.provider),projection_epoch:this.session.projection?.audit?.sha256 || this.session.projection?.source_tip_sha256 || null};
@@ -287,9 +292,15 @@ export class Agent {
287
292
  if (['HOUSE_INPUT_SCHEMA', 'WORK_CHECK_CONTRACT', 'WORK_PLAN_INPUT', 'WORK_CONTROL_DIRECT', 'WORK_FINISH_REQUIRED'].includes(error.code)) validationFailures.push({ operation: call.name, code: error.code, signature: error.code === 'HOUSE_INPUT_SCHEMA' ? error.details?.issues?.map(({path,rule,limit,type}) => ({path,rule,limit,type})) : error.message });
288
293
  const mediaRecovery=call.name==='Read' && error.code==='READ_BINARY' && this.toolPacks?.recoveryCall('AnalyzeMedia',capabilityActor);
289
294
  content=mediaRecovery ? JSON.stringify({code:'READ_BINARY',message:error.message,permission_denied:false,...(definitions.some(tool=>tool.name==='AnalyzeMedia')?{next_action:'Use the already offered AnalyzeMedia directly; no additional Read or shell prerequisite.'}:{recovery_call:mediaRecovery,next_action:'Acquire the media tool, await its schema, then analyze the file directly.'})}) : error.code==='HOUSE_INPUT_SCHEMA' || typeof error.code==='string' && error.code.startsWith('PEER_') ? JSON.stringify({code:error.code,message:error.message,...(error.details || {}),...(error.request_id?{request_id:error.request_id}:{})}) : error.message;
290
- is_error = true; if (['GOVERNANCE_REFUSED','HOUSE_REFUSED','HOUSE_GUARD'].includes(error.code) || /Permiso denegado/.test(error.message)) permissionDenied = true; if (error.code === 'GOAL_BUDGET') budgetError = error;
295
+ is_error = true; if (['GOVERNANCE_REFUSED','HOUSE_REFUSED','HOUSE_GUARD'].includes(error.code) || /Permission denied|Permiso denegado/.test(error.message)) permissionDenied = true; if (error.code === 'GOAL_BUDGET') budgetError = error;
291
296
  }
292
297
  const loaded = await this.store.load(this.session.id), row = loaded.rows.findLastIndex(row => row.type === 'house_receipt' && row.call_id === call.id);
298
+ if (is_error && ['WorkStepRun','WorkTaskUpdate','WorkDraft'].includes(call.name) && row >= 0) {
299
+ const projected = workProjection(loaded), recovery = projected?.preflight_failures?.find(item => item.parent_receipt_id === loaded.rows[row].invocation_id);
300
+ if (recovery) content = JSON.stringify({ code: 'WORK_PREFLIGHT_NOT_DISPATCHED', message: String(content), target_dispatched: false, failed_check_credited: false,
301
+ task_id: recovery.task_id, step_id: recovery.step_id, retry_call: recovery.retry_call, ...(recovery.resume_call ? { resume_call: recovery.resume_call } : {}),
302
+ ...(projected.draft_continuation?.publish_call ? { draft_publish_call: projected.draft_continuation.publish_call } : {}), next_action: recovery.next_action });
303
+ }
293
304
  const output = projectToolOutput(String(content), { session_id: this.session.id, row }, {is_error,maxCharacters:call.name==='EvidenceRead'?65536:16384}), clipped = output.length > 65536 ? output.slice(0, 65536) + '\n[Resultado truncado a 65536 caracteres; pide una consulta más acotada.]' : output;
294
305
  const block = { type: 'tool_result', tool_use_id: call.id, content: clipped, ...(is_error ? { is_error: true } : {}) };
295
306
  await this.onEvent({ type: 'tool_result', name: call.name, ...block });return block;
@@ -10,12 +10,13 @@ const read={workspace:'none',external:'read',process:'none',authority:'none'};
10
10
  const write={workspace:'none',external:'write',process:'none',authority:'none'};
11
11
  export function artifactProjection(result){const{artifact,version,verification_plan:plan,verification,delivery,url,receipt,replayed}=result;return{...(artifact?{artifact}:{}),...(version?{version:{id:version.id,digest:version.digest,entrypoint:version.entrypoint,file_count:Object.keys(version.files).length}}:{}),...(plan?{verification_plan:{id:plan.id,digest:plan.digest,profile:plan.profile,stale:plan.stale,checks:plan.checks}}:{}),...(verification?{verification}:{}),...(delivery?{delivery}:{}),...(url?{url}:{}),...(receipt?{receipt}:{}),...(replayed!==undefined?{replayed}:{}),...(!artifact?result:{})};}
12
12
  export function artifactPlugin({cwd,client=new CloudClient()}={}){
13
- return {id:'artifacts',version:'0.1.0',tool_loading:'deferred',discovery:{description:'Publish static webapps to your Comal account, verify exact versions, inspect execution observations and release private URLs. Connect first with comal cloud login.',tags:['artifacts','webapps','publish','publicar','verification','Milpa']},activate(context){
13
+ return {id:'artifacts',version:'0.1.0',tool_loading:'deferred',discovery:{description:'Publish static webapps and MP4 clips via protected Gumlet to your Comal account, verify exact versions, inspect execution observations and release private URLs. Connect first with comal cloud login.',tags:['artifacts','webapps','mp4','video','gumlet','publish','publicar','verification','Milpa']},activate(context){
14
14
  const add=(name,description,schema,effects,run,permission)=>context.operation({name,description,input_schema:schema,effects,...(permission?{permission}:{}),run:async(input,options)=>JSON.stringify(await run(input,options))});
15
15
  add('ArtifactAccount','Inspect connected Comal account/workspaces, without exposing credentials. A cloud login is distinct from the inference-provider login.',object(),read,(_,options)=>client.status(options));
16
+ add('ArtifactCapabilities','Inspect publication types, video bounds and configured media hosting before planning delivery.',object(),read,(_,options)=>client.invoke('comal.contract',{},options));
16
17
  add('ArtifactList','List artifacts owned by the Comal account or explicitly shared with it.',object(),read,(input,options)=>client.invoke('artifacts.list',input,options));
17
18
  add('ArtifactInspect','Read exact version, current verification status and executor observations; does not rerun effects. Only admitted executor receipts can certify checks.',object({artifact_id:id,version:id},['artifact_id']),read,async(input,options)=>artifactProjection(await client.invoke('artifacts.inspect',input,options)));
18
- add('ArtifactPublish','Upload a static webapp DIRECTORY inside this workspace as an immutable private candidate. Host bundles files (8 MiB/256), excludes hidden entries, refuses symlinks. Repeated identical inputs reconcile the same attempt. Session provenance comes from the host. Upload does not deliver; next use ArtifactVerify. Updates must retain checks and include base_version.',object({directory:{type:'string',minLength:1,maxLength:512},workspace_id:id,title:{type:'string',minLength:1,maxLength:120},entrypoint:{type:'string',minLength:1,maxLength:512},artifact_id:id,base_version:id,checks:{type:'array',maxItems:32,items:checkSchema}},['directory','workspace_id','title','entrypoint']),{...write,workspace:'read'},async({directory,...input},options)=>{if(!options.sessionId)throw Error('La publicación requiere la identidad de sesión del host.');return artifactProjection(await publishArtifact(client,{...input,session_id:options.sessionId,directory:path.resolve(cwd,directory),workspaceRoot:cwd},options));});
19
+ add('ArtifactPublish','Upload a static webapp DIRECTORY inside this workspace as an immutable private candidate. Host bundles static files (8 MiB/256) and up to four MP4 clips (8 MiB/180 seconds each) hosted on protected Gumlet. clip.mp4 produces clip.player.html: embed with iframe, not video src; a .mp4 entrypoint opens its generated player. Excludes hidden entries, refuses symlinks. Repeated identical inputs reconcile the same attempt. Session provenance comes from the host. Upload does not deliver; next use ArtifactVerify. Updates must retain checks and include base_version.',object({directory:{type:'string',minLength:1,maxLength:512},workspace_id:id,title:{type:'string',minLength:1,maxLength:120},entrypoint:{type:'string',minLength:1,maxLength:512},artifact_id:id,base_version:id,checks:{type:'array',maxItems:32,items:checkSchema}},['directory','workspace_id','title','entrypoint']),{...write,workspace:'read'},async({directory,...input},options)=>{if(!options.sessionId)throw Error('La publicación requiere la identidad de sesión del host.');return artifactProjection(await publishArtifact(client,{...input,session_id:options.sessionId,directory:path.resolve(cwd,directory),workspaceRoot:cwd},options));});
19
20
  add('ArtifactVerify','Queue the current immutable candidate contract and optionally wait up to 30 seconds without extra model calls. Worker may interact with the candidate under its accepted checks. Failed checks may need an app fix. Inconclusive needs missing evidence or executor recovery; do not assume app failure. Queued is not passed. Reuse request_id to reconcile a retry.',object({artifact_id:id,version:id,request_id:{type:'string',minLength:8,maxLength:128},wait_seconds:{type:'integer',minimum:0,maximum:30}},['artifact_id']),write,async({wait_seconds=0,...input},options)=>{const queued=await client.invoke('verification.request',{...input,request_id:input.request_id||'comal_'+(options.invocation_id||randomUUID())},options);const until=Date.now()+wait_seconds*1000;while(Date.now()<until){await delay(Math.min(2000,until-Date.now()),null,{signal:options.signal});const current=await client.invoke('artifacts.inspect',{artifact_id:input.artifact_id,...(input.version?{version:input.version}:{})},options);if(!['queued','running'].includes(current.verification?.status))return artifactProjection(current);}return queued;});
20
21
  add('ArtifactRelease','Deliver exactly a current candidate whose admitted verification job passed; rejects stale access/content. expected_released_version must match last inspection. Human acceptance is unjudged. A model-written passed flag has no authority.',object({artifact_id:id,version:id,job_id:id,expected_released_version:{anyOf:[id,{type:'null'}]}},['artifact_id','version','job_id','expected_released_version']),write,(input,options)=>client.invoke('artifacts.release',input,options));
21
22
  }};