@doist/automations-cli 1.21.3 → 1.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
collectSkillStatus,
|
|
8
8
|
getInstaller,
|
|
9
9
|
updateAllInstalledSkills
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-NB7HIIJZ.js";
|
|
11
11
|
|
|
12
12
|
// ../../node_modules/ajv/dist/compile/codegen/code.js
|
|
13
13
|
var require_code = __commonJS({
|
|
@@ -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.
|
|
6902
|
+
version: "1.22.1",
|
|
6903
6903
|
description: "Command-line client for Todoist Automations",
|
|
6904
6904
|
type: "module",
|
|
6905
6905
|
bin: {
|
|
@@ -6945,7 +6945,7 @@ var package_default = {
|
|
|
6945
6945
|
dependencies: {
|
|
6946
6946
|
"@doist/cli-core": "1.7.0",
|
|
6947
6947
|
"@napi-rs/keyring": "2.1.1",
|
|
6948
|
-
ai: "7.0.
|
|
6948
|
+
ai: "7.0.142",
|
|
6949
6949
|
commander: "15.0.0",
|
|
6950
6950
|
oauth4webapi: "3.8.8",
|
|
6951
6951
|
open: "11.0.4"
|
|
@@ -6959,7 +6959,7 @@ var package_default = {
|
|
|
6959
6959
|
"semantic-release": "25.0.9",
|
|
6960
6960
|
"semantic-release-monorepo": "8.0.2",
|
|
6961
6961
|
typescript: "6.0.3",
|
|
6962
|
-
vitest: "5.0.
|
|
6962
|
+
vitest: "5.0.5"
|
|
6963
6963
|
},
|
|
6964
6964
|
engines: {
|
|
6965
6965
|
node: ">=24"
|
|
@@ -33105,15 +33105,27 @@ function diffManifests(before, after) {
|
|
|
33105
33105
|
const added = [...nextSteps.keys()].filter((id) => !previousSteps.has(id));
|
|
33106
33106
|
const removed = [...previousSteps.keys()].filter((id) => !nextSteps.has(id));
|
|
33107
33107
|
const changed = [...nextSteps].filter(([id, step]) => previousSteps.has(id) && !isDeepEqual(previousSteps.get(id), step)).map(([id]) => id);
|
|
33108
|
+
const changedFields = Object.fromEntries(changed.map((id) => [id, differingPaths(previousSteps.get(id), nextSteps.get(id), "")]));
|
|
33108
33109
|
const sharedBefore = [...previousSteps.keys()].filter((id) => nextSteps.has(id));
|
|
33109
33110
|
const sharedAfter = [...nextSteps.keys()].filter((id) => previousSteps.has(id));
|
|
33110
33111
|
const reordered = sharedBefore.some((id, index) => sharedAfter[index] !== id);
|
|
33111
33112
|
return {
|
|
33112
33113
|
changedProperties,
|
|
33113
|
-
steps: { added, removed, changed, reordered },
|
|
33114
|
+
steps: { added, removed, changed, changedFields, reordered },
|
|
33114
33115
|
isEmpty: changedProperties.length === 0 && added.length === 0 && removed.length === 0 && changed.length === 0 && !reordered
|
|
33115
33116
|
};
|
|
33116
33117
|
}
|
|
33118
|
+
function differingPaths(before, after, path) {
|
|
33119
|
+
if (isDeepEqual(before, after))
|
|
33120
|
+
return [];
|
|
33121
|
+
if (isManifestRecord(before) && isManifestRecord(after)) {
|
|
33122
|
+
return [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort().flatMap((key) => differingPaths(before[key], after[key], path ? `${path}.${key}` : key));
|
|
33123
|
+
}
|
|
33124
|
+
if (path && Array.isArray(before) && Array.isArray(after) && before.length === after.length) {
|
|
33125
|
+
return before.flatMap((item, index) => differingPaths(item, after[index], `${path}[${index}]`));
|
|
33126
|
+
}
|
|
33127
|
+
return path ? [path] : [];
|
|
33128
|
+
}
|
|
33117
33129
|
function asManifest(value) {
|
|
33118
33130
|
return isManifestRecord(value) ? value : {};
|
|
33119
33131
|
}
|
|
@@ -33137,7 +33149,7 @@ function sortKeys(value) {
|
|
|
33137
33149
|
|
|
33138
33150
|
// ../../packages/sdk/dist/esm/drafts/publish-draft.js
|
|
33139
33151
|
async function publishDraft(draftApi, { draftId, confirmed }) {
|
|
33140
|
-
const { summary,
|
|
33152
|
+
const { summary, detail } = await previewPublish(draftApi, draftId);
|
|
33141
33153
|
if (!confirmed) {
|
|
33142
33154
|
return { action: "publish_preview", summary };
|
|
33143
33155
|
}
|
|
@@ -33164,7 +33176,7 @@ async function publishDraft(draftApi, { draftId, confirmed }) {
|
|
|
33164
33176
|
verification: { status: "unavailable", reason: getErrorMessage(error62) }
|
|
33165
33177
|
};
|
|
33166
33178
|
}
|
|
33167
|
-
const expected = normaliseManifest(
|
|
33179
|
+
const expected = normaliseManifest(detail.draft.partialManifest);
|
|
33168
33180
|
const actual = normaliseManifest(automation.manifest);
|
|
33169
33181
|
return {
|
|
33170
33182
|
action: "published",
|
|
@@ -33173,7 +33185,7 @@ async function publishDraft(draftApi, { draftId, confirmed }) {
|
|
|
33173
33185
|
verification: isDeepEqual(expected, actual) ? { status: "matched" } : { status: "mismatched", mismatch: diffManifests(expected, actual) }
|
|
33174
33186
|
};
|
|
33175
33187
|
}
|
|
33176
|
-
async function
|
|
33188
|
+
async function previewPublish(draftApi, draftId) {
|
|
33177
33189
|
const [detail, connections] = await Promise.all([
|
|
33178
33190
|
draftApi.get(draftId),
|
|
33179
33191
|
draftApi.getConnectionStatus(draftId)
|
|
@@ -33207,7 +33219,7 @@ async function summarizeForPublish(draftApi, draftId) {
|
|
|
33207
33219
|
schedule: describeSchedule(draft.partialManifest),
|
|
33208
33220
|
diff
|
|
33209
33221
|
};
|
|
33210
|
-
return { summary,
|
|
33222
|
+
return { summary, detail };
|
|
33211
33223
|
}
|
|
33212
33224
|
function describeSchedule(manifest) {
|
|
33213
33225
|
if (!hasTriggerType(manifest))
|
|
@@ -34513,6 +34525,9 @@ function parsePositiveInteger(value) {
|
|
|
34513
34525
|
return parsed;
|
|
34514
34526
|
}
|
|
34515
34527
|
|
|
34528
|
+
// src/lib/api-command.ts
|
|
34529
|
+
import { CliError as CliError3 } from "@doist/cli-core";
|
|
34530
|
+
|
|
34516
34531
|
// src/lib/command-error.ts
|
|
34517
34532
|
import { formatJson as formatJson4, formatNdjson as formatNdjson4, getErrorMessage as getErrorMessage6 } from "@doist/cli-core";
|
|
34518
34533
|
|
|
@@ -34646,10 +34661,11 @@ async function runApiCommand(command, operation, presentation, execution = {}) {
|
|
|
34646
34661
|
if (exitCode !== void 0) process.exitCode = exitCode;
|
|
34647
34662
|
} catch (error62) {
|
|
34648
34663
|
if (abortController.signal.aborted) {
|
|
34649
|
-
writeFailure(
|
|
34650
|
-
|
|
34651
|
-
|
|
34652
|
-
|
|
34664
|
+
writeFailure(
|
|
34665
|
+
mode,
|
|
34666
|
+
"interrupted",
|
|
34667
|
+
error62 instanceof CliError3 ? renderFailure(error62, { mode, source }) : { message: "Interrupted.", humanMessage: "Interrupted." }
|
|
34668
|
+
);
|
|
34653
34669
|
process.exitCode = 130;
|
|
34654
34670
|
return;
|
|
34655
34671
|
}
|
|
@@ -37251,7 +37267,7 @@ function registerConnectorCommand(program) {
|
|
|
37251
37267
|
}
|
|
37252
37268
|
|
|
37253
37269
|
// src/lib/manifest-input.ts
|
|
37254
|
-
import { CliError as
|
|
37270
|
+
import { CliError as CliError4, getErrorMessage as getErrorMessage7 } from "@doist/cli-core";
|
|
37255
37271
|
import { Option as Option6 } from "commander";
|
|
37256
37272
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
37257
37273
|
import { text } from "node:stream/consumers";
|
|
@@ -37265,7 +37281,7 @@ async function readManifestInput(options, input2 = process.stdin) {
|
|
|
37265
37281
|
try {
|
|
37266
37282
|
return JSON.parse(source.content);
|
|
37267
37283
|
} catch (error62) {
|
|
37268
|
-
throw new
|
|
37284
|
+
throw new CliError4(
|
|
37269
37285
|
"MANIFEST_UNREADABLE",
|
|
37270
37286
|
`${source.label} is not valid JSON: ${getErrorMessage7(error62)}`
|
|
37271
37287
|
);
|
|
@@ -37276,7 +37292,7 @@ async function readSource(options, input2) {
|
|
|
37276
37292
|
try {
|
|
37277
37293
|
return { label: options.file, content: await readFile2(options.file, "utf8") };
|
|
37278
37294
|
} catch (error62) {
|
|
37279
|
-
throw new
|
|
37295
|
+
throw new CliError4(
|
|
37280
37296
|
"MANIFEST_UNREADABLE",
|
|
37281
37297
|
`Could not read ${options.file}: ${getErrorMessage7(error62)}`
|
|
37282
37298
|
);
|
|
@@ -37286,17 +37302,17 @@ async function readSource(options, input2) {
|
|
|
37286
37302
|
try {
|
|
37287
37303
|
return { label: "Standard input", content: await text(input2) };
|
|
37288
37304
|
} catch (error62) {
|
|
37289
|
-
throw new
|
|
37305
|
+
throw new CliError4(
|
|
37290
37306
|
"MANIFEST_UNREADABLE",
|
|
37291
37307
|
`Could not read standard input: ${getErrorMessage7(error62)}`
|
|
37292
37308
|
);
|
|
37293
37309
|
}
|
|
37294
37310
|
}
|
|
37295
|
-
throw new
|
|
37311
|
+
throw new CliError4("MANIFEST_UNREADABLE", "Provide the manifest with --file <path> or --stdin.");
|
|
37296
37312
|
}
|
|
37297
37313
|
|
|
37298
37314
|
// src/commands/draft/draft-service.ts
|
|
37299
|
-
import { CliError as
|
|
37315
|
+
import { CliError as CliError5, getErrorMessage as getErrorMessage8 } from "@doist/cli-core";
|
|
37300
37316
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
37301
37317
|
function createDraft2(draftApi, input2) {
|
|
37302
37318
|
return withRecoveryHints(draftApi, createDraft(draftApi, input2));
|
|
@@ -37329,13 +37345,13 @@ async function withRecoveryHints(draftApi, operation) {
|
|
|
37329
37345
|
const draftId = error62.draftId ?? "<draft-id>";
|
|
37330
37346
|
switch (error62.code) {
|
|
37331
37347
|
case "manifest_invalid":
|
|
37332
|
-
throw new
|
|
37348
|
+
throw new CliError5("MANIFEST_INVALID", error62.message);
|
|
37333
37349
|
case "draft_conflict":
|
|
37334
|
-
throw new
|
|
37350
|
+
throw new CliError5("DRAFT_CONFLICT", error62.message, {
|
|
37335
37351
|
hints: draftHints(scope, draftId)
|
|
37336
37352
|
});
|
|
37337
37353
|
case "draft_manifest_rejected":
|
|
37338
|
-
throw new
|
|
37354
|
+
throw new CliError5("DRAFT_MANIFEST_REJECTED", error62.message, {
|
|
37339
37355
|
hints: draftHints(scope, draftId)
|
|
37340
37356
|
});
|
|
37341
37357
|
case "draft_not_ready":
|
|
@@ -37380,7 +37396,12 @@ async function startDraftTest2(draftApi, {
|
|
|
37380
37396
|
if (!waitFor) {
|
|
37381
37397
|
return { action: "test_started", ...identity, status: started.status };
|
|
37382
37398
|
}
|
|
37383
|
-
|
|
37399
|
+
let finished;
|
|
37400
|
+
try {
|
|
37401
|
+
finished = await waitForDraftTest(draftApi, started, { ...waitFor, signal });
|
|
37402
|
+
} catch (error62) {
|
|
37403
|
+
throw toDraftTestWaitError(error62, identity, signal);
|
|
37404
|
+
}
|
|
37384
37405
|
return {
|
|
37385
37406
|
action: "test_finished",
|
|
37386
37407
|
...identity,
|
|
@@ -37391,9 +37412,25 @@ async function startDraftTest2(draftApi, {
|
|
|
37391
37412
|
result: finished.result
|
|
37392
37413
|
};
|
|
37393
37414
|
}
|
|
37415
|
+
function toDraftTestWaitError(error62, identity, signal) {
|
|
37416
|
+
const run = `test run ${identity.testRunId} of draft ${identity.draftId}`;
|
|
37417
|
+
const hints = [`See how it ends: ${identity.command}`];
|
|
37418
|
+
if (signal.aborted) {
|
|
37419
|
+
return new CliError5(
|
|
37420
|
+
"DRAFT_TEST_WAIT_INTERRUPTED",
|
|
37421
|
+
`Stopped waiting for ${run}. It keeps running.`,
|
|
37422
|
+
{ hints }
|
|
37423
|
+
);
|
|
37424
|
+
}
|
|
37425
|
+
return new CliError5(
|
|
37426
|
+
"DRAFT_TEST_WAIT_FAILED",
|
|
37427
|
+
`Checking on ${run} failed: ${getErrorMessage8(error62).replace(/\.?$/, ".")} It keeps running.`,
|
|
37428
|
+
{ hints }
|
|
37429
|
+
);
|
|
37430
|
+
}
|
|
37394
37431
|
function draftNotReadyError(message, draftId, scope) {
|
|
37395
37432
|
const flag = scopeFlag(scope);
|
|
37396
|
-
return new
|
|
37433
|
+
return new CliError5("DRAFT_NOT_READY", message, {
|
|
37397
37434
|
hints: [
|
|
37398
37435
|
`See the issues: tda draft view ${draftId} ${flag}`,
|
|
37399
37436
|
`Bind connections: tda draft connect ${draftId} --auto ${flag}`
|
|
@@ -37407,13 +37444,13 @@ function toDraftTestCliError(refusal, draftId, scope) {
|
|
|
37407
37444
|
return draftNotReadyError(refusal.message, draftId, scope);
|
|
37408
37445
|
case "draft_test_payload_required":
|
|
37409
37446
|
case "draft_test_payload_filtered":
|
|
37410
|
-
return new
|
|
37447
|
+
return new CliError5(refusal.code.toUpperCase(), refusal.message, {
|
|
37411
37448
|
hints: [
|
|
37412
37449
|
`Test with a real event: tda draft test ${draftId} --trigger <event> --payload-file <path> ${flag}`
|
|
37413
37450
|
]
|
|
37414
37451
|
});
|
|
37415
37452
|
default:
|
|
37416
|
-
return new
|
|
37453
|
+
return new CliError5(refusal.code.toUpperCase(), refusal.message);
|
|
37417
37454
|
}
|
|
37418
37455
|
}
|
|
37419
37456
|
async function readTestPayloadFile(path) {
|
|
@@ -37421,7 +37458,7 @@ async function readTestPayloadFile(path) {
|
|
|
37421
37458
|
try {
|
|
37422
37459
|
content = await readFile3(path, "utf8");
|
|
37423
37460
|
} catch (error62) {
|
|
37424
|
-
throw new
|
|
37461
|
+
throw new CliError5(
|
|
37425
37462
|
"PAYLOAD_UNREADABLE",
|
|
37426
37463
|
`Could not read ${path}: ${getErrorMessage8(error62)}`
|
|
37427
37464
|
);
|
|
@@ -37429,7 +37466,7 @@ async function readTestPayloadFile(path) {
|
|
|
37429
37466
|
try {
|
|
37430
37467
|
return JSON.parse(content);
|
|
37431
37468
|
} catch (error62) {
|
|
37432
|
-
throw new
|
|
37469
|
+
throw new CliError5(
|
|
37433
37470
|
"PAYLOAD_UNREADABLE",
|
|
37434
37471
|
`${path} is not valid JSON: ${getErrorMessage8(error62)}`
|
|
37435
37472
|
);
|
|
@@ -37540,7 +37577,13 @@ function describeDiff(diff) {
|
|
|
37540
37577
|
}
|
|
37541
37578
|
if (diff.steps.added.length > 0) parts.push(`steps added ${diff.steps.added.join(", ")}`);
|
|
37542
37579
|
if (diff.steps.removed.length > 0) parts.push(`steps removed ${diff.steps.removed.join(", ")}`);
|
|
37543
|
-
if (diff.steps.changed.length > 0)
|
|
37580
|
+
if (diff.steps.changed.length > 0) {
|
|
37581
|
+
const changed = diff.steps.changed.map((id) => {
|
|
37582
|
+
const fields = diff.steps.changedFields[id] ?? [];
|
|
37583
|
+
return fields.length > 0 ? `${id} (${fields.join(", ")})` : id;
|
|
37584
|
+
});
|
|
37585
|
+
parts.push(`steps changed ${changed.join(", ")}`);
|
|
37586
|
+
}
|
|
37544
37587
|
if (diff.steps.reordered) parts.push("steps reordered");
|
|
37545
37588
|
return parts.join("; ");
|
|
37546
37589
|
}
|
|
@@ -37612,7 +37655,7 @@ function formatDraftTest(result) {
|
|
|
37612
37655
|
}
|
|
37613
37656
|
|
|
37614
37657
|
// src/commands/draft/validate-command.ts
|
|
37615
|
-
import { CliError as
|
|
37658
|
+
import { CliError as CliError6 } from "@doist/cli-core";
|
|
37616
37659
|
|
|
37617
37660
|
// src/lib/local-command.ts
|
|
37618
37661
|
async function runLocalCommand(command, operation, presentation, execution = {}) {
|
|
@@ -37644,7 +37687,7 @@ function registerDraftValidateCommand(draft) {
|
|
|
37644
37687
|
function validateManifestInput(manifest) {
|
|
37645
37688
|
const validation = validateManifest(manifest);
|
|
37646
37689
|
if (!validation.isValid) {
|
|
37647
|
-
throw new
|
|
37690
|
+
throw new CliError6(
|
|
37648
37691
|
"MANIFEST_INVALID",
|
|
37649
37692
|
`Manifest is invalid: ${validation.errors.join("; ")}`
|
|
37650
37693
|
);
|
|
@@ -37993,11 +38036,11 @@ function registerRunCommand(program) {
|
|
|
37993
38036
|
}
|
|
37994
38037
|
|
|
37995
38038
|
// src/commands/skill/shared.ts
|
|
37996
|
-
import { CliError as
|
|
38039
|
+
import { CliError as CliError7 } from "@doist/cli-core";
|
|
37997
38040
|
function requireInstaller(agent) {
|
|
37998
38041
|
const installer = getInstaller(agent);
|
|
37999
38042
|
if (!installer) {
|
|
38000
|
-
throw new
|
|
38043
|
+
throw new CliError7("UNKNOWN_AGENT", `Unknown agent: ${agent}.`, {
|
|
38001
38044
|
hints: [`Available agents: ${AGENT_NAMES.join(", ")}.`]
|
|
38002
38045
|
});
|
|
38003
38046
|
}
|
|
@@ -38075,7 +38118,7 @@ async function uninstallSkill(agent, options, command) {
|
|
|
38075
38118
|
}
|
|
38076
38119
|
|
|
38077
38120
|
// src/commands/skill/update.ts
|
|
38078
|
-
import { CliError as
|
|
38121
|
+
import { CliError as CliError8 } from "@doist/cli-core";
|
|
38079
38122
|
async function updateSkill(agent, options, command) {
|
|
38080
38123
|
await runLocalCommand(
|
|
38081
38124
|
command,
|
|
@@ -38101,7 +38144,7 @@ async function updateAllSkills(options, command) {
|
|
|
38101
38144
|
async () => {
|
|
38102
38145
|
const result = await updateAllInstalledSkills(options.local === true);
|
|
38103
38146
|
if (result.errors.length > 0) {
|
|
38104
|
-
throw new
|
|
38147
|
+
throw new CliError8(
|
|
38105
38148
|
"UPDATE_FAILED",
|
|
38106
38149
|
`Could not update ${result.errors.length} skill file(s).`,
|
|
38107
38150
|
{ hints: result.errors.map((error62) => `${error62.agent}: ${error62.message}`) }
|