@doist/automations-cli 1.18.0 → 1.19.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.
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  collectSkillStatus,
8
8
  getInstaller,
9
9
  updateAllInstalledSkills
10
- } from "./chunk-DTY2LZDU.js";
10
+ } from "./chunk-SABAHP32.js";
11
11
 
12
12
  // ../../node_modules/ajv/dist/compile/codegen/code.js
13
13
  var require_code = __commonJS({
@@ -2868,7 +2868,7 @@ var require_compile = __commonJS({
2868
2868
  }
2869
2869
  };
2870
2870
  exports.SchemaEnv = SchemaEnv;
2871
- function compileSchema(sch) {
2871
+ function compileSchema2(sch) {
2872
2872
  const _sch = getCompilingSchema.call(this, sch);
2873
2873
  if (_sch)
2874
2874
  return _sch;
@@ -2953,29 +2953,29 @@ var require_compile = __commonJS({
2953
2953
  this._compilations.delete(sch);
2954
2954
  }
2955
2955
  }
2956
- exports.compileSchema = compileSchema;
2957
- function resolveRef2(root15, baseId, ref) {
2956
+ exports.compileSchema = compileSchema2;
2957
+ function resolveRef2(root16, baseId, ref) {
2958
2958
  var _a3;
2959
2959
  ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
2960
- const schOrFunc = root15.refs[ref];
2960
+ const schOrFunc = root16.refs[ref];
2961
2961
  if (schOrFunc)
2962
2962
  return schOrFunc;
2963
- let _sch = resolve.call(this, root15, ref);
2963
+ let _sch = resolve.call(this, root16, ref);
2964
2964
  if (_sch === void 0) {
2965
- const schema = (_a3 = root15.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
2965
+ const schema = (_a3 = root16.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
2966
2966
  const { schemaId } = this.opts;
2967
2967
  if (schema)
2968
- _sch = new SchemaEnv({ schema, schemaId, root: root15, baseId });
2968
+ _sch = new SchemaEnv({ schema, schemaId, root: root16, baseId });
2969
2969
  }
2970
2970
  if (_sch === void 0)
2971
2971
  return;
2972
- return root15.refs[ref] = inlineOrCompile.call(this, _sch);
2972
+ return root16.refs[ref] = inlineOrCompile.call(this, _sch);
2973
2973
  }
2974
2974
  exports.resolveRef = resolveRef2;
2975
2975
  function inlineOrCompile(sch) {
2976
2976
  if ((0, resolve_1.inlineRef)(sch.schema, this.opts.inlineRefs))
2977
2977
  return sch.schema;
2978
- return sch.validate ? sch : compileSchema.call(this, sch);
2978
+ return sch.validate ? sch : compileSchema2.call(this, sch);
2979
2979
  }
2980
2980
  function getCompilingSchema(schEnv) {
2981
2981
  for (const sch of this._compilations) {
@@ -2987,23 +2987,23 @@ var require_compile = __commonJS({
2987
2987
  function sameSchemaEnv(s1, s2) {
2988
2988
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
2989
2989
  }
2990
- function resolve(root15, ref) {
2990
+ function resolve(root16, ref) {
2991
2991
  let sch;
2992
2992
  while (typeof (sch = this.refs[ref]) == "string")
2993
2993
  ref = sch;
2994
- return sch || this.schemas[ref] || resolveSchema.call(this, root15, ref);
2994
+ return sch || this.schemas[ref] || resolveSchema.call(this, root16, ref);
2995
2995
  }
2996
- function resolveSchema(root15, ref) {
2996
+ function resolveSchema(root16, ref) {
2997
2997
  const p = this.opts.uriResolver.parse(ref);
2998
2998
  const refPath = (0, resolve_1._getFullPath)(this.opts.uriResolver, p);
2999
- let baseId = (0, resolve_1.getFullPath)(this.opts.uriResolver, root15.baseId, void 0);
3000
- if (Object.keys(root15.schema).length > 0 && refPath === baseId) {
3001
- return getJsonPointer.call(this, p, root15);
2999
+ let baseId = (0, resolve_1.getFullPath)(this.opts.uriResolver, root16.baseId, void 0);
3000
+ if (Object.keys(root16.schema).length > 0 && refPath === baseId) {
3001
+ return getJsonPointer.call(this, p, root16);
3002
3002
  }
3003
3003
  const id = (0, resolve_1.normalizeId)(refPath);
3004
3004
  const schOrRef = this.refs[id] || this.schemas[id];
3005
3005
  if (typeof schOrRef == "string") {
3006
- const sch = resolveSchema.call(this, root15, schOrRef);
3006
+ const sch = resolveSchema.call(this, root16, schOrRef);
3007
3007
  if (typeof (sch === null || sch === void 0 ? void 0 : sch.schema) !== "object")
3008
3008
  return;
3009
3009
  return getJsonPointer.call(this, p, sch);
@@ -3011,14 +3011,14 @@ var require_compile = __commonJS({
3011
3011
  if (typeof (schOrRef === null || schOrRef === void 0 ? void 0 : schOrRef.schema) !== "object")
3012
3012
  return;
3013
3013
  if (!schOrRef.validate)
3014
- compileSchema.call(this, schOrRef);
3014
+ compileSchema2.call(this, schOrRef);
3015
3015
  if (id === (0, resolve_1.normalizeId)(ref)) {
3016
3016
  const { schema } = schOrRef;
3017
3017
  const { schemaId } = this.opts;
3018
3018
  const schId = schema[schemaId];
3019
3019
  if (schId)
3020
3020
  baseId = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, schId);
3021
- return new SchemaEnv({ schema, schemaId, root: root15, baseId });
3021
+ return new SchemaEnv({ schema, schemaId, root: root16, baseId });
3022
3022
  }
3023
3023
  return getJsonPointer.call(this, p, schOrRef);
3024
3024
  }
@@ -3030,7 +3030,7 @@ var require_compile = __commonJS({
3030
3030
  "dependencies",
3031
3031
  "definitions"
3032
3032
  ]);
3033
- function getJsonPointer(parsedRef, { baseId, schema, root: root15 }) {
3033
+ function getJsonPointer(parsedRef, { baseId, schema, root: root16 }) {
3034
3034
  var _a3;
3035
3035
  if (((_a3 = parsedRef.fragment) === null || _a3 === void 0 ? void 0 : _a3[0]) !== "/")
3036
3036
  return;
@@ -3049,10 +3049,10 @@ var require_compile = __commonJS({
3049
3049
  let env;
3050
3050
  if (typeof schema != "boolean" && schema.$ref && !(0, util_1.schemaHasRulesButRef)(schema, this.RULES)) {
3051
3051
  const $ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, schema.$ref);
3052
- env = resolveSchema.call(this, root15, $ref);
3052
+ env = resolveSchema.call(this, root16, $ref);
3053
3053
  }
3054
3054
  const { schemaId } = this.opts;
3055
- env = env || new SchemaEnv({ schema, schemaId, root: root15, baseId });
3055
+ env = env || new SchemaEnv({ schema, schemaId, root: root16, baseId });
3056
3056
  if (env.schema !== env.root.schema)
3057
3057
  return env;
3058
3058
  return void 0;
@@ -4033,7 +4033,7 @@ var require_core = __commonJS({
4033
4033
  uriResolver
4034
4034
  };
4035
4035
  }
4036
- var Ajv = class {
4036
+ var Ajv2 = class {
4037
4037
  constructor(opts = {}) {
4038
4038
  this.schemas = {};
4039
4039
  this.refs = {};
@@ -4207,8 +4207,8 @@ var require_core = __commonJS({
4207
4207
  keyRef = sch;
4208
4208
  if (sch === void 0) {
4209
4209
  const { schemaId } = this.opts;
4210
- const root15 = new compile_1.SchemaEnv({ schema: {}, schemaId });
4211
- sch = compile_1.resolveSchema.call(this, root15, keyRef);
4210
+ const root16 = new compile_1.SchemaEnv({ schema: {}, schemaId });
4211
+ sch = compile_1.resolveSchema.call(this, root16, keyRef);
4212
4212
  if (!sch)
4213
4213
  return;
4214
4214
  this.refs[keyRef] = sch;
@@ -4317,7 +4317,7 @@ var require_core = __commonJS({
4317
4317
  errorsText(errors = this.errors, { separator = ", ", dataVar = "data" } = {}) {
4318
4318
  if (!errors || errors.length === 0)
4319
4319
  return "No errors";
4320
- return errors.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text, msg) => text + separator + msg);
4320
+ return errors.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text2, msg) => text2 + separator + msg);
4321
4321
  }
4322
4322
  $dataMetaSchema(metaSchema, keywordsJsonPointers) {
4323
4323
  const rules = this.RULES.all;
@@ -4403,9 +4403,9 @@ var require_core = __commonJS({
4403
4403
  }
4404
4404
  }
4405
4405
  };
4406
- Ajv.ValidationError = validation_error_1.default;
4407
- Ajv.MissingRefError = ref_error_1.default;
4408
- exports.default = Ajv;
4406
+ Ajv2.ValidationError = validation_error_1.default;
4407
+ Ajv2.MissingRefError = ref_error_1.default;
4408
+ exports.default = Ajv2;
4409
4409
  function checkOptions(checkOpts, options, msg, log = "error") {
4410
4410
  for (const key in checkOpts) {
4411
4411
  const opt = key;
@@ -4569,20 +4569,20 @@ var require_ref = __commonJS({
4569
4569
  code(cxt) {
4570
4570
  const { gen, schema: $ref, it } = cxt;
4571
4571
  const { baseId, schemaEnv: env, validateName, opts, self } = it;
4572
- const { root: root15 } = env;
4573
- if (($ref === "#" || $ref === "#/") && baseId === root15.baseId)
4572
+ const { root: root16 } = env;
4573
+ if (($ref === "#" || $ref === "#/") && baseId === root16.baseId)
4574
4574
  return callRootRef();
4575
- const schOrEnv = compile_1.resolveRef.call(self, root15, baseId, $ref);
4575
+ const schOrEnv = compile_1.resolveRef.call(self, root16, baseId, $ref);
4576
4576
  if (schOrEnv === void 0)
4577
4577
  throw new ref_error_1.default(it.opts.uriResolver, baseId, $ref);
4578
4578
  if (schOrEnv instanceof compile_1.SchemaEnv)
4579
4579
  return callValidate(schOrEnv);
4580
4580
  return inlineRefSchema(schOrEnv);
4581
4581
  function callRootRef() {
4582
- if (env === root15)
4582
+ if (env === root16)
4583
4583
  return callRef(cxt, validateName, env, env.$async);
4584
- const rootName = gen.scopeValue("root", { ref: root15 });
4585
- return callRef(cxt, (0, codegen_1._)`${rootName}.validate`, root15, root15.$async);
4584
+ const rootName = gen.scopeValue("root", { ref: root16 });
4585
+ return callRef(cxt, (0, codegen_1._)`${rootName}.validate`, root16, root16.$async);
4586
4586
  }
4587
4587
  function callValidate(sch) {
4588
4588
  const v = getValidate(cxt, sch);
@@ -6516,7 +6516,7 @@ var require_ajv = __commonJS({
6516
6516
  var draft7MetaSchema = require_json_schema_draft_07();
6517
6517
  var META_SUPPORT_DATA = ["/properties"];
6518
6518
  var META_SCHEMA_ID = "http://json-schema.org/draft-07/schema";
6519
- var Ajv = class extends core_1.default {
6519
+ var Ajv2 = class extends core_1.default {
6520
6520
  _addVocabularies() {
6521
6521
  super._addVocabularies();
6522
6522
  draft7_1.default.forEach((v) => this.addVocabulary(v));
@@ -6535,11 +6535,11 @@ var require_ajv = __commonJS({
6535
6535
  return this.opts.defaultMeta = super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : void 0);
6536
6536
  }
6537
6537
  };
6538
- exports.Ajv = Ajv;
6539
- module.exports = exports = Ajv;
6540
- module.exports.Ajv = Ajv;
6538
+ exports.Ajv = Ajv2;
6539
+ module.exports = exports = Ajv2;
6540
+ module.exports.Ajv = Ajv2;
6541
6541
  Object.defineProperty(exports, "__esModule", { value: true });
6542
- exports.default = Ajv;
6542
+ exports.default = Ajv2;
6543
6543
  var validate_1 = require_validate();
6544
6544
  Object.defineProperty(exports, "KeywordCxt", { enumerable: true, get: function() {
6545
6545
  return validate_1.KeywordCxt;
@@ -6899,7 +6899,7 @@ import { fileURLToPath } from "node:url";
6899
6899
  // package.json
6900
6900
  var package_default = {
6901
6901
  name: "@doist/automations-cli",
6902
- version: "1.18.0",
6902
+ version: "1.19.0",
6903
6903
  description: "Command-line client for Todoist Automations",
6904
6904
  type: "module",
6905
6905
  bin: {
@@ -11206,7 +11206,7 @@ function handleIntersectionResults(result, left, right) {
11206
11206
  const unrecKeys = /* @__PURE__ */ new Map();
11207
11207
  let unrecIssue;
11208
11208
  const keyIssues = /* @__PURE__ */ new Map();
11209
- const collect3 = (iss, side) => {
11209
+ const collect2 = (iss, side) => {
11210
11210
  let keys;
11211
11211
  if (iss.code === "unrecognized_keys" && !iss.path?.length) {
11212
11212
  unrecIssue ?? (unrecIssue = iss);
@@ -11227,11 +11227,11 @@ function handleIntersectionResults(result, left, right) {
11227
11227
  return true;
11228
11228
  };
11229
11229
  for (const iss of left.issues) {
11230
- if (!collect3(iss, "l"))
11230
+ if (!collect2(iss, "l"))
11231
11231
  result.issues.push(iss);
11232
11232
  }
11233
11233
  for (const iss of right.issues) {
11234
- if (!collect3(iss, "r"))
11234
+ if (!collect2(iss, "r"))
11235
11235
  result.issues.push(iss);
11236
11236
  }
11237
11237
  const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k);
@@ -16534,8 +16534,8 @@ function ko_default() {
16534
16534
  }
16535
16535
 
16536
16536
  // ../../node_modules/zod/v4/locales/lt.js
16537
- var capitalizeFirstCharacter = (text) => {
16538
- return text.charAt(0).toUpperCase() + text.slice(1);
16537
+ var capitalizeFirstCharacter = (text2) => {
16538
+ return text2.charAt(0).toUpperCase() + text2.slice(1);
16539
16539
  };
16540
16540
  function getUnitTypeFromNumber(number4) {
16541
16541
  const abs = Math.abs(number4);
@@ -22892,8 +22892,8 @@ function encodeJSONPointerSegment(segment) {
22892
22892
  return segment.replace(/~/g, "~0").replace(/\//g, "~1");
22893
22893
  }
22894
22894
  function extractDefs(ctx, schema) {
22895
- const root15 = ctx.seen.get(schema);
22896
- if (!root15)
22895
+ const root16 = ctx.seen.get(schema);
22896
+ if (!root16)
22897
22897
  throw new Error("Unprocessed schema. This is a bug in Zod.");
22898
22898
  if (ctx.external && ctx.sharedDefsExtractedFor === ctx.external)
22899
22899
  return;
@@ -22922,7 +22922,7 @@ function extractDefs(ctx, schema) {
22922
22922
  }
22923
22923
  const uriPrefix = `#`;
22924
22924
  const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
22925
- if (entry[1] === root15 && !entry[1].schema.id) {
22925
+ if (entry[1] === root16 && !entry[1].schema.id) {
22926
22926
  return { ref: uriPrefix };
22927
22927
  }
22928
22928
  const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`;
@@ -23093,8 +23093,8 @@ function foldIntersection(json2) {
23093
23093
  assignProps(json2, folded);
23094
23094
  }
23095
23095
  function finalize(ctx, schema) {
23096
- const root15 = ctx.seen.get(schema);
23097
- if (!root15)
23096
+ const root16 = ctx.seen.get(schema);
23097
+ if (!root16)
23098
23098
  throw new Error("Unprocessed schema. This is a bug in Zod.");
23099
23099
  const flattenRef = (zodSchema) => {
23100
23100
  const seen = ctx.seen.get(zodSchema);
@@ -23205,7 +23205,7 @@ function finalize(ctx, schema) {
23205
23205
  throw new Error("Schema is missing an `id` property");
23206
23206
  result.$id = ctx.external.uri(id);
23207
23207
  }
23208
- assignProps(result, root15.defId ? root15.schema : root15.def ?? root15.schema);
23208
+ assignProps(result, root16.defId ? root16.schema : root16.def ?? root16.schema);
23209
23209
  const rootMetaId = ctx.metadataRegistry.get(schema)?.id;
23210
23210
  if (rootMetaId !== void 0 && result.id === rootMetaId)
23211
23211
  delete result.id;
@@ -27859,6 +27859,9 @@ function hasTriggerType(value) {
27859
27859
  function isManifestRecord(value) {
27860
27860
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
27861
27861
  }
27862
+ function isStepWithTools(step) {
27863
+ return "tools" in step && step.tools != null && typeof step.tools === "object";
27864
+ }
27862
27865
  function isStringTypedSchema(schema) {
27863
27866
  if (!schema)
27864
27867
  return false;
@@ -27914,6 +27917,180 @@ function resolvePropertySchemaInSchema(schema, propertyPath) {
27914
27917
  return null;
27915
27918
  return resolvePropertySchemaInSchema(propertySchema, remainingPath);
27916
27919
  }
27920
+ function parseWebhookTriggerConnector(trigger) {
27921
+ if (trigger.type !== "webhook")
27922
+ return null;
27923
+ const triggerEventId = trigger.event;
27924
+ if (typeof triggerEventId !== "string")
27925
+ return null;
27926
+ const connectorId = triggerEventId.split(".")[0];
27927
+ return connectorId ? { connectorId, triggerEventId } : null;
27928
+ }
27929
+ function getWebhookTriggerConnectors(manifest) {
27930
+ const triggers = getManifestTriggers(manifest);
27931
+ const results = [];
27932
+ for (const trigger of triggers) {
27933
+ const parsed = parseWebhookTriggerConnector(trigger);
27934
+ if (parsed) {
27935
+ results.push(parsed);
27936
+ }
27937
+ }
27938
+ return results;
27939
+ }
27940
+ function getRequiredConnectorsFromManifest(manifest) {
27941
+ const requirements = /* @__PURE__ */ new Map();
27942
+ if (manifest.steps) {
27943
+ for (const step of manifest.steps) {
27944
+ if (!isStepWithTools(step))
27945
+ continue;
27946
+ for (const connectorName of Object.keys(step.tools)) {
27947
+ if (!requirements.has(connectorName)) {
27948
+ requirements.set(connectorName, /* @__PURE__ */ new Set());
27949
+ }
27950
+ requirements.get(connectorName)?.add("mcp");
27951
+ }
27952
+ }
27953
+ }
27954
+ for (const { connectorId } of getWebhookTriggerConnectors(manifest)) {
27955
+ if (!requirements.has(connectorId)) {
27956
+ requirements.set(connectorId, /* @__PURE__ */ new Set());
27957
+ }
27958
+ requirements.get(connectorId)?.add("trigger");
27959
+ }
27960
+ return requirements;
27961
+ }
27962
+ function formatScheduleTime(hour, minute, timeFormat) {
27963
+ return new Intl.DateTimeFormat("en-US", {
27964
+ hour: timeFormat === "24h" ? "2-digit" : "numeric",
27965
+ minute: "2-digit",
27966
+ hour12: timeFormat !== "24h",
27967
+ hourCycle: timeFormat === "24h" ? "h23" : "h12",
27968
+ timeZone: "UTC"
27969
+ }).format(new Date(Date.UTC(2024, 0, 1, hour, minute)));
27970
+ }
27971
+ function parseIntegerToken(value, min, max) {
27972
+ if (!/^\d+$/.test(value)) {
27973
+ return null;
27974
+ }
27975
+ const parsed = Number(value);
27976
+ if (!Number.isInteger(parsed) || parsed < min || parsed > max) {
27977
+ return null;
27978
+ }
27979
+ return parsed;
27980
+ }
27981
+ function parseSimpleDayOfWeekList(value) {
27982
+ if (!/^\d(?:,\d)*$/.test(value)) {
27983
+ return null;
27984
+ }
27985
+ const parsed = value.split(",").map((token) => parseIntegerToken(token, 0, 6)).filter((token) => token != null);
27986
+ if (parsed.length === 0 || parsed.length !== new Set(parsed).size) {
27987
+ return null;
27988
+ }
27989
+ return [...parsed].sort((left, right) => left - right);
27990
+ }
27991
+ function formatList(values) {
27992
+ if (values.length <= 1) {
27993
+ return values[0] ?? "";
27994
+ }
27995
+ if (values.length === 2) {
27996
+ return `${values[0]} and ${values[1]}`;
27997
+ }
27998
+ return `${values.slice(0, -1).join(", ")}, and ${values.at(-1)}`;
27999
+ }
28000
+ function formatOrdinal(value) {
28001
+ const remainder100 = value % 100;
28002
+ if (remainder100 >= 11 && remainder100 <= 13) {
28003
+ return `${value}th`;
28004
+ }
28005
+ switch (value % 10) {
28006
+ case 1:
28007
+ return `${value}st`;
28008
+ case 2:
28009
+ return `${value}nd`;
28010
+ case 3:
28011
+ return `${value}rd`;
28012
+ default:
28013
+ return `${value}th`;
28014
+ }
28015
+ }
28016
+ function formatDuration(value) {
28017
+ const match = value.match(/^(\d+)(ms|s|m|h|d|w)$/);
28018
+ if (!match) {
28019
+ return value;
28020
+ }
28021
+ const [, rawAmount, unit] = match;
28022
+ const amount = Number(rawAmount);
28023
+ const unitLabelMap = {
28024
+ ms: amount === 1 ? "millisecond" : "milliseconds",
28025
+ s: amount === 1 ? "second" : "seconds",
28026
+ m: amount === 1 ? "minute" : "minutes",
28027
+ h: amount === 1 ? "hour" : "hours",
28028
+ d: amount === 1 ? "day" : "days",
28029
+ w: amount === 1 ? "week" : "weeks"
28030
+ };
28031
+ return `${amount} ${unitLabelMap[unit]}`;
28032
+ }
28033
+ function describeIntervalSchedule(value) {
28034
+ if (!value.includes("/")) {
28035
+ return `Runs every ${formatDuration(value)}`;
28036
+ }
28037
+ const [offset, interval] = value.split("/");
28038
+ if (!offset || !interval) {
28039
+ return `Runs on schedule: ${value}`;
28040
+ }
28041
+ return `Runs every ${formatDuration(interval)}, starting ${formatDuration(offset)} after activation`;
28042
+ }
28043
+ function describeCronSchedule(value, timeFormat) {
28044
+ const [minute, hour, dayOfMonth, month, dayOfWeek, extra] = value.expression.trim().split(/\s+/);
28045
+ if (!minute || !hour || !dayOfMonth || !month || !dayOfWeek || extra) {
28046
+ return `Runs on cron schedule ${value.expression} (${value.timezone})`;
28047
+ }
28048
+ const minuteNumber = parseIntegerToken(minute, 0, 59);
28049
+ const hourNumber = parseIntegerToken(hour, 0, 23);
28050
+ if (minuteNumber == null || hourNumber == null || month !== "*") {
28051
+ return `Runs on cron schedule ${value.expression} (${value.timezone})`;
28052
+ }
28053
+ const time3 = formatScheduleTime(hourNumber, minuteNumber, timeFormat);
28054
+ const timezone = value.timezone;
28055
+ const weekdayNames = [
28056
+ "Sunday",
28057
+ "Monday",
28058
+ "Tuesday",
28059
+ "Wednesday",
28060
+ "Thursday",
28061
+ "Friday",
28062
+ "Saturday"
28063
+ ];
28064
+ if (dayOfMonth === "*" && dayOfWeek === "*") {
28065
+ return `Runs every day at ${time3} in ${timezone}`;
28066
+ }
28067
+ if (dayOfMonth === "*" && dayOfWeek === "1-5") {
28068
+ return `Runs every weekday at ${time3} in ${timezone}`;
28069
+ }
28070
+ if (dayOfMonth === "*") {
28071
+ const daysOfWeek = parseSimpleDayOfWeekList(dayOfWeek);
28072
+ if (!daysOfWeek || daysOfWeek.length === 0) {
28073
+ return `Runs on cron schedule ${value.expression} (${value.timezone})`;
28074
+ }
28075
+ const dayNames = daysOfWeek.map((day) => weekdayNames[day] ?? String(day));
28076
+ return `Runs every ${formatList(dayNames)} at ${time3} in ${timezone}`;
28077
+ }
28078
+ if (dayOfWeek === "*") {
28079
+ const numericDayOfMonth = parseIntegerToken(dayOfMonth, 1, 31);
28080
+ if (numericDayOfMonth == null) {
28081
+ return `Runs on cron schedule ${value.expression} (${value.timezone})`;
28082
+ }
28083
+ return `Runs every month on the ${formatOrdinal(numericDayOfMonth)} at ${time3} in ${timezone}`;
28084
+ }
28085
+ return `Runs on cron schedule ${value.expression} (${value.timezone})`;
28086
+ }
28087
+ function getScheduleTriggerDescription(params) {
28088
+ const { value, timeFormat } = params;
28089
+ if (typeof value === "string") {
28090
+ return describeIntervalSchedule(value);
28091
+ }
28092
+ return describeCronSchedule(value, timeFormat);
28093
+ }
27917
28094
 
27918
28095
  // ../../packages/core/dist/esm/schemas/manifest.schema.js
27919
28096
  var uuidv7Regex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/i;
@@ -28289,9 +28466,9 @@ var partialManifestSchema = manifestSchemaBase.partial().extend({
28289
28466
  var templateVariableRegex = /\{\{\s*[\w.]+\s*\}\}/g;
28290
28467
  var codeStepReferenceRegex = /\bsteps\.([a-zA-Z][a-zA-Z0-9]*)(?:\.([a-zA-Z_][\w.]*))?/g;
28291
28468
  var backtickStepReferenceRegex = /`steps\.([a-zA-Z][a-zA-Z0-9]*)(?:\.([a-zA-Z_][\w.]*))?`/g;
28292
- function extractStepReferences(text, regex) {
28469
+ function extractStepReferences(text2, regex) {
28293
28470
  const references = [];
28294
- for (const match of text.matchAll(regex)) {
28471
+ for (const match of text2.matchAll(regex)) {
28295
28472
  const stepId = match[1];
28296
28473
  if (!stepId)
28297
28474
  continue;
@@ -28337,8 +28514,8 @@ function validateTemplateVariable({ variable, context, stepId, currentStepGuard,
28337
28514
  if (parts.length === 0) {
28338
28515
  return null;
28339
28516
  }
28340
- const [root15, ...rest] = parts;
28341
- if (root15 === "trigger") {
28517
+ const [root16, ...rest] = parts;
28518
+ if (root16 === "trigger") {
28342
28519
  if (rest.length === 0) {
28343
28520
  return `Step "${stepId}" ${sourceType} references "{{trigger}}" without a property. Use {{trigger.<property>}} syntax (e.g., {{trigger.payload}}, {{trigger.metadata}}).`;
28344
28521
  }
@@ -28361,7 +28538,7 @@ function validateTemplateVariable({ variable, context, stepId, currentStepGuard,
28361
28538
  }
28362
28539
  return null;
28363
28540
  }
28364
- if (root15 === "steps") {
28541
+ if (root16 === "steps") {
28365
28542
  const referencedStepId = rest[0];
28366
28543
  if (!referencedStepId) {
28367
28544
  return `Step "${stepId}" ${sourceType} references "steps" but is missing the step identifier in template variable "{{${variable}}}". Use {{steps.<stepId>}} syntax.`;
@@ -29148,6 +29325,17 @@ var finalizeAutomationDraftResponseSchema = external_exports.object({
29148
29325
  var testAutomationDraftResponseSchema = external_exports.object({
29149
29326
  success: external_exports.literal(true)
29150
29327
  });
29328
+ var AUTOMATION_OPEN_DRAFT_CONFLICT_CODE = "automation_open_draft_conflict";
29329
+ var AutomationOpenDraftConflictSchema = external_exports.object({
29330
+ code: external_exports.literal(AUTOMATION_OPEN_DRAFT_CONFLICT_CODE),
29331
+ message: external_exports.string(),
29332
+ draftId: external_exports.string()
29333
+ });
29334
+ var AUTOMATION_DRAFT_NOT_READY_CODE = "automation_draft_not_ready";
29335
+ var AutomationDraftNotReadySchema = external_exports.object({
29336
+ code: external_exports.literal(AUTOMATION_DRAFT_NOT_READY_CODE),
29337
+ message: external_exports.string()
29338
+ });
29151
29339
 
29152
29340
  // ../../packages/core/dist/esm/schemas/automation-draft-connection.schema.js
29153
29341
  var CreateAutomationDraftConnectionSchema = external_exports.object({
@@ -29791,7 +29979,143 @@ function assertKnownTimezone(timezone) {
29791
29979
  }
29792
29980
 
29793
29981
  // ../../packages/core/dist/esm/schemas/manifest.validation.js
29982
+ var import_ajv = __toESM(require_ajv(), 1);
29794
29983
  var import_ajv_formats = __toESM(require_dist(), 1);
29984
+ function validateManifest(manifest) {
29985
+ const allErrors = [];
29986
+ try {
29987
+ const validatedManifest = manifestSchema.parse(manifest);
29988
+ const triggerValidation = validateTriggerSchemas(validatedManifest);
29989
+ if (!triggerValidation.isValid) {
29990
+ allErrors.push(...triggerValidation.errors);
29991
+ }
29992
+ const stepValidation = validateStepSchemas(validatedManifest);
29993
+ if (!stepValidation.isValid) {
29994
+ allErrors.push(...stepValidation.errors);
29995
+ }
29996
+ const payloadValidation = validateWebhookPayloadStructure(validatedManifest);
29997
+ if (!payloadValidation.isValid) {
29998
+ allErrors.push(...payloadValidation.errors);
29999
+ }
30000
+ return {
30001
+ isValid: allErrors.length === 0,
30002
+ errors: allErrors
30003
+ };
30004
+ } catch (error62) {
30005
+ if (error62 instanceof external_exports.ZodError) {
30006
+ const zodErrors = error62.issues.map((err) => `${err.path.join(".")}: ${err.message}`);
30007
+ return { isValid: false, errors: zodErrors };
30008
+ }
30009
+ const message = error62 instanceof Error ? error62.message : "Unknown validation error";
30010
+ return { isValid: false, errors: [message] };
30011
+ }
30012
+ }
30013
+ function validatePartialManifest(manifest) {
30014
+ try {
30015
+ const data = partialManifestSchema.parse(manifest);
30016
+ return { isValid: true, errors: [], data };
30017
+ } catch (error62) {
30018
+ if (error62 instanceof external_exports.ZodError) {
30019
+ const errors = error62.issues.map((err) => `${err.path.join(".")}: ${err.message}`);
30020
+ return { isValid: false, errors };
30021
+ }
30022
+ const message = error62 instanceof Error ? error62.message : "Unknown validation error";
30023
+ return { isValid: false, errors: [message] };
30024
+ }
30025
+ }
30026
+ function compileSchema(schema, schemaName) {
30027
+ const ajv = new import_ajv.Ajv({ strict: true, validateFormats: true });
30028
+ import_ajv_formats.default.default(ajv);
30029
+ try {
30030
+ ajv.compile(schema);
30031
+ return { isValid: true };
30032
+ } catch (error62) {
30033
+ const message = error62 instanceof Error ? error62.message : String(error62);
30034
+ return {
30035
+ isValid: false,
30036
+ error: `${schemaName} is invalid JSON Schema: ${message}. Common issue: when using array keywords like "contains", you must explicitly declare "type": "array".`
30037
+ };
30038
+ }
30039
+ }
30040
+ function validateTriggerSchemas(manifest) {
30041
+ const errors = [];
30042
+ const triggers = getManifestTriggers(manifest);
30043
+ if (triggers.length === 0) {
30044
+ return { isValid: true, errors: [] };
30045
+ }
30046
+ for (const trigger of triggers) {
30047
+ if (trigger.type === "webhook" || trigger.type === "api") {
30048
+ const triggerLabel = trigger.type === "webhook" ? `Webhook trigger (${trigger.type === "webhook" ? trigger.event : ""})` : "API trigger";
30049
+ const outputResult = compileSchema(trigger.outputSchema, `${triggerLabel} outputSchema`);
30050
+ if (!outputResult.isValid && outputResult.error) {
30051
+ errors.push(outputResult.error);
30052
+ }
30053
+ if (trigger.inputSchema) {
30054
+ const inputResult = compileSchema(trigger.inputSchema, `${triggerLabel} inputSchema`);
30055
+ if (!inputResult.isValid && inputResult.error) {
30056
+ errors.push(inputResult.error);
30057
+ }
30058
+ }
30059
+ }
30060
+ }
30061
+ return {
30062
+ isValid: errors.length === 0,
30063
+ errors
30064
+ };
30065
+ }
30066
+ function validateStepSchemas(manifest) {
30067
+ const errors = [];
30068
+ if (!manifest.steps || !Array.isArray(manifest.steps)) {
30069
+ return { isValid: true, errors: [] };
30070
+ }
30071
+ for (const step of manifest.steps) {
30072
+ const outputResult = compileSchema(step.outputSchema, `Step "${step.id}" outputSchema`);
30073
+ if (!outputResult.isValid && outputResult.error) {
30074
+ errors.push(outputResult.error);
30075
+ }
30076
+ if (step.exitOn) {
30077
+ const exitOnResult = compileSchema(step.exitOn, `Step "${step.id}" exitOn`);
30078
+ if (!exitOnResult.isValid && exitOnResult.error) {
30079
+ errors.push(exitOnResult.error);
30080
+ }
30081
+ }
30082
+ }
30083
+ return {
30084
+ isValid: errors.length === 0,
30085
+ errors
30086
+ };
30087
+ }
30088
+ function validateWebhookPayloadStructure(manifest) {
30089
+ const errors = [];
30090
+ const triggers = getManifestTriggers(manifest);
30091
+ const webhookTriggers = triggers.filter((t) => t.type === "webhook");
30092
+ if (webhookTriggers.length === 0) {
30093
+ return { isValid: true, errors: [] };
30094
+ }
30095
+ for (const trigger of webhookTriggers) {
30096
+ if (trigger.type !== "webhook")
30097
+ continue;
30098
+ const eventLabel = trigger.event;
30099
+ const triggerOutputSchema = trigger.outputSchema;
30100
+ if (!triggerOutputSchema) {
30101
+ errors.push(`Webhook trigger "${eventLabel}" is missing outputSchema`);
30102
+ continue;
30103
+ }
30104
+ if (!triggerOutputSchema.properties || typeof triggerOutputSchema.properties !== "object") {
30105
+ errors.push(`Webhook trigger "${eventLabel}" outputSchema must have a "properties" field with a "payload" object. The webhook event data is wrapped in a payload field.`);
30106
+ continue;
30107
+ }
30108
+ const payloadSchema = triggerOutputSchema.properties.payload;
30109
+ if (!payloadSchema || typeof payloadSchema !== "object") {
30110
+ errors.push(`Webhook trigger "${eventLabel}" outputSchema must have a "payload" property. All webhook event data is wrapped in { payload: {...}, metadata: {...} }.`);
30111
+ continue;
30112
+ }
30113
+ if (!Array.isArray(triggerOutputSchema.required) || !triggerOutputSchema.required.includes("payload")) {
30114
+ errors.push(`Webhook trigger "${eventLabel}" outputSchema must include "payload" in the "required" array. The payload wrapper is mandatory.`);
30115
+ }
30116
+ }
30117
+ return { isValid: errors.length === 0, errors };
30118
+ }
29795
30119
 
29796
30120
  // ../../packages/core/dist/esm/schemas/notification.schema.js
29797
30121
  var NOTIFICATION_TYPES = ["notification", "prompt"];
@@ -30594,13 +30918,13 @@ function buildUrl(baseUrl, path, query) {
30594
30918
  return url2.toString();
30595
30919
  }
30596
30920
  async function readResponseBody(response) {
30597
- const text = await response.text();
30598
- if (text.length === 0)
30921
+ const text2 = await response.text();
30922
+ if (text2.length === 0)
30599
30923
  return void 0;
30600
30924
  try {
30601
- return JSON.parse(text);
30925
+ return JSON.parse(text2);
30602
30926
  } catch {
30603
- return text;
30927
+ return text2;
30604
30928
  }
30605
30929
  }
30606
30930
  async function request(args) {
@@ -30789,6 +31113,16 @@ var automationDraftsEndpoints = {
30789
31113
  };
30790
31114
 
30791
31115
  // ../../packages/sdk/dist/esm/clients/automation-drafts/automation-drafts-client.js
31116
+ function toCreateQuery(translate) {
31117
+ return translate === void 0 ? void 0 : { translate };
31118
+ }
31119
+ function getDraftNotReadyError(error62) {
31120
+ if (!(error62 instanceof AutomationsRequestError) || error62.httpStatusCode !== 400) {
31121
+ return null;
31122
+ }
31123
+ const parsed = AutomationDraftNotReadySchema.safeParse(error62.responseData);
31124
+ return parsed.success ? parsed.data : null;
31125
+ }
30792
31126
  var AutomationDraftsClient = class extends BaseClient {
30793
31127
  async list(args = {}, options) {
30794
31128
  const { cursor, limit } = CursorPaginationSchema.parse(args);
@@ -30811,11 +31145,13 @@ var AutomationDraftsClient = class extends BaseClient {
30811
31145
  }
30812
31146
  async create(manifest, options) {
30813
31147
  const body = partialManifestSchema.parse(manifest);
31148
+ const { translate, ...requestOptions } = options ?? {};
30814
31149
  const data = await this.request({
30815
31150
  method: "POST",
30816
31151
  path: automationDraftsEndpoints.list,
31152
+ query: toCreateQuery(translate),
30817
31153
  body,
30818
- options
31154
+ options: requestOptions
30819
31155
  });
30820
31156
  return automationDraftWithValidationSchema.parse(data);
30821
31157
  }
@@ -30918,6 +31254,13 @@ var automationsEndpoints = {
30918
31254
 
30919
31255
  // ../../packages/sdk/dist/esm/clients/automations/automations-client.js
30920
31256
  var createDraftResponseSchema = external_exports.object({ draft: automationDraftSchema });
31257
+ function getOpenDraftConflictError(error62) {
31258
+ if (!(error62 instanceof AutomationsRequestError) || error62.httpStatusCode !== 409) {
31259
+ return null;
31260
+ }
31261
+ const parsed = AutomationOpenDraftConflictSchema.safeParse(error62.responseData);
31262
+ return parsed.success ? parsed.data : null;
31263
+ }
30921
31264
  var AutomationsClient = class extends BaseClient {
30922
31265
  async list(args = {}, options) {
30923
31266
  const { cursor, limit } = CursorPaginationSchema.parse(args);
@@ -31096,11 +31439,23 @@ var WorkspaceAutomationRunsClient = class extends BaseClient {
31096
31439
 
31097
31440
  // ../../packages/sdk/dist/esm/clients/workspace-automation-draft-connections/endpoints.js
31098
31441
  var workspaceAutomationDraftConnectionsEndpoints = {
31099
- list: (workspaceId, draftId) => `/workspaces/${encodeURIComponent(workspaceId)}/automation-drafts/${encodeURIComponent(draftId)}/connections`
31442
+ list: (workspaceId, draftId) => root6(workspaceId, draftId),
31443
+ status: (workspaceId, draftId) => `${root6(workspaceId, draftId)}/status`
31100
31444
  };
31445
+ function root6(workspaceId, draftId) {
31446
+ return `/workspaces/${encodeURIComponent(workspaceId)}/automation-drafts/${encodeURIComponent(draftId)}/connections`;
31447
+ }
31101
31448
 
31102
31449
  // ../../packages/sdk/dist/esm/clients/workspace-automation-draft-connections/workspace-automation-draft-connections-client.js
31103
31450
  var WorkspaceAutomationDraftConnectionsClient = class extends BaseClient {
31451
+ async list(workspaceId, draftId, options) {
31452
+ const data = await this.request({
31453
+ method: "GET",
31454
+ path: workspaceAutomationDraftConnectionsEndpoints.list(IdSchema.parse(workspaceId), IdSchema.parse(draftId)),
31455
+ options
31456
+ });
31457
+ return GetAutomationDraftConnectionsResponseSchema.parse(data);
31458
+ }
31104
31459
  async upsert(workspaceId, draftId, body, options) {
31105
31460
  const parsedBody = CreateAutomationDraftConnectionSchema.parse(body);
31106
31461
  const data = await this.request({
@@ -31111,14 +31466,23 @@ var WorkspaceAutomationDraftConnectionsClient = class extends BaseClient {
31111
31466
  });
31112
31467
  return AutomationDraftConnectionSchema.parse(data);
31113
31468
  }
31469
+ async getStatus(workspaceId, draftId, options) {
31470
+ const data = await this.request({
31471
+ method: "GET",
31472
+ path: workspaceAutomationDraftConnectionsEndpoints.status(IdSchema.parse(workspaceId), IdSchema.parse(draftId)),
31473
+ options
31474
+ });
31475
+ return GetAutomationDraftConnectionValidationResponseSchema.parse(data);
31476
+ }
31114
31477
  };
31115
31478
 
31116
31479
  // ../../packages/sdk/dist/esm/clients/workspace-automation-drafts/endpoints.js
31117
31480
  var workspaceAutomationDraftsEndpoints = {
31118
- list: (workspaceId) => `${root6(workspaceId)}`,
31119
- detail: (workspaceId, id) => `${root6(workspaceId)}/${encodeURIComponent(id)}`
31481
+ list: (workspaceId) => `${root7(workspaceId)}`,
31482
+ detail: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}`,
31483
+ finalize: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/finalize`
31120
31484
  };
31121
- function root6(workspaceId) {
31485
+ function root7(workspaceId) {
31122
31486
  return `/workspaces/${encodeURIComponent(workspaceId)}/automation-drafts`;
31123
31487
  }
31124
31488
 
@@ -31142,6 +31506,29 @@ var WorkspaceAutomationDraftsClient = class extends BaseClient {
31142
31506
  });
31143
31507
  return automationDraftWithValidationSchema.parse(data);
31144
31508
  }
31509
+ async create(workspaceId, manifest, options) {
31510
+ const body = partialManifestSchema.parse(manifest);
31511
+ const { translate, ...requestOptions } = options ?? {};
31512
+ const data = await this.request({
31513
+ method: "POST",
31514
+ path: workspaceAutomationDraftsEndpoints.list(IdSchema.parse(workspaceId)),
31515
+ // Only sent when set, so a default create is unchanged on the wire.
31516
+ query: translate === void 0 ? void 0 : { translate },
31517
+ body,
31518
+ options: requestOptions
31519
+ });
31520
+ return automationDraftWithValidationSchema.parse(data);
31521
+ }
31522
+ async update(workspaceId, draftId, manifest, options) {
31523
+ const body = partialManifestSchema.parse(manifest);
31524
+ const data = await this.request({
31525
+ method: "PUT",
31526
+ path: workspaceAutomationDraftsEndpoints.detail(IdSchema.parse(workspaceId), IdSchema.parse(draftId)),
31527
+ body,
31528
+ options
31529
+ });
31530
+ return automationDraftWithValidationSchema.parse(data);
31531
+ }
31145
31532
  /** Deletes the draft. Only its owner can; the API answers 404 otherwise. */
31146
31533
  async delete(workspaceId, draftId, options) {
31147
31534
  await this.request({
@@ -31150,6 +31537,15 @@ var WorkspaceAutomationDraftsClient = class extends BaseClient {
31150
31537
  options
31151
31538
  });
31152
31539
  }
31540
+ /** Publishes the draft as a workspace automation, or updates the one it edits. */
31541
+ async finalize(workspaceId, draftId, options) {
31542
+ const data = await this.request({
31543
+ method: "POST",
31544
+ path: workspaceAutomationDraftsEndpoints.finalize(IdSchema.parse(workspaceId), IdSchema.parse(draftId)),
31545
+ options
31546
+ });
31547
+ return finalizeAutomationDraftResponseSchema.parse(data);
31548
+ }
31153
31549
  };
31154
31550
 
31155
31551
  // ../../packages/sdk/dist/esm/clients/workspace-chat/endpoints.js
@@ -31173,15 +31569,16 @@ var WorkspaceChatClient = class extends BaseClient {
31173
31569
 
31174
31570
  // ../../packages/sdk/dist/esm/clients/workspace-automations/endpoints.js
31175
31571
  var workspaceAutomationsEndpoints = {
31176
- list: (workspaceId) => `${root7(workspaceId)}`,
31177
- detail: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}`,
31178
- metadata: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/metadata`,
31179
- schedule: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/schedule`,
31180
- visibility: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/visibility`,
31181
- move: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/move`,
31182
- trigger: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/trigger`
31572
+ list: (workspaceId) => `${root8(workspaceId)}`,
31573
+ detail: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}`,
31574
+ metadata: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/metadata`,
31575
+ schedule: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/schedule`,
31576
+ visibility: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/visibility`,
31577
+ move: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/move`,
31578
+ trigger: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/trigger`,
31579
+ draft: (workspaceId, id) => `${root8(workspaceId)}/${encodeURIComponent(id)}/draft`
31183
31580
  };
31184
- function root7(workspaceId) {
31581
+ function root8(workspaceId) {
31185
31582
  return `/workspaces/${encodeURIComponent(workspaceId)}/automations`;
31186
31583
  }
31187
31584
 
@@ -31279,12 +31676,33 @@ var WorkspaceAutomationsClient = class extends BaseClient {
31279
31676
  options
31280
31677
  });
31281
31678
  }
31679
+ /** The edit draft currently open for the automation, if any (404 otherwise). */
31680
+ async getDraft(workspaceId, id, options) {
31681
+ const data = await this.request({
31682
+ method: "GET",
31683
+ path: workspaceAutomationsEndpoints.draft(IdSchema.parse(workspaceId), IdSchema.parse(id)),
31684
+ options
31685
+ });
31686
+ return automationDraftSchema.parse(data);
31687
+ }
31688
+ /**
31689
+ * Opens an edit draft seeded from the published manifest. Answers 409 when
31690
+ * one is already open; see `getOpenDraftConflictError`.
31691
+ */
31692
+ async createDraft(workspaceId, id, options) {
31693
+ const data = await this.request({
31694
+ method: "POST",
31695
+ path: workspaceAutomationsEndpoints.draft(IdSchema.parse(workspaceId), IdSchema.parse(id)),
31696
+ options
31697
+ });
31698
+ return createDraftResponseSchema.parse(data);
31699
+ }
31282
31700
  };
31283
31701
 
31284
31702
  // ../../packages/sdk/dist/esm/clients/workspaces/endpoints.js
31285
- var root8 = "/workspaces";
31703
+ var root9 = "/workspaces";
31286
31704
  var workspacesEndpoints = {
31287
- list: root8
31705
+ list: root9
31288
31706
  };
31289
31707
 
31290
31708
  // ../../packages/sdk/dist/esm/clients/workspaces/workspaces-client.js
@@ -31306,12 +31724,12 @@ var WorkspacesClient = class extends BaseClient {
31306
31724
  };
31307
31725
 
31308
31726
  // ../../packages/sdk/dist/esm/clients/chat/endpoints.js
31309
- var root9 = "/chat/conversations";
31727
+ var root10 = "/chat/conversations";
31310
31728
  var chatEndpoints = {
31311
- conversations: root9,
31312
- conversation: (id) => `${root9}/${encodeURIComponent(id)}`,
31313
- messages: (id) => `${root9}/${encodeURIComponent(id)}/messages`,
31314
- usagePreview: (id) => `${root9}/${encodeURIComponent(id)}/usage-preview`
31729
+ conversations: root10,
31730
+ conversation: (id) => `${root10}/${encodeURIComponent(id)}`,
31731
+ messages: (id) => `${root10}/${encodeURIComponent(id)}/messages`,
31732
+ usagePreview: (id) => `${root10}/${encodeURIComponent(id)}/usage-preview`
31315
31733
  };
31316
31734
 
31317
31735
  // ../../packages/sdk/dist/esm/clients/chat/chat-client.js
@@ -31385,15 +31803,15 @@ var ChatClient = class extends BaseClient {
31385
31803
  };
31386
31804
 
31387
31805
  // ../../packages/sdk/dist/esm/clients/connections/endpoints.js
31388
- var root10 = "/connections";
31806
+ var root11 = "/connections";
31389
31807
  var connectionsEndpoints = {
31390
- list: root10,
31391
- detail: (id) => `${root10}/${encodeURIComponent(id)}`,
31392
- token: (id) => `${root10}/${encodeURIComponent(id)}/token`,
31393
- dependentAutomations: (connectorId) => `${root10}/${encodeURIComponent(connectorId)}/automations`,
31394
- create: (connectorId, capability) => `${root10}/${encodeURIComponent(connectorId)}/${encodeURIComponent(capability)}`,
31395
- localOAuth: (connectorId, capability) => `${root10}/${encodeURIComponent(connectorId)}/${encodeURIComponent(capability)}/local-oauth`,
31396
- checkManifest: `${root10}/check-manifest`
31808
+ list: root11,
31809
+ detail: (id) => `${root11}/${encodeURIComponent(id)}`,
31810
+ token: (id) => `${root11}/${encodeURIComponent(id)}/token`,
31811
+ dependentAutomations: (connectorId) => `${root11}/${encodeURIComponent(connectorId)}/automations`,
31812
+ create: (connectorId, capability) => `${root11}/${encodeURIComponent(connectorId)}/${encodeURIComponent(capability)}`,
31813
+ localOAuth: (connectorId, capability) => `${root11}/${encodeURIComponent(connectorId)}/${encodeURIComponent(capability)}/local-oauth`,
31814
+ checkManifest: `${root11}/check-manifest`
31397
31815
  };
31398
31816
 
31399
31817
  // ../../packages/sdk/dist/esm/clients/connections/connections-client.js
@@ -31580,12 +31998,12 @@ function createClientContext(authToken, options = {}, apiOrigin = "automations")
31580
31998
  }
31581
31999
 
31582
32000
  // ../../packages/sdk/dist/esm/clients/notifications/endpoints.js
31583
- var root11 = "/notifications";
32001
+ var root12 = "/notifications";
31584
32002
  var notificationsEndpoints = {
31585
- list: root11,
31586
- pendingPromptAutomations: `${root11}/pending-prompt-automations`,
31587
- detail: (id) => `${root11}/${encodeURIComponent(id)}`,
31588
- respond: (id) => `${root11}/${encodeURIComponent(id)}/respond`
32003
+ list: root12,
32004
+ pendingPromptAutomations: `${root12}/pending-prompt-automations`,
32005
+ detail: (id) => `${root12}/${encodeURIComponent(id)}`,
32006
+ respond: (id) => `${root12}/${encodeURIComponent(id)}/respond`
31589
32007
  };
31590
32008
  var pushRoot = "/push-subscriptions";
31591
32009
  var pushSubscriptionsEndpoints = {
@@ -31709,11 +32127,11 @@ var NotificationsClient = class extends BaseClient {
31709
32127
  };
31710
32128
 
31711
32129
  // ../../packages/sdk/dist/esm/clients/user-settings/endpoints.js
31712
- var root12 = "/settings";
32130
+ var root13 = "/settings";
31713
32131
  var userSettingsEndpoints = {
31714
- onboarding: `${root12}/onboarding`,
31715
- preferences: `${root12}/preferences`,
31716
- terms: `${root12}/terms`
32132
+ onboarding: `${root13}/onboarding`,
32133
+ preferences: `${root13}/preferences`,
32134
+ terms: `${root13}/terms`
31717
32135
  };
31718
32136
 
31719
32137
  // ../../packages/sdk/dist/esm/clients/user-settings/user-settings-client.js
@@ -31875,11 +32293,11 @@ var UsageBillingClient = class extends BaseClient {
31875
32293
  };
31876
32294
 
31877
32295
  // ../../packages/sdk/dist/esm/clients/webhook-event-subscriptions/endpoints.js
31878
- var root13 = "/webhook-event-subscriptions";
32296
+ var root14 = "/webhook-event-subscriptions";
31879
32297
  var webhookEventSubscriptionsEndpoints = {
31880
- list: root13,
31881
- detail: (id) => `${root13}/${encodeURIComponent(id)}`,
31882
- deliveries: (id) => `${root13}/${encodeURIComponent(id)}/deliveries`
32298
+ list: root14,
32299
+ detail: (id) => `${root14}/${encodeURIComponent(id)}`,
32300
+ deliveries: (id) => `${root14}/${encodeURIComponent(id)}/deliveries`
31883
32301
  };
31884
32302
 
31885
32303
  // ../../packages/sdk/dist/esm/clients/webhook-event-subscriptions/webhook-event-subscriptions-client.js
@@ -31952,12 +32370,12 @@ var WebhookEventSubscriptionsClient = class extends BaseClient {
31952
32370
  };
31953
32371
 
31954
32372
  // ../../packages/sdk/dist/esm/clients/webhook-subscriptions/endpoints.js
31955
- function root14(automationId) {
32373
+ function root15(automationId) {
31956
32374
  return `/automations/${encodeURIComponent(automationId)}/subscriptions`;
31957
32375
  }
31958
32376
  var webhookSubscriptionsEndpoints = {
31959
- list: (automationId) => root14(automationId),
31960
- detail: (automationId, subscriptionId) => `${root14(automationId)}/${encodeURIComponent(subscriptionId)}`
32377
+ list: (automationId) => root15(automationId),
32378
+ detail: (automationId, subscriptionId) => `${root15(automationId)}/${encodeURIComponent(subscriptionId)}`
31961
32379
  };
31962
32380
 
31963
32381
  // ../../packages/sdk/dist/esm/clients/webhook-subscriptions/webhook-subscriptions-client.js
@@ -33951,8 +34369,8 @@ function getResourceName(manifest) {
33951
34369
  }
33952
34370
  function getMessageSummary(message) {
33953
34371
  if (!Array.isArray(message.parts)) return "(unstructured message parts)";
33954
- const text = message.parts.filter(isTextPart).map((part) => part.text).join("");
33955
- if (text) return text;
34372
+ const text2 = message.parts.filter(isTextPart).map((part) => part.text).join("");
34373
+ if (text2) return text2;
33956
34374
  const partTypes = message.parts.filter(isRecord2).map((part) => typeof part.type === "string" ? part.type : "unknown");
33957
34375
  return partTypes.length > 0 ? `[${partTypes.join(", ")}]` : "(no visible text)";
33958
34376
  }
@@ -34307,6 +34725,36 @@ async function runStreamingCommand(command, handlers) {
34307
34725
  }
34308
34726
  }
34309
34727
 
34728
+ // src/lib/connection-selection.ts
34729
+ function parseConnectionSelectionOption(value) {
34730
+ const separatorIndex = value.indexOf("=");
34731
+ if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
34732
+ throw new Error(
34733
+ `Invalid connection selection "${value}". Use connector[:mcp|trigger]=connection-id.`
34734
+ );
34735
+ }
34736
+ const selector = value.slice(0, separatorIndex);
34737
+ const connectionId = value.slice(separatorIndex + 1);
34738
+ const selectorParts = selector.split(":");
34739
+ if (selectorParts.length > 2) {
34740
+ throw new Error(`Invalid connection selection "${value}".`);
34741
+ }
34742
+ const [connectorId, rawConnectionType] = selectorParts;
34743
+ if (!connectorId) throw new Error(`Invalid connection selection "${value}".`);
34744
+ if (rawConnectionType && rawConnectionType !== "mcp" && rawConnectionType !== "trigger") {
34745
+ throw new Error(`Invalid connection type "${rawConnectionType}".`);
34746
+ }
34747
+ const connectionType = rawConnectionType === "mcp" || rawConnectionType === "trigger" ? rawConnectionType : void 0;
34748
+ return {
34749
+ connectorId,
34750
+ connectionType,
34751
+ connectionId
34752
+ };
34753
+ }
34754
+ function collectOption(value, previous) {
34755
+ return [...previous, value];
34756
+ }
34757
+
34310
34758
  // ../../packages/sdk/dist/esm/chat-turn/connection-requirements.js
34311
34759
  var CONNECTION_LOOKUP_CONCURRENCY = 4;
34312
34760
  function deduplicateConnectionRequirements(requirements) {
@@ -34415,11 +34863,11 @@ var toolUpdateMemoryResultSchema = external_exports.object({
34415
34863
  });
34416
34864
 
34417
34865
  // ../../packages/sdk/dist/esm/chat-turn/messages.js
34418
- function createUserMessage(text) {
34866
+ function createUserMessage(text2) {
34419
34867
  return {
34420
34868
  id: globalThis.crypto.randomUUID(),
34421
34869
  role: "user",
34422
- parts: [{ type: "text", text }]
34870
+ parts: [{ type: "text", text: text2 }]
34423
34871
  };
34424
34872
  }
34425
34873
  function toUiMessage(message) {
@@ -34944,8 +35392,8 @@ Interrupted. Resume with: tda chat continue ${sanitizeTerminalText(event.convers
34944
35392
  this.assistantLineOpen = false;
34945
35393
  break;
34946
35394
  case "session_status": {
34947
- const text = sanitizeTerminalText(String(event.humanText ?? ""));
34948
- this.stream.write(text.endsWith("\n") ? text : `${text}
35395
+ const text2 = sanitizeTerminalText(String(event.humanText ?? ""));
35396
+ this.stream.write(text2.endsWith("\n") ? text2 : `${text2}
34949
35397
  `);
34950
35398
  break;
34951
35399
  }
@@ -35476,9 +35924,9 @@ var ChatService = class {
35476
35924
  input: input2,
35477
35925
  pendingAction,
35478
35926
  signal,
35479
- onText: (text) => {
35927
+ onText: (text2) => {
35480
35928
  markActivity();
35481
- this.output.emit({ type: "assistant_text", conversationId, text });
35929
+ this.output.emit({ type: "assistant_text", conversationId, text: text2 });
35482
35930
  },
35483
35931
  onToolActivity: (activity) => {
35484
35932
  markActivity();
@@ -35659,31 +36107,6 @@ function getResumeCommand(summary) {
35659
36107
  }
35660
36108
  return `tda chat continue ${summary.conversationId} "<message>"`;
35661
36109
  }
35662
- function parseConnectionSelectionOption(value) {
35663
- const separatorIndex = value.indexOf("=");
35664
- if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
35665
- throw new Error(
35666
- `Invalid connection selection "${value}". Use connector[:mcp|trigger]=connection-id.`
35667
- );
35668
- }
35669
- const selector = value.slice(0, separatorIndex);
35670
- const connectionId = value.slice(separatorIndex + 1);
35671
- const selectorParts = selector.split(":");
35672
- if (selectorParts.length > 2) {
35673
- throw new Error(`Invalid connection selection "${value}".`);
35674
- }
35675
- const [connectorId, rawConnectionType] = selectorParts;
35676
- if (!connectorId) throw new Error(`Invalid connection selection "${value}".`);
35677
- if (rawConnectionType && rawConnectionType !== "mcp" && rawConnectionType !== "trigger") {
35678
- throw new Error(`Invalid connection type "${rawConnectionType}".`);
35679
- }
35680
- const connectionType = rawConnectionType === "mcp" || rawConnectionType === "trigger" ? rawConnectionType : void 0;
35681
- return {
35682
- connectorId,
35683
- connectionType,
35684
- connectionId
35685
- };
35686
- }
35687
36110
 
35688
36111
  // src/commands/chat/index.ts
35689
36112
  function registerChatCommand(program) {
@@ -35699,7 +36122,7 @@ function registerChatCommand(program) {
35699
36122
  chat.command("continue").description("Continue a persisted conversation").argument("<conversation-id>", "Conversation ID emitted by start").argument("[message...]", "Answer or follow-up message").option(
35700
36123
  "--connection <connector[:type]=connection-id>",
35701
36124
  "Resolve a pending connection selection; repeat for multiple connectors",
35702
- collect,
36125
+ collectOption,
35703
36126
  []
35704
36127
  ).action(
35705
36128
  async (conversationId, messageParts, options, command) => {
@@ -35782,9 +36205,6 @@ async function runCommand(command, operation) {
35782
36205
  }
35783
36206
  });
35784
36207
  }
35785
- function collect(value, previous) {
35786
- return [...previous, value];
35787
- }
35788
36208
 
35789
36209
  // src/commands/conversation/index.ts
35790
36210
  import { Option as Option3 } from "commander";
@@ -36356,6 +36776,343 @@ function registerConnectorCommand(program) {
36356
36776
  registerConnectorMutationCommands(connector);
36357
36777
  }
36358
36778
 
36779
+ // src/lib/manifest-input.ts
36780
+ import { CliError as CliError3, getErrorMessage as getErrorMessage6 } from "@doist/cli-core";
36781
+ import { Option as Option6 } from "commander";
36782
+ import { readFile as readFile2 } from "node:fs/promises";
36783
+ import { text } from "node:stream/consumers";
36784
+ function addManifestInputOptions(command) {
36785
+ return command.addOption(
36786
+ new Option6("--file <path>", "Read the manifest from this JSON file").conflicts("stdin")
36787
+ ).option("--stdin", "Read the manifest as JSON from standard input");
36788
+ }
36789
+ async function readManifestInput(options, input2 = process.stdin) {
36790
+ const source = await readSource(options, input2);
36791
+ try {
36792
+ return JSON.parse(source.content);
36793
+ } catch (error62) {
36794
+ throw new CliError3(
36795
+ "MANIFEST_UNREADABLE",
36796
+ `${source.label} is not valid JSON: ${getErrorMessage6(error62)}`
36797
+ );
36798
+ }
36799
+ }
36800
+ function parsePartialManifestInput(value) {
36801
+ const validation = validatePartialManifest(value);
36802
+ if (!validation.isValid) {
36803
+ throw new CliError3(
36804
+ "MANIFEST_INVALID",
36805
+ `Manifest is invalid: ${validation.errors.join("; ")}`
36806
+ );
36807
+ }
36808
+ return validation.data;
36809
+ }
36810
+ async function readSource(options, input2) {
36811
+ if (options.file !== void 0) {
36812
+ try {
36813
+ return { label: options.file, content: await readFile2(options.file, "utf8") };
36814
+ } catch (error62) {
36815
+ throw new CliError3(
36816
+ "MANIFEST_UNREADABLE",
36817
+ `Could not read ${options.file}: ${getErrorMessage6(error62)}`
36818
+ );
36819
+ }
36820
+ }
36821
+ if (options.stdin) {
36822
+ try {
36823
+ return { label: "Standard input", content: await text(input2) };
36824
+ } catch (error62) {
36825
+ throw new CliError3(
36826
+ "MANIFEST_UNREADABLE",
36827
+ `Could not read standard input: ${getErrorMessage6(error62)}`
36828
+ );
36829
+ }
36830
+ }
36831
+ throw new CliError3("MANIFEST_UNREADABLE", "Provide the manifest with --file <path> or --stdin.");
36832
+ }
36833
+
36834
+ // src/commands/draft/draft-service.ts
36835
+ import { CliError as CliError4, getErrorMessage as getErrorMessage7 } from "@doist/cli-core";
36836
+
36837
+ // src/lib/manifest-diff.ts
36838
+ function stableStringify(value) {
36839
+ return JSON.stringify(sortKeys(value));
36840
+ }
36841
+ function isDeepEqual(left, right) {
36842
+ return stableStringify(left) === stableStringify(right);
36843
+ }
36844
+ function diffManifests(before, after) {
36845
+ const previous = asManifest(before);
36846
+ const next = asManifest(after);
36847
+ const changedProperties = [.../* @__PURE__ */ new Set([...Object.keys(previous), ...Object.keys(next)])].filter((key) => key !== "steps").filter((key) => !isDeepEqual(previous[key], next[key])).sort();
36848
+ const previousSteps = stepsById(previous.steps);
36849
+ const nextSteps = stepsById(next.steps);
36850
+ const added = [...nextSteps.keys()].filter((id) => !previousSteps.has(id));
36851
+ const removed = [...previousSteps.keys()].filter((id) => !nextSteps.has(id));
36852
+ const changed = [...nextSteps].filter(([id, step]) => previousSteps.has(id) && !isDeepEqual(previousSteps.get(id), step)).map(([id]) => id);
36853
+ const sharedBefore = [...previousSteps.keys()].filter((id) => nextSteps.has(id));
36854
+ const sharedAfter = [...nextSteps.keys()].filter((id) => previousSteps.has(id));
36855
+ const reordered = sharedBefore.some((id, index) => sharedAfter[index] !== id);
36856
+ return {
36857
+ changedProperties,
36858
+ steps: { added, removed, changed, reordered },
36859
+ isEmpty: changedProperties.length === 0 && added.length === 0 && removed.length === 0 && changed.length === 0 && !reordered
36860
+ };
36861
+ }
36862
+ function asManifest(value) {
36863
+ return isRecord3(value) ? value : {};
36864
+ }
36865
+ function stepsById(steps) {
36866
+ const byId = /* @__PURE__ */ new Map();
36867
+ if (!Array.isArray(steps)) return byId;
36868
+ steps.forEach((step, index) => {
36869
+ const id = isRecord3(step) && typeof step.id === "string" ? step.id : `#${index}`;
36870
+ byId.set(id, step);
36871
+ });
36872
+ return byId;
36873
+ }
36874
+ function sortKeys(value) {
36875
+ if (Array.isArray(value)) return value.map(sortKeys);
36876
+ if (!isRecord3(value)) return value;
36877
+ return Object.fromEntries(
36878
+ Object.keys(value).sort().map((key) => [key, sortKeys(value[key])])
36879
+ );
36880
+ }
36881
+ function isRecord3(value) {
36882
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36883
+ }
36884
+
36885
+ // src/commands/draft/draft-service.ts
36886
+ function resolveDraftApi(api, workspaceId, signal) {
36887
+ const createOptions = { signal, translate: false };
36888
+ if (workspaceId === null) {
36889
+ return {
36890
+ scope: null,
36891
+ get: (draftId) => api.automationDrafts.get(draftId, { signal }),
36892
+ create: (manifest) => api.automationDrafts.create(manifest, createOptions),
36893
+ update: (draftId, manifest) => api.automationDrafts.update(draftId, manifest, { signal }),
36894
+ createAutomationDraft: (automationId) => api.automations.createDraft(automationId, { signal }),
36895
+ upsertConnection: (draftId, body) => api.automationDraftConnections.upsert(draftId, body, { signal }),
36896
+ getConnectionStatus: async (draftId) => (await api.automationDraftConnections.getStatus(draftId, { signal })).validation,
36897
+ finalize: (draftId) => api.automationDrafts.finalize(draftId, { signal }),
36898
+ getAutomation: (automationId) => api.automations.get(automationId, { signal })
36899
+ };
36900
+ }
36901
+ return {
36902
+ scope: workspaceId,
36903
+ get: (draftId) => api.workspaceAutomationDrafts.get(workspaceId, draftId, { signal }),
36904
+ create: (manifest) => api.workspaceAutomationDrafts.create(workspaceId, manifest, createOptions),
36905
+ update: (draftId, manifest) => api.workspaceAutomationDrafts.update(workspaceId, draftId, manifest, { signal }),
36906
+ createAutomationDraft: (automationId) => api.workspaceAutomations.createDraft(workspaceId, automationId, { signal }),
36907
+ upsertConnection: (draftId, body) => api.workspaceAutomationDraftConnections.upsert(workspaceId, draftId, body, { signal }),
36908
+ getConnectionStatus: async (draftId) => (await api.workspaceAutomationDraftConnections.getStatus(workspaceId, draftId, {
36909
+ signal
36910
+ })).validation,
36911
+ finalize: (draftId) => api.workspaceAutomationDrafts.finalize(workspaceId, draftId, { signal }),
36912
+ getAutomation: (automationId) => api.workspaceAutomations.get(workspaceId, automationId, { signal })
36913
+ };
36914
+ }
36915
+ async function createDraft(draftApi, { manifest, automationId }) {
36916
+ const partialManifest = parsePartialManifestInput(manifest);
36917
+ if (automationId === void 0) {
36918
+ const result = await draftApi.create(partialManifest);
36919
+ return { action: "created", target: toTarget(result.draft), ...result };
36920
+ }
36921
+ const { draft } = await openEditDraft(draftApi, automationId);
36922
+ try {
36923
+ const result = await draftApi.update(draft.id, partialManifest);
36924
+ return { action: "created", target: toTarget(result.draft), ...result };
36925
+ } catch (error62) {
36926
+ if (!isManifestRejection(error62)) throw error62;
36927
+ throw new CliError4(
36928
+ "DRAFT_MANIFEST_REJECTED",
36929
+ `Opened draft ${draft.id} for automation ${automationId}, but the manifest was rejected: ${getErrorMessage7(error62)}`,
36930
+ { hints: draftHints(draftApi.scope, draft.id) }
36931
+ );
36932
+ }
36933
+ }
36934
+ function isManifestRejection(error62) {
36935
+ return error62 instanceof AutomationsRequestError && (error62.httpStatusCode === 400 || error62.httpStatusCode === 422);
36936
+ }
36937
+ async function updateDraft(draftApi, { draftId, manifest }) {
36938
+ const partialManifest = parsePartialManifestInput(manifest);
36939
+ const result = await draftApi.update(draftId, partialManifest);
36940
+ return { action: "updated", target: toTarget(result.draft), ...result };
36941
+ }
36942
+ async function openEditDraft(draftApi, automationId) {
36943
+ try {
36944
+ return await draftApi.createAutomationDraft(automationId);
36945
+ } catch (error62) {
36946
+ const conflict = getOpenDraftConflictError(error62);
36947
+ if (!conflict) throw error62;
36948
+ throw new CliError4(
36949
+ "DRAFT_CONFLICT",
36950
+ `Automation ${automationId} already has an open draft ${conflict.draftId}.`,
36951
+ { hints: draftHints(draftApi.scope, conflict.draftId) }
36952
+ );
36953
+ }
36954
+ }
36955
+ function draftHints(scope, draftId) {
36956
+ const scopeFlag = scope === null ? "--personal" : `--workspace ${scope}`;
36957
+ return [
36958
+ `Apply the file to it: tda draft update ${draftId} --file <path> ${scopeFlag}`,
36959
+ `Or discard it first: tda draft delete ${draftId} --yes ${scopeFlag}`
36960
+ ];
36961
+ }
36962
+ function toTarget(draft) {
36963
+ return draft.automationId === null ? { kind: "new" } : { kind: "automation", automationId: draft.automationId };
36964
+ }
36965
+ async function connectDraft(draftApi, api, {
36966
+ draftId,
36967
+ selections,
36968
+ auto
36969
+ }) {
36970
+ const bound = [];
36971
+ const required2 = selections.length > 0 ? getRequiredConnectorsFromManifest(
36972
+ (await draftApi.get(draftId)).draft.partialManifest
36973
+ ) : /* @__PURE__ */ new Map();
36974
+ for (const selection of selections) {
36975
+ const types = required2.get(selection.connectorId);
36976
+ if (!types || selection.connectionType && !types.has(selection.connectionType)) {
36977
+ const slot = selection.connectionType ? `${selection.connectorId} (${selection.connectionType})` : selection.connectorId;
36978
+ throw new Error(
36979
+ `Connector ${slot} is not used by draft ${draftId}. Required: ${describeRequired(required2)}.`
36980
+ );
36981
+ }
36982
+ const connectionTypes = selection.connectionType ? [selection.connectionType] : [...types];
36983
+ for (const connectionType of connectionTypes) {
36984
+ await draftApi.upsertConnection(draftId, {
36985
+ connectorId: selection.connectorId,
36986
+ connectionType,
36987
+ connectionId: selection.connectionId
36988
+ });
36989
+ bound.push({ ...selection, connectionType, mode: "explicit" });
36990
+ }
36991
+ }
36992
+ const unresolved = [];
36993
+ if (auto) {
36994
+ const status = await draftApi.getConnectionStatus(draftId);
36995
+ for (const connector of status.connectors) {
36996
+ for (const connectionType of ["mcp", "trigger"]) {
36997
+ const slot = connector[connectionType];
36998
+ if (!slot.required || slot.status !== "missing") continue;
36999
+ const { connections } = await api.connections.list({
37000
+ connectorId: connector.id,
37001
+ capability: connectionType,
37002
+ status: "authorized"
37003
+ });
37004
+ const [only] = connections;
37005
+ if (connections.length === 1 && only) {
37006
+ await draftApi.upsertConnection(draftId, {
37007
+ connectorId: connector.id,
37008
+ connectionType,
37009
+ connectionId: only.id
37010
+ });
37011
+ bound.push({
37012
+ connectorId: connector.id,
37013
+ connectionType,
37014
+ connectionId: only.id,
37015
+ mode: "auto"
37016
+ });
37017
+ continue;
37018
+ }
37019
+ unresolved.push({
37020
+ connectorId: connector.id,
37021
+ connectionType,
37022
+ reason: connections.length === 0 ? "no_connection" : "multiple_connections",
37023
+ candidateConnectionIds: connections.map((connection) => connection.id)
37024
+ });
37025
+ }
37026
+ }
37027
+ }
37028
+ const { isValid, missing } = await draftApi.getConnectionStatus(draftId);
37029
+ return { action: "connected", draftId, bound, unresolved, isValid, missing };
37030
+ }
37031
+ function describeRequired(required2) {
37032
+ if (required2.size === 0) return "none";
37033
+ return [...required2].map(([connectorId, types]) => `${connectorId} (${[...types].join(", ")})`).join(", ");
37034
+ }
37035
+ async function publishDraft(draftApi, { draftId, confirmed }) {
37036
+ const { summary, manifest } = await summarizeForPublish(draftApi, draftId);
37037
+ if (!confirmed) {
37038
+ return { action: "publish_preview", summary };
37039
+ }
37040
+ let published;
37041
+ try {
37042
+ published = await draftApi.finalize(draftId);
37043
+ } catch (error62) {
37044
+ const notReady = getDraftNotReadyError(error62);
37045
+ if (!notReady) throw error62;
37046
+ throw new CliError4("DRAFT_NOT_READY", notReady.message, {
37047
+ hints: [
37048
+ `See the issues: tda draft view ${draftId}`,
37049
+ `Bind connections: tda draft connect ${draftId} --auto`
37050
+ ]
37051
+ });
37052
+ }
37053
+ const automation = await draftApi.getAutomation(published.automation.id);
37054
+ const expected = normaliseManifest(manifest);
37055
+ const actual = normaliseManifest(automation.manifest);
37056
+ const verified = isDeepEqual(expected, actual);
37057
+ return {
37058
+ action: "published",
37059
+ summary,
37060
+ automation,
37061
+ verified,
37062
+ mismatch: verified ? null : diffManifests(expected, actual)
37063
+ };
37064
+ }
37065
+ async function summarizeForPublish(draftApi, draftId) {
37066
+ const [detail, connections] = await Promise.all([
37067
+ draftApi.get(draftId),
37068
+ draftApi.getConnectionStatus(draftId)
37069
+ ]);
37070
+ const { draft } = detail;
37071
+ const target = toTarget(draft);
37072
+ const published = target.kind === "automation" ? await draftApi.getAutomation(target.automationId) : null;
37073
+ const diff = published ? diffManifests(
37074
+ normaliseManifest(published.manifest),
37075
+ normaliseManifest(draft.partialManifest)
37076
+ ) : null;
37077
+ const summary = {
37078
+ draftId,
37079
+ name: getResourceName(draft.partialManifest),
37080
+ scope: draft.workspaceId === null ? { kind: "personal" } : {
37081
+ kind: "workspace",
37082
+ workspaceId: draft.workspaceId,
37083
+ // A new workspace automation publishes team-visible; an
37084
+ // edit keeps whatever the automation already has.
37085
+ visibility: published?.visibility ?? "workspace"
37086
+ },
37087
+ target,
37088
+ validation: { state: detail.state, issues: detail.issues },
37089
+ connections: {
37090
+ isValid: connections.isValid,
37091
+ connected: connections.connected.map(
37092
+ ({ connectorId, connectionType, connectionId }) => ({
37093
+ connectorId,
37094
+ connectionType,
37095
+ connectionId
37096
+ })
37097
+ ),
37098
+ missing: connections.missing
37099
+ },
37100
+ schedule: describeSchedule(draft.partialManifest),
37101
+ diff
37102
+ };
37103
+ return { summary, manifest: draft.partialManifest };
37104
+ }
37105
+ function describeSchedule(manifest) {
37106
+ if (!hasTriggerType(manifest)) return null;
37107
+ const schedule = getManifestTriggers(manifest).find((trigger) => trigger.type === "schedule");
37108
+ if (!schedule || schedule.type !== "schedule") return null;
37109
+ return getScheduleTriggerDescription({ value: schedule.value, timeFormat: "24h" });
37110
+ }
37111
+ function normaliseManifest(manifest) {
37112
+ const parsed = manifestSchema.safeParse(manifest);
37113
+ return parsed.success ? parsed.data : manifest;
37114
+ }
37115
+
36359
37116
  // src/commands/draft/format.ts
36360
37117
  function formatDraftDelete(result) {
36361
37118
  if (result.action === "delete_preview") {
@@ -36367,10 +37124,144 @@ function formatDraftDelete(result) {
36367
37124
  }
36368
37125
  return `Deleted draft ${result.draftId}.`;
36369
37126
  }
37127
+ function formatDraftChange(result) {
37128
+ const verb = result.action === "created" ? "Created" : "Updated";
37129
+ const target = result.target.kind === "new" ? "for a new automation" : `to update automation ${result.target.automationId}`;
37130
+ return [
37131
+ `${verb} draft ${result.draft.id} ${target}.`,
37132
+ `Validation: ${result.state}`,
37133
+ `Issues: ${result.issues.length > 0 ? result.issues.join("; ") : "none"}`
37134
+ ].join("\n");
37135
+ }
37136
+ function formatDraftConnect(result) {
37137
+ const lines = [`Draft ${result.draftId} connections:`];
37138
+ if (result.bound.length === 0) {
37139
+ lines.push(" (nothing bound)");
37140
+ }
37141
+ for (const binding of result.bound) {
37142
+ const how = binding.mode === "auto" ? "auto (only authorised connection)" : "explicit";
37143
+ lines.push(
37144
+ ` ${binding.connectorId} ${binding.connectionType} ${binding.connectionId} ${how}`
37145
+ );
37146
+ }
37147
+ if (result.unresolved.length > 0) {
37148
+ lines.push("Unresolved:");
37149
+ for (const slot of result.unresolved) {
37150
+ lines.push(
37151
+ slot.reason === "no_connection" ? ` ${slot.connectorId} ${slot.connectionType} no authorised connection; run: tda connector connect ${slot.connectorId} --capability ${slot.connectionType}` : ` ${slot.connectorId} ${slot.connectionType} ${slot.candidateConnectionIds.length} authorised connections; pick one: --connection ${slot.connectorId}:${slot.connectionType}=<connection-id> (${slot.candidateConnectionIds.join(", ")})`
37152
+ );
37153
+ }
37154
+ }
37155
+ lines.push(
37156
+ result.isValid ? "Connections: ready" : `Connections: missing ${result.missing.map((entry) => `${entry.connectorName} ${entry.connectionType} (${entry.reason})`).join(", ")}`
37157
+ );
37158
+ return lines.join("\n");
37159
+ }
37160
+ function formatDraftPublish(result) {
37161
+ if (result.action === "publish_preview") {
37162
+ return [...describePublishSummary(result.summary), "Use --yes to publish."].join("\n");
37163
+ }
37164
+ const { summary, automation } = result;
37165
+ const how = summary.target.kind === "new" ? "new automation" : "updated";
37166
+ return [
37167
+ `Published draft ${summary.draftId} as automation ${automation.id} (${how}).`,
37168
+ result.verified ? "Verified: published manifest matches the draft." : `Warning: published manifest differs from the draft: ${describeDiff(result.mismatch)}.`
37169
+ ].join("\n");
37170
+ }
37171
+ function summarizeDraftPublish(result) {
37172
+ if (result.action === "publish_preview") return result;
37173
+ return { ...result, automation: summarizeAutomation(result.automation) };
37174
+ }
37175
+ function describePublishSummary(summary) {
37176
+ const lines = [
37177
+ `Draft: ${summary.name} (${summary.draftId})`,
37178
+ summary.scope.kind === "personal" ? "Scope: personal" : `Scope: workspace ${summary.scope.workspaceId} (${describeVisibility2(summary)})`,
37179
+ summary.target.kind === "new" ? "Action: create a new automation" : `Action: update automation ${summary.target.automationId}`,
37180
+ summary.validation.issues.length === 0 ? `Validation: ${summary.validation.state}` : `Validation: ${summary.validation.state}; ${summary.validation.issues.join("; ")}`,
37181
+ summary.connections.isValid ? "Connections: ready" : `Connections: missing ${summary.connections.missing.map((entry) => `${entry.connectorName} ${entry.connectionType} (${entry.reason})`).join(", ")}`,
37182
+ `Schedule: ${summary.schedule ?? "none (runs on its trigger)"}`
37183
+ ];
37184
+ if (summary.diff) {
37185
+ lines.push(
37186
+ summary.diff.isEmpty ? "Changes vs published automation: none" : `Changes vs published automation: ${describeDiff(summary.diff)}`
37187
+ );
37188
+ }
37189
+ return lines;
37190
+ }
37191
+ function describeVisibility2(summary) {
37192
+ if (summary.scope.kind !== "workspace") return "";
37193
+ const visibility = summary.scope.visibility === "workspace" ? "visible to the workspace" : "private";
37194
+ return summary.target.kind === "new" ? `publishes ${visibility}` : `stays ${visibility}`;
37195
+ }
37196
+ function describeDiff(diff) {
37197
+ if (!diff || diff.isEmpty) return "none";
37198
+ const parts = [];
37199
+ if (diff.changedProperties.length > 0) {
37200
+ parts.push(`properties ${diff.changedProperties.join(", ")}`);
37201
+ }
37202
+ if (diff.steps.added.length > 0) parts.push(`steps added ${diff.steps.added.join(", ")}`);
37203
+ if (diff.steps.removed.length > 0) parts.push(`steps removed ${diff.steps.removed.join(", ")}`);
37204
+ if (diff.steps.changed.length > 0) parts.push(`steps changed ${diff.steps.changed.join(", ")}`);
37205
+ if (diff.steps.reordered) parts.push("steps reordered");
37206
+ return parts.join("; ");
37207
+ }
37208
+
37209
+ // src/commands/draft/validate-command.ts
37210
+ import { CliError as CliError5 } from "@doist/cli-core";
37211
+
37212
+ // src/lib/local-command.ts
37213
+ async function runLocalCommand(command, operation, presentation, execution = {}) {
37214
+ let mode = "human";
37215
+ try {
37216
+ mode = getOutputMode(getGlobalOptions(command));
37217
+ const result = await withSpinner({ text: execution.spinner ?? "Loading..." }, operation);
37218
+ stopEarlySpinner();
37219
+ writeResult(mode, result, presentation);
37220
+ } catch (error62) {
37221
+ writeFailure(mode, "error", renderFailure(error62, { mode }));
37222
+ process.exitCode = 1;
37223
+ }
37224
+ }
37225
+
37226
+ // src/commands/draft/validate-command.ts
37227
+ function registerDraftValidateCommand(draft) {
37228
+ addManifestInputOptions(
37229
+ draft.command("validate").description("Check a manifest file against the full manifest schema, offline")
37230
+ ).action(async (options, command) => {
37231
+ await runLocalCommand(
37232
+ command,
37233
+ async () => validateManifestInput(await readManifestInput(options)),
37234
+ { human: formatManifestValidation },
37235
+ { spinner: "Validating manifest..." }
37236
+ );
37237
+ });
37238
+ }
37239
+ function validateManifestInput(manifest) {
37240
+ const validation = validateManifest(manifest);
37241
+ if (!validation.isValid) {
37242
+ throw new CliError5(
37243
+ "MANIFEST_INVALID",
37244
+ `Manifest is invalid: ${validation.errors.join("; ")}`
37245
+ );
37246
+ }
37247
+ const parsed = manifestSchema.parse(manifest);
37248
+ return {
37249
+ action: "validated",
37250
+ name: parsed.name,
37251
+ steps: parsed.steps.length,
37252
+ triggers: getManifestTriggers(parsed).map((trigger) => trigger.type)
37253
+ };
37254
+ }
37255
+ function formatManifestValidation(result) {
37256
+ const steps = `${result.steps} step${result.steps === 1 ? "" : "s"}`;
37257
+ const triggers = result.triggers.length === 0 ? "no triggers" : `trigger ${result.triggers.join(", ")}`;
37258
+ return `Manifest "${result.name}" is valid: ${steps}, ${triggers}.`;
37259
+ }
36370
37260
 
36371
37261
  // src/commands/draft/index.ts
36372
37262
  function registerDraftCommand(program) {
36373
- const draft = program.command("draft").description("Inspect and delete automation drafts");
37263
+ const draft = program.command("draft").description("Author and inspect automation drafts");
37264
+ registerDraftValidateCommand(draft);
36374
37265
  addWorkspaceScopeOptions(
36375
37266
  addCursorPaginationOptions(
36376
37267
  draft.command("list").description("List drafts").option(
@@ -36414,6 +37305,85 @@ function registerDraftCommand(program) {
36414
37305
  { spinner: "Loading draft..." }
36415
37306
  );
36416
37307
  });
37308
+ addWorkspaceScopeOptions(
37309
+ addManifestInputOptions(
37310
+ draft.command("create").description("Create a draft from a manifest file").option(
37311
+ "--automation <automation-id>",
37312
+ "Open an edit draft for this automation and apply the manifest to it"
37313
+ )
37314
+ )
37315
+ ).action(async (options, command) => {
37316
+ await runApiCommand(
37317
+ command,
37318
+ async ({ api, signal }) => {
37319
+ const manifest = await readManifestInput(options);
37320
+ const draftApi = resolveDraftApi(api, await resolveWorkspaceScope(options), signal);
37321
+ return createDraft(draftApi, { manifest, automationId: options.automation });
37322
+ },
37323
+ { human: formatDraftChange },
37324
+ { spinner: "Creating draft..." }
37325
+ );
37326
+ });
37327
+ addWorkspaceScopeOptions(
37328
+ addManifestInputOptions(
37329
+ draft.command("update").description("Replace a draft's manifest with a manifest file").argument("<draft-id>", "Draft ID")
37330
+ )
37331
+ ).action(async (draftId, options, command) => {
37332
+ await runApiCommand(
37333
+ command,
37334
+ async ({ api, signal }) => {
37335
+ const manifest = await readManifestInput(options);
37336
+ const draftApi = resolveDraftApi(api, await resolveWorkspaceScope(options), signal);
37337
+ return updateDraft(draftApi, { draftId, manifest });
37338
+ },
37339
+ { human: formatDraftChange },
37340
+ { spinner: "Updating draft..." }
37341
+ );
37342
+ });
37343
+ addWorkspaceScopeOptions(
37344
+ draft.command("connect").description("Bind the user's service connections to a draft").argument("<draft-id>", "Draft ID").option(
37345
+ "--connection <connector[:type]=connection-id>",
37346
+ "Bind this connection; repeat for multiple connectors",
37347
+ collectOption,
37348
+ []
37349
+ ).option(
37350
+ "--auto",
37351
+ "Bind every remaining required connector that has exactly one authorised connection"
37352
+ )
37353
+ ).action(async (draftId, options, command) => {
37354
+ await runApiCommand(
37355
+ command,
37356
+ async ({ api, signal }) => {
37357
+ if (options.connection.length === 0 && options.auto !== true) {
37358
+ throw new Error(
37359
+ "Provide --connection connector[:type]=connection-id or --auto."
37360
+ );
37361
+ }
37362
+ const selections = options.connection.map(parseConnectionSelectionOption);
37363
+ const draftApi = resolveDraftApi(api, await resolveWorkspaceScope(options), signal);
37364
+ return connectDraft(draftApi, api, {
37365
+ draftId,
37366
+ selections,
37367
+ auto: options.auto === true
37368
+ });
37369
+ },
37370
+ { human: formatDraftConnect },
37371
+ { spinner: "Connecting..." }
37372
+ );
37373
+ });
37374
+ addWorkspaceScopeOptions(
37375
+ draft.command("publish").description("Publish a draft after previewing what it will do").argument("<draft-id>", "Draft ID").option("--yes", "Confirm publication")
37376
+ ).action(async (draftId, options, command) => {
37377
+ await runApiCommand(
37378
+ command,
37379
+ async ({ api, signal }) => {
37380
+ const draftApi = resolveDraftApi(api, await resolveWorkspaceScope(options), signal);
37381
+ return publishDraft(draftApi, { draftId, confirmed: options.yes === true });
37382
+ },
37383
+ { human: formatDraftPublish, json: summarizeDraftPublish },
37384
+ { spinner: options.yes === true ? "Publishing..." : "Loading draft..." }
37385
+ );
37386
+ });
36417
37387
  addWorkspaceScopeOptions(
36418
37388
  draft.command("delete").description("Delete a draft after previewing which one it is").argument("<draft-id>", "Draft ID").option("--yes", "Confirm deletion")
36419
37389
  ).action(async (draftId, options, command) => {
@@ -36452,7 +37422,7 @@ function streamDraftList(options, fetchPage) {
36452
37422
  }
36453
37423
 
36454
37424
  // src/commands/run/index.ts
36455
- import { Option as Option6 } from "commander";
37425
+ import { Option as Option7 } from "commander";
36456
37426
  function registerRunCommand(program) {
36457
37427
  const run = program.command("run").description("Inspect automation runs");
36458
37428
  addWorkspaceScopeOptions(
@@ -36460,7 +37430,7 @@ function registerRunCommand(program) {
36460
37430
  run.command("list").description("List runs for an automation").argument("<automation-id>", "Automation ID")
36461
37431
  )
36462
37432
  ).addOption(
36463
- new Option6("--status <status>", "Only show runs with this status").choices([
37433
+ new Option7("--status <status>", "Only show runs with this status").choices([
36464
37434
  ...AUTOMATION_RUN_STATUSES
36465
37435
  ])
36466
37436
  ).option(
@@ -36544,26 +37514,12 @@ function registerRunCommand(program) {
36544
37514
  );
36545
37515
  }
36546
37516
 
36547
- // src/lib/local-command.ts
36548
- async function runLocalCommand(command, operation, presentation, execution = {}) {
36549
- let mode = "human";
36550
- try {
36551
- mode = getOutputMode(getGlobalOptions(command));
36552
- const result = await withSpinner({ text: execution.spinner ?? "Loading..." }, operation);
36553
- stopEarlySpinner();
36554
- writeResult(mode, result, presentation);
36555
- } catch (error62) {
36556
- writeFailure(mode, "error", renderFailure(error62, { mode }));
36557
- process.exitCode = 1;
36558
- }
36559
- }
36560
-
36561
37517
  // src/commands/skill/shared.ts
36562
- import { CliError as CliError3 } from "@doist/cli-core";
37518
+ import { CliError as CliError6 } from "@doist/cli-core";
36563
37519
  function requireInstaller(agent) {
36564
37520
  const installer = getInstaller(agent);
36565
37521
  if (!installer) {
36566
- throw new CliError3("UNKNOWN_AGENT", `Unknown agent: ${agent}.`, {
37522
+ throw new CliError6("UNKNOWN_AGENT", `Unknown agent: ${agent}.`, {
36567
37523
  hints: [`Available agents: ${AGENT_NAMES.join(", ")}.`]
36568
37524
  });
36569
37525
  }
@@ -36641,7 +37597,7 @@ async function uninstallSkill(agent, options, command) {
36641
37597
  }
36642
37598
 
36643
37599
  // src/commands/skill/update.ts
36644
- import { CliError as CliError4 } from "@doist/cli-core";
37600
+ import { CliError as CliError7 } from "@doist/cli-core";
36645
37601
  async function updateSkill(agent, options, command) {
36646
37602
  await runLocalCommand(
36647
37603
  command,
@@ -36667,7 +37623,7 @@ async function updateAllSkills(options, command) {
36667
37623
  async () => {
36668
37624
  const result = await updateAllInstalledSkills(options.local === true);
36669
37625
  if (result.errors.length > 0) {
36670
- throw new CliError4(
37626
+ throw new CliError7(
36671
37627
  "UPDATE_FAILED",
36672
37628
  `Could not update ${result.errors.length} skill file(s).`,
36673
37629
  { hints: result.errors.map((error62) => `${error62.agent}: ${error62.message}`) }
@@ -36828,13 +37784,13 @@ async function findWorkspace(api, workspaceId, signal) {
36828
37784
  // src/lib/command-output.ts
36829
37785
  function configureCommandOutput(command) {
36830
37786
  return command.configureOutput({
36831
- writeOut: (text) => {
37787
+ writeOut: (text2) => {
36832
37788
  stopEarlySpinner();
36833
- process.stdout.write(text);
37789
+ process.stdout.write(text2);
36834
37790
  },
36835
- writeErr: (text) => {
37791
+ writeErr: (text2) => {
36836
37792
  stopEarlySpinner();
36837
- process.stderr.write(text);
37793
+ process.stderr.write(text2);
36838
37794
  }
36839
37795
  });
36840
37796
  }
@@ -36846,7 +37802,7 @@ function createProgram() {
36846
37802
  `Target environment: ${ENVIRONMENT_NAMES.join(", ")}`,
36847
37803
  parseEnvironmentOption,
36848
37804
  initialEnvironmentName()
36849
- ).option("--api-url <url>", "Automations API base URL (overrides --env)").option("-H, --header <name:value>", "Additional API header", collect2, []).option("--json", "Emit one final JSON document").option("--ndjson", "Emit newline-delimited JSON").option("--no-interactive", "Complete one server turn and exit").option("--no-open", "Print connection setup URLs without opening a browser").option("--no-spinner", "Disable the loading spinner").showHelpAfterError();
37805
+ ).option("--api-url <url>", "Automations API base URL (overrides --env)").option("-H, --header <name:value>", "Additional API header", collect, []).option("--json", "Emit one final JSON document").option("--ndjson", "Emit newline-delimited JSON").option("--no-interactive", "Complete one server turn and exit").option("--no-open", "Print connection setup URLs without opening a browser").option("--no-spinner", "Disable the loading spinner").showHelpAfterError();
36850
37806
  configureCommandOutput(program);
36851
37807
  registerAuthCommand(program);
36852
37808
  registerAutomationCommand(program);
@@ -36860,7 +37816,7 @@ function createProgram() {
36860
37816
  registerWorkspaceCommand(program);
36861
37817
  return program;
36862
37818
  }
36863
- function collect2(value, previous) {
37819
+ function collect(value, previous) {
36864
37820
  return [...previous, value];
36865
37821
  }
36866
37822
  if (isEntrypoint()) {