@oxygen-agent/cli 1.700.10 → 1.717.9

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 (43) hide show
  1. package/README.md +1 -1
  2. package/dist/help.js +2 -0
  3. package/dist/http-client.js +11 -1
  4. package/dist/index.js +523 -85
  5. package/dist/transcript.js +2 -2
  6. package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +4 -0
  7. package/node_modules/@oxygen/shared/dist/billing.d.ts +1 -1
  8. package/node_modules/@oxygen/shared/dist/billing.js +7 -6
  9. package/node_modules/@oxygen/shared/dist/dnc-identities.d.ts +53 -0
  10. package/node_modules/@oxygen/shared/dist/dnc-identities.js +175 -0
  11. package/node_modules/@oxygen/shared/dist/file-import.d.ts +36 -1
  12. package/node_modules/@oxygen/shared/dist/file-import.js +80 -1
  13. package/node_modules/@oxygen/shared/dist/image-sniff.d.ts +39 -0
  14. package/node_modules/@oxygen/shared/dist/image-sniff.js +75 -0
  15. package/node_modules/@oxygen/shared/dist/import-limits.d.ts +28 -0
  16. package/node_modules/@oxygen/shared/dist/import-limits.js +30 -0
  17. package/node_modules/@oxygen/shared/dist/index.d.ts +2 -0
  18. package/node_modules/@oxygen/shared/dist/index.js +2 -0
  19. package/node_modules/@oxygen/shared/dist/mailbox-import.d.ts +10 -4
  20. package/node_modules/@oxygen/shared/dist/mailbox-import.js +18 -10
  21. package/node_modules/@oxygen/shared/dist/member-columns.d.ts +64 -0
  22. package/node_modules/@oxygen/shared/dist/member-columns.js +111 -0
  23. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +65 -0
  24. package/node_modules/@oxygen/shared/dist/object-storage.js +100 -0
  25. package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +2 -1
  26. package/node_modules/@oxygen/shared/dist/plan-limits.js +12 -2
  27. package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +9 -0
  28. package/node_modules/@oxygen/shared/dist/spend-safety.js +10 -0
  29. package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
  30. package/node_modules/@oxygen/shared/dist/version.js +1 -1
  31. package/node_modules/@oxygen/shared/package.json +20 -0
  32. package/node_modules/@oxygen/workflows/dist/graph/lint.js +79 -11
  33. package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +679 -0
  34. package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.js +80 -1
  35. package/node_modules/@oxygen/workflows/dist/graph/remap.js +8 -1
  36. package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +72 -3
  37. package/node_modules/@oxygen/workflows/dist/graph/types.js +12 -0
  38. package/node_modules/@oxygen/workflows/dist/index.d.ts +16 -0
  39. package/node_modules/@oxygen/workflows/dist/index.js +45 -3
  40. package/node_modules/@oxygen/workflows/dist/portable.d.ts +43 -0
  41. package/node_modules/@oxygen/workflows/dist/portable.js +319 -0
  42. package/node_modules/@oxygen/workflows/dist/usage-estimate.js +18 -4
  43. package/package.json +1 -1
@@ -7,7 +7,7 @@
7
7
  // why ./index.ts (the "@oxygen/workflows/graph" entry) does not re-export this
8
8
  // module — the editor lints through the API, not in the bundle.
9
9
  import { validateFormulaExpression } from "@oxygen/formula";
10
- import { isWorkflowToolRejected, validateOptionalMaxCredits, validatePureFunctionSource, validateTrigger, } from "../index.js";
10
+ import { isWorkflowToolRejected, lintRecipeManifest, validateOptionalMaxCredits, validatePureFunctionSource, validateTrigger, } from "../index.js";
11
11
  import { UNARY_COMPARE_OPS, WORKFLOW_COMPARE_OPS, compileConditionPattern, parseScopePath, SCOPE_PATH_ROOTS, } from "./expression.js";
12
12
  import { missingToolParams, unknownToolParams } from "./params.js";
13
13
  import { danglingEdges, findIllegalCycles, loopBodyNodeIds, reachableNodeIds } from "./topology.js";
@@ -254,14 +254,7 @@ node, path, add, scope, options) {
254
254
  lintApprovalNode(node, path, add, scope);
255
255
  return;
256
256
  case "code":
257
- // v2 `code` nodes run through the same sandbox as v1 transform steps, so
258
- // they clear the same purity scan; every issue it raises is re-labelled to
259
- // the v2 code so callers match on one code for "this source is not safe".
260
- if (typeof node.run_source !== "string") {
261
- add(`${path}.run_source`, "unsafe_code_source", "Code node run_source is required.");
262
- return;
263
- }
264
- validatePureFunctionSource(node.run_source, `${path}.run_source`, (issuePath, _code, message) => add(issuePath, "unsafe_code_source", message));
257
+ lintCodeNode(node, path, add, scope, options);
265
258
  return;
266
259
  case "workflow":
267
260
  if (!isNonEmptyString(node.workflow_id)) {
@@ -280,7 +273,67 @@ node, path, add, scope, options) {
280
273
  return;
281
274
  }
282
275
  }
276
+ function lintCodeNode(node, path, add, scope, options) {
277
+ const hasSource = typeof node.run_source === "string";
278
+ const hasRecipe = isRecord(node.recipe);
279
+ if (hasSource === hasRecipe) {
280
+ add(path, "ambiguous_code_runtime", "A code node must declare exactly one executable runtime: run_source or recipe.");
281
+ return;
282
+ }
283
+ if (hasSource) {
284
+ // v2 source nodes run through the same sandbox as v1 transform steps, so
285
+ // they clear the same purity scan; every issue it raises is re-labelled to
286
+ // the v2 code so callers match on one code for "this source is not safe".
287
+ validatePureFunctionSource(node.run_source, `${path}.run_source`, (issuePath, _code, message) => add(issuePath, "unsafe_code_source", message));
288
+ validateLegacyContext(node, path, add);
289
+ if (node.configuration !== undefined) {
290
+ add(`${path}.configuration`, "unexpected_recipe_configuration", "Source code nodes cannot declare recipe configuration.");
291
+ }
292
+ return;
293
+ }
294
+ // The graph owns configuration as value refs, which are resolved only at run
295
+ // time. The standalone recipe linter validates concrete JSON values, so lint
296
+ // the executable envelope without its literal configuration and validate the
297
+ // graph binding shape/required keys below instead.
298
+ const { configuration_schema: _configurationSchema, configuration: _configuration, ...recipeEnvelope } = node.recipe;
299
+ const recipeResult = lintRecipeManifest(recipeEnvelope, options);
300
+ for (const issue of recipeResult.issues) {
301
+ const suffix = issue.path === "$" ? "" : issue.path.slice(1);
302
+ add(`${path}.recipe${suffix}`, issue.code, issue.message);
303
+ }
304
+ validateValueRefRecord(node.configuration, `${path}.configuration`, add, scope);
305
+ if (node.legacy_context !== undefined) {
306
+ add(`${path}.legacy_context`, "unexpected_legacy_context", "Durable recipe nodes do not use legacy_context.");
307
+ }
308
+ const rawSchema = node.recipe.configuration_schema;
309
+ if (rawSchema !== undefined && !isRecord(rawSchema)) {
310
+ add(`${path}.recipe.configuration_schema`, "invalid_configuration_schema", "Recipe configuration_schema must be a JSON Schema object.");
311
+ }
312
+ const schema = isRecord(rawSchema)
313
+ ? node.recipe.configuration_schema
314
+ : null;
315
+ if (!schema)
316
+ return;
317
+ const configuration = isRecord(node.configuration) ? node.configuration : {};
318
+ const properties = isRecord(schema.properties) ? schema.properties : {};
319
+ const required = Array.isArray(schema.required)
320
+ ? schema.required.filter((name) => typeof name === "string")
321
+ : [];
322
+ for (const name of required) {
323
+ if (!Object.hasOwn(configuration, name)) {
324
+ add(`${path}.configuration`, "incomplete_recipe_configuration", `Durable recipe configuration still needs '${name}'.`);
325
+ }
326
+ }
327
+ if (schema.additionalProperties === false) {
328
+ for (const name of Object.keys(configuration)) {
329
+ if (!Object.hasOwn(properties, name)) {
330
+ add(`${path}.configuration.${name}`, "unknown_recipe_configuration", `Durable recipe configuration has no field called '${name}'.`);
331
+ }
332
+ }
333
+ }
334
+ }
283
335
  function lintToolNode(node, path, add, scope, options) {
336
+ const hasPayloadSource = typeof node.payload_source === "string";
284
337
  if (!isNonEmptyString(node.tool)) {
285
338
  add(`${path}.tool`, "missing_tool", "Tool node tool id is required.");
286
339
  }
@@ -296,7 +349,7 @@ function lintToolNode(node, path, add, scope, options) {
296
349
  // refused an unconfigured node while apply accepted the identical manifest, and
297
350
  // a CLI-authored one was never checked at all — a guarantee the GUI enforces
298
351
  // alone is not a guarantee.
299
- if (isNonEmptyString(node.tool) && options.resolveToolParamFields) {
352
+ if (!hasPayloadSource && isNonEmptyString(node.tool) && options.resolveToolParamFields) {
300
353
  const resolved = options.resolveToolParamFields(node.tool);
301
354
  // Array.isArray does not narrow a `readonly T[]` union, so normalize once.
302
355
  const bag = resolved == null
@@ -341,7 +394,7 @@ function lintToolNode(node, path, add, scope, options) {
341
394
  if (resolveEffect) {
342
395
  const canonicalEffect = resolveEffect(node.tool);
343
396
  if (canonicalEffect !== null && node.effect !== canonicalEffect) {
344
- add(`${path}.effect`, "tool_effect_mismatch", `Tool '${node.tool}' has canonical effect '${canonicalEffect}', not '${String(node.effect)}'.`);
397
+ add(`${path}.effect`, "tool_effect_mismatch", `Tool '${node.tool}' has canonical effect '${canonicalEffect}', not '${String(node.effect)}'. Set node.effect to '${canonicalEffect}'.`);
345
398
  }
346
399
  }
347
400
  }
@@ -353,6 +406,21 @@ function lintToolNode(node, path, add, scope, options) {
353
406
  }
354
407
  validateOptionalMaxCredits(node.max_credits, `${path}.max_credits`, add);
355
408
  validateValueRefRecord(node.params, `${path}.params`, add, scope);
409
+ if (hasPayloadSource) {
410
+ validatePureFunctionSource(node.payload_source, `${path}.payload_source`, (issuePath, _code, message) => add(issuePath, "unsafe_payload_source", message));
411
+ if (isRecord(node.params) && Object.keys(node.params).length > 0) {
412
+ add(`${path}.params`, "ambiguous_tool_inputs", "A tool node cannot use mapped params and payload_source at the same time.");
413
+ }
414
+ }
415
+ else if (node.payload_source !== undefined) {
416
+ add(`${path}.payload_source`, "unsafe_payload_source", "Tool payload_source must be a string.");
417
+ }
418
+ validateLegacyContext(node, path, add);
419
+ }
420
+ function validateLegacyContext(node, path, add) {
421
+ if (node.legacy_context !== undefined && node.legacy_context !== "v1") {
422
+ add(`${path}.legacy_context`, "invalid_legacy_context", "Imported node legacy_context must be 'v1'.");
423
+ }
356
424
  }
357
425
  function lintSwitchNode(node, path, add, scope) {
358
426
  const cases = asArray(node.cases);