@doist/automations-cli 1.17.1 → 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.17.1",
6902
+ version: "1.19.0",
6903
6903
  description: "Command-line client for Todoist Automations",
6904
6904
  type: "module",
6905
6905
  bin: {
@@ -6953,13 +6953,13 @@ var package_default = {
6953
6953
  devDependencies: {
6954
6954
  "@doist/automations-core": "*",
6955
6955
  "@doist/automations-sdk": "*",
6956
- "@types/node": "24.13.6",
6956
+ "@types/node": "24.19.1",
6957
6957
  "conventional-changelog-conventionalcommits": "9.3.1",
6958
6958
  esbuild: "0.28.2",
6959
6959
  "semantic-release": "25.0.9",
6960
6960
  "semantic-release-monorepo": "8.0.2",
6961
6961
  typescript: "6.0.3",
6962
- vitest: "4.1.11"
6962
+ vitest: "5.0.3"
6963
6963
  },
6964
6964
  engines: {
6965
6965
  node: ">=24"
@@ -7037,6 +7037,10 @@ var API_SCOPES = {
7037
7037
  };
7038
7038
  var API_SCOPE_CODES = Object.keys(API_SCOPES);
7039
7039
 
7040
+ // ../../packages/core/dist/esm/constants/cli-client.constants.js
7041
+ var AUTOMATIONS_CLI_CLIENT_NAME = "Todoist Automations CLI";
7042
+ var AUTOMATIONS_CLI_LOGO_URL = "https://todoist.b-cdn.net/agentist-icons/service_automations-cli_color_192px.png";
7043
+
7040
7044
  // ../../packages/core/dist/esm/constants/connection.constants.js
7041
7045
  var CONNECTION_STATUSES = ["pending", "authorized", "expired", "error"];
7042
7046
  var CONNECTION_TYPES = ["mcp", "trigger", "api"];
@@ -7124,71 +7128,98 @@ var MODEL_CATALOG = {
7124
7128
  "gemini-2.5-flash-lite": {
7125
7129
  provider: "gemini",
7126
7130
  family: "2.5",
7127
- providerModelId: "gemini-2.5-flash-lite"
7131
+ providerModelId: "gemini-2.5-flash-lite",
7132
+ manifestSelectable: true
7128
7133
  },
7129
7134
  "gemini-2.5-flash": {
7130
7135
  provider: "gemini",
7131
7136
  family: "2.5",
7132
- providerModelId: "gemini-2.5-flash"
7137
+ providerModelId: "gemini-2.5-flash",
7138
+ manifestSelectable: true
7133
7139
  },
7134
7140
  "gemini-3.1-pro": {
7135
7141
  provider: "gemini",
7136
7142
  family: "3",
7137
- providerModelId: "gemini-3.1-pro-preview"
7143
+ providerModelId: "gemini-3.1-pro-preview",
7144
+ manifestSelectable: true
7138
7145
  },
7139
7146
  "gemini-3.8-flash": {
7140
7147
  provider: "gemini",
7141
7148
  family: "3",
7142
- providerModelId: "gemini-3.8-flash"
7149
+ providerModelId: "gemini-3.8-flash",
7150
+ manifestSelectable: true
7143
7151
  },
7144
7152
  "claude-opus-4-6": {
7145
7153
  provider: "anthropic",
7146
7154
  family: "4.6",
7147
- providerModelId: "claude-opus-4-6"
7155
+ providerModelId: "claude-opus-4-6",
7156
+ manifestSelectable: true
7148
7157
  },
7149
7158
  "claude-sonnet-5": {
7150
7159
  provider: "anthropic",
7151
7160
  family: "5",
7152
- providerModelId: "claude-sonnet-5"
7161
+ providerModelId: "claude-sonnet-5",
7162
+ manifestSelectable: true
7163
+ },
7164
+ "claude-sonnet-5-5": {
7165
+ provider: "anthropic",
7166
+ family: "5",
7167
+ providerModelId: "claude-sonnet-5-5",
7168
+ manifestSelectable: false
7169
+ },
7170
+ "claude-haiku-5-5": {
7171
+ provider: "anthropic",
7172
+ family: "5",
7173
+ providerModelId: "claude-haiku-5-5",
7174
+ manifestSelectable: false
7153
7175
  },
7154
7176
  "claude-sonnet-4-6": {
7155
7177
  provider: "anthropic",
7156
7178
  family: "4.6",
7157
- providerModelId: "claude-sonnet-4-6"
7179
+ providerModelId: "claude-sonnet-4-6",
7180
+ manifestSelectable: true
7158
7181
  },
7159
7182
  "claude-haiku-4-5": {
7160
7183
  provider: "anthropic",
7161
7184
  family: "4.5",
7162
- providerModelId: "claude-haiku-4-5"
7185
+ providerModelId: "claude-haiku-4-5",
7186
+ manifestSelectable: true
7163
7187
  },
7164
7188
  "deepseek-v4-flash": {
7165
7189
  provider: "openrouter",
7166
7190
  family: "deepseek",
7167
- providerModelId: "deepseek/deepseek-v4-flash-0731"
7191
+ providerModelId: "deepseek/deepseek-v4-flash-0731",
7192
+ manifestSelectable: true
7168
7193
  },
7169
7194
  "deepseek-v4-pro": {
7170
7195
  provider: "openrouter",
7171
7196
  family: "deepseek",
7172
- providerModelId: "deepseek/deepseek-v4-pro"
7197
+ providerModelId: "deepseek/deepseek-v4-pro",
7198
+ manifestSelectable: true
7173
7199
  },
7174
7200
  "mimo-v2.5": {
7175
7201
  provider: "openrouter",
7176
7202
  family: "mimo",
7177
- providerModelId: "xiaomi/mimo-v2.5"
7203
+ providerModelId: "xiaomi/mimo-v2.5",
7204
+ manifestSelectable: true
7178
7205
  },
7179
7206
  "mimo-v2.5-pro": {
7180
7207
  provider: "openrouter",
7181
7208
  family: "mimo",
7182
- providerModelId: "xiaomi/mimo-v2.5-pro"
7209
+ providerModelId: "xiaomi/mimo-v2.5-pro",
7210
+ manifestSelectable: true
7183
7211
  },
7184
7212
  "glm-5.2": {
7185
7213
  provider: "openrouter",
7186
7214
  family: "glm",
7187
- providerModelId: "z-ai/glm-5.2"
7215
+ providerModelId: "z-ai/glm-5.2",
7216
+ manifestSelectable: true
7188
7217
  }
7189
7218
  };
7190
7219
  var SUPPORTED_LLM_MODELS = Object.keys(MODEL_CATALOG);
7191
7220
  var SUPPORTED_SEARCH_MODELS = SUPPORTED_LLM_MODELS.filter(supportsWebSearch);
7221
+ var MANIFEST_LLM_MODELS = SUPPORTED_LLM_MODELS.filter((modelId) => MODEL_CATALOG[modelId].manifestSelectable);
7222
+ var MANIFEST_SEARCH_MODELS = MANIFEST_LLM_MODELS.filter((modelId) => supportsWebSearch(modelId));
7192
7223
  function supportsWebSearch(modelId) {
7193
7224
  const { provider } = MODEL_CATALOG[modelId];
7194
7225
  return provider === "gemini" || provider === "anthropic";
@@ -11175,7 +11206,7 @@ function handleIntersectionResults(result, left, right) {
11175
11206
  const unrecKeys = /* @__PURE__ */ new Map();
11176
11207
  let unrecIssue;
11177
11208
  const keyIssues = /* @__PURE__ */ new Map();
11178
- const collect3 = (iss, side) => {
11209
+ const collect2 = (iss, side) => {
11179
11210
  let keys;
11180
11211
  if (iss.code === "unrecognized_keys" && !iss.path?.length) {
11181
11212
  unrecIssue ?? (unrecIssue = iss);
@@ -11196,11 +11227,11 @@ function handleIntersectionResults(result, left, right) {
11196
11227
  return true;
11197
11228
  };
11198
11229
  for (const iss of left.issues) {
11199
- if (!collect3(iss, "l"))
11230
+ if (!collect2(iss, "l"))
11200
11231
  result.issues.push(iss);
11201
11232
  }
11202
11233
  for (const iss of right.issues) {
11203
- if (!collect3(iss, "r"))
11234
+ if (!collect2(iss, "r"))
11204
11235
  result.issues.push(iss);
11205
11236
  }
11206
11237
  const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k);
@@ -16503,8 +16534,8 @@ function ko_default() {
16503
16534
  }
16504
16535
 
16505
16536
  // ../../node_modules/zod/v4/locales/lt.js
16506
- var capitalizeFirstCharacter = (text) => {
16507
- return text.charAt(0).toUpperCase() + text.slice(1);
16537
+ var capitalizeFirstCharacter = (text2) => {
16538
+ return text2.charAt(0).toUpperCase() + text2.slice(1);
16508
16539
  };
16509
16540
  function getUnitTypeFromNumber(number4) {
16510
16541
  const abs = Math.abs(number4);
@@ -22861,8 +22892,8 @@ function encodeJSONPointerSegment(segment) {
22861
22892
  return segment.replace(/~/g, "~0").replace(/\//g, "~1");
22862
22893
  }
22863
22894
  function extractDefs(ctx, schema) {
22864
- const root15 = ctx.seen.get(schema);
22865
- if (!root15)
22895
+ const root16 = ctx.seen.get(schema);
22896
+ if (!root16)
22866
22897
  throw new Error("Unprocessed schema. This is a bug in Zod.");
22867
22898
  if (ctx.external && ctx.sharedDefsExtractedFor === ctx.external)
22868
22899
  return;
@@ -22891,7 +22922,7 @@ function extractDefs(ctx, schema) {
22891
22922
  }
22892
22923
  const uriPrefix = `#`;
22893
22924
  const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
22894
- if (entry[1] === root15 && !entry[1].schema.id) {
22925
+ if (entry[1] === root16 && !entry[1].schema.id) {
22895
22926
  return { ref: uriPrefix };
22896
22927
  }
22897
22928
  const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`;
@@ -23062,8 +23093,8 @@ function foldIntersection(json2) {
23062
23093
  assignProps(json2, folded);
23063
23094
  }
23064
23095
  function finalize(ctx, schema) {
23065
- const root15 = ctx.seen.get(schema);
23066
- if (!root15)
23096
+ const root16 = ctx.seen.get(schema);
23097
+ if (!root16)
23067
23098
  throw new Error("Unprocessed schema. This is a bug in Zod.");
23068
23099
  const flattenRef = (zodSchema) => {
23069
23100
  const seen = ctx.seen.get(zodSchema);
@@ -23174,7 +23205,7 @@ function finalize(ctx, schema) {
23174
23205
  throw new Error("Schema is missing an `id` property");
23175
23206
  result.$id = ctx.external.uri(id);
23176
23207
  }
23177
- assignProps(result, root15.defId ? root15.schema : root15.def ?? root15.schema);
23208
+ assignProps(result, root16.defId ? root16.schema : root16.def ?? root16.schema);
23178
23209
  const rootMetaId = ctx.metadataRegistry.get(schema)?.id;
23179
23210
  if (rootMetaId !== void 0 && result.id === rootMetaId)
23180
23211
  delete result.id;
@@ -27675,7 +27706,12 @@ var ConnectorSchema = external_exports.object({
27675
27706
  * connection types — one onboarding covers both action and trigger uses.
27676
27707
  * The FE collapses per-type rows into a single account when this is true.
27677
27708
  */
27678
- isManaged: external_exports.boolean().optional()
27709
+ isManaged: external_exports.boolean().optional(),
27710
+ /**
27711
+ * The service only admits loopback OAuth clients, so account setup runs in
27712
+ * the Automations CLI on the user's machine instead of the web app.
27713
+ */
27714
+ connectsViaCli: external_exports.boolean().optional()
27679
27715
  });
27680
27716
  var GetConnectorsQuerySchema = external_exports.object({
27681
27717
  query: external_exports.string().optional()
@@ -27701,6 +27737,11 @@ var connectorListResponseSchema = external_exports.object({
27701
27737
  nextCursor: external_exports.string().nullable()
27702
27738
  });
27703
27739
 
27740
+ // ../../packages/core/dist/esm/utils/cli-command.js
27741
+ function connectViaCliCommand(connectorId, capability) {
27742
+ return `tda connector connect ${connectorId} --capability ${capability}`;
27743
+ }
27744
+
27704
27745
  // ../../packages/core/dist/esm/utils/duration.js
27705
27746
  var durationUnits = ["ms", "s", "m", "h", "d", "w"];
27706
27747
  var createDurationPattern = (units) => units.join("|");
@@ -27818,6 +27859,9 @@ function hasTriggerType(value) {
27818
27859
  function isManifestRecord(value) {
27819
27860
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
27820
27861
  }
27862
+ function isStepWithTools(step) {
27863
+ return "tools" in step && step.tools != null && typeof step.tools === "object";
27864
+ }
27821
27865
  function isStringTypedSchema(schema) {
27822
27866
  if (!schema)
27823
27867
  return false;
@@ -27873,6 +27917,180 @@ function resolvePropertySchemaInSchema(schema, propertyPath) {
27873
27917
  return null;
27874
27918
  return resolvePropertySchemaInSchema(propertySchema, remainingPath);
27875
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
+ }
27876
28094
 
27877
28095
  // ../../packages/core/dist/esm/schemas/manifest.schema.js
27878
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;
@@ -28068,7 +28286,7 @@ var baseStepSchema = external_exports.object({
28068
28286
  })
28069
28287
  });
28070
28288
  var MODEL_TIERS = ["lite", "flash", "pro"];
28071
- var SUPPORTED_MODEL_REFERENCES = [...MODEL_TIERS, ...SUPPORTED_LLM_MODELS];
28289
+ var SUPPORTED_MODEL_REFERENCES = [...MODEL_TIERS, ...MANIFEST_LLM_MODELS];
28072
28290
  var modelReferenceSchema = external_exports.enum(SUPPORTED_MODEL_REFERENCES).meta({
28073
28291
  description: "A stable model tier (lite, flash, pro) or a supported literal model override."
28074
28292
  });
@@ -28124,7 +28342,7 @@ var searchStepSchema = baseStepSchema.merge(external_exports.object({
28124
28342
  description: "The search prompt to execute using web search."
28125
28343
  }),
28126
28344
  outputSchema: searchStepOutputSchema,
28127
- model: external_exports.enum([...MODEL_TIERS, ...SUPPORTED_SEARCH_MODELS]).optional().meta({
28345
+ model: external_exports.enum([...MODEL_TIERS, ...MANIFEST_SEARCH_MODELS]).optional().meta({
28128
28346
  description: "A stable tier (lite, flash, pro) or a supported search-enabled literal model override."
28129
28347
  })
28130
28348
  }));
@@ -28248,9 +28466,9 @@ var partialManifestSchema = manifestSchemaBase.partial().extend({
28248
28466
  var templateVariableRegex = /\{\{\s*[\w.]+\s*\}\}/g;
28249
28467
  var codeStepReferenceRegex = /\bsteps\.([a-zA-Z][a-zA-Z0-9]*)(?:\.([a-zA-Z_][\w.]*))?/g;
28250
28468
  var backtickStepReferenceRegex = /`steps\.([a-zA-Z][a-zA-Z0-9]*)(?:\.([a-zA-Z_][\w.]*))?`/g;
28251
- function extractStepReferences(text, regex) {
28469
+ function extractStepReferences(text2, regex) {
28252
28470
  const references = [];
28253
- for (const match of text.matchAll(regex)) {
28471
+ for (const match of text2.matchAll(regex)) {
28254
28472
  const stepId = match[1];
28255
28473
  if (!stepId)
28256
28474
  continue;
@@ -28296,8 +28514,8 @@ function validateTemplateVariable({ variable, context, stepId, currentStepGuard,
28296
28514
  if (parts.length === 0) {
28297
28515
  return null;
28298
28516
  }
28299
- const [root15, ...rest] = parts;
28300
- if (root15 === "trigger") {
28517
+ const [root16, ...rest] = parts;
28518
+ if (root16 === "trigger") {
28301
28519
  if (rest.length === 0) {
28302
28520
  return `Step "${stepId}" ${sourceType} references "{{trigger}}" without a property. Use {{trigger.<property>}} syntax (e.g., {{trigger.payload}}, {{trigger.metadata}}).`;
28303
28521
  }
@@ -28320,7 +28538,7 @@ function validateTemplateVariable({ variable, context, stepId, currentStepGuard,
28320
28538
  }
28321
28539
  return null;
28322
28540
  }
28323
- if (root15 === "steps") {
28541
+ if (root16 === "steps") {
28324
28542
  const referencedStepId = rest[0];
28325
28543
  if (!referencedStepId) {
28326
28544
  return `Step "${stepId}" ${sourceType} references "steps" but is missing the step identifier in template variable "{{${variable}}}". Use {{steps.<stepId>}} syntax.`;
@@ -28753,6 +28971,29 @@ var CreateConnectionParamsSchema = external_exports.object({
28753
28971
  var CreateConnectionBodySchema = external_exports.object({
28754
28972
  automationIds: external_exports.array(external_exports.uuid()).optional()
28755
28973
  });
28974
+ var ImportLocalOAuthConnectionBodySchema = external_exports.object({
28975
+ /** The public client the CLI registered; the server bound the grant to it. */
28976
+ clientId: external_exports.string().min(1),
28977
+ accessToken: external_exports.string().min(1),
28978
+ refreshToken: external_exports.string().min(1).optional(),
28979
+ /** Seconds until `accessToken` expires, as the token endpoint reported it. */
28980
+ expiresIn: external_exports.number().int().positive().optional(),
28981
+ /**
28982
+ * A broken connection of the caller's, for the same connector, whose
28983
+ * automation bindings move to the new grant when the account cannot be
28984
+ * matched to it.
28985
+ */
28986
+ repairConnectionId: external_exports.uuid().optional()
28987
+ });
28988
+ var LocalOAuthSetupSchema = external_exports.object({
28989
+ /** RFC 7591 registration endpoint; null when the server offers none. */
28990
+ registrationEndpoint: external_exports.string().url().nullable(),
28991
+ authorizationEndpoint: external_exports.string().url(),
28992
+ tokenEndpoint: external_exports.string().url(),
28993
+ /** RFC 8707 resource indicator for the MCP server, when it advertises one. */
28994
+ resource: external_exports.string().url().nullable(),
28995
+ scopes: external_exports.array(external_exports.string())
28996
+ });
28756
28997
  var OAuthConnectionSetupSchema = external_exports.object({
28757
28998
  kind: external_exports.literal("oauth"),
28758
28999
  authorizationUrl: external_exports.string().url()
@@ -29084,6 +29325,17 @@ var finalizeAutomationDraftResponseSchema = external_exports.object({
29084
29325
  var testAutomationDraftResponseSchema = external_exports.object({
29085
29326
  success: external_exports.literal(true)
29086
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
+ });
29087
29339
 
29088
29340
  // ../../packages/core/dist/esm/schemas/automation-draft-connection.schema.js
29089
29341
  var CreateAutomationDraftConnectionSchema = external_exports.object({
@@ -29572,7 +29824,9 @@ var FRONTEND_COHORT_EVENTS = [
29572
29824
  "chat:sent",
29573
29825
  "automation:repaired",
29574
29826
  "template:used",
29575
- "top-up:completed"
29827
+ "top-up:completed",
29828
+ "guided-creation:started",
29829
+ "guided-creation:completed"
29576
29830
  ];
29577
29831
  var BACKEND_COHORT_EVENTS = [
29578
29832
  // API-process (publish lifecycle)
@@ -29725,7 +29979,143 @@ function assertKnownTimezone(timezone) {
29725
29979
  }
29726
29980
 
29727
29981
  // ../../packages/core/dist/esm/schemas/manifest.validation.js
29982
+ var import_ajv = __toESM(require_ajv(), 1);
29728
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
+ }
29729
30119
 
29730
30120
  // ../../packages/core/dist/esm/schemas/notification.schema.js
29731
30121
  var NOTIFICATION_TYPES = ["notification", "prompt"];
@@ -30528,13 +30918,13 @@ function buildUrl(baseUrl, path, query) {
30528
30918
  return url2.toString();
30529
30919
  }
30530
30920
  async function readResponseBody(response) {
30531
- const text = await response.text();
30532
- if (text.length === 0)
30921
+ const text2 = await response.text();
30922
+ if (text2.length === 0)
30533
30923
  return void 0;
30534
30924
  try {
30535
- return JSON.parse(text);
30925
+ return JSON.parse(text2);
30536
30926
  } catch {
30537
- return text;
30927
+ return text2;
30538
30928
  }
30539
30929
  }
30540
30930
  async function request(args) {
@@ -30723,6 +31113,16 @@ var automationDraftsEndpoints = {
30723
31113
  };
30724
31114
 
30725
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
+ }
30726
31126
  var AutomationDraftsClient = class extends BaseClient {
30727
31127
  async list(args = {}, options) {
30728
31128
  const { cursor, limit } = CursorPaginationSchema.parse(args);
@@ -30745,11 +31145,13 @@ var AutomationDraftsClient = class extends BaseClient {
30745
31145
  }
30746
31146
  async create(manifest, options) {
30747
31147
  const body = partialManifestSchema.parse(manifest);
31148
+ const { translate, ...requestOptions } = options ?? {};
30748
31149
  const data = await this.request({
30749
31150
  method: "POST",
30750
31151
  path: automationDraftsEndpoints.list,
31152
+ query: toCreateQuery(translate),
30751
31153
  body,
30752
- options
31154
+ options: requestOptions
30753
31155
  });
30754
31156
  return automationDraftWithValidationSchema.parse(data);
30755
31157
  }
@@ -30852,6 +31254,13 @@ var automationsEndpoints = {
30852
31254
 
30853
31255
  // ../../packages/sdk/dist/esm/clients/automations/automations-client.js
30854
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
+ }
30855
31264
  var AutomationsClient = class extends BaseClient {
30856
31265
  async list(args = {}, options) {
30857
31266
  const { cursor, limit } = CursorPaginationSchema.parse(args);
@@ -31030,11 +31439,23 @@ var WorkspaceAutomationRunsClient = class extends BaseClient {
31030
31439
 
31031
31440
  // ../../packages/sdk/dist/esm/clients/workspace-automation-draft-connections/endpoints.js
31032
31441
  var workspaceAutomationDraftConnectionsEndpoints = {
31033
- 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`
31034
31444
  };
31445
+ function root6(workspaceId, draftId) {
31446
+ return `/workspaces/${encodeURIComponent(workspaceId)}/automation-drafts/${encodeURIComponent(draftId)}/connections`;
31447
+ }
31035
31448
 
31036
31449
  // ../../packages/sdk/dist/esm/clients/workspace-automation-draft-connections/workspace-automation-draft-connections-client.js
31037
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
+ }
31038
31459
  async upsert(workspaceId, draftId, body, options) {
31039
31460
  const parsedBody = CreateAutomationDraftConnectionSchema.parse(body);
31040
31461
  const data = await this.request({
@@ -31045,14 +31466,23 @@ var WorkspaceAutomationDraftConnectionsClient = class extends BaseClient {
31045
31466
  });
31046
31467
  return AutomationDraftConnectionSchema.parse(data);
31047
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
+ }
31048
31477
  };
31049
31478
 
31050
31479
  // ../../packages/sdk/dist/esm/clients/workspace-automation-drafts/endpoints.js
31051
31480
  var workspaceAutomationDraftsEndpoints = {
31052
- list: (workspaceId) => `${root6(workspaceId)}`,
31053
- 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`
31054
31484
  };
31055
- function root6(workspaceId) {
31485
+ function root7(workspaceId) {
31056
31486
  return `/workspaces/${encodeURIComponent(workspaceId)}/automation-drafts`;
31057
31487
  }
31058
31488
 
@@ -31076,6 +31506,29 @@ var WorkspaceAutomationDraftsClient = class extends BaseClient {
31076
31506
  });
31077
31507
  return automationDraftWithValidationSchema.parse(data);
31078
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
+ }
31079
31532
  /** Deletes the draft. Only its owner can; the API answers 404 otherwise. */
31080
31533
  async delete(workspaceId, draftId, options) {
31081
31534
  await this.request({
@@ -31084,6 +31537,15 @@ var WorkspaceAutomationDraftsClient = class extends BaseClient {
31084
31537
  options
31085
31538
  });
31086
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
+ }
31087
31549
  };
31088
31550
 
31089
31551
  // ../../packages/sdk/dist/esm/clients/workspace-chat/endpoints.js
@@ -31107,15 +31569,16 @@ var WorkspaceChatClient = class extends BaseClient {
31107
31569
 
31108
31570
  // ../../packages/sdk/dist/esm/clients/workspace-automations/endpoints.js
31109
31571
  var workspaceAutomationsEndpoints = {
31110
- list: (workspaceId) => `${root7(workspaceId)}`,
31111
- detail: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}`,
31112
- metadata: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/metadata`,
31113
- schedule: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/schedule`,
31114
- visibility: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/visibility`,
31115
- move: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/move`,
31116
- 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`
31117
31580
  };
31118
- function root7(workspaceId) {
31581
+ function root8(workspaceId) {
31119
31582
  return `/workspaces/${encodeURIComponent(workspaceId)}/automations`;
31120
31583
  }
31121
31584
 
@@ -31213,12 +31676,33 @@ var WorkspaceAutomationsClient = class extends BaseClient {
31213
31676
  options
31214
31677
  });
31215
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
+ }
31216
31700
  };
31217
31701
 
31218
31702
  // ../../packages/sdk/dist/esm/clients/workspaces/endpoints.js
31219
- var root8 = "/workspaces";
31703
+ var root9 = "/workspaces";
31220
31704
  var workspacesEndpoints = {
31221
- list: root8
31705
+ list: root9
31222
31706
  };
31223
31707
 
31224
31708
  // ../../packages/sdk/dist/esm/clients/workspaces/workspaces-client.js
@@ -31240,12 +31724,12 @@ var WorkspacesClient = class extends BaseClient {
31240
31724
  };
31241
31725
 
31242
31726
  // ../../packages/sdk/dist/esm/clients/chat/endpoints.js
31243
- var root9 = "/chat/conversations";
31727
+ var root10 = "/chat/conversations";
31244
31728
  var chatEndpoints = {
31245
- conversations: root9,
31246
- conversation: (id) => `${root9}/${encodeURIComponent(id)}`,
31247
- messages: (id) => `${root9}/${encodeURIComponent(id)}/messages`,
31248
- 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`
31249
31733
  };
31250
31734
 
31251
31735
  // ../../packages/sdk/dist/esm/clients/chat/chat-client.js
@@ -31319,14 +31803,15 @@ var ChatClient = class extends BaseClient {
31319
31803
  };
31320
31804
 
31321
31805
  // ../../packages/sdk/dist/esm/clients/connections/endpoints.js
31322
- var root10 = "/connections";
31806
+ var root11 = "/connections";
31323
31807
  var connectionsEndpoints = {
31324
- list: root10,
31325
- detail: (id) => `${root10}/${encodeURIComponent(id)}`,
31326
- token: (id) => `${root10}/${encodeURIComponent(id)}/token`,
31327
- dependentAutomations: (connectorId) => `${root10}/${encodeURIComponent(connectorId)}/automations`,
31328
- create: (connectorId, capability) => `${root10}/${encodeURIComponent(connectorId)}/${encodeURIComponent(capability)}`,
31329
- 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`
31330
31815
  };
31331
31816
 
31332
31817
  // ../../packages/sdk/dist/esm/clients/connections/connections-client.js
@@ -31405,6 +31890,41 @@ var ConnectionsClient = class extends BaseClient {
31405
31890
  });
31406
31891
  return CreateConnectionResponseSchema.parse(data);
31407
31892
  }
31893
+ /**
31894
+ * The authorization server endpoints and scopes for running a
31895
+ * `connectsViaCli` connector's OAuth flow with a loopback client.
31896
+ */
31897
+ async getLocalOAuthSetup(args, options) {
31898
+ const { connectorId, capability } = CreateConnectionParamsSchema.parse({
31899
+ connectorId: IdSchema.parse(args.connectorId),
31900
+ capability: args.capability
31901
+ });
31902
+ const data = await this.request({
31903
+ method: "GET",
31904
+ path: connectionsEndpoints.localOAuth(connectorId, capability),
31905
+ options
31906
+ });
31907
+ return LocalOAuthSetupSchema.parse(data);
31908
+ }
31909
+ /**
31910
+ * Stores a grant the CLI obtained with a loopback OAuth client, for a
31911
+ * connector whose authorization server admits no hosted clients
31912
+ * (`connectsViaCli`). The connection comes back already authorized.
31913
+ */
31914
+ async importLocalOAuth(args, options) {
31915
+ const { connectorId, capability } = CreateConnectionParamsSchema.parse({
31916
+ connectorId: IdSchema.parse(args.connectorId),
31917
+ capability: args.capability
31918
+ });
31919
+ const body = ImportLocalOAuthConnectionBodySchema.parse(args.grant);
31920
+ const data = await this.request({
31921
+ method: "POST",
31922
+ path: connectionsEndpoints.localOAuth(connectorId, capability),
31923
+ body,
31924
+ options
31925
+ });
31926
+ return CreateConnectionResponseSchema.parse(data);
31927
+ }
31408
31928
  async checkManifest(manifest, options) {
31409
31929
  const parsedManifest = partialManifestSchema.parse(manifest);
31410
31930
  const data = await this.request({
@@ -31478,12 +31998,12 @@ function createClientContext(authToken, options = {}, apiOrigin = "automations")
31478
31998
  }
31479
31999
 
31480
32000
  // ../../packages/sdk/dist/esm/clients/notifications/endpoints.js
31481
- var root11 = "/notifications";
32001
+ var root12 = "/notifications";
31482
32002
  var notificationsEndpoints = {
31483
- list: root11,
31484
- pendingPromptAutomations: `${root11}/pending-prompt-automations`,
31485
- detail: (id) => `${root11}/${encodeURIComponent(id)}`,
31486
- 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`
31487
32007
  };
31488
32008
  var pushRoot = "/push-subscriptions";
31489
32009
  var pushSubscriptionsEndpoints = {
@@ -31607,11 +32127,11 @@ var NotificationsClient = class extends BaseClient {
31607
32127
  };
31608
32128
 
31609
32129
  // ../../packages/sdk/dist/esm/clients/user-settings/endpoints.js
31610
- var root12 = "/settings";
32130
+ var root13 = "/settings";
31611
32131
  var userSettingsEndpoints = {
31612
- onboarding: `${root12}/onboarding`,
31613
- preferences: `${root12}/preferences`,
31614
- terms: `${root12}/terms`
32132
+ onboarding: `${root13}/onboarding`,
32133
+ preferences: `${root13}/preferences`,
32134
+ terms: `${root13}/terms`
31615
32135
  };
31616
32136
 
31617
32137
  // ../../packages/sdk/dist/esm/clients/user-settings/user-settings-client.js
@@ -31773,11 +32293,11 @@ var UsageBillingClient = class extends BaseClient {
31773
32293
  };
31774
32294
 
31775
32295
  // ../../packages/sdk/dist/esm/clients/webhook-event-subscriptions/endpoints.js
31776
- var root13 = "/webhook-event-subscriptions";
32296
+ var root14 = "/webhook-event-subscriptions";
31777
32297
  var webhookEventSubscriptionsEndpoints = {
31778
- list: root13,
31779
- detail: (id) => `${root13}/${encodeURIComponent(id)}`,
31780
- deliveries: (id) => `${root13}/${encodeURIComponent(id)}/deliveries`
32298
+ list: root14,
32299
+ detail: (id) => `${root14}/${encodeURIComponent(id)}`,
32300
+ deliveries: (id) => `${root14}/${encodeURIComponent(id)}/deliveries`
31781
32301
  };
31782
32302
 
31783
32303
  // ../../packages/sdk/dist/esm/clients/webhook-event-subscriptions/webhook-event-subscriptions-client.js
@@ -31850,12 +32370,12 @@ var WebhookEventSubscriptionsClient = class extends BaseClient {
31850
32370
  };
31851
32371
 
31852
32372
  // ../../packages/sdk/dist/esm/clients/webhook-subscriptions/endpoints.js
31853
- function root14(automationId) {
32373
+ function root15(automationId) {
31854
32374
  return `/automations/${encodeURIComponent(automationId)}/subscriptions`;
31855
32375
  }
31856
32376
  var webhookSubscriptionsEndpoints = {
31857
- list: (automationId) => root14(automationId),
31858
- detail: (automationId, subscriptionId) => `${root14(automationId)}/${encodeURIComponent(subscriptionId)}`
32377
+ list: (automationId) => root15(automationId),
32378
+ detail: (automationId, subscriptionId) => `${root15(automationId)}/${encodeURIComponent(subscriptionId)}`
31859
32379
  };
31860
32380
 
31861
32381
  // ../../packages/sdk/dist/esm/clients/webhook-subscriptions/webhook-subscriptions-client.js
@@ -33849,8 +34369,8 @@ function getResourceName(manifest) {
33849
34369
  }
33850
34370
  function getMessageSummary(message) {
33851
34371
  if (!Array.isArray(message.parts)) return "(unstructured message parts)";
33852
- const text = message.parts.filter(isTextPart).map((part) => part.text).join("");
33853
- if (text) return text;
34372
+ const text2 = message.parts.filter(isTextPart).map((part) => part.text).join("");
34373
+ if (text2) return text2;
33854
34374
  const partTypes = message.parts.filter(isRecord2).map((part) => typeof part.type === "string" ? part.type : "unknown");
33855
34375
  return partTypes.length > 0 ? `[${partTypes.join(", ")}]` : "(no visible text)";
33856
34376
  }
@@ -34205,6 +34725,36 @@ async function runStreamingCommand(command, handlers) {
34205
34725
  }
34206
34726
  }
34207
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
+
34208
34758
  // ../../packages/sdk/dist/esm/chat-turn/connection-requirements.js
34209
34759
  var CONNECTION_LOOKUP_CONCURRENCY = 4;
34210
34760
  function deduplicateConnectionRequirements(requirements) {
@@ -34313,11 +34863,11 @@ var toolUpdateMemoryResultSchema = external_exports.object({
34313
34863
  });
34314
34864
 
34315
34865
  // ../../packages/sdk/dist/esm/chat-turn/messages.js
34316
- function createUserMessage(text) {
34866
+ function createUserMessage(text2) {
34317
34867
  return {
34318
34868
  id: globalThis.crypto.randomUUID(),
34319
34869
  role: "user",
34320
- parts: [{ type: "text", text }]
34870
+ parts: [{ type: "text", text: text2 }]
34321
34871
  };
34322
34872
  }
34323
34873
  function toUiMessage(message) {
@@ -34842,8 +35392,8 @@ Interrupted. Resume with: tda chat continue ${sanitizeTerminalText(event.convers
34842
35392
  this.assistantLineOpen = false;
34843
35393
  break;
34844
35394
  case "session_status": {
34845
- const text = sanitizeTerminalText(String(event.humanText ?? ""));
34846
- this.stream.write(text.endsWith("\n") ? text : `${text}
35395
+ const text2 = sanitizeTerminalText(String(event.humanText ?? ""));
35396
+ this.stream.write(text2.endsWith("\n") ? text2 : `${text2}
34847
35397
  `);
34848
35398
  break;
34849
35399
  }
@@ -35374,9 +35924,9 @@ var ChatService = class {
35374
35924
  input: input2,
35375
35925
  pendingAction,
35376
35926
  signal,
35377
- onText: (text) => {
35927
+ onText: (text2) => {
35378
35928
  markActivity();
35379
- this.output.emit({ type: "assistant_text", conversationId, text });
35929
+ this.output.emit({ type: "assistant_text", conversationId, text: text2 });
35380
35930
  },
35381
35931
  onToolActivity: (activity) => {
35382
35932
  markActivity();
@@ -35557,31 +36107,6 @@ function getResumeCommand(summary) {
35557
36107
  }
35558
36108
  return `tda chat continue ${summary.conversationId} "<message>"`;
35559
36109
  }
35560
- function parseConnectionSelectionOption(value) {
35561
- const separatorIndex = value.indexOf("=");
35562
- if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
35563
- throw new Error(
35564
- `Invalid connection selection "${value}". Use connector[:mcp|trigger]=connection-id.`
35565
- );
35566
- }
35567
- const selector = value.slice(0, separatorIndex);
35568
- const connectionId = value.slice(separatorIndex + 1);
35569
- const selectorParts = selector.split(":");
35570
- if (selectorParts.length > 2) {
35571
- throw new Error(`Invalid connection selection "${value}".`);
35572
- }
35573
- const [connectorId, rawConnectionType] = selectorParts;
35574
- if (!connectorId) throw new Error(`Invalid connection selection "${value}".`);
35575
- if (rawConnectionType && rawConnectionType !== "mcp" && rawConnectionType !== "trigger") {
35576
- throw new Error(`Invalid connection type "${rawConnectionType}".`);
35577
- }
35578
- const connectionType = rawConnectionType === "mcp" || rawConnectionType === "trigger" ? rawConnectionType : void 0;
35579
- return {
35580
- connectorId,
35581
- connectionType,
35582
- connectionId
35583
- };
35584
- }
35585
36110
 
35586
36111
  // src/commands/chat/index.ts
35587
36112
  function registerChatCommand(program) {
@@ -35597,7 +36122,7 @@ function registerChatCommand(program) {
35597
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(
35598
36123
  "--connection <connector[:type]=connection-id>",
35599
36124
  "Resolve a pending connection selection; repeat for multiple connectors",
35600
- collect,
36125
+ collectOption,
35601
36126
  []
35602
36127
  ).action(
35603
36128
  async (conversationId, messageParts, options, command) => {
@@ -35680,9 +36205,6 @@ async function runCommand(command, operation) {
35680
36205
  }
35681
36206
  });
35682
36207
  }
35683
- function collect(value, previous) {
35684
- return [...previous, value];
35685
- }
35686
36208
 
35687
36209
  // src/commands/conversation/index.ts
35688
36210
  import { Option as Option3 } from "commander";
@@ -35815,6 +36337,13 @@ async function* streamConnectorNdjsonItems(api, options, signal) {
35815
36337
  }
35816
36338
  yield { _meta: true, connectionsIncluded: options.connections };
35817
36339
  }
36340
+ async function findListedConnector(api, connectorId, signal) {
36341
+ for await (const page of iterateConnectorPages(api, void 0, { signal })) {
36342
+ const connector = page.data.find((candidate) => candidate.id === connectorId);
36343
+ if (connector) return connector;
36344
+ }
36345
+ return void 0;
36346
+ }
35818
36347
  function findConnector2(api, connectorId, signal) {
35819
36348
  return findConnector(api, connectorId, { signal });
35820
36349
  }
@@ -35842,6 +36371,8 @@ async function runAuthorizationCommand(command, operation) {
35842
36371
  return operation({
35843
36372
  api,
35844
36373
  signal,
36374
+ output: output2,
36375
+ openBrowser: options.open,
35845
36376
  authorizer: new ApiConnectionAuthorizer({
35846
36377
  connections: api.connections,
35847
36378
  output: output2,
@@ -35931,17 +36462,172 @@ function summarizeAffectedAutomation(automation) {
35931
36462
  };
35932
36463
  }
35933
36464
 
36465
+ // src/commands/connector/local-oauth-connect.ts
36466
+ import { createDcrProvider, runOAuthFlow } from "@doist/cli-core/auth";
36467
+ var PREFERRED_CALLBACK_PORT = 24369;
36468
+ async function connectViaLocalOAuth({
36469
+ api,
36470
+ connector,
36471
+ capability,
36472
+ repairConnectionId,
36473
+ output: output2,
36474
+ openBrowser,
36475
+ signal
36476
+ }) {
36477
+ const setup = await api.connections.getLocalOAuthSetup(
36478
+ { connectorId: connector.id, capability },
36479
+ { signal }
36480
+ );
36481
+ const { registrationEndpoint } = setup;
36482
+ if (!registrationEndpoint) {
36483
+ throw new Error(
36484
+ `${connector.name} does not support dynamic client registration, so the CLI cannot connect it.`
36485
+ );
36486
+ }
36487
+ const grant = await runLoopbackGrant({
36488
+ connector,
36489
+ capability,
36490
+ setup,
36491
+ registrationEndpoint,
36492
+ output: output2,
36493
+ openBrowser,
36494
+ signal
36495
+ });
36496
+ const created = await api.connections.importLocalOAuth(
36497
+ {
36498
+ connectorId: connector.id,
36499
+ capability,
36500
+ grant: {
36501
+ clientId: grant.account.clientId,
36502
+ accessToken: grant.bundle.accessToken,
36503
+ refreshToken: grant.bundle.refreshToken,
36504
+ expiresIn: expiresInSeconds(grant.bundle.accessTokenExpiresAt),
36505
+ ...repairConnectionId ? { repairConnectionId } : {}
36506
+ }
36507
+ },
36508
+ { signal }
36509
+ );
36510
+ output2.emit({
36511
+ type: "connection_authorized",
36512
+ connectionId: created.connectionId,
36513
+ connectorId: connector.id,
36514
+ serviceName: connector.name,
36515
+ connectionType: capability,
36516
+ state: "completed",
36517
+ terminal: false
36518
+ });
36519
+ return created.connectionId;
36520
+ }
36521
+ async function runLoopbackGrant({
36522
+ connector,
36523
+ capability,
36524
+ setup,
36525
+ registrationEndpoint,
36526
+ output: output2,
36527
+ openBrowser,
36528
+ signal
36529
+ }) {
36530
+ const retryHint = `Try again: ${connectViaCliCommand(connector.id, capability)}`;
36531
+ const provider = createDcrProvider({
36532
+ registrationUrl: registrationEndpoint,
36533
+ authorizeUrl: setup.authorizationEndpoint,
36534
+ tokenUrl: setup.tokenEndpoint,
36535
+ resource: setup.resource ?? void 0,
36536
+ clientMetadata: {
36537
+ clientName: AUTOMATIONS_CLI_CLIENT_NAME,
36538
+ logoUri: AUTOMATIONS_CLI_LOGO_URL,
36539
+ applicationType: "native",
36540
+ // The backend refreshes with the client id alone, so the client
36541
+ // must be public: no secret to copy across.
36542
+ tokenEndpointAuthMethod: "none",
36543
+ grantTypes: ["authorization_code", "refresh_token"]
36544
+ },
36545
+ // The grant is handed to the backend as-is; here the "account" only
36546
+ // carries the client id the server bound it to.
36547
+ validate: async ({ handshake }) => ({
36548
+ id: connector.id,
36549
+ label: connector.name,
36550
+ clientId: requireClientId(handshake)
36551
+ }),
36552
+ errorHints: [retryHint]
36553
+ });
36554
+ let captured;
36555
+ const store2 = {
36556
+ active: async () => null,
36557
+ set: async () => {
36558
+ },
36559
+ setBundle: async (account, bundle) => {
36560
+ captured = { account, bundle };
36561
+ },
36562
+ clear: async () => null,
36563
+ list: async () => [],
36564
+ setDefault: async () => {
36565
+ }
36566
+ };
36567
+ await runOAuthFlow({
36568
+ provider,
36569
+ store: store2,
36570
+ scopes: setup.scopes,
36571
+ readOnly: false,
36572
+ flags: {},
36573
+ preferredPort: PREFERRED_CALLBACK_PORT,
36574
+ renderSuccess: renderAuthSuccessPage,
36575
+ renderError: renderAuthErrorPage,
36576
+ ...openBrowser ? {} : { openBrowser: async () => {
36577
+ } },
36578
+ onAuthorizeUrl: (url2) => {
36579
+ output2.emit({
36580
+ type: "connection_authorization_started",
36581
+ connectorId: connector.id,
36582
+ serviceName: connector.name,
36583
+ connectionType: capability,
36584
+ state: "waiting_for_user",
36585
+ terminal: false,
36586
+ setupKind: "oauth",
36587
+ authorizationUrl: url2
36588
+ });
36589
+ },
36590
+ timeoutMs: CONNECTION_AUTHORIZATION_TIMEOUT_MS,
36591
+ signal
36592
+ });
36593
+ if (!captured) {
36594
+ throw new Error(`${connector.name} sign-in finished without a token. ${retryHint}`);
36595
+ }
36596
+ return captured;
36597
+ }
36598
+ function requireClientId(handshake) {
36599
+ const clientId = handshake.clientId;
36600
+ if (typeof clientId !== "string" || clientId.length === 0) {
36601
+ throw new Error("The authorization server did not return a client id.");
36602
+ }
36603
+ return clientId;
36604
+ }
36605
+ function expiresInSeconds(expiresAt) {
36606
+ if (expiresAt === void 0) return void 0;
36607
+ const seconds = Math.floor((expiresAt - Date.now()) / 1e3);
36608
+ return seconds > 0 ? seconds : void 0;
36609
+ }
36610
+
35934
36611
  // src/commands/connector/mutation-commands.ts
35935
36612
  function registerConnectorMutationCommands(connector) {
35936
36613
  connector.command("connect").description("Create a service connection and wait for authorization").argument("<connector-id>", "Connector ID").addOption(
35937
36614
  new Option4("--capability <capability>", "Capability to authorize").choices(["mcp", "trigger"]).makeOptionMandatory()
35938
36615
  ).action(async (connectorId, options, command) => {
35939
- await runAuthorizationCommand(command, async ({ api, authorizer, signal }) => {
36616
+ await runAuthorizationCommand(command, async (context) => {
36617
+ const { api, authorizer, signal } = context;
35940
36618
  const selected2 = await findConnector2(api, connectorId, signal);
35941
36619
  assertConnectorSupportsCapability(selected2, options.capability);
35942
36620
  if (!selected2.requiresConnection) {
35943
36621
  throw new Error(`${selected2.name} does not require a connection.`);
35944
36622
  }
36623
+ if (selected2.connectsViaCli) {
36624
+ const connectionId2 = await connectViaLocalOAuth({
36625
+ ...context,
36626
+ connector: selected2,
36627
+ capability: options.capability
36628
+ });
36629
+ return { action: "connected", connectionId: connectionId2 };
36630
+ }
35945
36631
  const connectionId = await authorizer.authorize(
35946
36632
  {
35947
36633
  connectorId: selected2.id,
@@ -35978,7 +36664,8 @@ function registerConnectorMutationCommands(connector) {
35978
36664
  });
35979
36665
  });
35980
36666
  connector.command("repair").description("Start a replacement setup for a broken or expired connection").argument("<connection-id>", "Connection ID").action(async (connectionId, _options, command) => {
35981
- await runAuthorizationCommand(command, async ({ api, authorizer, signal }) => {
36667
+ await runAuthorizationCommand(command, async (context) => {
36668
+ const { api, authorizer, signal } = context;
35982
36669
  const connection = await api.connections.get(connectionId, { signal });
35983
36670
  if (connection.status === "authorized") {
35984
36671
  throw new Error(`Connection ${connectionId} is already authorized.`);
@@ -35992,7 +36679,19 @@ function registerConnectorMutationCommands(connector) {
35992
36679
  await authorizer.resume(request2, connection.id, connection.setup, signal);
35993
36680
  return { action: "connected", connectionId };
35994
36681
  }
35995
- const affectedAutomations = await findAffectedAutomations(api, connectionId, signal);
36682
+ const [selected2, affectedAutomations] = await Promise.all([
36683
+ findListedConnector(api, connection.connectorId, signal),
36684
+ findAffectedAutomations(api, connectionId, signal)
36685
+ ]);
36686
+ if (selected2?.connectsViaCli) {
36687
+ const repairedConnectionId2 = await connectViaLocalOAuth({
36688
+ ...context,
36689
+ connector: selected2,
36690
+ capability: request2.connectionType,
36691
+ repairConnectionId: connection.id
36692
+ });
36693
+ return { action: "connected", connectionId: repairedConnectionId2 };
36694
+ }
35996
36695
  const repairedConnectionId = await authorizer.authorize(
35997
36696
  {
35998
36697
  ...request2,
@@ -36077,6 +36776,343 @@ function registerConnectorCommand(program) {
36077
36776
  registerConnectorMutationCommands(connector);
36078
36777
  }
36079
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
+
36080
37116
  // src/commands/draft/format.ts
36081
37117
  function formatDraftDelete(result) {
36082
37118
  if (result.action === "delete_preview") {
@@ -36088,10 +37124,144 @@ function formatDraftDelete(result) {
36088
37124
  }
36089
37125
  return `Deleted draft ${result.draftId}.`;
36090
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
+ }
36091
37260
 
36092
37261
  // src/commands/draft/index.ts
36093
37262
  function registerDraftCommand(program) {
36094
- 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);
36095
37265
  addWorkspaceScopeOptions(
36096
37266
  addCursorPaginationOptions(
36097
37267
  draft.command("list").description("List drafts").option(
@@ -36135,6 +37305,85 @@ function registerDraftCommand(program) {
36135
37305
  { spinner: "Loading draft..." }
36136
37306
  );
36137
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
+ });
36138
37387
  addWorkspaceScopeOptions(
36139
37388
  draft.command("delete").description("Delete a draft after previewing which one it is").argument("<draft-id>", "Draft ID").option("--yes", "Confirm deletion")
36140
37389
  ).action(async (draftId, options, command) => {
@@ -36173,7 +37422,7 @@ function streamDraftList(options, fetchPage) {
36173
37422
  }
36174
37423
 
36175
37424
  // src/commands/run/index.ts
36176
- import { Option as Option6 } from "commander";
37425
+ import { Option as Option7 } from "commander";
36177
37426
  function registerRunCommand(program) {
36178
37427
  const run = program.command("run").description("Inspect automation runs");
36179
37428
  addWorkspaceScopeOptions(
@@ -36181,7 +37430,7 @@ function registerRunCommand(program) {
36181
37430
  run.command("list").description("List runs for an automation").argument("<automation-id>", "Automation ID")
36182
37431
  )
36183
37432
  ).addOption(
36184
- new Option6("--status <status>", "Only show runs with this status").choices([
37433
+ new Option7("--status <status>", "Only show runs with this status").choices([
36185
37434
  ...AUTOMATION_RUN_STATUSES
36186
37435
  ])
36187
37436
  ).option(
@@ -36265,26 +37514,12 @@ function registerRunCommand(program) {
36265
37514
  );
36266
37515
  }
36267
37516
 
36268
- // src/lib/local-command.ts
36269
- async function runLocalCommand(command, operation, presentation, execution = {}) {
36270
- let mode = "human";
36271
- try {
36272
- mode = getOutputMode(getGlobalOptions(command));
36273
- const result = await withSpinner({ text: execution.spinner ?? "Loading..." }, operation);
36274
- stopEarlySpinner();
36275
- writeResult(mode, result, presentation);
36276
- } catch (error62) {
36277
- writeFailure(mode, "error", renderFailure(error62, { mode }));
36278
- process.exitCode = 1;
36279
- }
36280
- }
36281
-
36282
37517
  // src/commands/skill/shared.ts
36283
- import { CliError as CliError3 } from "@doist/cli-core";
37518
+ import { CliError as CliError6 } from "@doist/cli-core";
36284
37519
  function requireInstaller(agent) {
36285
37520
  const installer = getInstaller(agent);
36286
37521
  if (!installer) {
36287
- throw new CliError3("UNKNOWN_AGENT", `Unknown agent: ${agent}.`, {
37522
+ throw new CliError6("UNKNOWN_AGENT", `Unknown agent: ${agent}.`, {
36288
37523
  hints: [`Available agents: ${AGENT_NAMES.join(", ")}.`]
36289
37524
  });
36290
37525
  }
@@ -36362,7 +37597,7 @@ async function uninstallSkill(agent, options, command) {
36362
37597
  }
36363
37598
 
36364
37599
  // src/commands/skill/update.ts
36365
- import { CliError as CliError4 } from "@doist/cli-core";
37600
+ import { CliError as CliError7 } from "@doist/cli-core";
36366
37601
  async function updateSkill(agent, options, command) {
36367
37602
  await runLocalCommand(
36368
37603
  command,
@@ -36388,7 +37623,7 @@ async function updateAllSkills(options, command) {
36388
37623
  async () => {
36389
37624
  const result = await updateAllInstalledSkills(options.local === true);
36390
37625
  if (result.errors.length > 0) {
36391
- throw new CliError4(
37626
+ throw new CliError7(
36392
37627
  "UPDATE_FAILED",
36393
37628
  `Could not update ${result.errors.length} skill file(s).`,
36394
37629
  { hints: result.errors.map((error62) => `${error62.agent}: ${error62.message}`) }
@@ -36549,13 +37784,13 @@ async function findWorkspace(api, workspaceId, signal) {
36549
37784
  // src/lib/command-output.ts
36550
37785
  function configureCommandOutput(command) {
36551
37786
  return command.configureOutput({
36552
- writeOut: (text) => {
37787
+ writeOut: (text2) => {
36553
37788
  stopEarlySpinner();
36554
- process.stdout.write(text);
37789
+ process.stdout.write(text2);
36555
37790
  },
36556
- writeErr: (text) => {
37791
+ writeErr: (text2) => {
36557
37792
  stopEarlySpinner();
36558
- process.stderr.write(text);
37793
+ process.stderr.write(text2);
36559
37794
  }
36560
37795
  });
36561
37796
  }
@@ -36567,7 +37802,7 @@ function createProgram() {
36567
37802
  `Target environment: ${ENVIRONMENT_NAMES.join(", ")}`,
36568
37803
  parseEnvironmentOption,
36569
37804
  initialEnvironmentName()
36570
- ).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();
36571
37806
  configureCommandOutput(program);
36572
37807
  registerAuthCommand(program);
36573
37808
  registerAutomationCommand(program);
@@ -36581,7 +37816,7 @@ function createProgram() {
36581
37816
  registerWorkspaceCommand(program);
36582
37817
  return program;
36583
37818
  }
36584
- function collect2(value, previous) {
37819
+ function collect(value, previous) {
36585
37820
  return [...previous, value];
36586
37821
  }
36587
37822
  if (isEntrypoint()) {