@viewportai/daemon 0.20.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. package/README.md +34 -0
  2. package/dist/adapters/claude.d.ts +7 -1
  3. package/dist/adapters/claude.d.ts.map +1 -1
  4. package/dist/adapters/claude.js +71 -0
  5. package/dist/adapters/claude.js.map +1 -1
  6. package/dist/adapters/codex-event-normalizers.d.ts.map +1 -1
  7. package/dist/adapters/codex-event-normalizers.js +55 -2
  8. package/dist/adapters/codex-event-normalizers.js.map +1 -1
  9. package/dist/adapters/codex.d.ts +2 -1
  10. package/dist/adapters/codex.d.ts.map +1 -1
  11. package/dist/adapters/codex.js +35 -0
  12. package/dist/adapters/codex.js.map +1 -1
  13. package/dist/adapters/gemini-cli.d.ts +2 -1
  14. package/dist/adapters/gemini-cli.d.ts.map +1 -1
  15. package/dist/adapters/gemini-cli.js +24 -0
  16. package/dist/adapters/gemini-cli.js.map +1 -1
  17. package/dist/adapters/pty.d.ts +2 -1
  18. package/dist/adapters/pty.d.ts.map +1 -1
  19. package/dist/adapters/pty.js +26 -1
  20. package/dist/adapters/pty.js.map +1 -1
  21. package/dist/cli/args.d.ts.map +1 -1
  22. package/dist/cli/args.js +7 -3
  23. package/dist/cli/args.js.map +1 -1
  24. package/dist/cli/commands.d.ts +3 -0
  25. package/dist/cli/commands.d.ts.map +1 -1
  26. package/dist/cli/commands.js +3 -0
  27. package/dist/cli/commands.js.map +1 -1
  28. package/dist/cli/context-command.js +2 -0
  29. package/dist/cli/context-command.js.map +1 -1
  30. package/dist/cli/context-sync-target.d.ts +2 -0
  31. package/dist/cli/context-sync-target.d.ts.map +1 -1
  32. package/dist/cli/context-sync-target.js +4 -0
  33. package/dist/cli/context-sync-target.js.map +1 -1
  34. package/dist/cli/daemon-client.d.ts +1 -0
  35. package/dist/cli/daemon-client.d.ts.map +1 -1
  36. package/dist/cli/daemon-client.js +13 -1
  37. package/dist/cli/daemon-client.js.map +1 -1
  38. package/dist/cli/global-flags.d.ts.map +1 -1
  39. package/dist/cli/global-flags.js +3 -2
  40. package/dist/cli/global-flags.js.map +1 -1
  41. package/dist/cli/hook-command.d.ts +7 -0
  42. package/dist/cli/hook-command.d.ts.map +1 -1
  43. package/dist/cli/hook-command.js +35 -20
  44. package/dist/cli/hook-command.js.map +1 -1
  45. package/dist/cli/install-command.d.ts +5 -1
  46. package/dist/cli/install-command.d.ts.map +1 -1
  47. package/dist/cli/install-command.js +37 -28
  48. package/dist/cli/install-command.js.map +1 -1
  49. package/dist/cli/lifecycle-commands.d.ts.map +1 -1
  50. package/dist/cli/lifecycle-commands.js +5 -2
  51. package/dist/cli/lifecycle-commands.js.map +1 -1
  52. package/dist/cli/lifecycle-pair-command.d.ts.map +1 -1
  53. package/dist/cli/lifecycle-pair-command.js +51 -6
  54. package/dist/cli/lifecycle-pair-command.js.map +1 -1
  55. package/dist/cli/lifecycle-pair-server.d.ts +2 -0
  56. package/dist/cli/lifecycle-pair-server.d.ts.map +1 -1
  57. package/dist/cli/lifecycle-pair-server.js.map +1 -1
  58. package/dist/cli/lifecycle-status-command.d.ts.map +1 -1
  59. package/dist/cli/lifecycle-status-command.js +43 -0
  60. package/dist/cli/lifecycle-status-command.js.map +1 -1
  61. package/dist/cli/setup-command.d.ts.map +1 -1
  62. package/dist/cli/setup-command.js +8 -8
  63. package/dist/cli/setup-command.js.map +1 -1
  64. package/dist/cli/team-resource-command.d.ts +2 -0
  65. package/dist/cli/team-resource-command.d.ts.map +1 -0
  66. package/dist/cli/team-resource-command.js +364 -0
  67. package/dist/cli/team-resource-command.js.map +1 -0
  68. package/dist/cli/watch-command.d.ts +3 -0
  69. package/dist/cli/watch-command.d.ts.map +1 -0
  70. package/dist/cli/watch-command.js +42 -0
  71. package/dist/cli/watch-command.js.map +1 -0
  72. package/dist/cli/worker-command.d.ts +3 -0
  73. package/dist/cli/worker-command.d.ts.map +1 -0
  74. package/dist/cli/worker-command.js +132 -0
  75. package/dist/cli/worker-command.js.map +1 -0
  76. package/dist/cli/worker-profile.d.ts +65 -0
  77. package/dist/cli/worker-profile.d.ts.map +1 -0
  78. package/dist/cli/worker-profile.js +228 -0
  79. package/dist/cli/worker-profile.js.map +1 -0
  80. package/dist/cli/worker-runtime.d.ts +19 -0
  81. package/dist/cli/worker-runtime.d.ts.map +1 -0
  82. package/dist/cli/worker-runtime.js +606 -0
  83. package/dist/cli/worker-runtime.js.map +1 -0
  84. package/dist/cli/workflow-managed-worker-format.d.ts +4 -3
  85. package/dist/cli/workflow-managed-worker-format.d.ts.map +1 -1
  86. package/dist/cli/workflow-managed-worker-format.js +71 -10
  87. package/dist/cli/workflow-managed-worker-format.js.map +1 -1
  88. package/dist/cli/workflow-managed-worker-types.d.ts +17 -0
  89. package/dist/cli/workflow-managed-worker-types.d.ts.map +1 -1
  90. package/dist/cli/workflow-managed-worker.d.ts.map +1 -1
  91. package/dist/cli/workflow-managed-worker.js +568 -39
  92. package/dist/cli/workflow-managed-worker.js.map +1 -1
  93. package/dist/config-resolution/provider-defaults.d.ts.map +1 -1
  94. package/dist/config-resolution/provider-defaults.js +4 -0
  95. package/dist/config-resolution/provider-defaults.js.map +1 -1
  96. package/dist/config-resolution/schema.d.ts +2 -0
  97. package/dist/config-resolution/schema.d.ts.map +1 -1
  98. package/dist/config-resolution/schema.js +2 -0
  99. package/dist/config-resolution/schema.js.map +1 -1
  100. package/dist/config-resolution/types.d.ts +1 -1
  101. package/dist/config-resolution/types.d.ts.map +1 -1
  102. package/dist/context/local-edge-sync.d.ts +2 -0
  103. package/dist/context/local-edge-sync.d.ts.map +1 -1
  104. package/dist/context/local-edge-sync.js +2 -0
  105. package/dist/context/local-edge-sync.js.map +1 -1
  106. package/dist/context-providers/confluence-provider.d.ts +3 -0
  107. package/dist/context-providers/confluence-provider.d.ts.map +1 -0
  108. package/dist/context-providers/confluence-provider.js +170 -0
  109. package/dist/context-providers/confluence-provider.js.map +1 -0
  110. package/dist/context-providers/notion-provider.d.ts +3 -0
  111. package/dist/context-providers/notion-provider.d.ts.map +1 -0
  112. package/dist/context-providers/notion-provider.js +157 -0
  113. package/dist/context-providers/notion-provider.js.map +1 -0
  114. package/dist/context-providers/registry.d.ts.map +1 -1
  115. package/dist/context-providers/registry.js +9 -1
  116. package/dist/context-providers/registry.js.map +1 -1
  117. package/dist/context-providers/types.d.ts +18 -0
  118. package/dist/context-providers/types.d.ts.map +1 -1
  119. package/dist/core/config-schema.d.ts +96 -3
  120. package/dist/core/config-schema.d.ts.map +1 -1
  121. package/dist/core/config-schema.js +53 -0
  122. package/dist/core/config-schema.js.map +1 -1
  123. package/dist/core/config.d.ts +88 -0
  124. package/dist/core/config.d.ts.map +1 -1
  125. package/dist/core/config.js +6 -0
  126. package/dist/core/config.js.map +1 -1
  127. package/dist/core/daemon.d.ts +5 -1
  128. package/dist/core/daemon.d.ts.map +1 -1
  129. package/dist/core/daemon.js +8 -0
  130. package/dist/core/daemon.js.map +1 -1
  131. package/dist/core/interfaces.d.ts +137 -1
  132. package/dist/core/interfaces.d.ts.map +1 -1
  133. package/dist/core/permission-coordinator.d.ts.map +1 -1
  134. package/dist/core/permission-coordinator.js +4 -2
  135. package/dist/core/permission-coordinator.js.map +1 -1
  136. package/dist/core/session-manager.d.ts.map +1 -1
  137. package/dist/core/session-manager.js +47 -20
  138. package/dist/core/session-manager.js.map +1 -1
  139. package/dist/core/types.d.ts +31 -0
  140. package/dist/core/types.d.ts.map +1 -1
  141. package/dist/core/types.js.map +1 -1
  142. package/dist/discovery/watcher.d.ts.map +1 -1
  143. package/dist/discovery/watcher.js +51 -8
  144. package/dist/discovery/watcher.js.map +1 -1
  145. package/dist/index.d.ts +2 -0
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +12 -1
  148. package/dist/index.js.map +1 -1
  149. package/dist/plugins/loader.d.ts.map +1 -1
  150. package/dist/plugins/loader.js +10 -1
  151. package/dist/plugins/loader.js.map +1 -1
  152. package/dist/security/child-env.d.ts +3 -0
  153. package/dist/security/child-env.d.ts.map +1 -0
  154. package/dist/security/child-env.js +44 -0
  155. package/dist/security/child-env.js.map +1 -0
  156. package/dist/server/http-request-schemas.d.ts +6 -0
  157. package/dist/server/http-request-schemas.d.ts.map +1 -1
  158. package/dist/server/http-request-schemas.js +15 -0
  159. package/dist/server/http-request-schemas.js.map +1 -1
  160. package/dist/server/http-server.d.ts.map +1 -1
  161. package/dist/server/http-server.js +4 -2
  162. package/dist/server/http-server.js.map +1 -1
  163. package/dist/workflows/action-adapters.d.ts.map +1 -1
  164. package/dist/workflows/action-adapters.js +42 -0
  165. package/dist/workflows/action-adapters.js.map +1 -1
  166. package/dist/workflows/action-provider-adapters.d.ts.map +1 -1
  167. package/dist/workflows/action-provider-adapters.js +156 -13
  168. package/dist/workflows/action-provider-adapters.js.map +1 -1
  169. package/dist/workflows/action-provider-utils.d.ts +6 -0
  170. package/dist/workflows/action-provider-utils.d.ts.map +1 -1
  171. package/dist/workflows/action-provider-utils.js +21 -0
  172. package/dist/workflows/action-provider-utils.js.map +1 -1
  173. package/dist/workflows/approval-actor.d.ts +6 -0
  174. package/dist/workflows/approval-actor.d.ts.map +1 -0
  175. package/dist/workflows/approval-actor.js +27 -0
  176. package/dist/workflows/approval-actor.js.map +1 -0
  177. package/dist/workflows/approval-on-reject.js +1 -0
  178. package/dist/workflows/approval-on-reject.js.map +1 -1
  179. package/dist/workflows/checkout-node.d.ts +21 -0
  180. package/dist/workflows/checkout-node.d.ts.map +1 -0
  181. package/dist/workflows/checkout-node.js +181 -0
  182. package/dist/workflows/checkout-node.js.map +1 -0
  183. package/dist/workflows/context-node-resolver.d.ts +48 -1
  184. package/dist/workflows/context-node-resolver.d.ts.map +1 -1
  185. package/dist/workflows/context-node-resolver.js +405 -8
  186. package/dist/workflows/context-node-resolver.js.map +1 -1
  187. package/dist/workflows/context-update-targets.d.ts +12 -0
  188. package/dist/workflows/context-update-targets.d.ts.map +1 -0
  189. package/dist/workflows/context-update-targets.js +52 -0
  190. package/dist/workflows/context-update-targets.js.map +1 -0
  191. package/dist/workflows/daemon-session.d.ts +11 -0
  192. package/dist/workflows/daemon-session.d.ts.map +1 -1
  193. package/dist/workflows/daemon-session.js +168 -6
  194. package/dist/workflows/daemon-session.js.map +1 -1
  195. package/dist/workflows/event-types.d.ts +1 -1
  196. package/dist/workflows/event-types.d.ts.map +1 -1
  197. package/dist/workflows/expression.d.ts +4 -0
  198. package/dist/workflows/expression.d.ts.map +1 -1
  199. package/dist/workflows/expression.js +1 -1
  200. package/dist/workflows/expression.js.map +1 -1
  201. package/dist/workflows/git-publish-node.d.ts +23 -0
  202. package/dist/workflows/git-publish-node.d.ts.map +1 -0
  203. package/dist/workflows/git-publish-node.js +237 -0
  204. package/dist/workflows/git-publish-node.js.map +1 -0
  205. package/dist/workflows/inline-agent-types.d.ts +7 -0
  206. package/dist/workflows/inline-agent-types.d.ts.map +1 -1
  207. package/dist/workflows/inline-agents.d.ts +4 -1
  208. package/dist/workflows/inline-agents.d.ts.map +1 -1
  209. package/dist/workflows/inline-agents.js +24 -1
  210. package/dist/workflows/inline-agents.js.map +1 -1
  211. package/dist/workflows/loop-executor.js +1 -0
  212. package/dist/workflows/loop-executor.js.map +1 -1
  213. package/dist/workflows/node-executor.d.ts +7 -0
  214. package/dist/workflows/node-executor.d.ts.map +1 -1
  215. package/dist/workflows/node-executor.js +135 -7
  216. package/dist/workflows/node-executor.js.map +1 -1
  217. package/dist/workflows/node-registry.d.ts.map +1 -1
  218. package/dist/workflows/node-registry.js +553 -4
  219. package/dist/workflows/node-registry.js.map +1 -1
  220. package/dist/workflows/parser.d.ts.map +1 -1
  221. package/dist/workflows/parser.js +70 -5
  222. package/dist/workflows/parser.js.map +1 -1
  223. package/dist/workflows/platform-command-applier.d.ts.map +1 -1
  224. package/dist/workflows/platform-command-applier.js +5 -14
  225. package/dist/workflows/platform-command-applier.js.map +1 -1
  226. package/dist/workflows/platform-context-client.d.ts +74 -0
  227. package/dist/workflows/platform-context-client.d.ts.map +1 -0
  228. package/dist/workflows/platform-context-client.js +228 -0
  229. package/dist/workflows/platform-context-client.js.map +1 -0
  230. package/dist/workflows/platform-sync-format.d.ts +1 -1
  231. package/dist/workflows/platform-sync-format.d.ts.map +1 -1
  232. package/dist/workflows/platform-sync-format.js +3 -1
  233. package/dist/workflows/platform-sync-format.js.map +1 -1
  234. package/dist/workflows/platform-sync-payload.d.ts +1 -0
  235. package/dist/workflows/platform-sync-payload.d.ts.map +1 -1
  236. package/dist/workflows/platform-sync-payload.js +160 -8
  237. package/dist/workflows/platform-sync-payload.js.map +1 -1
  238. package/dist/workflows/platform-sync.d.ts.map +1 -1
  239. package/dist/workflows/platform-sync.js +10 -1
  240. package/dist/workflows/platform-sync.js.map +1 -1
  241. package/dist/workflows/plugin-loader.d.ts.map +1 -1
  242. package/dist/workflows/plugin-loader.js +3 -0
  243. package/dist/workflows/plugin-loader.js.map +1 -1
  244. package/dist/workflows/preflight.d.ts.map +1 -1
  245. package/dist/workflows/preflight.js +9 -1
  246. package/dist/workflows/preflight.js.map +1 -1
  247. package/dist/workflows/prompt-output.d.ts +6 -2
  248. package/dist/workflows/prompt-output.d.ts.map +1 -1
  249. package/dist/workflows/prompt-output.js +8 -2
  250. package/dist/workflows/prompt-output.js.map +1 -1
  251. package/dist/workflows/run-preparation.d.ts +24 -0
  252. package/dist/workflows/run-preparation.d.ts.map +1 -0
  253. package/dist/workflows/run-preparation.js +258 -0
  254. package/dist/workflows/run-preparation.js.map +1 -0
  255. package/dist/workflows/run-types.d.ts +11 -0
  256. package/dist/workflows/run-types.d.ts.map +1 -1
  257. package/dist/workflows/runner-scheduler.d.ts +2 -0
  258. package/dist/workflows/runner-scheduler.d.ts.map +1 -1
  259. package/dist/workflows/runner-scheduler.js +35 -4
  260. package/dist/workflows/runner-scheduler.js.map +1 -1
  261. package/dist/workflows/runner-shared.d.ts.map +1 -1
  262. package/dist/workflows/runner-shared.js +9 -0
  263. package/dist/workflows/runner-shared.js.map +1 -1
  264. package/dist/workflows/runner.d.ts +2 -0
  265. package/dist/workflows/runner.d.ts.map +1 -1
  266. package/dist/workflows/runner.js +171 -6
  267. package/dist/workflows/runner.js.map +1 -1
  268. package/dist/workflows/runtime-helpers.d.ts +20 -1
  269. package/dist/workflows/runtime-helpers.d.ts.map +1 -1
  270. package/dist/workflows/runtime-helpers.js +98 -3
  271. package/dist/workflows/runtime-helpers.js.map +1 -1
  272. package/dist/workflows/session-output.d.ts +9 -0
  273. package/dist/workflows/session-output.d.ts.map +1 -1
  274. package/dist/workflows/session-output.js +156 -0
  275. package/dist/workflows/session-output.js.map +1 -1
  276. package/dist/workflows/session-policy.d.ts +30 -0
  277. package/dist/workflows/session-policy.d.ts.map +1 -0
  278. package/dist/workflows/session-policy.js +45 -0
  279. package/dist/workflows/session-policy.js.map +1 -0
  280. package/dist/workflows/structured-outputs.d.ts +5 -0
  281. package/dist/workflows/structured-outputs.d.ts.map +1 -1
  282. package/dist/workflows/structured-outputs.js +82 -3
  283. package/dist/workflows/structured-outputs.js.map +1 -1
  284. package/dist/workflows/subflow-executor.js +5 -1
  285. package/dist/workflows/subflow-executor.js.map +1 -1
  286. package/dist/workflows/types.d.ts +107 -4
  287. package/dist/workflows/types.d.ts.map +1 -1
  288. package/dist/workflows/workflow-authority-contract.d.ts +25 -0
  289. package/dist/workflows/workflow-authority-contract.d.ts.map +1 -0
  290. package/dist/workflows/workflow-authority-contract.js +366 -0
  291. package/dist/workflows/workflow-authority-contract.js.map +1 -0
  292. package/dist/workflows/workflow-executor-schema.d.ts +1 -1
  293. package/dist/workflows/workflow-production-schema.d.ts +62 -10
  294. package/dist/workflows/workflow-production-schema.d.ts.map +1 -1
  295. package/dist/workflows/workflow-production-schema.js +63 -4
  296. package/dist/workflows/workflow-production-schema.js.map +1 -1
  297. package/dist/workflows/workflow-production-types.d.ts +42 -3
  298. package/dist/workflows/workflow-production-types.d.ts.map +1 -1
  299. package/dist/workflows/workflow-schema-common.d.ts +248 -2
  300. package/dist/workflows/workflow-schema-common.d.ts.map +1 -1
  301. package/dist/workflows/workflow-schema-common.js +58 -2
  302. package/dist/workflows/workflow-schema-common.js.map +1 -1
  303. package/dist/workflows/workflow-schema.d.ts +1966 -16
  304. package/dist/workflows/workflow-schema.d.ts.map +1 -1
  305. package/dist/workflows/workflow-schema.js +97 -3
  306. package/dist/workflows/workflow-schema.js.map +1 -1
  307. package/docs/releasing.md +4 -1
  308. package/node_modules/@viewportai/context-engine/schemas/context_event_v1.schema.json +2 -0
  309. package/node_modules/@viewportai/context-engine/src/repo/candidates.js +2 -0
  310. package/node_modules/@viewportai/context-engine/src/repo/events.js +15 -1
  311. package/node_modules/@viewportai/context-engine/src/repo/vault.js +18 -2
  312. package/package.json +2 -2
@@ -1,10 +1,17 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
1
3
  import { executeLoopNode } from './loop-executor.js';
2
4
  import { executeContextNode } from './context-node-resolver.js';
3
5
  import { executeActionAdapter, WorkflowActionError } from './action-adapters.js';
4
- import { addEvent, renderOptionalTemplate, renderTemplate, resolveNodeCwd, runShellNode, } from './runtime-helpers.js';
6
+ import { addEvent, renderOptionalTemplate, runArgvNode, renderShellCommandTemplate, renderTemplate, resolveNodeCwd, runShellNode, ShellNodeError, } from './runtime-helpers.js';
7
+ import { envNameForCredentialRef } from './action-provider-utils.js';
5
8
  import { executeSubflowNode } from './subflow-executor.js';
6
9
  import { buildExpressionContext, evaluateConditionExpression } from './expression.js';
7
10
  import { sanitizePlanProposalMetadata } from '../hooks/plan-extractor.js';
11
+ import { readPromptNodeOutput } from './prompt-output.js';
12
+ import { shellAuthorityDenial } from './workflow-authority-contract.js';
13
+ import { checkoutAuthorityDenial, executeCheckoutNode } from './checkout-node.js';
14
+ import { executeGitPublishNode, gitPublishAuthorityDenial } from './git-publish-node.js';
8
15
  /**
9
16
  * Mutable registry of node executors keyed by `node.type`. Built-ins are
10
17
  * registered at module load (immediately below); the plugin loader extends
@@ -13,20 +20,224 @@ import { sanitizePlanProposalMetadata } from '../hooks/plan-extractor.js';
13
20
  * is one entry, not five files.
14
21
  */
15
22
  export const NODE_EXECUTORS = new Map();
23
+ const SECRET_LIKE_ENV_NAME_PATTERN = /(^|_)(AUTHORIZATION|CREDENTIAL|PASSWORD|PASSWD|PRIVATE_KEY|SECRET|TOKEN|API_KEY)(_|$)/i;
24
+ function isSecretLikeEnvName(name) {
25
+ return SECRET_LIKE_ENV_NAME_PATTERN.test(name);
26
+ }
16
27
  export function registerNodeExecutor(type, executor) {
17
28
  NODE_EXECUTORS.set(type, executor);
18
29
  }
19
30
  const BUILTIN_NODE_EXECUTORS = {
31
+ checkout: async (context, run, nodeId, node) => {
32
+ if (node.type !== 'checkout')
33
+ return { result: 'completed' };
34
+ const state = run.nodes[nodeId];
35
+ const renderedNode = {
36
+ ...node,
37
+ repository: await renderTemplate(node.repository, run),
38
+ ...(node.remote ? { remote: await renderTemplate(node.remote, run) } : {}),
39
+ ...(node.path ? { path: await renderTemplate(node.path, run) } : {}),
40
+ ...(node.ref ? { ref: await renderTemplate(node.ref, run) } : {}),
41
+ ...(node.branch ? { branch: await renderTemplate(node.branch, run) } : {}),
42
+ };
43
+ const denial = checkoutAuthorityDenial(run, nodeId, renderedNode);
44
+ if (denial) {
45
+ addEvent(run, 'checkout-blocked', denial.detail, { workflow_authority_denial: denial }, nodeId);
46
+ throw new Error(denial.detail);
47
+ }
48
+ const credentialRef = node.credentialRef;
49
+ const credential = credentialRef && credentialRef.trim() !== ''
50
+ ? {
51
+ envName: envNameForCredentialRef(credentialRef),
52
+ secret: context.runtimeSecretEnv?.[envNameForCredentialRef(credentialRef)] ??
53
+ process.env[envNameForCredentialRef(credentialRef)],
54
+ }
55
+ : undefined;
56
+ const result = await executeCheckoutNode(run, renderedNode, credential);
57
+ if (state) {
58
+ state.output = JSON.stringify(result);
59
+ state.worktreePath = result.path;
60
+ state.outputs = {
61
+ ...(state.outputs ?? {}),
62
+ repository: result.repository,
63
+ path: result.path,
64
+ ref: result.ref,
65
+ branch: result.branch,
66
+ commit: result.commit,
67
+ sourceCategory: result.sourceCategory,
68
+ readWriteMode: result.readWriteMode,
69
+ };
70
+ state.metadata = {
71
+ ...(state.metadata ?? {}),
72
+ checkout: {
73
+ schema: 'viewport.checkout_receipt/v1',
74
+ repository: result.repository,
75
+ remote: result.remote,
76
+ path: result.path,
77
+ source_category: result.sourceCategory,
78
+ read_write_mode: result.readWriteMode,
79
+ requested_ref: result.ref,
80
+ requested_branch: result.branch,
81
+ ref: result.ref,
82
+ branch: result.branch,
83
+ exact_commit: result.commit,
84
+ commit: result.commit,
85
+ credentialMode: result.credentialMode,
86
+ credentialRef: result.credentialRef,
87
+ },
88
+ };
89
+ }
90
+ addEvent(run, 'checkout-completed', `Checked out ${result.repository}`, {
91
+ repository: result.repository,
92
+ remote: result.remote,
93
+ path: result.path,
94
+ source_category: result.sourceCategory,
95
+ read_write_mode: result.readWriteMode,
96
+ ref: result.ref,
97
+ branch: result.branch,
98
+ exact_commit: result.commit,
99
+ commit: result.commit,
100
+ }, nodeId);
101
+ return { result: 'completed', artifactCwd: result.path };
102
+ },
103
+ git_publish: async (context, run, nodeId, node) => {
104
+ if (node.type !== 'git_publish')
105
+ return { result: 'completed' };
106
+ const state = run.nodes[nodeId];
107
+ const renderedNode = {
108
+ ...node,
109
+ repository: await renderTemplate(node.repository, run),
110
+ ...(node.credentialRef
111
+ ? { credentialRef: await renderTemplate(node.credentialRef, run) }
112
+ : {}),
113
+ ...(node.paths
114
+ ? { paths: await Promise.all(node.paths.map((entry) => renderTemplate(entry, run))) }
115
+ : {}),
116
+ };
117
+ const input = {
118
+ cwd: resolveNodeCwd(run.directoryPath, await renderOptionalTemplate(node.cwd, run)),
119
+ branch: await renderTemplate(node.branch, run),
120
+ message: await renderTemplate(node.message, run),
121
+ };
122
+ const denial = await gitPublishAuthorityDenial(run, nodeId, renderedNode, input);
123
+ if (denial) {
124
+ addEvent(run, 'git-publish-blocked', denial.detail, { workflow_authority_denial: denial }, nodeId);
125
+ throw new Error(denial.detail);
126
+ }
127
+ const credentialRef = renderedNode.credentialRef;
128
+ const credential = credentialRef && credentialRef.trim() !== ''
129
+ ? {
130
+ envName: envNameForCredentialRef(credentialRef),
131
+ secret: context.runtimeSecretEnv?.[envNameForCredentialRef(credentialRef)] ??
132
+ process.env[envNameForCredentialRef(credentialRef)],
133
+ }
134
+ : undefined;
135
+ const result = await executeGitPublishNode(renderedNode, input, credential);
136
+ if (state) {
137
+ state.output = JSON.stringify(result);
138
+ state.outputs = {
139
+ ...(state.outputs ?? {}),
140
+ repository: result.repository,
141
+ branch: result.branch,
142
+ commit: result.commit,
143
+ pushed: result.pushed,
144
+ changed: result.changed,
145
+ };
146
+ state.metadata = {
147
+ ...(state.metadata ?? {}),
148
+ git_publish: {
149
+ schema: 'viewport.git_publish_receipt/v1',
150
+ repository: result.repository,
151
+ branch: result.branch,
152
+ commit: result.commit,
153
+ pushed: result.pushed,
154
+ changed: result.changed,
155
+ credentialMode: result.credentialMode,
156
+ credentialRef: result.credentialRef,
157
+ },
158
+ };
159
+ }
160
+ addEvent(run, 'git-publish-completed', `Published ${result.repository} branch ${result.branch}`, { ...result }, nodeId);
161
+ return { result: 'completed', artifactCwd: input.cwd };
162
+ },
20
163
  shell: async (context, run, nodeId, node) => {
21
164
  if (node.type !== 'shell')
22
165
  return { result: 'completed' };
23
166
  const state = run.nodes[nodeId];
167
+ const startedAt = Date.now();
24
168
  const artifactCwd = resolveNodeCwd(run.directoryPath, await renderOptionalTemplate(node.cwd, run));
169
+ const invocation = await renderShellInvocation(node, run);
170
+ const env = await resolveNodeEnv(context, run, node);
171
+ if (state) {
172
+ state.metadata = {
173
+ ...(state.metadata ?? {}),
174
+ shell_execution: buildShellExecutionReceipt({
175
+ run,
176
+ nodeId,
177
+ commandDigestMaterial: invocation.digestMaterial,
178
+ executor: invocation.executor,
179
+ cwd: artifactCwd,
180
+ env,
181
+ timeoutSeconds: node.timeoutSeconds,
182
+ startedAt,
183
+ status: 'preflight',
184
+ }),
185
+ };
186
+ }
187
+ const workspaceDenial = shellWorkspaceCwdDenial(run, nodeId, artifactCwd);
188
+ if (workspaceDenial) {
189
+ if (state) {
190
+ state.metadata = {
191
+ ...(state.metadata ?? {}),
192
+ shell_execution: buildShellExecutionReceipt({
193
+ run,
194
+ nodeId,
195
+ commandDigestMaterial: invocation.digestMaterial,
196
+ executor: invocation.executor,
197
+ cwd: artifactCwd,
198
+ env,
199
+ timeoutSeconds: node.timeoutSeconds,
200
+ startedAt,
201
+ completedAt: Date.now(),
202
+ status: 'denied',
203
+ denial: workspaceDenial,
204
+ }),
205
+ };
206
+ }
207
+ addEvent(run, 'shell-blocked', workspaceDenial.detail, { workflow_authority_denial: workspaceDenial }, nodeId);
208
+ throw new Error(workspaceDenial.detail);
209
+ }
210
+ const denial = shellAuthorityDenial(run, nodeId, invocation.authorityCommand, artifactCwd, {
211
+ executorKind: typeof invocation.executor.kind === 'string' ? invocation.executor.kind : undefined,
212
+ });
213
+ if (denial) {
214
+ if (state) {
215
+ state.metadata = {
216
+ ...(state.metadata ?? {}),
217
+ shell_execution: buildShellExecutionReceipt({
218
+ run,
219
+ nodeId,
220
+ commandDigestMaterial: invocation.digestMaterial,
221
+ executor: invocation.executor,
222
+ cwd: artifactCwd,
223
+ env,
224
+ timeoutSeconds: node.timeoutSeconds,
225
+ startedAt,
226
+ completedAt: Date.now(),
227
+ status: 'denied',
228
+ denial,
229
+ }),
230
+ };
231
+ }
232
+ addEvent(run, 'shell-blocked', denial.detail, { workflow_authority_denial: denial }, nodeId);
233
+ throw new Error(denial.detail);
234
+ }
25
235
  const abort = context.shellAbortRegistry.create(run.id, `node:${nodeId}`);
26
236
  let result;
27
237
  try {
28
- result = await runShellNode(await renderTemplate(node.command, run), {
238
+ result = await invocation.run({
29
239
  cwd: artifactCwd,
240
+ env,
30
241
  timeoutSeconds: node.timeoutSeconds,
31
242
  signal: abort.signal,
32
243
  onOutput: ({ source, chunk, output }) => {
@@ -36,12 +247,55 @@ const BUILTIN_NODE_EXECUTORS = {
36
247
  },
37
248
  });
38
249
  }
250
+ catch (error) {
251
+ if (state) {
252
+ if (error instanceof ShellNodeError) {
253
+ state.output = error.output || state.output;
254
+ state.exitCode = error.exitCode ?? undefined;
255
+ }
256
+ state.metadata = {
257
+ ...(state.metadata ?? {}),
258
+ shell_execution: buildShellExecutionReceipt({
259
+ run,
260
+ nodeId,
261
+ commandDigestMaterial: invocation.digestMaterial,
262
+ executor: invocation.executor,
263
+ cwd: artifactCwd,
264
+ env,
265
+ timeoutSeconds: node.timeoutSeconds,
266
+ startedAt,
267
+ completedAt: Date.now(),
268
+ status: error instanceof ShellNodeError && error.message.includes('canceled')
269
+ ? 'canceled'
270
+ : 'failed',
271
+ exitCode: error instanceof ShellNodeError ? error.exitCode : null,
272
+ }),
273
+ };
274
+ }
275
+ throw error;
276
+ }
39
277
  finally {
40
278
  abort.dispose();
41
279
  }
42
280
  if (state) {
43
281
  state.output = result.output;
44
282
  state.exitCode = result.exitCode;
283
+ state.metadata = {
284
+ ...(state.metadata ?? {}),
285
+ shell_execution: buildShellExecutionReceipt({
286
+ run,
287
+ nodeId,
288
+ commandDigestMaterial: invocation.digestMaterial,
289
+ executor: invocation.executor,
290
+ cwd: artifactCwd,
291
+ env,
292
+ timeoutSeconds: node.timeoutSeconds,
293
+ startedAt,
294
+ completedAt: Date.now(),
295
+ status: 'completed',
296
+ exitCode: result.exitCode,
297
+ }),
298
+ };
45
299
  }
46
300
  addEvent(run, 'node-output', `Node ${nodeId} produced shell output`, { output: result.output, exitCode: result.exitCode }, nodeId);
47
301
  return { result: 'completed', artifactCwd };
@@ -50,7 +304,8 @@ const BUILTIN_NODE_EXECUTORS = {
50
304
  if (node.type !== 'prompt')
51
305
  return { result: 'completed' };
52
306
  await helpers.executePromptNode(context, run, nodeId, node);
53
- return { result: 'completed' };
307
+ const artifactCwd = run.nodes[nodeId]?.worktreePath;
308
+ return artifactCwd ? { result: 'completed', artifactCwd } : { result: 'completed' };
54
309
  },
55
310
  agent: async (context, run, nodeId, node, helpers) => {
56
311
  if (node.type !== 'agent')
@@ -63,7 +318,8 @@ const BUILTIN_NODE_EXECUTORS = {
63
318
  if (node.handoff) {
64
319
  addEvent(run, 'node-output', `Agent node ${nodeId} prepared handoff metadata`, { handoff: node.handoff }, nodeId);
65
320
  }
66
- return { result: 'completed' };
321
+ const artifactCwd = run.nodes[nodeId]?.worktreePath;
322
+ return artifactCwd ? { result: 'completed', artifactCwd } : { result: 'completed' };
67
323
  },
68
324
  approval: async (context, run, nodeId, node, helpers) => {
69
325
  if (node.type !== 'approval')
@@ -83,6 +339,86 @@ const BUILTIN_NODE_EXECUTORS = {
83
339
  await executeContextNode(run, nodeId, node);
84
340
  return { result: 'completed' };
85
341
  },
342
+ context_update: async (context, run, nodeId, node) => {
343
+ if (node.type !== 'context_update')
344
+ return { result: 'completed' };
345
+ const state = run.nodes[nodeId];
346
+ const targetRef = await renderTemplate(node.targetRef, run);
347
+ const title = await renderTemplate(node.title, run);
348
+ const summary = await renderOptionalTemplate(node.summary, run);
349
+ const idempotencyKey = await renderOptionalTemplate(node.idempotencyKey, run);
350
+ const patch = await renderContextUpdatePatch(node.patch, run);
351
+ try {
352
+ const proposal = await context.platformContextClient?.proposeContextUpdate({
353
+ run,
354
+ nodeId,
355
+ targetRef,
356
+ title,
357
+ summary,
358
+ patch,
359
+ idempotencyKey,
360
+ });
361
+ const output = proposal?.proposalId
362
+ ? `Context update proposal ${proposal.proposalId}`
363
+ : `Context update proposal prepared for ${targetRef}`;
364
+ if (state) {
365
+ state.output = output;
366
+ state.outputs = {
367
+ ...(state.outputs ?? {}),
368
+ target_ref: targetRef,
369
+ proposal_id: proposal?.proposalId ?? null,
370
+ inbox_item_id: proposal?.inboxItemId ?? null,
371
+ status: proposal?.status ?? 'prepared',
372
+ };
373
+ state.metadata = {
374
+ ...(state.metadata ?? {}),
375
+ context_update: {
376
+ target_ref: targetRef,
377
+ title,
378
+ summary: summary ?? null,
379
+ patch: redactedContextUpdatePatch(patch),
380
+ patch_digest: patchDigest(patch),
381
+ idempotency_key: idempotencyKey ?? null,
382
+ proposal_id: proposal?.proposalId ?? null,
383
+ inbox_item_id: proposal?.inboxItemId ?? null,
384
+ status: proposal?.status ?? 'prepared',
385
+ plaintext_patch_persisted: false,
386
+ },
387
+ };
388
+ }
389
+ addEvent(run, 'context-update-proposed', proposal?.proposalId
390
+ ? `Context update proposal ${proposal.proposalId} created for ${targetRef}`
391
+ : `Context update proposal prepared for ${targetRef}`, {
392
+ targetRef,
393
+ title,
394
+ proposalId: proposal?.proposalId ?? null,
395
+ inboxItemId: proposal?.inboxItemId ?? null,
396
+ status: proposal?.status ?? 'prepared',
397
+ patchDigest: patchDigest(patch),
398
+ }, nodeId);
399
+ return { result: 'completed' };
400
+ }
401
+ catch (error) {
402
+ const message = error instanceof Error ? error.message : String(error);
403
+ if (state) {
404
+ state.output = `Context update proposal failed: ${message}`;
405
+ state.metadata = {
406
+ ...(state.metadata ?? {}),
407
+ context_update: {
408
+ target_ref: targetRef,
409
+ title,
410
+ status: 'failed',
411
+ error: message,
412
+ patch: redactedContextUpdatePatch(patch),
413
+ patch_digest: patchDigest(patch),
414
+ plaintext_patch_persisted: false,
415
+ },
416
+ };
417
+ }
418
+ addEvent(run, 'context-update-proposal-failed', `Context update proposal failed for ${targetRef}: ${message}`, { targetRef, title, error: message, patchDigest: patchDigest(patch) }, nodeId);
419
+ throw error;
420
+ }
421
+ },
86
422
  condition: async (_context, run, nodeId, node) => {
87
423
  if (node.type !== 'condition')
88
424
  return { result: 'completed' };
@@ -191,6 +527,7 @@ const BUILTIN_NODE_EXECUTORS = {
191
527
  if (node.type !== 'plan')
192
528
  return { result: 'completed' };
193
529
  const state = run.nodes[nodeId];
530
+ await backfillPromptDependencyOutputs(run, node.needs);
194
531
  const title = await renderTemplate(node.title ?? nodeId, run);
195
532
  const body = await renderTemplate(node.body, run);
196
533
  const summary = await renderOptionalTemplate(node.summary, run);
@@ -205,6 +542,8 @@ const BUILTIN_NODE_EXECUTORS = {
205
542
  body,
206
543
  source: node.source ?? 'workflow',
207
544
  sourceRef: sourceRef || `viewport://workflow-runs/${run.id}/nodes/${nodeId}`,
545
+ ...(node.recipients ? { recipients: node.recipients } : {}),
546
+ ...(node.revision ? { revision: node.revision } : {}),
208
547
  },
209
548
  };
210
549
  }
@@ -231,8 +570,218 @@ const BUILTIN_NODE_EXECUTORS = {
231
570
  return { result: 'blocked' };
232
571
  },
233
572
  };
573
+ async function backfillPromptDependencyOutputs(run, needs) {
574
+ for (const dependencyId of needs ?? []) {
575
+ const dependency = run.nodes[dependencyId];
576
+ if (!dependency || dependency.type !== 'prompt' || dependency.output)
577
+ continue;
578
+ const output = await readPromptNodeOutput(run, dependency);
579
+ if (output)
580
+ dependency.output = output;
581
+ }
582
+ }
234
583
  // Seed the mutable registry with built-ins. Plugin entries register at boot.
235
584
  for (const [type, executor] of Object.entries(BUILTIN_NODE_EXECUTORS)) {
236
585
  NODE_EXECUTORS.set(type, executor);
237
586
  }
587
+ async function resolveNodeEnv(context, run, node) {
588
+ if (!node.env || Object.keys(node.env).length === 0)
589
+ return undefined;
590
+ const env = {};
591
+ for (const [name, value] of Object.entries(node.env)) {
592
+ if (value.value !== undefined) {
593
+ if (isSecretLikeEnvName(name)) {
594
+ throw new Error(`Env ${name} looks secret-like and must use a credential secret handle instead of a literal value.`);
595
+ }
596
+ env[name] = await renderTemplate(value.value, run);
597
+ continue;
598
+ }
599
+ if (!value.secret)
600
+ continue;
601
+ const envName = envNameForCredentialRef(value.secret);
602
+ const material = context.runtimeSecretEnv?.[envName] ?? process.env[envName];
603
+ if (!material) {
604
+ throw new Error(`Secret binding ${value.secret} was not materialized for env ${name}. Select it in the workflow/profile and keep runner-local material in ${envName} when using BYO secrets.`);
605
+ }
606
+ env[name] = material;
607
+ }
608
+ return env;
609
+ }
610
+ async function renderContextUpdatePatch(patch, run) {
611
+ if (!patch)
612
+ return undefined;
613
+ const textDigest = patch.text ? digest(await renderTemplate(patch.text, run)) : undefined;
614
+ const files = patch.files
615
+ ? await Promise.all(patch.files.map(async (file) => {
616
+ const path = await renderTemplate(file.path, run);
617
+ const operation = file.operation ? await renderTemplate(file.operation, run) : undefined;
618
+ const artifactRef = file.artifact_ref
619
+ ? await renderTemplate(file.artifact_ref, run)
620
+ : undefined;
621
+ const beforeDigest = file.before_digest
622
+ ? await renderTemplate(file.before_digest, run)
623
+ : undefined;
624
+ const afterDigest = file.after_digest
625
+ ? await renderTemplate(file.after_digest, run)
626
+ : undefined;
627
+ const patchDigest = file.patch_digest
628
+ ? await renderTemplate(file.patch_digest, run)
629
+ : digest(JSON.stringify({
630
+ path,
631
+ operation,
632
+ artifactRef,
633
+ beforeDigest,
634
+ afterDigest,
635
+ textDigest,
636
+ }));
637
+ return {
638
+ path,
639
+ ...(operation ? { operation } : {}),
640
+ ...(artifactRef ? { artifact_ref: artifactRef } : {}),
641
+ ...(beforeDigest ? { before_digest: beforeDigest } : {}),
642
+ ...(afterDigest ? { after_digest: afterDigest } : {}),
643
+ patch_digest: patchDigest,
644
+ };
645
+ }))
646
+ : undefined;
647
+ return {
648
+ ...(patch.mode ? { mode: patch.mode } : {}),
649
+ ...(textDigest ? { text_digest: textDigest } : {}),
650
+ ...(patch.digest ? { digest: await renderTemplate(patch.digest, run) } : {}),
651
+ ...(patch.operation ? { operation: await renderTemplate(patch.operation, run) } : {}),
652
+ ...(files ? { files } : {}),
653
+ };
654
+ }
655
+ function patchDigest(patch) {
656
+ if (!patch)
657
+ return null;
658
+ return digest(JSON.stringify(patch));
659
+ }
660
+ function redactedContextUpdatePatch(patch) {
661
+ if (!patch)
662
+ return null;
663
+ return {
664
+ ...(typeof patch.mode === 'string' ? { mode: patch.mode } : {}),
665
+ ...(typeof patch.operation === 'string' ? { operation: patch.operation } : {}),
666
+ ...(typeof patch.digest === 'string' ? { digest: patch.digest } : {}),
667
+ ...(typeof patch.text_digest === 'string' ? { text_digest: patch.text_digest } : {}),
668
+ ...(Array.isArray(patch.files) ? { files: patch.files } : {}),
669
+ plaintext_patch_persisted: false,
670
+ };
671
+ }
672
+ async function renderShellInvocation(node, run) {
673
+ if (node.argv && node.argv.length > 0) {
674
+ const argv = await Promise.all(node.argv.map((entry) => renderTemplate(entry, run)));
675
+ return {
676
+ authorityCommand: argv.join(' '),
677
+ digestMaterial: JSON.stringify({ argv }),
678
+ executor: {
679
+ kind: 'argv',
680
+ command: argv[0] ?? null,
681
+ args_count: Math.max(0, argv.length - 1),
682
+ raw_args_persisted: false,
683
+ },
684
+ run: (options) => runArgvNode(argv, options),
685
+ };
686
+ }
687
+ if (!node.command) {
688
+ throw new Error(`Shell node must set command or argv.`);
689
+ }
690
+ const command = await renderShellCommandTemplate(node.command, run);
691
+ return {
692
+ authorityCommand: command,
693
+ digestMaterial: command,
694
+ executor: {
695
+ kind: 'shell',
696
+ command: 'sh',
697
+ args: ['-lc'],
698
+ },
699
+ run: (options) => runShellNode(command, options),
700
+ };
701
+ }
702
+ function buildShellExecutionReceipt(input) {
703
+ const durationMs = input.completedAt !== undefined ? Math.max(0, input.completedAt - input.startedAt) : null;
704
+ return {
705
+ schema: 'viewport.shell_execution_receipt/v1',
706
+ node_id: input.nodeId,
707
+ status: input.status,
708
+ executor: input.executor,
709
+ command_digest: digest(input.commandDigestMaterial),
710
+ command_persisted: false,
711
+ cwd: input.cwd,
712
+ cwd_digest: digest(input.cwd),
713
+ env_keys: Object.keys(input.env ?? {}).sort(),
714
+ env_values_persisted: false,
715
+ timeout_seconds: input.timeoutSeconds ?? null,
716
+ authority: shellAuthorityReceipt(input.run),
717
+ started_at: new Date(input.startedAt).toISOString(),
718
+ completed_at: input.completedAt !== undefined ? new Date(input.completedAt).toISOString() : null,
719
+ duration_ms: durationMs,
720
+ exit_code: input.exitCode ?? null,
721
+ denial: input.denial
722
+ ? {
723
+ reason: input.denial.reason,
724
+ detail: input.denial.detail,
725
+ }
726
+ : null,
727
+ };
728
+ }
729
+ function shellWorkspaceCwdDenial(run, nodeId, cwd) {
730
+ if (isPathWithin(cwd, run.directoryPath))
731
+ return null;
732
+ return {
733
+ schema: 'viewport.workflow_authority_denial/v1',
734
+ reason: 'shell_cwd_outside_run_workspace',
735
+ runId: run.id,
736
+ nodeId,
737
+ detail: `Shell cwd ${cwd} is outside the run worktree.`,
738
+ };
739
+ }
740
+ function shellAuthorityReceipt(run) {
741
+ const contract = run.workflowAuthorityContract;
742
+ if (!contract || typeof contract !== 'object') {
743
+ return {
744
+ source: 'legacy_local',
745
+ shell_policy: 'legacy',
746
+ authority_contract_present: false,
747
+ };
748
+ }
749
+ const shellPolicy = authorityShellPolicy(contract);
750
+ return {
751
+ source: 'workflow_authority_contract',
752
+ shell_policy: shellPolicy ?? null,
753
+ legacy_command_allowed: authorityLegacyShellCommandAllowed(contract),
754
+ authority_contract_present: true,
755
+ authority_contract_digest: typeof contract.digest === 'string' ? contract.digest : null,
756
+ };
757
+ }
758
+ function authorityShellPolicy(contract) {
759
+ const nested = contract['shell'];
760
+ if (nested && typeof nested === 'object' && !Array.isArray(nested)) {
761
+ const policy = nested['policy'];
762
+ if (typeof policy === 'string' && policy.trim() !== '')
763
+ return policy;
764
+ }
765
+ const flat = contract['shell_policy'];
766
+ if (typeof flat === 'string' && flat.trim() !== '')
767
+ return flat;
768
+ return null;
769
+ }
770
+ function authorityLegacyShellCommandAllowed(contract) {
771
+ const nested = contract['shell'];
772
+ if (nested && typeof nested === 'object' && !Array.isArray(nested)) {
773
+ const allowed = nested['allow_legacy_command'];
774
+ if (typeof allowed === 'boolean')
775
+ return allowed;
776
+ }
777
+ const flat = contract['shell_allow_legacy_command'];
778
+ return typeof flat === 'boolean' ? flat : false;
779
+ }
780
+ function isPathWithin(candidate, root) {
781
+ const relative = path.relative(path.resolve(root), path.resolve(candidate));
782
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
783
+ }
784
+ function digest(value) {
785
+ return `sha256:${createHash('sha256').update(value).digest('hex')}`;
786
+ }
238
787
  //# sourceMappingURL=node-registry.js.map