@withandeo/cli 0.11.0 → 0.12.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/README.md +18 -0
- package/dist/api.d.ts +6 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +9 -2
- package/dist/api.js.map +1 -1
- package/dist/artifact-limits.d.ts +8 -0
- package/dist/artifact-limits.d.ts.map +1 -0
- package/dist/artifact-limits.js +10 -0
- package/dist/artifact-limits.js.map +1 -0
- package/dist/artifact.d.ts.map +1 -1
- package/dist/artifact.js +28 -11
- package/dist/artifact.js.map +1 -1
- package/dist/contracts.d.ts +3 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +16 -1
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +100 -6
- package/dist/main.js.map +1 -1
- package/dist/workflow-config.d.ts +9 -0
- package/dist/workflow-config.d.ts.map +1 -0
- package/dist/workflow-config.js +76 -0
- package/dist/workflow-config.js.map +1 -0
- package/dist/workflow-contract.d.ts +34 -0
- package/dist/workflow-contract.d.ts.map +1 -0
- package/dist/workflow-contract.js +96 -0
- package/dist/workflow-contract.js.map +1 -0
- package/dist/workflow-coordinator.d.ts +4 -0
- package/dist/workflow-coordinator.d.ts.map +1 -0
- package/dist/workflow-coordinator.js +49 -0
- package/dist/workflow-coordinator.js.map +1 -0
- package/dist/workflow-dev-host.d.ts +2 -0
- package/dist/workflow-dev-host.d.ts.map +1 -0
- package/dist/workflow-dev-host.js +34 -0
- package/dist/workflow-dev-host.js.map +1 -0
- package/dist/workflow-dev.d.ts +5 -0
- package/dist/workflow-dev.d.ts.map +1 -0
- package/dist/workflow-dev.js +112 -0
- package/dist/workflow-dev.js.map +1 -0
- package/dist/workflow-package.d.ts +5 -0
- package/dist/workflow-package.d.ts.map +1 -0
- package/dist/workflow-package.js +116 -0
- package/dist/workflow-package.js.map +1 -0
- package/package.json +8 -1
- package/skill/tender-accounts/SKILL.md +9 -0
- package/templates/shopify-customer-account/apps/gateway/README.md +2 -0
package/dist/main.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createHash } from "node:crypto";
|
|
|
7
7
|
import { AgentApiClient } from "./api.js";
|
|
8
8
|
import { CLI_AUTH_SCHEMA, DEFAULT_AUTH_PROFILE, createDefaultAuthStore, validateAuthProfile, validateNamedAuthProfile, } from "./auth-store.js";
|
|
9
9
|
import { labelLocalArtifact, verifyArtifact } from "./artifact.js";
|
|
10
|
+
import { packageAppWorkflows } from "./workflow-package.js";
|
|
10
11
|
import { BUILD_ENVELOPE_FILENAME, CLI_CONFIG_SCHEMA, CLI_LINK_SCHEMA, } from "./contracts.js";
|
|
11
12
|
import { CliApiError, CliError } from "./errors.js";
|
|
12
13
|
import { loadProjectContext, normalizeApiUrl, pathExists, readBoundedFile, readOptionalToken, requiredProjectId, resolveArtifactDirectory, safeArtifactPath, writeProjectLink, } from "./files.js";
|
|
@@ -90,6 +91,8 @@ export async function runCli(argv, overrides = {}) {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
async function execute(topic, options, cwd, runtime) {
|
|
94
|
+
if (topic.startsWith("workflows "))
|
|
95
|
+
return { value: await workflowCommand(topic.slice(10), cwd, options, runtime) };
|
|
93
96
|
switch (topic) {
|
|
94
97
|
case "init":
|
|
95
98
|
return { value: await initializeStarter({
|
|
@@ -200,6 +203,52 @@ async function execute(topic, options, cwd, runtime) {
|
|
|
200
203
|
throw new CliError("command_unknown", `Unknown command: ${topic}.`, "tender-accounts --help");
|
|
201
204
|
}
|
|
202
205
|
}
|
|
206
|
+
async function workflowCommand(action, cwd, options, runtime) {
|
|
207
|
+
const context = await optionalContext(cwd);
|
|
208
|
+
const { client, projectId } = await sourceProjectAccess(cwd, context?.link ?? null, options, runtime, false);
|
|
209
|
+
const query = Object.fromEntries(["environment", "limit", "offset", "cursor"].flatMap(key => options.flags.has(key) ? [[key, options.flags.get(key)]] : []));
|
|
210
|
+
if (action === "list")
|
|
211
|
+
return client.appWorkflows(projectId, [], { query });
|
|
212
|
+
if (action === "preview-services")
|
|
213
|
+
return client.appWorkflows(projectId, ["preview-services"]);
|
|
214
|
+
if (action === "preview-service-set")
|
|
215
|
+
return client.appWorkflows(projectId, ["preview-services"], { method: "PUT", body: {
|
|
216
|
+
targetProjectId: requiredFlag(options, "target-project"), previewAppId: requiredFlag(options, "preview") === "none" ? null : requiredFlag(options, "preview"),
|
|
217
|
+
} });
|
|
218
|
+
const scope = requiredFlag(options, "scope");
|
|
219
|
+
if (action === "runs")
|
|
220
|
+
return client.appWorkflows(projectId, [scope, "runs"], { query });
|
|
221
|
+
const id = requiredFlag(options, "run");
|
|
222
|
+
if (action === "acknowledge") {
|
|
223
|
+
if (options.flags.get("confirm") !== id)
|
|
224
|
+
throw new CliError("confirmation_required", "Use --confirm RUN_ID after inspecting history. Acknowledgment does not resend or confirm event delivery.");
|
|
225
|
+
return client.appWorkflows(projectId, [scope, "runs", id, "acknowledge"], { method: "POST", body: { confirm: true, controlId: requiredFlag(options, "control") } });
|
|
226
|
+
}
|
|
227
|
+
if (action === "status")
|
|
228
|
+
return client.appWorkflows(projectId, [scope, "runs", id]);
|
|
229
|
+
if (["history", "diagnostics", "export"].includes(action))
|
|
230
|
+
return client.appWorkflows(projectId, [scope, "runs", id, action], { query });
|
|
231
|
+
let payload = {};
|
|
232
|
+
if (options.flags.has("input-file")) {
|
|
233
|
+
try {
|
|
234
|
+
payload = JSON.parse(new TextDecoder("utf8", { fatal: true }).decode(await readBoundedFile(resolve(cwd, requiredFlag(options, "input-file")), 64 * 1024)));
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
throw new CliError("workflow_input_invalid", "The input file must contain valid JSON of at most 64 KiB. Do not put API credentials in workflow input.");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (action === "start")
|
|
241
|
+
return client.appWorkflows(projectId, [scope, "runs"], { method: "POST", body: { id, params: payload } });
|
|
242
|
+
if (action === "event")
|
|
243
|
+
return client.appWorkflows(projectId, [scope, "runs", id, "sendEvent"], { method: "POST", body: { type: requiredFlag(options, "type"), payload } });
|
|
244
|
+
if (["pause", "resume", "terminate", "restart"].includes(action)) {
|
|
245
|
+
if (["terminate", "restart"].includes(action) && options.flags.get("confirm") !== id) {
|
|
246
|
+
throw new CliError("confirmation_required", "Confirm the exact run with --confirm RUN_ID. Restart can repeat business operations.");
|
|
247
|
+
}
|
|
248
|
+
return client.appWorkflows(projectId, [scope, "runs", id, action], { method: "POST", body: { confirm: true } });
|
|
249
|
+
}
|
|
250
|
+
throw new CliError("command_unknown", "Unknown workflow command.", "andeo workflows --help");
|
|
251
|
+
}
|
|
203
252
|
async function sourceStatus(cwd, options, runtime) {
|
|
204
253
|
const context = await optionalContext(cwd);
|
|
205
254
|
const { client, projectId } = await sourceProjectAccess(cwd, context?.link ?? null, options, runtime, false);
|
|
@@ -1432,6 +1481,20 @@ async function doctor(cwd, options, runtime) {
|
|
|
1432
1481
|
}
|
|
1433
1482
|
async function runDev(cwd, options, runtime) {
|
|
1434
1483
|
const context = await loadProjectContext(cwd);
|
|
1484
|
+
const { readWorkflowConfig } = await import("./workflow-config.js");
|
|
1485
|
+
if ((await readWorkflowConfig(context.root, runtime.environment.WRANGLER_ENV))?.declarations.length) {
|
|
1486
|
+
await buildProject(cwd, options, runtime);
|
|
1487
|
+
const { startWorkflowDev } = await import("./workflow-dev.js");
|
|
1488
|
+
const local = await startWorkflowDev(context.root, resolveArtifactDirectory(context));
|
|
1489
|
+
runtime.stderr.write("Andeo workflow development: http://127.0.0.1:8787 (local execution, not hosted authorization). Restart after rebuilding changes.\n");
|
|
1490
|
+
try {
|
|
1491
|
+
await new Promise(resolve => { const remove = runtime.onInterrupt(() => { remove(); resolve(); }); });
|
|
1492
|
+
}
|
|
1493
|
+
finally {
|
|
1494
|
+
await local.dispose();
|
|
1495
|
+
}
|
|
1496
|
+
return { value: { status: "stopped", workflowExecution: "local" } };
|
|
1497
|
+
}
|
|
1435
1498
|
if (!context.config.commands.dev) {
|
|
1436
1499
|
throw new CliError("dev_command_missing", "This app does not declare commands.dev in tender-accounts.json.");
|
|
1437
1500
|
}
|
|
@@ -1460,6 +1523,7 @@ async function buildProject(cwd, options, runtime) {
|
|
|
1460
1523
|
const source = await sourceState(context.root, runtime);
|
|
1461
1524
|
await runBuildStage(cwd, options, runtime, "check", { TENDER_SOURCE_REVISION: source.revision });
|
|
1462
1525
|
await runBuildStage(cwd, options, runtime, "package", { TENDER_SOURCE_REVISION: source.revision });
|
|
1526
|
+
await packageAppWorkflows(context.root, resolveArtifactDirectory(context), runtime.environment.WRANGLER_ENV);
|
|
1463
1527
|
let artifact = await verifyArtifact(resolveArtifactDirectory(context));
|
|
1464
1528
|
artifact = await labelLocalArtifact(artifact, { gitRevision: source.revision, dirty: source.dirty });
|
|
1465
1529
|
return buildSummary(artifact, source.dirty);
|
|
@@ -1529,6 +1593,7 @@ async function preview(cwd, options, runtime, uploadOnly = false) {
|
|
|
1529
1593
|
previewUrl: session.url,
|
|
1530
1594
|
previewGrantId: session.grantId,
|
|
1531
1595
|
previewExpiresAt: session.expiresAt,
|
|
1596
|
+
sourceVerification: session.sourceVerification,
|
|
1532
1597
|
from: session.from,
|
|
1533
1598
|
entry: session.entry,
|
|
1534
1599
|
selection: session.selection,
|
|
@@ -1574,8 +1639,10 @@ async function previewOpen(cwd, options, runtime) {
|
|
|
1574
1639
|
}
|
|
1575
1640
|
async function deliveryRetry(cwd, options, runtime) {
|
|
1576
1641
|
const context = await loadProjectContext(cwd);
|
|
1642
|
+
if (options.booleans.has("reauthorize") && !context.link)
|
|
1643
|
+
throw new CliError("project_not_linked", "Link the exact app before reauthorizing its preview.", "andeo link --json");
|
|
1577
1644
|
const { client } = await authenticatedClient(cwd, context.link, options, runtime);
|
|
1578
|
-
return await client.retryDelivery(requiredDeliveryId(options));
|
|
1645
|
+
return await client.retryDelivery(requiredDeliveryId(options), options.booleans.has("reauthorize") ? context.link.projectId : undefined);
|
|
1579
1646
|
}
|
|
1580
1647
|
async function authenticatedClient(cwd, link, options, runtime) {
|
|
1581
1648
|
let apiUrl = selectedApiUrl(options, link, runtime.environment, runtime.defaultApiUrl);
|
|
@@ -1902,7 +1969,7 @@ function commandTopic(argv) {
|
|
|
1902
1969
|
const topic = `preview ${argv[1]}`;
|
|
1903
1970
|
return argv.includes("--help") || argv.includes("-h") ? { topic: "help", values: [topic] } : { topic, values: argv.slice(2) };
|
|
1904
1971
|
}
|
|
1905
|
-
if (parent === "auth" || parent === "delivery" || parent === "source" || parent === "skill" || parent === "config" || parent === "production") {
|
|
1972
|
+
if (parent === "auth" || parent === "delivery" || parent === "source" || parent === "skill" || parent === "config" || parent === "production" || parent === "workflows") {
|
|
1906
1973
|
const child = argv[1];
|
|
1907
1974
|
if (!child || child.startsWith("--"))
|
|
1908
1975
|
return { topic: "help", values: [parent] };
|
|
@@ -1932,7 +1999,7 @@ function parseOptions(values) {
|
|
|
1932
1999
|
const booleans = new Set();
|
|
1933
2000
|
const positionals = [];
|
|
1934
2001
|
const booleanNames = new Set([
|
|
1935
|
-
"json", "token-stdin", "dry-run", "no-wait", "force",
|
|
2002
|
+
"json", "token-stdin", "dry-run", "no-wait", "force", "reauthorize",
|
|
1936
2003
|
"device", "wait", "no-open", "local", "all", "production",
|
|
1937
2004
|
]);
|
|
1938
2005
|
for (let index = 0; index < values.length; index += 1) {
|
|
@@ -1965,6 +2032,21 @@ function assertAllowedOptions(topic, options) {
|
|
|
1965
2032
|
const common = ["cwd", "json"];
|
|
1966
2033
|
const authentication = ["api-url", "token-stdin", "profile"];
|
|
1967
2034
|
const allowed = {
|
|
2035
|
+
"workflows list": [...common, ...authentication, "project", "environment", "limit", "offset"],
|
|
2036
|
+
"workflows runs": [...common, ...authentication, "project", "scope", "limit", "offset"],
|
|
2037
|
+
"workflows status": [...common, ...authentication, "project", "scope", "run"],
|
|
2038
|
+
"workflows history": [...common, ...authentication, "project", "scope", "run", "cursor"],
|
|
2039
|
+
"workflows diagnostics": [...common, ...authentication, "project", "scope", "run", "limit", "offset"],
|
|
2040
|
+
"workflows export": [...common, ...authentication, "project", "scope", "run", "limit", "offset"],
|
|
2041
|
+
"workflows start": [...common, ...authentication, "project", "scope", "run", "input-file"],
|
|
2042
|
+
"workflows event": [...common, ...authentication, "project", "scope", "run", "input-file", "type"],
|
|
2043
|
+
"workflows pause": [...common, ...authentication, "project", "scope", "run"],
|
|
2044
|
+
"workflows resume": [...common, ...authentication, "project", "scope", "run"],
|
|
2045
|
+
"workflows restart": [...common, ...authentication, "project", "scope", "run", "confirm"],
|
|
2046
|
+
"workflows acknowledge": [...common, ...authentication, "project", "scope", "run", "control", "confirm"],
|
|
2047
|
+
"workflows terminate": [...common, ...authentication, "project", "scope", "run", "confirm"],
|
|
2048
|
+
"workflows preview-services": [...common, ...authentication, "project"],
|
|
2049
|
+
"workflows preview-service-set": [...common, ...authentication, "project", "target-project", "preview"],
|
|
1968
2050
|
init: [...common, "name", "slug", "directory", "template", "dry-run"],
|
|
1969
2051
|
"config example": common,
|
|
1970
2052
|
"skill print": common,
|
|
@@ -2045,7 +2127,7 @@ function assertAllowedOptions(topic, options) {
|
|
|
2045
2127
|
"sampling-rate",
|
|
2046
2128
|
],
|
|
2047
2129
|
"delivery status": [...common, ...authentication, "delivery"],
|
|
2048
|
-
"delivery retry": [...common, ...authentication, "delivery"],
|
|
2130
|
+
"delivery retry": [...common, ...authentication, "delivery", "reauthorize"],
|
|
2049
2131
|
};
|
|
2050
2132
|
const accepted = new Set(allowed[topic] ?? common);
|
|
2051
2133
|
const provided = [...options.flags.keys(), ...options.booleans];
|
|
@@ -2146,6 +2228,18 @@ function writeOutput(value, options, runtime) {
|
|
|
2146
2228
|
runtime.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
2147
2229
|
}
|
|
2148
2230
|
function helpText(topic) {
|
|
2231
|
+
if (topic === "workflows" || topic?.startsWith("workflows "))
|
|
2232
|
+
return `Usage: andeo workflows <list|runs|status|start|event|pause|resume|terminate|restart|acknowledge|history|diagnostics|export|preview-services|preview-service-set> [options]
|
|
2233
|
+
|
|
2234
|
+
All commands support --project PROJECT_ID and --json. List scopes with workflows list [--environment preview|production].
|
|
2235
|
+
Runs: --scope SCOPE_ID. Inspect/control one run: --scope SCOPE_ID --run APP_LOCAL_ID.
|
|
2236
|
+
Start: --input-file params.json (optional). Event: --type NAME [--input-file event.json].
|
|
2237
|
+
Restart and terminate require --confirm APP_LOCAL_ID. Mutations are never automatically retried.
|
|
2238
|
+
Acknowledge an uncertain event with --control CONTROL_ID --confirm APP_LOCAL_ID after inspection; this never resends or confirms delivery.
|
|
2239
|
+
History resumes with --cursor N; lists/diagnostics/export support --limit 1..100 and --offset N.
|
|
2240
|
+
Choose background preview routing with preview-service-set --target-project PROJECT_ID --preview APP_ID|none.
|
|
2241
|
+
Only non-secret JSON belongs in workflow params/events. Keep credentials in the connected service's native secrets.
|
|
2242
|
+
Account workflow entitlement is required for new starts. Run status is authoritative; list results are a timestamped projection.`;
|
|
2149
2243
|
const topics = {
|
|
2150
2244
|
init: "Usage: andeo init --name NAME [--slug SLUG] [--directory PATH] [--template shopify-customer-account] [--dry-run] [--json]\n\nCreate a new merchant-owned Shopify gateway and React portal in an empty directory.\n\nExamples:\n andeo init --name \"Acme account\" --directory ./acme-account\n andeo init --name \"Acme account\" --directory ./acme-account --dry-run --json",
|
|
2151
2245
|
auth: "Usage: andeo auth <login|create|activate|deactivate|status|list|delete|logout> [options]",
|
|
@@ -2194,7 +2288,7 @@ function helpText(topic) {
|
|
|
2194
2288
|
"delivery status": "Usage: andeo delivery status --delivery dly_... [--json]\n\nRead one developer preview delivery. Do not pass a dwf_ production workflow ID.",
|
|
2195
2289
|
"preview entries": "Usage: andeo preview entries [--json]\n\nList eligible published entry apps and the selected default for this linked app.",
|
|
2196
2290
|
"preview open": "Usage: andeo preview open --from dly_...|sbl_... [--through PROJECT_ID] [--return-path /account] [--json]\n\nOpen the exact deployed preview without rebuilding or uploading. Private apps open through their published connections. Opening again renews access.",
|
|
2197
|
-
"delivery retry": "Usage: andeo delivery retry --delivery dly_... [--json]\n\nRetry one requested or failed developer preview idempotently. A dwf_ production workflow is resumed by a merchant administrator from Activity.",
|
|
2291
|
+
"delivery retry": "Usage: andeo delivery retry --delivery dly_... [--reauthorize] [--json]\n\nRetry one requested or failed developer preview idempotently. --reauthorize explicitly authorizes a legacy preview for the same owner and linked project using the current CLI login; it cannot replace another login's recorded grant or publish production. Normal credential refresh needs no flag. A dwf_ production workflow is resumed by a merchant administrator from Activity.",
|
|
2198
2292
|
skill: "Usage: andeo skill <print|install> [options]",
|
|
2199
2293
|
"skill print": "Usage: andeo skill print [--json]",
|
|
2200
2294
|
"skill install": "Usage: andeo skill install [--agent codex|claude] [--directory PATH] [--force] [--json]\n\nInstall globally for the current user by default: ~/.agents/skills for Codex or ~/.claude/skills for Claude. --directory is an explicit custom or repository-local override.",
|
|
@@ -2203,7 +2297,7 @@ function helpText(topic) {
|
|
|
2203
2297
|
};
|
|
2204
2298
|
if (topic && topics[topic])
|
|
2205
2299
|
return topics[topic];
|
|
2206
|
-
return `Andeo merchant developer CLI ${CLI_VERSION}\n\nCommands:\n init Create a new Shopify account starter\n auth login Create or refresh the default login\n auth create Create or re-authorize a named login\n auth activate Bind a named login to a directory tree\n auth deactivate Remove an exact directory binding\n auth status Validate one login or scoped credential\n auth list List local login profiles and bindings\n auth delete Revoke one named login\n auth logout Revoke the default or every login\n link Link this checkout to one permitted project\n doctor Check developer readiness\n dev Run the project-owned local dev command\n check Run project validation\n build Package and verify a portable artifact\n upload Retain a build for administrator publication\n preview Build and deploy an exact preview\n preview entries List eligible connected entry apps\n preview open Reopen an exact deployed preview\n source status Inspect Andeo-managed Git and recent builds\n source branches List exact managed branches and default policy\n source compare Compare two managed branches\n source connect Connect this linked project to managed Git\n source pull Clone or fast-forward the exact connected repository\n source token Issue a short-lived repository credential\n source push Push the exact commit without persisting a token\n source promote Fast-forward the default after successful preview checks\n source history Run guarded, archived source-history migration\n tail Stream logs for one exact linked project\n delivery status Read preview workflow state\n delivery retry Retry a failed preview workflow\n skill install Install the Andeo agent skill\n config example Print the project configuration contract\n\nThere is intentionally no production publish command.\nRun andeo <command> --help for examples.`;
|
|
2300
|
+
return `Andeo merchant developer CLI ${CLI_VERSION}\n\nCommands:\n init Create a new Shopify account starter\n auth login Create or refresh the default login\n auth create Create or re-authorize a named login\n auth activate Bind a named login to a directory tree\n auth deactivate Remove an exact directory binding\n auth status Validate one login or scoped credential\n auth list List local login profiles and bindings\n auth delete Revoke one named login\n auth logout Revoke the default or every login\n link Link this checkout to one permitted project\n doctor Check developer readiness\n dev Run the project-owned local dev command\n check Run project validation\n build Package and verify a portable artifact\n upload Retain a build for administrator publication\n preview Build and deploy an exact preview\n preview entries List eligible connected entry apps\n preview open Reopen an exact deployed preview\n source status Inspect Andeo-managed Git and recent builds\n source branches List exact managed branches and default policy\n source compare Compare two managed branches\n source connect Connect this linked project to managed Git\n source pull Clone or fast-forward the exact connected repository\n source token Issue a short-lived repository credential\n source push Push the exact commit without persisting a token\n source promote Fast-forward the default after successful preview checks\n source history Run guarded, archived source-history migration\n workflows Inspect and control app-defined background runs\n tail Stream logs for one exact linked project\n delivery status Read preview workflow state\n delivery retry Retry a failed preview workflow\n skill install Install the Andeo agent skill\n config example Print the project configuration contract\n\nThere is intentionally no production publish command.\nRun andeo <command> --help for examples.`;
|
|
2207
2301
|
}
|
|
2208
2302
|
function normalizeError(error) {
|
|
2209
2303
|
if (error instanceof CliApiError) {
|