@tomflow/proflow-platform-cli 0.1.34 → 0.1.36
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/deployment/adapter.d.ts +7 -7
- package/dist/deployment/descriptor.d.ts +1 -1
- package/dist/deployment/descriptor.js +1 -1
- package/dist/src/cli.d.ts +5 -0
- package/dist/src/cli.js +169 -101
- package/dist/src/lifecycle/thin.d.ts +1 -0
- package/dist/src/lifecycle/thin.js +18 -4
- package/dist/src/progress.d.ts +3 -1
- package/dist/src/terminal.js +33 -19
- package/package.json +3 -3
- package/proflow.module.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @tomflow/proflow-platform-cli
|
|
2
2
|
|
|
3
|
+
## 0.1.36
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Distinguish dependency blocking from verified failure, expose Module-owned status diagnostics, remove automatic docs paging, consolidate start checks, add contextual help, and clarify uninstall output.
|
|
8
|
+
|
|
9
|
+
## 0.1.35
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Render retryable package-manager warnings as warnings instead of failed subprocess events.
|
|
14
|
+
|
|
3
15
|
## 0.1.34
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ Platform does not interpret Module-private configuration or recreate a cross-Mod
|
|
|
41
41
|
`platform status` validates and aggregates only Module-owned observations:
|
|
42
42
|
|
|
43
43
|
```text
|
|
44
|
-
setupStatus: READY | ACTION_REQUIRED | FAILED
|
|
44
|
+
setupStatus: READY | ACTION_REQUIRED | BLOCKED | FAILED
|
|
45
45
|
runtimeStatus: RUNNING | STOPPED | FAILED | NOT_APPLICABLE
|
|
46
46
|
```
|
|
47
47
|
|
|
@@ -6,7 +6,7 @@ export declare const behaviorAdapter: {
|
|
|
6
6
|
readonly ok: true;
|
|
7
7
|
readonly status: "SUCCEEDED";
|
|
8
8
|
readonly moduleRef: "platform-cli";
|
|
9
|
-
readonly moduleVersion: "0.1.
|
|
9
|
+
readonly moduleVersion: "0.1.36";
|
|
10
10
|
};
|
|
11
11
|
observedEffects: never[];
|
|
12
12
|
}>;
|
|
@@ -16,7 +16,7 @@ export declare const behaviorAdapter: {
|
|
|
16
16
|
readonly ok: true;
|
|
17
17
|
readonly status: "SUCCEEDED";
|
|
18
18
|
readonly moduleRef: "platform-cli";
|
|
19
|
-
readonly moduleVersion: "0.1.
|
|
19
|
+
readonly moduleVersion: "0.1.36";
|
|
20
20
|
};
|
|
21
21
|
observedEffects: never[];
|
|
22
22
|
}>;
|
|
@@ -26,7 +26,7 @@ export declare const behaviorAdapter: {
|
|
|
26
26
|
ok: true;
|
|
27
27
|
status: "SUCCEEDED";
|
|
28
28
|
moduleRef: "platform-cli";
|
|
29
|
-
moduleVersion: "0.1.
|
|
29
|
+
moduleVersion: "0.1.36";
|
|
30
30
|
data: {
|
|
31
31
|
readonly setupStatus: "READY";
|
|
32
32
|
readonly runtimeStatus: "NOT_APPLICABLE";
|
|
@@ -40,7 +40,7 @@ export declare const behaviorAdapter: {
|
|
|
40
40
|
readonly ok: true;
|
|
41
41
|
readonly status: "SUCCEEDED";
|
|
42
42
|
readonly moduleRef: "platform-cli";
|
|
43
|
-
readonly moduleVersion: "0.1.
|
|
43
|
+
readonly moduleVersion: "0.1.36";
|
|
44
44
|
};
|
|
45
45
|
observedEffects: never[];
|
|
46
46
|
}>;
|
|
@@ -50,7 +50,7 @@ export declare const behaviorAdapter: {
|
|
|
50
50
|
ok: true;
|
|
51
51
|
status: "SUCCEEDED";
|
|
52
52
|
moduleRef: "platform-cli";
|
|
53
|
-
moduleVersion: "0.1.
|
|
53
|
+
moduleVersion: "0.1.36";
|
|
54
54
|
data: {
|
|
55
55
|
docs: string;
|
|
56
56
|
};
|
|
@@ -63,7 +63,7 @@ export declare const behaviorAdapter: {
|
|
|
63
63
|
readonly ok: true;
|
|
64
64
|
readonly status: "SUCCEEDED";
|
|
65
65
|
readonly moduleRef: "platform-cli";
|
|
66
|
-
readonly moduleVersion: "0.1.
|
|
66
|
+
readonly moduleVersion: "0.1.36";
|
|
67
67
|
};
|
|
68
68
|
observedEffects: never[];
|
|
69
69
|
}>;
|
|
@@ -73,7 +73,7 @@ export declare const behaviorAdapter: {
|
|
|
73
73
|
readonly ok: true;
|
|
74
74
|
readonly status: "SUCCEEDED";
|
|
75
75
|
readonly moduleRef: "platform-cli";
|
|
76
|
-
readonly moduleVersion: "0.1.
|
|
76
|
+
readonly moduleVersion: "0.1.36";
|
|
77
77
|
};
|
|
78
78
|
observedEffects: never[];
|
|
79
79
|
}>;
|
|
@@ -3,7 +3,7 @@ export declare const descriptor: {
|
|
|
3
3
|
readonly contractVersion: "1.0.0";
|
|
4
4
|
readonly moduleRef: "platform-cli";
|
|
5
5
|
readonly packageName: "@tomflow/proflow-platform-cli";
|
|
6
|
-
readonly moduleVersion: "0.1.
|
|
6
|
+
readonly moduleVersion: "0.1.36";
|
|
7
7
|
readonly kind: "cli";
|
|
8
8
|
readonly templateVersion: "1.0.0";
|
|
9
9
|
readonly platformCompatibility: ">=1.0.0 <2.0.0";
|
|
@@ -3,7 +3,7 @@ export const descriptor = {
|
|
|
3
3
|
contractVersion: "1.0.0",
|
|
4
4
|
moduleRef: "platform-cli",
|
|
5
5
|
packageName: "@tomflow/proflow-platform-cli",
|
|
6
|
-
moduleVersion: "0.1.
|
|
6
|
+
moduleVersion: "0.1.36",
|
|
7
7
|
kind: "cli",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
package/dist/src/cli.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { type PackageCommandRunner } from "./install/package-manager.ts";
|
|
3
3
|
import { type PlatformProgressReporter } from "./progress.ts";
|
|
4
4
|
import { type NpmCommandRunner } from "./registry/index.ts";
|
|
5
|
+
declare const COMMANDS: readonly ["install", "uninstall", "status", "setup", "docs", "start", "stop"];
|
|
6
|
+
type Command = (typeof COMMANDS)[number];
|
|
5
7
|
export type CliStatus = "SUCCEEDED" | "ACTION_REQUIRED" | "BLOCKED" | "FAILED";
|
|
6
8
|
export interface CliOutcome {
|
|
7
9
|
command: string;
|
|
@@ -11,6 +13,8 @@ export interface CliOutcome {
|
|
|
11
13
|
error?: {
|
|
12
14
|
code: string;
|
|
13
15
|
message: string;
|
|
16
|
+
category?: "USAGE" | "OPERATION";
|
|
17
|
+
helpCommand?: Command;
|
|
14
18
|
};
|
|
15
19
|
}
|
|
16
20
|
export interface CliRuntimeOptions {
|
|
@@ -26,3 +30,4 @@ export interface HumanRenderOptions {
|
|
|
26
30
|
width?: number;
|
|
27
31
|
}
|
|
28
32
|
export declare function renderHumanResult(result: CliOutcome, options?: HumanRenderOptions): string;
|
|
33
|
+
export {};
|
package/dist/src/cli.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
2
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
4
3
|
import { resolve } from "node:path";
|
|
5
4
|
import { moduleDocsDataSchema, moduleSetupPlanDataSchema, moduleStatusObservationSchema, } from "@tomflow/proflow-module-contract";
|
|
@@ -120,7 +119,9 @@ function batchStatus(result) {
|
|
|
120
119
|
if (result.blockedBy)
|
|
121
120
|
return result.blockedBy.setupStatus === "ACTION_REQUIRED"
|
|
122
121
|
? "ACTION_REQUIRED"
|
|
123
|
-
: "
|
|
122
|
+
: result.blockedBy.setupStatus === "BLOCKED"
|
|
123
|
+
? "BLOCKED"
|
|
124
|
+
: "FAILED";
|
|
124
125
|
const statuses = result.results.map((item) => statusFromModule(item.result.status));
|
|
125
126
|
if (statuses.includes("FAILED"))
|
|
126
127
|
return "FAILED";
|
|
@@ -154,6 +155,9 @@ async function handleStatus(root, runtime) {
|
|
|
154
155
|
version: module.moduleVersion,
|
|
155
156
|
setupStatus: parsed.data.setupStatus,
|
|
156
157
|
runtimeStatus: parsed.data.runtimeStatus,
|
|
158
|
+
...(parsed.data.issues === undefined
|
|
159
|
+
? {}
|
|
160
|
+
: { issues: parsed.data.issues }),
|
|
157
161
|
};
|
|
158
162
|
});
|
|
159
163
|
reportProgress(runtime.onProgress, {
|
|
@@ -351,7 +355,11 @@ function reportPackageManagerOutput(runtime, command, output) {
|
|
|
351
355
|
command,
|
|
352
356
|
phase: "packages",
|
|
353
357
|
kind: "subprocess",
|
|
354
|
-
status:
|
|
358
|
+
status: /\b(?:warn|warning)\b/i.test(output.line)
|
|
359
|
+
? "WARNING"
|
|
360
|
+
: /(?:error|ERR_)/i.test(output.line)
|
|
361
|
+
? "FAILED"
|
|
362
|
+
: "STARTED",
|
|
355
363
|
message: output.line,
|
|
356
364
|
});
|
|
357
365
|
}
|
|
@@ -453,7 +461,8 @@ export async function runCli(argv, runtime = {}) {
|
|
|
453
461
|
parsed = parseArgs(argv);
|
|
454
462
|
}
|
|
455
463
|
catch (error) {
|
|
456
|
-
|
|
464
|
+
const helpCommand = argv.find((value) => COMMANDS.includes(value));
|
|
465
|
+
return errorOutcome("unknown", error, "USAGE", helpCommand);
|
|
457
466
|
}
|
|
458
467
|
try {
|
|
459
468
|
if (parsed.command === "help")
|
|
@@ -484,12 +493,17 @@ export async function runCli(argv, runtime = {}) {
|
|
|
484
493
|
return errorOutcome(parsed.command, error);
|
|
485
494
|
}
|
|
486
495
|
}
|
|
487
|
-
function errorOutcome(command, error) {
|
|
496
|
+
function errorOutcome(command, error, category = "OPERATION", helpCommand) {
|
|
488
497
|
if (error instanceof PlatformError)
|
|
489
498
|
return {
|
|
490
499
|
command,
|
|
491
500
|
status: "FAILED",
|
|
492
|
-
error: {
|
|
501
|
+
error: {
|
|
502
|
+
code: error.code,
|
|
503
|
+
message: error.message,
|
|
504
|
+
category,
|
|
505
|
+
...(helpCommand === undefined ? {} : { helpCommand }),
|
|
506
|
+
},
|
|
493
507
|
};
|
|
494
508
|
return {
|
|
495
509
|
command,
|
|
@@ -497,6 +511,7 @@ function errorOutcome(command, error) {
|
|
|
497
511
|
error: {
|
|
498
512
|
code: "COMMAND_FAILED",
|
|
499
513
|
message: error instanceof Error ? error.message : String(error),
|
|
514
|
+
category,
|
|
500
515
|
},
|
|
501
516
|
};
|
|
502
517
|
}
|
|
@@ -520,6 +535,7 @@ function humanTheme(options = {}) {
|
|
|
520
535
|
title: (value) => paint("bold", paint("cyan", value)),
|
|
521
536
|
section: (value) => paint("bold", value),
|
|
522
537
|
command: (value) => paint("blue", value),
|
|
538
|
+
info: (value) => paint("blue", value),
|
|
523
539
|
muted: (value) => paint("dim", value),
|
|
524
540
|
success: (value) => paint("green", value),
|
|
525
541
|
warning: (value) => paint("yellow", value),
|
|
@@ -532,6 +548,7 @@ function renderStatus(data, theme) {
|
|
|
532
548
|
const setupLabels = {
|
|
533
549
|
READY: "已就绪",
|
|
534
550
|
ACTION_REQUIRED: "需要操作",
|
|
551
|
+
BLOCKED: "等待依赖",
|
|
535
552
|
FAILED: "失败",
|
|
536
553
|
};
|
|
537
554
|
const runtimeLabels = {
|
|
@@ -541,40 +558,40 @@ function renderStatus(data, theme) {
|
|
|
541
558
|
NOT_APPLICABLE: "无独立进程",
|
|
542
559
|
};
|
|
543
560
|
const modules = data.modules.filter(isRecord);
|
|
544
|
-
const
|
|
561
|
+
const failedModules = modules.filter((item) => item.setupStatus === "FAILED" || item.runtimeStatus === "FAILED");
|
|
562
|
+
const actionModules = modules.filter((item) => item.setupStatus === "ACTION_REQUIRED" && item.runtimeStatus !== "FAILED");
|
|
563
|
+
const blockedModules = modules.filter((item) => item.setupStatus === "BLOCKED" && item.runtimeStatus !== "FAILED");
|
|
545
564
|
const running = modules.filter((item) => item.setupStatus === "READY" && item.runtimeStatus === "RUNNING");
|
|
546
565
|
const healthy = modules.filter((item) => item.setupStatus === "READY" &&
|
|
547
566
|
item.runtimeStatus !== "RUNNING" &&
|
|
548
567
|
item.runtimeStatus !== "FAILED");
|
|
549
568
|
const lines = [theme.title("ProFlow 状态"), ""];
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
?
|
|
562
|
-
:
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
lines.push(` 原因:${setupStatus === "FAILED" ? "模块配置检查失败" : "模块运行状态异常"}`, ` 下一步:${theme.command(`platform setup --module ${moduleRef}`)}`);
|
|
572
|
-
}
|
|
573
|
-
else if (actionRequired) {
|
|
574
|
-
lines.push(" 原因:模块尚未完成配置", ` 下一步:${theme.command(`platform setup --module ${moduleRef}`)}`);
|
|
569
|
+
const renderProblems = (title, entries, tone, icon) => {
|
|
570
|
+
if (entries.length === 0)
|
|
571
|
+
return;
|
|
572
|
+
lines.push(theme.section(title), "");
|
|
573
|
+
for (const raw of entries) {
|
|
574
|
+
const moduleRef = String(raw.moduleRef);
|
|
575
|
+
const setupStatus = String(raw.setupStatus);
|
|
576
|
+
const runtimeStatus = String(raw.runtimeStatus);
|
|
577
|
+
lines.push(`${tone(icon)} ${theme.section(moduleRef)} ${theme.muted(String(raw.version))}`);
|
|
578
|
+
lines.push(` ${tone(setupLabels[setupStatus] ?? "未知")} · ${runtimeLabels[runtimeStatus] ?? "未知"}`);
|
|
579
|
+
const issues = Array.isArray(raw.issues)
|
|
580
|
+
? raw.issues.filter(isRecord)
|
|
581
|
+
: [];
|
|
582
|
+
for (const issue of issues) {
|
|
583
|
+
lines.push(` 原因:${String(issue.message)}`);
|
|
584
|
+
if (Array.isArray(issue.relatedModuleRefs) &&
|
|
585
|
+
issue.relatedModuleRefs.length > 0)
|
|
586
|
+
lines.push(` 依赖:${issue.relatedModuleRefs.map(String).join("、")}`);
|
|
587
|
+
lines.push(` 下一步:${theme.command(String(issue.nextCommand))}`);
|
|
588
|
+
}
|
|
589
|
+
lines.push("");
|
|
575
590
|
}
|
|
576
|
-
|
|
577
|
-
|
|
591
|
+
};
|
|
592
|
+
renderProblems("失败", failedModules, theme.failure, "✕");
|
|
593
|
+
renderProblems("需要操作", actionModules, theme.warning, "◆");
|
|
594
|
+
renderProblems("等待依赖", blockedModules, theme.info, "◇");
|
|
578
595
|
const compact = (title, entries, symbol) => {
|
|
579
596
|
if (entries.length === 0)
|
|
580
597
|
return;
|
|
@@ -590,7 +607,8 @@ function renderStatus(data, theme) {
|
|
|
590
607
|
const ready = modules.filter((item) => item.setupStatus === "READY").length;
|
|
591
608
|
const action = modules.filter((item) => item.setupStatus === "ACTION_REQUIRED").length;
|
|
592
609
|
const failed = modules.filter((item) => item.setupStatus === "FAILED").length;
|
|
593
|
-
|
|
610
|
+
const blocked = modules.filter((item) => item.setupStatus === "BLOCKED").length;
|
|
611
|
+
lines.push(theme.section("汇总"), `${theme.success(`${ready} 已就绪`)} · ${theme.warning(`${action} 需要操作`)} · ${theme.info(`${blocked} 等待依赖`)} · ${failed > 0 ? theme.failure(`${failed} 失败`) : `${failed} 失败`}`);
|
|
594
612
|
return lines.join("\n");
|
|
595
613
|
}
|
|
596
614
|
function renderTerminalMarkdown(source, theme) {
|
|
@@ -746,6 +764,86 @@ function renderSetup(data, theme) {
|
|
|
746
764
|
lines.push(theme.section("汇总"), `汇总:${theme.success(`${ready} 个已就绪`)},${theme.warning(`${needsAction} 个需要操作`)},${blocked > 0 ? theme.failure(`${blocked} 个系统阻塞`) : `${blocked} 个系统阻塞`}`);
|
|
747
765
|
return lines.join("\n").trimEnd();
|
|
748
766
|
}
|
|
767
|
+
function renderHelp(theme, command) {
|
|
768
|
+
const commandHelp = {
|
|
769
|
+
install: {
|
|
770
|
+
usage: "platform install [--workspace <路径>]",
|
|
771
|
+
description: "安装并初始化全部 ProFlow 模块",
|
|
772
|
+
},
|
|
773
|
+
uninstall: {
|
|
774
|
+
usage: "platform uninstall [--workspace <路径>]",
|
|
775
|
+
description: "卸载模块包,保留 Workspace 数据",
|
|
776
|
+
},
|
|
777
|
+
status: {
|
|
778
|
+
usage: "platform status [--workspace <路径>]",
|
|
779
|
+
description: "查看模块配置与运行状态",
|
|
780
|
+
},
|
|
781
|
+
setup: {
|
|
782
|
+
usage: "platform setup [--workspace <路径>] [--module <模块名>]",
|
|
783
|
+
description: "自动配置并列出全部剩余步骤",
|
|
784
|
+
},
|
|
785
|
+
docs: {
|
|
786
|
+
usage: "platform docs [--workspace <路径>]",
|
|
787
|
+
description: "阅读全部模块能力文档",
|
|
788
|
+
},
|
|
789
|
+
start: {
|
|
790
|
+
usage: "platform start [--workspace <路径>]",
|
|
791
|
+
description: "完成全量检查后启动平台",
|
|
792
|
+
},
|
|
793
|
+
stop: {
|
|
794
|
+
usage: "platform stop [--workspace <路径>]",
|
|
795
|
+
description: "按逆依赖顺序停止平台",
|
|
796
|
+
},
|
|
797
|
+
};
|
|
798
|
+
if (command) {
|
|
799
|
+
const item = commandHelp[command];
|
|
800
|
+
return [
|
|
801
|
+
theme.title(`platform ${command}`),
|
|
802
|
+
item.description,
|
|
803
|
+
"",
|
|
804
|
+
theme.section("用法"),
|
|
805
|
+
` ${theme.command(item.usage)}`,
|
|
806
|
+
"",
|
|
807
|
+
theme.section("帮助"),
|
|
808
|
+
` ${theme.command(`platform ${command} --help`)}`,
|
|
809
|
+
].join("\n");
|
|
810
|
+
}
|
|
811
|
+
return [
|
|
812
|
+
theme.title("ProFlow 平台命令行"),
|
|
813
|
+
"管理 ProFlow 模块的安装、配置、文档和运行生命周期。",
|
|
814
|
+
"",
|
|
815
|
+
theme.section("用法"),
|
|
816
|
+
` ${theme.command("platform <command> [--workspace <路径>]")}`,
|
|
817
|
+
"",
|
|
818
|
+
theme.section("命令"),
|
|
819
|
+
...Object.entries(commandHelp).map(([name, item]) => ` ${theme.command(`platform ${name}`.padEnd(21))}${item.description}`),
|
|
820
|
+
"",
|
|
821
|
+
theme.section("公共参数"),
|
|
822
|
+
" --workspace <路径> 指定 ProFlow Workspace",
|
|
823
|
+
" setup --module <模块名> 只查看指定模块的配置步骤",
|
|
824
|
+
" -h, --help 显示帮助",
|
|
825
|
+
" -v, --version 显示版本",
|
|
826
|
+
"",
|
|
827
|
+
theme.section("推荐流程"),
|
|
828
|
+
` ${theme.command("install → status → docs → setup → start → status → stop")}`,
|
|
829
|
+
"",
|
|
830
|
+
theme.section("人工配置示例"),
|
|
831
|
+
` 人工:${theme.command("pnpm exec -- proflow-chatgpt-carrier setup")}`,
|
|
832
|
+
` AI: ${theme.command("pnpm exec -- proflow-chatgpt-carrier setup")}`,
|
|
833
|
+
` ${theme.command("--carrier-url <url>")}`,
|
|
834
|
+
"",
|
|
835
|
+
theme.section("状态图例"),
|
|
836
|
+
` ${theme.success("已就绪")} 配置与验证完成`,
|
|
837
|
+
` ${theme.warning("需要操作")} 需要执行 setup 步骤`,
|
|
838
|
+
` ${theme.info("等待依赖")} 等待上游 Module 或外部服务`,
|
|
839
|
+
` ${theme.failure("失败")} 已确认配置或运行故障`,
|
|
840
|
+
" 运行中 服务进程正在运行",
|
|
841
|
+
" 无独立进程 该模块无需启动",
|
|
842
|
+
"",
|
|
843
|
+
theme.section("遇到问题"),
|
|
844
|
+
` 先运行 ${theme.command("platform status")};配置问题运行 ${theme.command("platform setup")}。`,
|
|
845
|
+
].join("\n");
|
|
846
|
+
}
|
|
749
847
|
export function renderHumanResult(result, options = {}) {
|
|
750
848
|
const theme = humanTheme(options);
|
|
751
849
|
if (result.command === "setup" &&
|
|
@@ -756,18 +854,35 @@ export function renderHumanResult(result, options = {}) {
|
|
|
756
854
|
const blockers = Array.isArray(result.data.blockers)
|
|
757
855
|
? result.data.blockers.filter(isRecord)
|
|
758
856
|
: [];
|
|
759
|
-
if (blockers.length > 0)
|
|
760
|
-
|
|
761
|
-
theme.failure
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
"",
|
|
769
|
-
|
|
770
|
-
|
|
857
|
+
if (blockers.length > 0) {
|
|
858
|
+
const groups = [
|
|
859
|
+
{ status: "FAILED", title: "失败", icon: "✕", tone: theme.failure },
|
|
860
|
+
{
|
|
861
|
+
status: "ACTION_REQUIRED",
|
|
862
|
+
title: "需要操作",
|
|
863
|
+
icon: "◆",
|
|
864
|
+
tone: theme.warning,
|
|
865
|
+
},
|
|
866
|
+
{ status: "BLOCKED", title: "等待依赖", icon: "◇", tone: theme.info },
|
|
867
|
+
];
|
|
868
|
+
const lines = [theme.failure("平台未启动:存在未就绪模块"), ""];
|
|
869
|
+
for (const group of groups) {
|
|
870
|
+
const entries = blockers.filter((item) => item.setupStatus === group.status);
|
|
871
|
+
if (entries.length === 0)
|
|
872
|
+
continue;
|
|
873
|
+
lines.push(theme.section(group.title));
|
|
874
|
+
for (const item of entries)
|
|
875
|
+
lines.push(`${group.tone(group.icon)} ${theme.section(String(item.moduleRef))}`, ` 原因:${typeof item.reason === "string" ? item.reason : "模块尚未就绪"}`, ` 下一步:${theme.command(typeof item.nextCommand === "string" ? item.nextCommand : `platform setup --module ${String(item.moduleRef)}`)}`);
|
|
876
|
+
lines.push("");
|
|
877
|
+
}
|
|
878
|
+
const readyCount = Array.isArray(result.data.results)
|
|
879
|
+
? result.data.results.filter((item) => isRecord(item) &&
|
|
880
|
+
isRecord(item.result) &&
|
|
881
|
+
item.result.status === "SUCCEEDED").length - blockers.length
|
|
882
|
+
: 0;
|
|
883
|
+
lines.push(theme.section("检查汇总"), `${Math.max(0, readyCount)} 已就绪 · ${blockers.length} 未就绪 · 0 个模块已启动`, `处理方式:${theme.command(`platform setup${result.workspaceRoot ? ` --workspace "${result.workspaceRoot}"` : ""}`)}`);
|
|
884
|
+
return lines.join("\n");
|
|
885
|
+
}
|
|
771
886
|
}
|
|
772
887
|
if (result.status === "FAILED" && result.error)
|
|
773
888
|
return [
|
|
@@ -775,42 +890,12 @@ export function renderHumanResult(result, options = {}) {
|
|
|
775
890
|
`${theme.failure("│")} ${theme.section(result.error.code)}`,
|
|
776
891
|
`${theme.failure("│")} ${result.error.message}`,
|
|
777
892
|
theme.failure("╰─ 请根据提示修复后重试"),
|
|
893
|
+
...(result.error.category === "USAGE"
|
|
894
|
+
? ["", renderHelp(theme, result.error.helpCommand)]
|
|
895
|
+
: []),
|
|
778
896
|
].join("\n");
|
|
779
897
|
if (result.command === "help")
|
|
780
|
-
return
|
|
781
|
-
theme.title("ProFlow 平台命令行"),
|
|
782
|
-
"管理 ProFlow 模块的安装、配置、文档和运行生命周期。",
|
|
783
|
-
"",
|
|
784
|
-
theme.section("用法"),
|
|
785
|
-
` ${theme.command("platform <command> [--workspace <路径>]")}`,
|
|
786
|
-
"",
|
|
787
|
-
theme.section("命令"),
|
|
788
|
-
`${theme.command("platform install")} 安装并初始化全部 ProFlow 模块`,
|
|
789
|
-
"platform uninstall 卸载模块包,保留 Workspace 数据",
|
|
790
|
-
"platform status 查看模块配置与运行状态",
|
|
791
|
-
"platform setup 自动配置并列出全部剩余步骤",
|
|
792
|
-
"platform docs 阅读模块能力文档",
|
|
793
|
-
"platform start 完成全量检查后启动平台",
|
|
794
|
-
"platform stop 按逆依赖顺序停止平台",
|
|
795
|
-
"",
|
|
796
|
-
theme.section("公共参数"),
|
|
797
|
-
" --workspace <路径> 指定 ProFlow Workspace",
|
|
798
|
-
" setup --module <模块名> 只查看指定模块的配置步骤",
|
|
799
|
-
"",
|
|
800
|
-
theme.section("推荐流程"),
|
|
801
|
-
` ${theme.command("install → status → docs → setup → start → status → stop")}`,
|
|
802
|
-
"",
|
|
803
|
-
theme.section("人工配置示例"),
|
|
804
|
-
` 人工:${theme.command("pnpm exec -- proflow-chatgpt-carrier setup")}`,
|
|
805
|
-
` AI: ${theme.command("pnpm exec -- proflow-chatgpt-carrier setup --carrier-url <url>")}`,
|
|
806
|
-
"",
|
|
807
|
-
theme.section("状态图例"),
|
|
808
|
-
` ${theme.success("已就绪")} 配置完成 ${theme.warning("需要操作")} 运行 setup`,
|
|
809
|
-
` ${theme.failure("失败")} 存在阻塞 无独立进程 无需启动`,
|
|
810
|
-
"",
|
|
811
|
-
theme.section("遇到问题"),
|
|
812
|
-
` 先运行 ${theme.command("platform status")};配置问题运行 ${theme.command("platform setup")}。`,
|
|
813
|
-
].join("\n");
|
|
898
|
+
return renderHelp(theme);
|
|
814
899
|
if (result.command === "version" && isRecord(result.data))
|
|
815
900
|
return String(result.data.version ?? platformCliDescriptor.moduleVersion);
|
|
816
901
|
if (result.command === "status")
|
|
@@ -847,6 +932,8 @@ export function renderHumanResult(result, options = {}) {
|
|
|
847
932
|
start: "启动",
|
|
848
933
|
stop: "停止",
|
|
849
934
|
};
|
|
935
|
+
if (result.command === "uninstall" && result.status === "SUCCEEDED")
|
|
936
|
+
return `${theme.success("✓ 已经卸载")}${result.workspaceRoot ? `\n${theme.muted("Workspace")} ${result.workspaceRoot}` : ""}`;
|
|
850
937
|
return `${result.status === "SUCCEEDED" ? theme.success("✓") : theme.failure("✕")} ${labels[result.command] ?? result.command}${result.status === "SUCCEEDED" ? "成功" : "未完成"}${result.workspaceRoot ? `\n${theme.muted("Workspace")} ${result.workspaceRoot}` : ""}`;
|
|
851
938
|
}
|
|
852
939
|
if (import.meta.main) {
|
|
@@ -861,26 +948,7 @@ if (import.meta.main) {
|
|
|
861
948
|
color,
|
|
862
949
|
width: process.stdout.columns,
|
|
863
950
|
})}\n`;
|
|
864
|
-
|
|
865
|
-
process.stdout.isTTY === true &&
|
|
866
|
-
rendered.split("\n").length > (process.stdout.rows ?? 24)) {
|
|
867
|
-
await writeThroughPager(rendered);
|
|
868
|
-
}
|
|
869
|
-
else
|
|
870
|
-
process.stdout.write(rendered);
|
|
951
|
+
process.stdout.write(rendered);
|
|
871
952
|
if (result.status !== "SUCCEEDED")
|
|
872
953
|
process.exitCode = 1;
|
|
873
954
|
}
|
|
874
|
-
async function writeThroughPager(content) {
|
|
875
|
-
await new Promise((resolvePromise) => {
|
|
876
|
-
const pager = spawn("less", ["-FIRX"], {
|
|
877
|
-
stdio: ["pipe", "inherit", "inherit"],
|
|
878
|
-
});
|
|
879
|
-
pager.once("error", () => {
|
|
880
|
-
process.stdout.write(content);
|
|
881
|
-
resolvePromise();
|
|
882
|
-
});
|
|
883
|
-
pager.once("close", () => resolvePromise());
|
|
884
|
-
pager.stdin.end(content);
|
|
885
|
-
});
|
|
886
|
-
}
|
|
@@ -78,7 +78,9 @@ async function runOrdered(catalog, modules, workspaceRoot, command, reverse, rep
|
|
|
78
78
|
total: modulesInOrder.length,
|
|
79
79
|
moduleRef: module.moduleRef,
|
|
80
80
|
status: "STARTED",
|
|
81
|
-
message:
|
|
81
|
+
message: command === "uninstall"
|
|
82
|
+
? `正在卸载 ${module.moduleRef}`
|
|
83
|
+
: `${module.moduleRef}`,
|
|
82
84
|
});
|
|
83
85
|
const result = await dispatchModuleCommand(catalog, module, command, context(workspaceRoot));
|
|
84
86
|
results.push(result);
|
|
@@ -232,22 +234,26 @@ export async function startModulesThin(catalog, modules, workspaceRoot, reporter
|
|
|
232
234
|
reportProgress(reporter, {
|
|
233
235
|
command: "start",
|
|
234
236
|
phase: "status",
|
|
237
|
+
kind: "detail",
|
|
238
|
+
retention: "REPLACE",
|
|
235
239
|
current: index + 1,
|
|
236
240
|
total: modulesInOrder.length,
|
|
237
241
|
moduleRef: module.moduleRef,
|
|
238
242
|
status: "STARTED",
|
|
239
|
-
message:
|
|
243
|
+
message: `正在检查模块状态 · ${module.moduleRef}`,
|
|
240
244
|
});
|
|
241
245
|
const status = await dispatchModuleCommand(catalog, module, "status", context(workspaceRoot));
|
|
242
246
|
results.push(status);
|
|
243
247
|
reportProgress(reporter, {
|
|
244
248
|
command: "start",
|
|
245
249
|
phase: "status",
|
|
250
|
+
kind: "detail",
|
|
251
|
+
retention: "REPLACE",
|
|
246
252
|
current: index + 1,
|
|
247
253
|
total: modulesInOrder.length,
|
|
248
254
|
moduleRef: module.moduleRef,
|
|
249
255
|
status: succeeded(status.result) ? "SUCCEEDED" : "FAILED",
|
|
250
|
-
message:
|
|
256
|
+
message: `正在检查模块状态 · ${module.moduleRef}`,
|
|
251
257
|
});
|
|
252
258
|
if (!succeeded(status.result)) {
|
|
253
259
|
blockers.push({
|
|
@@ -259,11 +265,19 @@ export async function startModulesThin(catalog, modules, workspaceRoot, reporter
|
|
|
259
265
|
}
|
|
260
266
|
const observed = moduleStatusObservationSchema.parse(status.result.data);
|
|
261
267
|
runtimeByRef.set(module.moduleRef, observed.runtimeStatus);
|
|
262
|
-
if (observed.setupStatus !== "READY")
|
|
268
|
+
if (observed.setupStatus !== "READY") {
|
|
269
|
+
const issue = observed.issues?.find((item) => item.scope === "SETUP");
|
|
263
270
|
blockers.push({
|
|
264
271
|
moduleRef: module.moduleRef,
|
|
265
272
|
setupStatus: observed.setupStatus,
|
|
273
|
+
...(issue
|
|
274
|
+
? {
|
|
275
|
+
reason: issue.message,
|
|
276
|
+
nextCommand: issue.nextCommand,
|
|
277
|
+
}
|
|
278
|
+
: {}),
|
|
266
279
|
});
|
|
280
|
+
}
|
|
267
281
|
}
|
|
268
282
|
if (results.some((item) => !succeeded(item.result)) || blockers.length > 0)
|
|
269
283
|
return {
|
package/dist/src/progress.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export type PlatformProgressStatus = "STARTED" | "SUCCEEDED" | "ACTION_REQUIRED" | "FAILED" | "SKIPPED";
|
|
1
|
+
export type PlatformProgressStatus = "STARTED" | "SUCCEEDED" | "WARNING" | "ACTION_REQUIRED" | "FAILED" | "SKIPPED";
|
|
2
2
|
export type PlatformProgressKind = "phase" | "detail" | "subprocess";
|
|
3
|
+
export type PlatformProgressRetention = "KEEP" | "REPLACE";
|
|
3
4
|
export interface PlatformProgressEvent {
|
|
4
5
|
command: string;
|
|
5
6
|
phase: string;
|
|
6
7
|
kind?: PlatformProgressKind;
|
|
8
|
+
retention?: PlatformProgressRetention;
|
|
7
9
|
current?: number;
|
|
8
10
|
total?: number;
|
|
9
11
|
moduleRef?: string;
|
package/dist/src/terminal.js
CHANGED
|
@@ -17,35 +17,43 @@ function progressLine(event, color, spinner = "") {
|
|
|
17
17
|
const elapsed = event.elapsedMs !== undefined
|
|
18
18
|
? ` · ${(event.elapsedMs / 1000).toFixed(1)}s`
|
|
19
19
|
: "";
|
|
20
|
-
const suffix = event.status === "SUCCEEDED"
|
|
21
|
-
? "
|
|
22
|
-
: event.status === "
|
|
23
|
-
? "
|
|
24
|
-
: event.status === "
|
|
25
|
-
? "
|
|
26
|
-
: event.status === "
|
|
27
|
-
? "
|
|
28
|
-
: ""
|
|
20
|
+
const suffix = event.command === "uninstall" && event.status === "SUCCEEDED"
|
|
21
|
+
? "已经卸载"
|
|
22
|
+
: event.status === "SUCCEEDED"
|
|
23
|
+
? "完成"
|
|
24
|
+
: event.status === "WARNING"
|
|
25
|
+
? "警告"
|
|
26
|
+
: event.status === "ACTION_REQUIRED"
|
|
27
|
+
? "待处理"
|
|
28
|
+
: event.status === "FAILED"
|
|
29
|
+
? "失败"
|
|
30
|
+
: event.status === "SKIPPED"
|
|
31
|
+
? "跳过"
|
|
32
|
+
: "";
|
|
29
33
|
const symbol = event.kind === "subprocess"
|
|
30
34
|
? "│"
|
|
31
35
|
: event.status === "STARTED"
|
|
32
36
|
? spinner
|
|
33
37
|
: event.status === "SUCCEEDED"
|
|
34
38
|
? "✓"
|
|
35
|
-
: event.status === "
|
|
36
|
-
? "
|
|
37
|
-
: event.status === "
|
|
38
|
-
? "
|
|
39
|
-
: "
|
|
39
|
+
: event.status === "WARNING"
|
|
40
|
+
? "!"
|
|
41
|
+
: event.status === "FAILED"
|
|
42
|
+
? "✕"
|
|
43
|
+
: event.status === "ACTION_REQUIRED"
|
|
44
|
+
? "◆"
|
|
45
|
+
: "○";
|
|
40
46
|
if (!color)
|
|
41
47
|
return `${symbol ? `${symbol} ` : ""}${prefix}${event.message}${suffix ? ` · ${suffix}` : ""}${elapsed}`;
|
|
42
48
|
const tone = event.status === "SUCCEEDED"
|
|
43
49
|
? colors.green
|
|
44
|
-
: event.status === "
|
|
45
|
-
? colors.
|
|
46
|
-
: event.
|
|
47
|
-
? colors.
|
|
48
|
-
:
|
|
50
|
+
: event.status === "WARNING"
|
|
51
|
+
? colors.yellow
|
|
52
|
+
: event.status === "FAILED"
|
|
53
|
+
? colors.red
|
|
54
|
+
: event.kind === "subprocess"
|
|
55
|
+
? colors.blue
|
|
56
|
+
: colors.yellow;
|
|
49
57
|
return `${tone}${symbol}${colors.reset} ${colors.dim}${prefix}${colors.reset}${event.message}${suffix ? ` · ${tone}${suffix}${colors.reset}` : ""}${event.elapsedMs === undefined ? "" : `${colors.dim}${elapsed}${colors.reset}`}`;
|
|
50
58
|
}
|
|
51
59
|
export function createTerminalProgressReporter(stream = process.stderr) {
|
|
@@ -79,6 +87,12 @@ export function createTerminalProgressReporter(stream = process.stderr) {
|
|
|
79
87
|
stream.write(`${line}\n`);
|
|
80
88
|
return;
|
|
81
89
|
}
|
|
90
|
+
if (event.retention === "REPLACE" && event.status !== "STARTED") {
|
|
91
|
+
cursorTo(stream, 0);
|
|
92
|
+
clearLine(stream, 0);
|
|
93
|
+
active = undefined;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
82
96
|
cursorTo(stream, 0);
|
|
83
97
|
clearLine(stream, 0);
|
|
84
98
|
stream.write(line);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomflow/proflow-platform-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"SETUP.md"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@tomflow/proflow-module-contract": "^0.1.
|
|
27
|
+
"@tomflow/proflow-module-contract": "^0.1.12"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@tomflow/proflow-deployment-conformance": "^0.1.
|
|
30
|
+
"@tomflow/proflow-deployment-conformance": "^0.1.10",
|
|
31
31
|
"@tomflow/proflow-module-template": "^0.1.9"
|
|
32
32
|
},
|
|
33
33
|
"description": "Thin Platform CLI for Module discovery, documentation, package synchronization and lifecycle orchestration.",
|
package/proflow.module.json
CHANGED