@fieldwangai/agentflow 0.1.160 → 0.1.163
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/bin/lib/auth.mjs +231 -14
- package/bin/lib/catalog-flows.mjs +2 -0
- package/bin/lib/cli-auth-page.mjs +103 -0
- package/bin/lib/flow-dsl/codegen.mjs +23 -2
- package/bin/lib/flow-dsl/lint.mjs +44 -0
- package/bin/lib/flow-dsl/parser.mjs +68 -1
- package/bin/lib/marketplace-usage.mjs +218 -0
- package/bin/lib/marketplace.mjs +183 -3
- package/bin/lib/node-package-manifest.mjs +1 -1
- package/bin/lib/skill-runtime.mjs +6 -0
- package/bin/lib/spaces.mjs +200 -0
- package/bin/lib/table.mjs +2 -3
- package/bin/lib/ui-server.mjs +471 -84
- package/bin/lib/workspace-draft.mjs +74 -0
- package/bin/lib/workspace-routes.mjs +484 -4
- package/bin/lib/workspace-server.mjs +373 -30
- package/bin/lib/workspace-state.mjs +2 -1
- package/builtin/nodes/agent_subAgent.md +5 -1
- package/builtin/nodes/context_bundle.md +44 -0
- package/builtin/nodes/context_knowledge.md +29 -0
- package/builtin/nodes/context_skills.md +29 -0
- package/builtin/nodes/context_workspace.md +36 -0
- package/builtin/nodes/control_while.md +12 -5
- package/builtin/nodes/tool_git_worktree_load.md +4 -3
- package/builtin/pipelines/new/workspace.flow.js +1 -1
- package/builtin/web-ui/dist/assets/{WorkflowAssistantThread-Bfo9Ythw.js → WorkflowAssistantThread-DmhIgoD7.js} +1 -1
- package/builtin/web-ui/dist/assets/index-CI9J6Unt.js +873 -0
- package/builtin/web-ui/dist/assets/index-DY5vE7v1.css +1 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +5 -1
- package/shared/slot-types.js +1 -0
- package/skills/agentflow-author-flow/SKILL.md +81 -8
- package/skills/agentflow-author-flow/agents/openai.yaml +3 -3
- package/skills/agentflow-cli/SKILL.md +179 -27
- package/skills/agentflow-cli/agents/openai.yaml +2 -2
- package/skills/agentflow-cli/runtime/bin/lib/skill-runtime.mjs +14879 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/agent_subAgent.md +38 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/context_bundle.md +44 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/context_knowledge.md +29 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/context_skills.md +29 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/context_workspace.md +36 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_agent_toBool.md +26 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_anyOne.md +19 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_cancelled.md +26 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_cd_workspace.md +50 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_delay.md +31 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_end.md +13 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_if.md +21 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_interval_loop.md +55 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_load_mcp.md +24 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_load_skills.md +35 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_parse_json.md +25 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_start.md +13 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_subflow_call.md +27 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_toBool.md +27 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_user_workspace.md +24 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_wait_until.md +34 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/control_while.md +131 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_ascii.md +24 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_chart.md +32 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_code.md +39 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_html.md +32 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_image.md +36 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_markdown.md +24 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_mermaid.md +24 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_react_app.md +53 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/display_table.md +32 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/provide_bool.md +14 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/provide_file.md +14 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/provide_json.md +14 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/provide_password.md +14 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/provide_str.md +14 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_display_share_link.md +47 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_get_env.md +20 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_git_checkout.md +70 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_git_worktree_load.md +74 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_git_worktree_unload.md +52 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_gitlab_create_mr.md +114 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_jenkins_build.md +67 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_load_key.md +26 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_nodejs.md +52 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_print.md +21 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_save_key.md +26 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_set_run_env.md +38 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_user_ask.md +27 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_user_check.md +26 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_wecom_send_app_markdown.md +57 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/tool_wecom_send_group_markdown.md +45 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/workspace_one_click_task.md +44 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/workspace_run.md +16 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/workspace_scheduled_run.md +16 -0
- package/skills/agentflow-cli/runtime/builtin/nodes/workspace_subflow_input.md +14 -0
- package/skills/agentflow-cli/runtime/package.json +6 -0
- package/skills/agentflow-cli/scripts/agentflow-auth-store.mjs +113 -0
- package/skills/agentflow-cli/scripts/agentflow-cli.mjs +457 -28
- package/skills/agentflow-cli/scripts/agentflow-runtime.mjs +11 -4
- package/skills/agentflow-flow-add-instances/SKILL.md +2 -2
- package/skills/agentflow-flow-dsl/SKILL.md +73 -8
- package/skills/agentflow-flow-dsl/agents/openai.yaml +2 -2
- package/skills/agentflow-flow-dsl/references/node-calls.md +6 -2
- package/skills/agentflow-flow-dsl/references/subflow-authoring.md +34 -7
- package/skills/agentflow-flow-edit-node-fields/SKILL.md +3 -3
- package/skills/agentflow-flow-recipes/SKILL.md +1 -1
- package/skills/agentflow-flow-recipes/references/recipes.md +1 -2
- package/skills/agentflow-flow-sync-ui/SKILL.md +1 -1
- package/skills/agentflow-node-dsl/SKILL.md +5 -13
- package/skills/agentflow-node-reference/references/builtin-nodes.md +37 -5
- package/skills/agentflow-workspace-markdown/SKILL.md +1 -1
- package/builtin/web-ui/dist/assets/index-XbeI5foV.js +0 -872
- package/builtin/web-ui/dist/assets/index-e1omCEau.css +0 -1
- package/skills/agentflow-workspace-graph/SKILL.md +0 -85
|
@@ -7,6 +7,15 @@ import {
|
|
|
7
7
|
loadAgentFlowRuntime,
|
|
8
8
|
resolveAgentFlowPackageRoot,
|
|
9
9
|
} from "./agentflow-runtime.mjs";
|
|
10
|
+
import {
|
|
11
|
+
agentFlowAuthFile,
|
|
12
|
+
clearAgentFlowPendingAuthorization,
|
|
13
|
+
clearAgentFlowProfile,
|
|
14
|
+
saveAgentFlowPendingAuthorization,
|
|
15
|
+
saveAgentFlowProfile,
|
|
16
|
+
savedAgentFlowPendingAuthorization,
|
|
17
|
+
savedAgentFlowProfile,
|
|
18
|
+
} from "./agentflow-auth-store.mjs";
|
|
10
19
|
import { createWorkflowReportClient } from "./workflow-report-client.mjs";
|
|
11
20
|
|
|
12
21
|
const DEFAULT_BASE_URL = "http://ai.mengma.bigo.inner/";
|
|
@@ -48,13 +57,20 @@ Usage:
|
|
|
48
57
|
Config:
|
|
49
58
|
--base-url <url> Override AGENTFLOW_BASE_URL
|
|
50
59
|
--token <token> Override AGENTFLOW_TOKEN
|
|
51
|
-
--agentflow-package-root <dir>
|
|
60
|
+
--agentflow-package-root <dir> Development override for the bundled Skill runtime
|
|
52
61
|
AGENTFLOW_BASE_URL Defaults to ${DEFAULT_BASE_URL}
|
|
53
|
-
AGENTFLOW_TOKEN
|
|
62
|
+
AGENTFLOW_TOKEN Overrides saved browser authorization
|
|
54
63
|
AGENTFLOW_ENV_FILE Optional dotenv file path
|
|
64
|
+
AGENTFLOW_AUTH_FILE Optional saved authorization path
|
|
55
65
|
|
|
56
66
|
Commands:
|
|
57
67
|
config
|
|
68
|
+
auth start | auth login
|
|
69
|
+
auth complete
|
|
70
|
+
auth status
|
|
71
|
+
auth logout
|
|
72
|
+
dsl-lint --file <flowDir|workspace.flow.js> [--workspace-root <dir>]
|
|
73
|
+
dsl-layout --file <flowDir|workspace.flow.js> [--workspace-root <dir>] [--all]
|
|
58
74
|
list-workspace | list-workspaces
|
|
59
75
|
list-flows
|
|
60
76
|
node-package-list
|
|
@@ -62,18 +78,32 @@ Commands:
|
|
|
62
78
|
node-package-publish --file <nodePackageDir>
|
|
63
79
|
node-package-install --node <id>@<version> [--workspace-root <dir>]
|
|
64
80
|
node-package-sync --flow <flowDir|workspace.flow.js> [--workspace-root <dir>]
|
|
81
|
+
marketplace-list [--kind flow|node] [--owned] [--query <text>]
|
|
82
|
+
marketplace-flow-publish --flow-id <id> [--flow-source user] [--version 1.0.0] [--visibility public|private]
|
|
83
|
+
marketplace-flow-install --flow <id>@<version> [--flow-id <targetId>]
|
|
84
|
+
marketplace-visibility --kind flow|node --resource <id>@<version> --visibility public|private
|
|
65
85
|
pull-flow --flow-id <id> [--flow-source user] [--output <flowDir>] [--workspace-root <dir>] [--replace]
|
|
66
|
-
publish-flow --flow-id <id> --file <flowDir|workspace.flow.js|flow.yaml> [--target-space personal|workspace|team] [--with-dependencies] [--replace]
|
|
86
|
+
publish-flow --flow-id <id> --file <flowDir|workspace.flow.js|flow.yaml> [--target-space personal|workspace|team] [--schedule enabled|disabled|preserve] [--with-dependencies] [--replace]
|
|
67
87
|
get-graph --flow-id <id> [--flow-source user]
|
|
68
88
|
migrate-flow --flow-id <id> [--flow-source user] [--archived] [--allow-loss]
|
|
69
89
|
migrate-all [--include-archived] [--allow-loss] [--dry-run]
|
|
70
90
|
workspace-preview --file <flowDir|workspace.flow.js|workspace.graph.json> [--preview-id <id>] [--ttl-seconds <n>]
|
|
91
|
+
draft-create --file <flowDir|workspace.flow.js|workspace.graph.json> [--draft-id <id>] [--ttl-seconds <n>] [--with-dependencies]
|
|
92
|
+
draft-pull --draft-id <id> [--output <flowDir>] [--workspace-root <dir>] [--replace]
|
|
93
|
+
draft-update --draft-id <id> --base-revision <revision> --file <flowDir|workspace.flow.js|workspace.graph.json> [--ttl-seconds <n>] [--with-dependencies]
|
|
94
|
+
draft-run --draft-id <id> [--run-node-id <id>] [--input k=v]
|
|
95
|
+
draft-publish --draft-id <id> --flow-id <id> [--target-space personal|workspace|team] [--schedule enabled|disabled|preserve]
|
|
71
96
|
run --flow-id <id> [--flow-source user] [--run-node-id <id>] [--input k=v]
|
|
72
97
|
status --flow-id <id> [--flow-source user]
|
|
73
98
|
list-run-by-workspace | list-runs-by-workspace --workspace <flowId> [--limit 20]
|
|
74
99
|
list-runs [--flow-id <id>] [--flow-source user] [--limit 20]
|
|
75
100
|
logs --run-id <id>
|
|
76
101
|
display-outputs --flow-id <id> [--flow-source user]
|
|
102
|
+
schedule-list [--flow-id <id>] [--flow-source user]
|
|
103
|
+
schedule-set --flow-id <id> --schedule-node-id <id> [--enabled true|false] [--cron <expr>] [--timezone <tz>] [--overlap-policy skip]
|
|
104
|
+
schedule-enable --flow-id <id> --schedule-node-id <id>
|
|
105
|
+
schedule-disable --flow-id <id> --schedule-node-id <id>
|
|
106
|
+
schedule-run-now --flow-id <id> --schedule-node-id <id> [--input k=v]
|
|
77
107
|
sync-workspace --workspace <id>
|
|
78
108
|
workflow-get --workflow tapd:<id> [--flow-id <id>] [--runtime-only] [--admin-operation repair-version-membership]
|
|
79
109
|
workflow-access-sync --workflow tapd:<id> --file <access.json>
|
|
@@ -158,11 +188,23 @@ function normalizedBaseUrl(args) {
|
|
|
158
188
|
return String(raw).replace(/\/+$/, "");
|
|
159
189
|
}
|
|
160
190
|
|
|
191
|
+
function resolvedAuth(args) {
|
|
192
|
+
const fromFlag = option(args, "token");
|
|
193
|
+
if (fromFlag) return { token: fromFlag, source: "flag", profile: null };
|
|
194
|
+
const fromTokenEnv = String(process.env.AGENTFLOW_TOKEN || "").trim();
|
|
195
|
+
if (fromTokenEnv) return { token: fromTokenEnv, source: "AGENTFLOW_TOKEN", profile: null };
|
|
196
|
+
const fromSessionEnv = String(process.env.AGENTFLOW_SESSION_TOKEN || "").trim();
|
|
197
|
+
if (fromSessionEnv) return { token: fromSessionEnv, source: "AGENTFLOW_SESSION_TOKEN", profile: null };
|
|
198
|
+
const profile = savedAgentFlowProfile(normalizedBaseUrl(args));
|
|
199
|
+
return profile?.token
|
|
200
|
+
? { token: profile.token, source: "saved-auth", profile }
|
|
201
|
+
: { token: "", source: "", profile: null };
|
|
202
|
+
}
|
|
203
|
+
|
|
161
204
|
function authToken(args, required = true) {
|
|
162
|
-
const
|
|
163
|
-
const trimmed = String(token).trim();
|
|
205
|
+
const trimmed = String(resolvedAuth(args).token || "").trim();
|
|
164
206
|
if (required && !trimmed) {
|
|
165
|
-
throw new Error("
|
|
207
|
+
throw new Error("AgentFlow authorization is missing. Run `auth start`, open the returned URL, then run `auth complete`; or set AGENTFLOW_TOKEN.");
|
|
166
208
|
}
|
|
167
209
|
return trimmed;
|
|
168
210
|
}
|
|
@@ -333,6 +375,11 @@ function searchNodePackageCatalog(nodes, queryText, limitValue) {
|
|
|
333
375
|
inputs: node.inputs || node.input || [],
|
|
334
376
|
outputs: node.outputs || node.output || [],
|
|
335
377
|
contentSha256: node.contentSha256 || "",
|
|
378
|
+
visibility: node.visibility || "public",
|
|
379
|
+
useCount: Number(node.useCount || 0),
|
|
380
|
+
installCount: Number(node.installCount || 0),
|
|
381
|
+
uniqueUserCount: Number(node.uniqueUserCount || 0),
|
|
382
|
+
lastUsedAt: node.lastUsedAt || "",
|
|
336
383
|
installCommand: `node-package-install --node ${node.id}@${node.version}`,
|
|
337
384
|
}));
|
|
338
385
|
}
|
|
@@ -488,6 +535,7 @@ async function pullFlow(args) {
|
|
|
488
535
|
ok: true,
|
|
489
536
|
flowId,
|
|
490
537
|
flowSource,
|
|
538
|
+
draft: current.draft === true,
|
|
491
539
|
outputDir,
|
|
492
540
|
revision: current.revision || "",
|
|
493
541
|
format: written.format,
|
|
@@ -529,6 +577,60 @@ function parseInputs(args) {
|
|
|
529
577
|
return inputs;
|
|
530
578
|
}
|
|
531
579
|
|
|
580
|
+
function parseBooleanOption(value, name) {
|
|
581
|
+
if (value === true || value === "true" || value === "1") return true;
|
|
582
|
+
if (value === false || value === "false" || value === "0") return false;
|
|
583
|
+
throw new Error(`${name} must be true or false.`);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
async function runRemoteWorkspace(args, { flowId, flowSource = "user", runNodeId = "" }) {
|
|
587
|
+
const graphPayload = await httpJson(args, `/api/workspace/graph${query({ flowId, flowSource })}`);
|
|
588
|
+
const result = await httpJson(args, "/api/workspace/run", {
|
|
589
|
+
method: "POST",
|
|
590
|
+
body: {
|
|
591
|
+
flowId,
|
|
592
|
+
flowSource,
|
|
593
|
+
runNodeId,
|
|
594
|
+
runAlias: option(args, "run-alias") || "",
|
|
595
|
+
graph: graphPayload.graph,
|
|
596
|
+
inputs: parseInputs(args),
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
return {
|
|
600
|
+
...result,
|
|
601
|
+
displayOutputs: extractDisplayOutputs(result?.graph),
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async function prepareDraftGraph(args) {
|
|
606
|
+
const requestedFile = option(args, "file");
|
|
607
|
+
const withDependencies = args["with-dependencies"] === true;
|
|
608
|
+
let publishedNodePackages = [];
|
|
609
|
+
let rewrittenImports = [];
|
|
610
|
+
if (withDependencies) {
|
|
611
|
+
const rawSource = readFlowSourceFile(requestedFile, { allowPackageDependencies: true });
|
|
612
|
+
const source = await prepareFlowWithDependencies(args, requestedFile, rawSource);
|
|
613
|
+
publishedNodePackages = source.publishedNodePackages || [];
|
|
614
|
+
rewrittenImports = source.rewrittenImports || [];
|
|
615
|
+
}
|
|
616
|
+
const graph = await readWorkspaceGraphArg(requestedFile, path.resolve(option(args, "workspace-root") || process.cwd()));
|
|
617
|
+
const nodeDependencies = await graphNodePackageDependencies(graph);
|
|
618
|
+
if (nodeDependencies.length) {
|
|
619
|
+
const remoteByKey = await remoteNodePackageCatalog(args);
|
|
620
|
+
const missing = nodeDependencies.filter((item) => !remoteByKey.has(`${item.id}@${item.version}`));
|
|
621
|
+
if (missing.length) {
|
|
622
|
+
throw new Error(`Cannot create draft: server is missing node packages ${missing.map((item) => item.specifier).join(", ")}.`);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
graph,
|
|
627
|
+
file: path.resolve(String(requestedFile || "")),
|
|
628
|
+
nodeDependencies: nodeDependencies.map((item) => item.specifier),
|
|
629
|
+
publishedNodePackages,
|
|
630
|
+
rewrittenImports,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
532
634
|
function slotText(slots, names = []) {
|
|
533
635
|
const wanted = new Set(names.map(String));
|
|
534
636
|
for (const slot of Array.isArray(slots) ? slots : []) {
|
|
@@ -566,6 +668,125 @@ function printJson(data) {
|
|
|
566
668
|
process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
|
|
567
669
|
}
|
|
568
670
|
|
|
671
|
+
function authAction(command, args) {
|
|
672
|
+
if (command === "auth") return String(args._[1] || "status").trim().toLowerCase();
|
|
673
|
+
if (command.startsWith("auth-")) return command.slice("auth-".length).toLowerCase();
|
|
674
|
+
return "";
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
async function runAuthCommand(action, args) {
|
|
678
|
+
const baseUrl = normalizedBaseUrl(args);
|
|
679
|
+
if (action === "start" || action === "login") {
|
|
680
|
+
const authorization = await httpJson(args, "/api/auth/cli/device", {
|
|
681
|
+
method: "POST",
|
|
682
|
+
tokenRequired: false,
|
|
683
|
+
body: {
|
|
684
|
+
clientName: option(args, "client-name") || "AgentFlow CLI",
|
|
685
|
+
},
|
|
686
|
+
});
|
|
687
|
+
const saved = saveAgentFlowPendingAuthorization(baseUrl, authorization);
|
|
688
|
+
printJson({
|
|
689
|
+
status: "authorization_required",
|
|
690
|
+
baseUrl,
|
|
691
|
+
requestId: saved.requestId,
|
|
692
|
+
userCode: saved.userCode,
|
|
693
|
+
verificationUrl: saved.verificationUrl,
|
|
694
|
+
expiresAt: saved.expiresAt,
|
|
695
|
+
next: "Open verificationUrl, approve access, then run `auth complete`.",
|
|
696
|
+
});
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (action === "complete") {
|
|
701
|
+
const pending = savedAgentFlowPendingAuthorization(baseUrl);
|
|
702
|
+
if (!pending?.deviceCode) {
|
|
703
|
+
throw new Error("No pending AgentFlow authorization. Run `auth start` first.");
|
|
704
|
+
}
|
|
705
|
+
let result;
|
|
706
|
+
try {
|
|
707
|
+
result = await httpJson(args, "/api/auth/cli/token", {
|
|
708
|
+
method: "POST",
|
|
709
|
+
tokenRequired: false,
|
|
710
|
+
body: { deviceCode: pending.deviceCode },
|
|
711
|
+
});
|
|
712
|
+
} catch (error) {
|
|
713
|
+
const code = String(error?.response?.code || "");
|
|
714
|
+
if (["access_denied", "expired_token", "invalid_grant"].includes(code)) {
|
|
715
|
+
clearAgentFlowPendingAuthorization(baseUrl);
|
|
716
|
+
}
|
|
717
|
+
throw error;
|
|
718
|
+
}
|
|
719
|
+
if (result?.code === "authorization_pending") {
|
|
720
|
+
printJson({
|
|
721
|
+
status: "authorization_pending",
|
|
722
|
+
baseUrl,
|
|
723
|
+
requestId: pending.requestId,
|
|
724
|
+
verificationUrl: pending.verificationUrl,
|
|
725
|
+
expiresAt: pending.expiresAt,
|
|
726
|
+
});
|
|
727
|
+
process.exitCode = 2;
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (!result?.token) throw new Error("AgentFlow authorization exchange did not return a token.");
|
|
731
|
+
const saved = saveAgentFlowProfile(baseUrl, result);
|
|
732
|
+
printJson({
|
|
733
|
+
status: "authenticated",
|
|
734
|
+
baseUrl,
|
|
735
|
+
user: result.user || null,
|
|
736
|
+
scopes: Array.isArray(result.scopes) ? result.scopes : [],
|
|
737
|
+
expiresAt: result.expiresAt || 0,
|
|
738
|
+
credentialFile: saved.file,
|
|
739
|
+
});
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (action === "status") {
|
|
744
|
+
const auth = resolvedAuth(args);
|
|
745
|
+
if (!auth.token) {
|
|
746
|
+
printJson({ authenticated: false, baseUrl, tokenSource: "", credentialFile: agentFlowAuthFile() });
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const me = await httpJson(args, "/api/auth/me", { tokenRequired: false });
|
|
750
|
+
printJson({
|
|
751
|
+
authenticated: Boolean(me?.authenticated),
|
|
752
|
+
baseUrl,
|
|
753
|
+
tokenSource: auth.source,
|
|
754
|
+
user: me?.user || null,
|
|
755
|
+
expiresAt: auth.profile?.expiresAt || me?.user?.sessionExpiresAt || 0,
|
|
756
|
+
credentialFile: auth.source === "saved-auth" ? agentFlowAuthFile() : "",
|
|
757
|
+
});
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (action === "logout") {
|
|
762
|
+
const auth = resolvedAuth(args);
|
|
763
|
+
let revoked = false;
|
|
764
|
+
let remoteError = "";
|
|
765
|
+
if (auth.token) {
|
|
766
|
+
try {
|
|
767
|
+
const response = await httpJson(args, "/api/auth/cli/revoke", { method: "POST", body: {} });
|
|
768
|
+
revoked = Boolean(response?.ok);
|
|
769
|
+
} catch (error) {
|
|
770
|
+
remoteError = error?.message || String(error);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
const localCleared = clearAgentFlowProfile(baseUrl);
|
|
774
|
+
printJson({
|
|
775
|
+
authenticated: false,
|
|
776
|
+
baseUrl,
|
|
777
|
+
revoked,
|
|
778
|
+
localCleared,
|
|
779
|
+
tokenSource: auth.source,
|
|
780
|
+
warning: auth.source && auth.source !== "saved-auth"
|
|
781
|
+
? `${auth.source} is still configured outside the CLI credential store.`
|
|
782
|
+
: remoteError || "",
|
|
783
|
+
});
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
throw new Error(`Unknown auth command: ${action}. Use auth start, complete, status, or logout.`);
|
|
788
|
+
}
|
|
789
|
+
|
|
569
790
|
function requireFlowId(args) {
|
|
570
791
|
const flowId = option(args, "flow-id") || option(args, "flow");
|
|
571
792
|
if (!flowId) throw new Error("Missing --flow-id.");
|
|
@@ -755,16 +976,48 @@ function isMissingPublishedFlowError(error) {
|
|
|
755
976
|
return error?.status === 400 && /Pipeline directory not found/i.test(String(error?.message || ""));
|
|
756
977
|
}
|
|
757
978
|
|
|
758
|
-
async function importFlow(args, { flowId, targetSpace, resolved, flowYaml }) {
|
|
979
|
+
async function importFlow(args, { flowId, targetSpace, scheduleMode = "disabled", resolved, flowYaml }) {
|
|
759
980
|
const form = new FormData();
|
|
760
981
|
form.set("flowId", flowId);
|
|
761
982
|
form.set("targetSpace", targetSpace);
|
|
983
|
+
form.set("scheduleMode", scheduleMode);
|
|
762
984
|
const name = path.basename(resolved);
|
|
763
985
|
const mime = /\.m?js$/i.test(name) ? "application/javascript" : "application/yaml";
|
|
764
986
|
form.set("file", new Blob([flowYaml], { type: mime }), name);
|
|
765
987
|
return httpMultipart(args, "/api/flows/import", form);
|
|
766
988
|
}
|
|
767
989
|
|
|
990
|
+
function normalizeScheduleMode(args, fallback = "disabled") {
|
|
991
|
+
const scheduleMode = String(option(args, "schedule") || fallback).trim().toLowerCase();
|
|
992
|
+
if (!["enabled", "disabled", "preserve"].includes(scheduleMode)) {
|
|
993
|
+
throw new Error("--schedule must be enabled, disabled, or preserve.");
|
|
994
|
+
}
|
|
995
|
+
return scheduleMode;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
function graphWithScheduleMode(graph, scheduleMode = "disabled") {
|
|
999
|
+
if (scheduleMode === "preserve") return graph;
|
|
1000
|
+
const instances = { ...(graph?.instances || {}) };
|
|
1001
|
+
let scheduleCount = 0;
|
|
1002
|
+
for (const [nodeId, instance] of Object.entries(instances)) {
|
|
1003
|
+
if (String(instance?.definitionId || "") !== "workspace_scheduled_run") continue;
|
|
1004
|
+
scheduleCount += 1;
|
|
1005
|
+
let config = {};
|
|
1006
|
+
try {
|
|
1007
|
+
const parsed = JSON.parse(String(instance.body || "{}"));
|
|
1008
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) config = parsed;
|
|
1009
|
+
} catch {}
|
|
1010
|
+
instances[nodeId] = {
|
|
1011
|
+
...instance,
|
|
1012
|
+
body: JSON.stringify({ ...config, enabled: scheduleMode === "enabled" }),
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (scheduleMode === "enabled" && scheduleCount === 0) {
|
|
1016
|
+
throw new Error("Cannot enable scheduling: the Flow has no Scheduled Run node.");
|
|
1017
|
+
}
|
|
1018
|
+
return { ...graph, instances };
|
|
1019
|
+
}
|
|
1020
|
+
|
|
768
1021
|
async function resolvePublishTeam(args, shareWithTeam) {
|
|
769
1022
|
if (!shareWithTeam) return null;
|
|
770
1023
|
const result = await httpJson(args, "/api/teams/me");
|
|
@@ -793,6 +1046,12 @@ async function main() {
|
|
|
793
1046
|
return;
|
|
794
1047
|
}
|
|
795
1048
|
|
|
1049
|
+
const selectedAuthAction = authAction(command, args);
|
|
1050
|
+
if (selectedAuthAction) {
|
|
1051
|
+
await runAuthCommand(selectedAuthAction, args);
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
796
1055
|
if (command === "config") {
|
|
797
1056
|
let localRuntime = { available: false, root: "", version: "" };
|
|
798
1057
|
try {
|
|
@@ -802,15 +1061,39 @@ async function main() {
|
|
|
802
1061
|
} catch (error) {
|
|
803
1062
|
localRuntime.error = error?.message || String(error);
|
|
804
1063
|
}
|
|
1064
|
+
const auth = resolvedAuth(args);
|
|
805
1065
|
printJson({
|
|
806
1066
|
baseUrl: normalizedBaseUrl(args),
|
|
807
|
-
hasToken: Boolean(
|
|
808
|
-
tokenSource:
|
|
1067
|
+
hasToken: Boolean(auth.token),
|
|
1068
|
+
tokenSource: auth.source,
|
|
1069
|
+
credentialFile: auth.source === "saved-auth" ? agentFlowAuthFile() : "",
|
|
809
1070
|
localRuntime,
|
|
810
1071
|
});
|
|
811
1072
|
return;
|
|
812
1073
|
}
|
|
813
1074
|
|
|
1075
|
+
if (command === "dsl-lint" || command === "dsl-layout") {
|
|
1076
|
+
const target = option(args, "file");
|
|
1077
|
+
if (!target) throw new Error(`${command} requires --file <flowDir|workspace.flow.js>.`);
|
|
1078
|
+
const resolved = path.resolve(target);
|
|
1079
|
+
const stat = fs.statSync(resolved);
|
|
1080
|
+
const flowDir = stat.isDirectory() ? resolved : path.dirname(resolved);
|
|
1081
|
+
const workspaceRoot = path.resolve(option(args, "workspace-root") || process.cwd());
|
|
1082
|
+
const runtime = await loadAgentFlowRuntime();
|
|
1083
|
+
if (command === "dsl-lint") {
|
|
1084
|
+
const result = runtime.lintWorkspaceFlowDir(flowDir, { workspaceRoot });
|
|
1085
|
+
printJson(result);
|
|
1086
|
+
if (result.errors.length) process.exitCode = 1;
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
const result = runtime.layoutWorkspaceFlowDir(flowDir, {
|
|
1090
|
+
all: args.all === true,
|
|
1091
|
+
workspaceRoot,
|
|
1092
|
+
});
|
|
1093
|
+
printJson(result);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
814
1097
|
if (command === "list-workspace" || command === "list-workspaces") {
|
|
815
1098
|
printJson(await httpJson(args, "/api/workspaces"));
|
|
816
1099
|
return;
|
|
@@ -878,6 +1161,61 @@ async function main() {
|
|
|
878
1161
|
return;
|
|
879
1162
|
}
|
|
880
1163
|
|
|
1164
|
+
if (command === "marketplace-list") {
|
|
1165
|
+
const kind = String(option(args, "kind") || "flow").trim().toLowerCase();
|
|
1166
|
+
if (kind !== "flow" && kind !== "node") throw new Error("--kind must be flow or node.");
|
|
1167
|
+
const result = await httpJson(args, `/api/marketplace/resources${query({
|
|
1168
|
+
kind,
|
|
1169
|
+
scope: args.owned === true ? "owned" : "",
|
|
1170
|
+
q: option(args, "query") || option(args, "q"),
|
|
1171
|
+
sort: "useCount",
|
|
1172
|
+
order: "desc",
|
|
1173
|
+
})}`);
|
|
1174
|
+
printJson(result);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
if (command === "marketplace-flow-publish") {
|
|
1179
|
+
const flowId = requireFlowId(args);
|
|
1180
|
+
const visibility = String(option(args, "visibility") || "public").trim().toLowerCase();
|
|
1181
|
+
if (visibility !== "public" && visibility !== "private") throw new Error("--visibility must be public or private.");
|
|
1182
|
+
printJson(await httpJson(args, "/api/marketplace/flows/publish", {
|
|
1183
|
+
method: "POST",
|
|
1184
|
+
body: {
|
|
1185
|
+
flowId,
|
|
1186
|
+
flowSource: option(args, "flow-source") || "user",
|
|
1187
|
+
id: option(args, "marketplace-id") || flowId,
|
|
1188
|
+
displayName: option(args, "display-name") || flowId,
|
|
1189
|
+
description: option(args, "description") || "",
|
|
1190
|
+
version: option(args, "version") || "1.0.0",
|
|
1191
|
+
visibility,
|
|
1192
|
+
},
|
|
1193
|
+
}));
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (command === "marketplace-flow-install") {
|
|
1198
|
+
const spec = parseNodePackageSpec(option(args, "flow"));
|
|
1199
|
+
printJson(await httpJson(args, "/api/marketplace/flows/install", {
|
|
1200
|
+
method: "POST",
|
|
1201
|
+
body: { id: spec.id, version: spec.version, flowId: option(args, "flow-id") || spec.id },
|
|
1202
|
+
}));
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
if (command === "marketplace-visibility") {
|
|
1207
|
+
const kind = String(option(args, "kind") || "").trim().toLowerCase();
|
|
1208
|
+
if (kind !== "flow" && kind !== "node") throw new Error("--kind must be flow or node.");
|
|
1209
|
+
const spec = parseNodePackageSpec(option(args, "resource"));
|
|
1210
|
+
const visibility = String(option(args, "visibility") || "").trim().toLowerCase();
|
|
1211
|
+
if (visibility !== "public" && visibility !== "private") throw new Error("--visibility must be public or private.");
|
|
1212
|
+
printJson(await httpJson(args, "/api/marketplace/visibility", {
|
|
1213
|
+
method: "PATCH",
|
|
1214
|
+
body: { kind, id: spec.id, version: spec.version, visibility },
|
|
1215
|
+
}));
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
881
1219
|
if (command === "pull-flow") {
|
|
882
1220
|
const result = await pullFlow(args);
|
|
883
1221
|
printJson(result);
|
|
@@ -885,10 +1223,23 @@ async function main() {
|
|
|
885
1223
|
return;
|
|
886
1224
|
}
|
|
887
1225
|
|
|
1226
|
+
if (command === "draft-pull") {
|
|
1227
|
+
const draftId = option(args, "draft-id");
|
|
1228
|
+
if (!draftId) throw new Error("draft-pull requires --draft-id <id>.");
|
|
1229
|
+
args["flow-id"] = draftId;
|
|
1230
|
+
args["flow-source"] = "user";
|
|
1231
|
+
const result = await pullFlow(args);
|
|
1232
|
+
if (result.ok && result.draft !== true) throw new Error(`${draftId} is not a Workspace Draft.`);
|
|
1233
|
+
printJson({ ...result, draftId });
|
|
1234
|
+
if (!result.ok) process.exitCode = 2;
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
888
1238
|
if (command === "publish-flow") {
|
|
889
1239
|
const flowId = requireFlowId(args);
|
|
890
1240
|
const destination = targetDestinationFromArgs(args);
|
|
891
1241
|
const targetSpace = destination.flowSource;
|
|
1242
|
+
const scheduleMode = normalizeScheduleMode(args);
|
|
892
1243
|
const withDependencies = args["with-dependencies"] === true;
|
|
893
1244
|
const requestedFile = option(args, "file");
|
|
894
1245
|
const rawSource = readFlowSourceFile(requestedFile, { allowPackageDependencies: withDependencies });
|
|
@@ -915,7 +1266,7 @@ async function main() {
|
|
|
915
1266
|
const dependencyPreflight = await preflightRemoteFlowDependencies(args, source);
|
|
916
1267
|
|
|
917
1268
|
if (!replace) {
|
|
918
|
-
const result = await importFlow(args, { flowId, targetSpace, ...source });
|
|
1269
|
+
const result = await importFlow(args, { flowId, targetSpace, scheduleMode, ...source });
|
|
919
1270
|
const sharedTeam = await sharePublishedFlowWithTeam(args, { flowId, flowSource: targetSpace, team });
|
|
920
1271
|
printJson({ ...result, action: "created", targetSpace: team ? "team" : targetSpace, team: sharedTeam, file: source.resolved, nodeDependencies: dependencyPreflight.map((item) => item.specifier), rewrittenImports: source.rewrittenImports || [], publishedNodePackages: source.publishedNodePackages || [] });
|
|
921
1272
|
return;
|
|
@@ -924,16 +1275,16 @@ async function main() {
|
|
|
924
1275
|
// 更新走哪条路取决于存储格式:yaml 流程改 /api/flow,代码化流程改 Workspace 图。
|
|
925
1276
|
// /api/flow 只认 flowYaml 字符串,代码化的流程发过去等于把图退回成 yaml。
|
|
926
1277
|
if (!current) {
|
|
927
|
-
const result = await importFlow(args, { flowId, targetSpace, ...source });
|
|
1278
|
+
const result = await importFlow(args, { flowId, targetSpace, scheduleMode, ...source });
|
|
928
1279
|
const sharedTeam = await sharePublishedFlowWithTeam(args, { flowId, flowSource: targetSpace, team });
|
|
929
1280
|
printJson({ ...result, action: "created", targetSpace: team ? "team" : targetSpace, team: sharedTeam, file: source.resolved, nodeDependencies: dependencyPreflight.map((item) => item.specifier), rewrittenImports: source.rewrittenImports || [], publishedNodePackages: source.publishedNodePackages || [] });
|
|
930
1281
|
return;
|
|
931
1282
|
}
|
|
932
1283
|
if (source.isCode) {
|
|
933
|
-
const graph = await readWorkspaceGraphArg(
|
|
1284
|
+
const graph = graphWithScheduleMode(await readWorkspaceGraphArg(
|
|
934
1285
|
option(args, "file"),
|
|
935
1286
|
path.resolve(option(args, "workspace-root") || process.cwd()),
|
|
936
|
-
);
|
|
1287
|
+
), scheduleMode);
|
|
937
1288
|
const updated = await httpJson(args, "/api/workspace/graph", {
|
|
938
1289
|
method: "POST",
|
|
939
1290
|
body: { flowId, flowSource: targetSpace, graph, baseRevision: current.revision },
|
|
@@ -1088,26 +1439,66 @@ async function main() {
|
|
|
1088
1439
|
return;
|
|
1089
1440
|
}
|
|
1090
1441
|
|
|
1091
|
-
if (command === "
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
const
|
|
1095
|
-
|
|
1096
|
-
|
|
1442
|
+
if (command === "draft-create" || command === "draft-update" || command === "workspace-draft") {
|
|
1443
|
+
const draftId = option(args, "draft-id") || "";
|
|
1444
|
+
if (command === "draft-update" && !draftId) throw new Error("draft-update requires --draft-id <id>.");
|
|
1445
|
+
const baseRevision = option(args, "base-revision") || "";
|
|
1446
|
+
if (command === "draft-update" && !baseRevision) {
|
|
1447
|
+
throw new Error("draft-update requires --base-revision <revision>. Pull the Draft first if the revision is unknown.");
|
|
1448
|
+
}
|
|
1449
|
+
const prepared = await prepareDraftGraph(args);
|
|
1450
|
+
const result = await httpJson(args, "/api/workspace/draft", {
|
|
1097
1451
|
method: "POST",
|
|
1098
1452
|
body: {
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1453
|
+
graph: prepared.graph,
|
|
1454
|
+
draftId,
|
|
1455
|
+
baseRevision,
|
|
1456
|
+
title: option(args, "title") || "Workspace Draft",
|
|
1457
|
+
ttlSeconds: option(args, "ttl-seconds") ? Number(option(args, "ttl-seconds")) : undefined,
|
|
1458
|
+
resetRuntime: args["keep-runtime"] !== true,
|
|
1105
1459
|
},
|
|
1106
1460
|
});
|
|
1107
|
-
printJson({
|
|
1108
|
-
|
|
1109
|
-
|
|
1461
|
+
printJson({ ...result, ...prepared });
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
if (command === "draft-run") {
|
|
1466
|
+
const draftId = option(args, "draft-id");
|
|
1467
|
+
if (!draftId) throw new Error("draft-run requires --draft-id <id>.");
|
|
1468
|
+
printJson(await runRemoteWorkspace(args, {
|
|
1469
|
+
flowId: draftId,
|
|
1470
|
+
flowSource: "user",
|
|
1471
|
+
runNodeId: option(args, "run-node-id") || "",
|
|
1472
|
+
}));
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
if (command === "draft-publish" || command === "draft-promote") {
|
|
1477
|
+
const draftId = option(args, "draft-id");
|
|
1478
|
+
if (!draftId) throw new Error("draft-publish requires --draft-id <id>.");
|
|
1479
|
+
const flowId = requireFlowId(args);
|
|
1480
|
+
const destination = targetDestinationFromArgs(args);
|
|
1481
|
+
const targetSpace = destination.shareWithTeam ? "team" : destination.flowSource === "user" ? "personal" : "workspace";
|
|
1482
|
+
const scheduleMode = normalizeScheduleMode(args);
|
|
1483
|
+
const team = await resolvePublishTeam(args, destination.shareWithTeam);
|
|
1484
|
+
const result = await httpJson(args, "/api/workspace/draft/publish", {
|
|
1485
|
+
method: "POST",
|
|
1486
|
+
body: { draftId, flowId, targetSpace, scheduleMode },
|
|
1110
1487
|
});
|
|
1488
|
+
const sharedTeam = await sharePublishedFlowWithTeam(args, {
|
|
1489
|
+
flowId,
|
|
1490
|
+
flowSource: destination.flowSource,
|
|
1491
|
+
team,
|
|
1492
|
+
});
|
|
1493
|
+
printJson({ ...result, team: sharedTeam, targetSpace });
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
if (command === "run") {
|
|
1498
|
+
const flowId = requireFlowId(args);
|
|
1499
|
+
const flowSource = option(args, "flow-source") || "user";
|
|
1500
|
+
const runNodeId = option(args, "run-node-id") || "";
|
|
1501
|
+
printJson(await runRemoteWorkspace(args, { flowId, flowSource, runNodeId }));
|
|
1111
1502
|
return;
|
|
1112
1503
|
}
|
|
1113
1504
|
|
|
@@ -1151,6 +1542,44 @@ async function main() {
|
|
|
1151
1542
|
return;
|
|
1152
1543
|
}
|
|
1153
1544
|
|
|
1545
|
+
if (command === "schedule-list") {
|
|
1546
|
+
const flowId = option(args, "flow-id") || "";
|
|
1547
|
+
const flowSource = option(args, "flow-source") || "user";
|
|
1548
|
+
if (flowId) {
|
|
1549
|
+
printJson(await httpJson(args, `/api/workspace/schedules${query({ flowId, flowSource })}`));
|
|
1550
|
+
} else {
|
|
1551
|
+
printJson(await httpJson(args, "/api/schedules"));
|
|
1552
|
+
}
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
if (["schedule-set", "schedule-enable", "schedule-disable"].includes(command)) {
|
|
1557
|
+
const flowId = requireFlowId(args);
|
|
1558
|
+
const flowSource = option(args, "flow-source") || "user";
|
|
1559
|
+
const scheduleNodeId = option(args, "schedule-node-id");
|
|
1560
|
+
if (!scheduleNodeId) throw new Error(`${command} requires --schedule-node-id <id>.`);
|
|
1561
|
+
const body = { flowId, flowSource, scheduleNodeId };
|
|
1562
|
+
if (command === "schedule-enable") body.enabled = true;
|
|
1563
|
+
if (command === "schedule-disable") body.enabled = false;
|
|
1564
|
+
if (command === "schedule-set" && args.enabled !== undefined) {
|
|
1565
|
+
body.enabled = parseBooleanOption(args.enabled, "--enabled");
|
|
1566
|
+
}
|
|
1567
|
+
if (args.cron !== undefined) body.cron = option(args, "cron");
|
|
1568
|
+
if (args.timezone !== undefined) body.timezone = option(args, "timezone");
|
|
1569
|
+
if (args["overlap-policy"] !== undefined) body.overlapPolicy = option(args, "overlap-policy");
|
|
1570
|
+
printJson(await httpJson(args, "/api/workspace/schedule/config", { method: "POST", body }));
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
if (command === "schedule-run-now") {
|
|
1575
|
+
const flowId = requireFlowId(args);
|
|
1576
|
+
const flowSource = option(args, "flow-source") || "user";
|
|
1577
|
+
const scheduleNodeId = option(args, "schedule-node-id");
|
|
1578
|
+
if (!scheduleNodeId) throw new Error("schedule-run-now requires --schedule-node-id <id>.");
|
|
1579
|
+
printJson(await runRemoteWorkspace(args, { flowId, flowSource, runNodeId: scheduleNodeId }));
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1154
1583
|
if (command === "workflow-get") {
|
|
1155
1584
|
const workflow = workflowReferenceFromArgs(args);
|
|
1156
1585
|
if (workflow.namespace !== "tapd") {
|