@tomflow/proflow-platform-cli 0.1.36 → 0.1.38
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.js +78 -43
- package/dist/src/deployment-order.d.ts +2 -0
- package/dist/src/deployment-order.js +39 -0
- package/dist/src/lifecycle/dispatch.d.ts +1 -0
- package/dist/src/lifecycle/dispatch.js +8 -1
- package/dist/src/lifecycle/thin.js +56 -13
- package/dist/src/registry/index.d.ts +1 -1
- package/dist/src/registry/index.js +1 -1
- package/dist/src/registry/npm-registry.d.ts +2 -0
- package/dist/src/registry/npm-registry.js +11 -6
- package/package.json +4 -4
- 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.38
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Retire the obsolete Carrier package and Browser standalone management CLI, make Platform setup/status preserve owner and dependency semantics, and enforce read-only status observation across the final Real-3 deployment closeout.
|
|
8
|
+
|
|
9
|
+
## 0.1.37
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Ship the Phase 3 browser, tunnel, model automation, platform readiness, and documentation closure as one verifiable platform snapshot.
|
|
14
|
+
|
|
3
15
|
## 0.1.36
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Platform does not interpret Module-private configuration or recreate a cross-Mod
|
|
|
32
32
|
|
|
33
33
|
## Install / Uninstall
|
|
34
34
|
|
|
35
|
-
`platform install` validates or creates the minimal Workspace metadata, discovers the complete governed package set from the Registry, synchronizes that set, validates the installed descriptors, then invokes `Module.install` in dependency
|
|
35
|
+
`platform install` validates or creates the minimal Workspace metadata, discovers the complete governed package set from the Registry, synchronizes that set, validates the installed descriptors, then invokes `Module.install` in the frozen Deployment Install Order. This product deployment order is distinct from Runtime dependency topology: Chrome is first, followed by Browser Extension, Agent packages, Gateway/Tunnel, runtime/data foundations and governance packages. It does not perform human setup work.
|
|
36
36
|
|
|
37
37
|
`platform uninstall` invokes `Module.uninstall` in reverse dependency order before package removal. `.proflow` is Workspace/user data and is preserved unless an owning Module explicitly removes its own artifacts.
|
|
38
38
|
|
|
@@ -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.38";
|
|
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.38";
|
|
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.38";
|
|
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.38";
|
|
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.38";
|
|
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.38";
|
|
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.38";
|
|
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.38";
|
|
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.38",
|
|
7
7
|
kind: "cli",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
package/dist/src/cli.js
CHANGED
|
@@ -158,6 +158,9 @@ async function handleStatus(root, runtime) {
|
|
|
158
158
|
...(parsed.data.issues === undefined
|
|
159
159
|
? {}
|
|
160
160
|
: { issues: parsed.data.issues }),
|
|
161
|
+
...(item.externalAvailabilityClaim === undefined
|
|
162
|
+
? {}
|
|
163
|
+
: { externalAvailabilityClaim: item.externalAvailabilityClaim }),
|
|
161
164
|
};
|
|
162
165
|
});
|
|
163
166
|
reportProgress(runtime.onProgress, {
|
|
@@ -558,9 +561,17 @@ function renderStatus(data, theme) {
|
|
|
558
561
|
NOT_APPLICABLE: "无独立进程",
|
|
559
562
|
};
|
|
560
563
|
const modules = data.modules.filter(isRecord);
|
|
564
|
+
const productOrder = new Map([
|
|
565
|
+
["execution-browser-extension", 0],
|
|
566
|
+
["dev-tunnel", 1],
|
|
567
|
+
["model-provider-api", 2],
|
|
568
|
+
]);
|
|
569
|
+
const orderedProblems = (entries) => [...entries].sort((a, b) => (productOrder.get(String(a.moduleRef)) ?? 100) -
|
|
570
|
+
(productOrder.get(String(b.moduleRef)) ?? 100));
|
|
561
571
|
const failedModules = modules.filter((item) => item.setupStatus === "FAILED" || item.runtimeStatus === "FAILED");
|
|
562
|
-
const actionModules = modules.filter((item) => item.setupStatus === "ACTION_REQUIRED" &&
|
|
563
|
-
|
|
572
|
+
const actionModules = orderedProblems(modules.filter((item) => item.setupStatus === "ACTION_REQUIRED" &&
|
|
573
|
+
item.runtimeStatus !== "FAILED"));
|
|
574
|
+
const blockedModules = orderedProblems(modules.filter((item) => item.setupStatus === "BLOCKED" && item.runtimeStatus !== "FAILED"));
|
|
564
575
|
const running = modules.filter((item) => item.setupStatus === "READY" && item.runtimeStatus === "RUNNING");
|
|
565
576
|
const healthy = modules.filter((item) => item.setupStatus === "READY" &&
|
|
566
577
|
item.runtimeStatus !== "RUNNING" &&
|
|
@@ -574,8 +585,11 @@ function renderStatus(data, theme) {
|
|
|
574
585
|
const moduleRef = String(raw.moduleRef);
|
|
575
586
|
const setupStatus = String(raw.setupStatus);
|
|
576
587
|
const runtimeStatus = String(raw.runtimeStatus);
|
|
588
|
+
const runtimeLabel = raw.externalAvailabilityClaim === "AVAILABLE"
|
|
589
|
+
? "外部资源可用"
|
|
590
|
+
: (runtimeLabels[runtimeStatus] ?? "未知");
|
|
577
591
|
lines.push(`${tone(icon)} ${theme.section(moduleRef)} ${theme.muted(String(raw.version))}`);
|
|
578
|
-
lines.push(` ${tone(setupLabels[setupStatus] ?? "未知")} · ${
|
|
592
|
+
lines.push(` ${tone(setupLabels[setupStatus] ?? "未知")} · ${runtimeLabel}`);
|
|
579
593
|
const issues = Array.isArray(raw.issues)
|
|
580
594
|
? raw.issues.filter(isRecord)
|
|
581
595
|
: [];
|
|
@@ -584,7 +598,8 @@ function renderStatus(data, theme) {
|
|
|
584
598
|
if (Array.isArray(issue.relatedModuleRefs) &&
|
|
585
599
|
issue.relatedModuleRefs.length > 0)
|
|
586
600
|
lines.push(` 依赖:${issue.relatedModuleRefs.map(String).join("、")}`);
|
|
587
|
-
|
|
601
|
+
if (setupStatus !== "BLOCKED")
|
|
602
|
+
lines.push(` 下一步:${theme.command(String(issue.nextCommand))}`);
|
|
588
603
|
}
|
|
589
604
|
lines.push("");
|
|
590
605
|
}
|
|
@@ -597,18 +612,20 @@ function renderStatus(data, theme) {
|
|
|
597
612
|
return;
|
|
598
613
|
lines.push(theme.section(title), "");
|
|
599
614
|
for (const item of entries) {
|
|
600
|
-
const runtime =
|
|
615
|
+
const runtime = item.externalAvailabilityClaim === "AVAILABLE"
|
|
616
|
+
? "外部资源可用"
|
|
617
|
+
: (runtimeLabels[String(item.runtimeStatus)] ?? "未知");
|
|
601
618
|
lines.push(`${theme.success(symbol)} ${String(item.moduleRef).padEnd(32)} ${theme.muted(String(item.version).padEnd(9))} ${runtime}`);
|
|
602
619
|
}
|
|
603
620
|
lines.push("");
|
|
604
621
|
};
|
|
605
622
|
compact("运行中", running, "●");
|
|
606
623
|
compact("已就绪", healthy, "○");
|
|
607
|
-
const ready =
|
|
608
|
-
const action = modules.filter((item) => item.setupStatus === "ACTION_REQUIRED").length;
|
|
609
|
-
const failed =
|
|
610
|
-
const blocked = modules.filter((item) => item.setupStatus === "BLOCKED").length;
|
|
611
|
-
lines.push(theme.section("汇总"), `${theme.success(`${ready}
|
|
624
|
+
const ready = healthy.length + running.length;
|
|
625
|
+
const action = modules.filter((item) => item.setupStatus === "ACTION_REQUIRED" && item.runtimeStatus !== "FAILED").length;
|
|
626
|
+
const failed = failedModules.length;
|
|
627
|
+
const blocked = modules.filter((item) => item.setupStatus === "BLOCKED" && item.runtimeStatus !== "FAILED").length;
|
|
628
|
+
lines.push(theme.section("汇总"), `${theme.success(`${ready} 配置已完成`)} · ${theme.warning(`${action} 根阻塞`)} · ${theme.info(`${blocked} 下游等待`)} · ${failed > 0 ? theme.failure(`${failed} 失败`) : `${failed} 失败`} · ${running.length} 个真实进程运行中`, `PLATFORM_READY=${action === 0 && blocked === 0 && failed === 0 ? "YES" : "NO"}`);
|
|
612
629
|
return lines.join("\n");
|
|
613
630
|
}
|
|
614
631
|
function renderTerminalMarkdown(source, theme) {
|
|
@@ -652,37 +669,33 @@ function renderDocs(data, theme) {
|
|
|
652
669
|
return lines.join("\n");
|
|
653
670
|
}
|
|
654
671
|
const setupCommands = {
|
|
655
|
-
"chatgpt-carrier": {
|
|
656
|
-
ai: "pnpm exec -- proflow-chatgpt-carrier setup --carrier-url <url>",
|
|
657
|
-
inputs: "Custom GPT URL",
|
|
658
|
-
},
|
|
659
672
|
"dev-tunnel": {
|
|
660
|
-
ai: "
|
|
661
|
-
inputs: "
|
|
673
|
+
ai: "platform setup --module dev-tunnel",
|
|
674
|
+
inputs: "无",
|
|
662
675
|
},
|
|
663
676
|
"model-provider-api": {
|
|
664
|
-
ai: "
|
|
665
|
-
inputs: "
|
|
677
|
+
ai: "platform setup --module model-provider-api",
|
|
678
|
+
inputs: "无(等待 Deployment resolver 提供 endpoint)",
|
|
666
679
|
},
|
|
667
680
|
"model-runtime": {
|
|
668
|
-
ai: "
|
|
669
|
-
inputs: "
|
|
681
|
+
ai: "platform setup --module model-runtime",
|
|
682
|
+
inputs: "无(仅等价合格候选歧义时选择)",
|
|
670
683
|
},
|
|
671
684
|
"execution-browser-extension": {
|
|
672
|
-
ai: "
|
|
673
|
-
inputs: "
|
|
685
|
+
ai: "platform setup --module execution-browser-extension",
|
|
686
|
+
inputs: "无",
|
|
674
687
|
},
|
|
675
688
|
"agent-controller-dev": {
|
|
676
|
-
ai: "
|
|
677
|
-
inputs: "
|
|
689
|
+
ai: "platform setup --module agent-controller-dev",
|
|
690
|
+
inputs: "无",
|
|
678
691
|
},
|
|
679
692
|
"agent-product": {
|
|
680
|
-
ai: "
|
|
681
|
-
inputs: "
|
|
693
|
+
ai: "platform setup --module agent-product",
|
|
694
|
+
inputs: "无",
|
|
682
695
|
},
|
|
683
696
|
"agent-test-ops": {
|
|
684
|
-
ai: "
|
|
685
|
-
inputs: "
|
|
697
|
+
ai: "platform setup --module agent-test-ops",
|
|
698
|
+
inputs: "无",
|
|
686
699
|
},
|
|
687
700
|
};
|
|
688
701
|
function renderSetup(data, theme) {
|
|
@@ -693,10 +706,12 @@ function renderSetup(data, theme) {
|
|
|
693
706
|
let ready = skipped.filter((item) => isRecord(item) && item.reason === "READY").length;
|
|
694
707
|
let needsAction = 0;
|
|
695
708
|
let blocked = 0;
|
|
709
|
+
const renderedModuleRefs = new Set();
|
|
696
710
|
for (const raw of data.results) {
|
|
697
711
|
if (!isRecord(raw) || !isRecord(raw.result))
|
|
698
712
|
continue;
|
|
699
713
|
const moduleRef = String(raw.moduleRef ?? raw.result.moduleRef ?? "unknown");
|
|
714
|
+
renderedModuleRefs.add(moduleRef);
|
|
700
715
|
const status = String(raw.result.status ?? "UNKNOWN");
|
|
701
716
|
if (status === "SUCCEEDED") {
|
|
702
717
|
ready += 1;
|
|
@@ -739,13 +754,13 @@ function renderSetup(data, theme) {
|
|
|
739
754
|
const error = raw.result.error;
|
|
740
755
|
if (status !== "FAILED") {
|
|
741
756
|
const commands = setupCommands[moduleRef] ?? {
|
|
742
|
-
ai: `
|
|
757
|
+
ai: `platform setup --module ${moduleRef}`,
|
|
743
758
|
inputs: "按命令提示提供",
|
|
744
759
|
};
|
|
745
|
-
lines.push(`
|
|
760
|
+
lines.push(` 人工执行:${commands.ai}`);
|
|
746
761
|
lines.push(` AI 执行:${commands.ai}`);
|
|
747
762
|
lines.push(` 需要输入:${commands.inputs}`);
|
|
748
|
-
lines.push(
|
|
763
|
+
lines.push(" 验证:platform status");
|
|
749
764
|
lines.push(" 完成条件:配置状态变为“已就绪”");
|
|
750
765
|
}
|
|
751
766
|
else if (isRecord(error)) {
|
|
@@ -759,6 +774,16 @@ function renderSetup(data, theme) {
|
|
|
759
774
|
}
|
|
760
775
|
lines.push("");
|
|
761
776
|
}
|
|
777
|
+
const dependencyBlockers = Array.isArray(data.blockers)
|
|
778
|
+
? data.blockers.filter(isRecord)
|
|
779
|
+
: [];
|
|
780
|
+
for (const item of dependencyBlockers) {
|
|
781
|
+
const moduleRef = String(item.moduleRef ?? "unknown");
|
|
782
|
+
if (renderedModuleRefs.has(moduleRef))
|
|
783
|
+
continue;
|
|
784
|
+
blocked += 1;
|
|
785
|
+
lines.push(`${theme.info("◇")} ${theme.section(moduleRef)}`, ` 原因:${typeof item.reason === "string" ? item.reason : "等待上游 Module 就绪"}`, ` 下一步:${theme.command(typeof item.nextCommand === "string" ? item.nextCommand : `platform setup --module ${moduleRef}`)}`, "");
|
|
786
|
+
}
|
|
762
787
|
if (needsAction === 0 && blocked === 0)
|
|
763
788
|
lines.push("全部模块均已就绪。");
|
|
764
789
|
lines.push(theme.section("汇总"), `汇总:${theme.success(`${ready} 个已就绪`)},${theme.warning(`${needsAction} 个需要操作`)},${blocked > 0 ? theme.failure(`${blocked} 个系统阻塞`) : `${blocked} 个系统阻塞`}`);
|
|
@@ -827,18 +852,17 @@ function renderHelp(theme, command) {
|
|
|
827
852
|
theme.section("推荐流程"),
|
|
828
853
|
` ${theme.command("install → status → docs → setup → start → status → stop")}`,
|
|
829
854
|
"",
|
|
830
|
-
theme.section("
|
|
831
|
-
`
|
|
832
|
-
` AI: ${theme.command("pnpm exec -- proflow-chatgpt-carrier setup")}`,
|
|
833
|
-
` ${theme.command("--carrier-url <url>")}`,
|
|
855
|
+
theme.section("配置入口"),
|
|
856
|
+
` ${theme.command("platform setup")}`,
|
|
834
857
|
"",
|
|
835
858
|
theme.section("状态图例"),
|
|
836
859
|
` ${theme.success("已就绪")} 配置与验证完成`,
|
|
837
860
|
` ${theme.warning("需要操作")} 需要执行 setup 步骤`,
|
|
838
861
|
` ${theme.info("等待依赖")} 等待上游 Module 或外部服务`,
|
|
839
862
|
` ${theme.failure("失败")} 已确认配置或运行故障`,
|
|
840
|
-
" 运行中
|
|
841
|
-
"
|
|
863
|
+
" 运行中 服务进程正在运行",
|
|
864
|
+
" 外部资源可用 Chrome 等外部资源已通过真实探测",
|
|
865
|
+
" 无独立进程 该模块无需启动",
|
|
842
866
|
"",
|
|
843
867
|
theme.section("遇到问题"),
|
|
844
868
|
` 先运行 ${theme.command("platform status")};配置问题运行 ${theme.command("platform setup")}。`,
|
|
@@ -855,24 +879,35 @@ export function renderHumanResult(result, options = {}) {
|
|
|
855
879
|
? result.data.blockers.filter(isRecord)
|
|
856
880
|
: [];
|
|
857
881
|
if (blockers.length > 0) {
|
|
882
|
+
const productOrder = new Map([
|
|
883
|
+
["execution-browser-extension", 0],
|
|
884
|
+
["dev-tunnel", 1],
|
|
885
|
+
["model-provider-api", 2],
|
|
886
|
+
]);
|
|
858
887
|
const groups = [
|
|
859
888
|
{ status: "FAILED", title: "失败", icon: "✕", tone: theme.failure },
|
|
860
889
|
{
|
|
861
890
|
status: "ACTION_REQUIRED",
|
|
862
|
-
title: "
|
|
891
|
+
title: "当前根阻塞",
|
|
863
892
|
icon: "◆",
|
|
864
893
|
tone: theme.warning,
|
|
865
894
|
},
|
|
866
|
-
{ status: "BLOCKED", title: "
|
|
895
|
+
{ status: "BLOCKED", title: "下游等待", icon: "◇", tone: theme.info },
|
|
867
896
|
];
|
|
868
897
|
const lines = [theme.failure("平台未启动:存在未就绪模块"), ""];
|
|
869
898
|
for (const group of groups) {
|
|
870
|
-
const entries = blockers
|
|
899
|
+
const entries = blockers
|
|
900
|
+
.filter((item) => item.setupStatus === group.status)
|
|
901
|
+
.sort((a, b) => (productOrder.get(String(a.moduleRef)) ?? 100) -
|
|
902
|
+
(productOrder.get(String(b.moduleRef)) ?? 100));
|
|
871
903
|
if (entries.length === 0)
|
|
872
904
|
continue;
|
|
873
905
|
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 : "模块尚未就绪"}
|
|
906
|
+
for (const item of entries) {
|
|
907
|
+
lines.push(`${group.tone(group.icon)} ${theme.section(String(item.moduleRef))}`, ` 原因:${typeof item.reason === "string" ? item.reason : "模块尚未就绪"}`);
|
|
908
|
+
if (group.status !== "BLOCKED")
|
|
909
|
+
lines.push(` 下一步:${theme.command(typeof item.nextCommand === "string" ? item.nextCommand : `platform setup --module ${String(item.moduleRef)}`)}`);
|
|
910
|
+
}
|
|
876
911
|
lines.push("");
|
|
877
912
|
}
|
|
878
913
|
const readyCount = Array.isArray(result.data.results)
|
|
@@ -880,7 +915,7 @@ export function renderHumanResult(result, options = {}) {
|
|
|
880
915
|
isRecord(item.result) &&
|
|
881
916
|
item.result.status === "SUCCEEDED").length - blockers.length
|
|
882
917
|
: 0;
|
|
883
|
-
lines.push(theme.section("检查汇总"), `${Math.max(0, readyCount)}
|
|
918
|
+
lines.push(theme.section("检查汇总"), `${Math.max(0, readyCount)} 配置已完成 · ${blockers.filter((item) => item.setupStatus === "ACTION_REQUIRED").length} 根阻塞 · ${blockers.filter((item) => item.setupStatus === "BLOCKED").length} 下游等待 · 0 个真实进程启动`, "PLATFORM_READY=NO", `处理方式:${theme.command(`platform setup${result.workspaceRoot ? ` --workspace "${result.workspaceRoot}"` : ""}`)}`);
|
|
884
919
|
return lines.join("\n");
|
|
885
920
|
}
|
|
886
921
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const FROZEN_DEPLOYMENT_INSTALL_ORDER: readonly ["chrome-runtime", "execution-browser-extension", "agent-controller-dev", "agent-product", "agent-test-ops", "agent-gateway", "dev-tunnel", "agent-runtime", "platform-host", "execution-runtime", "execution-local", "model-provider-api", "model-runtime", "task-orchestration", "task-store-sqlite", "task-migration-runner", "execution-contracts", "model-contracts", "module-contract", "module-skill", "module-template", "deployment-conformance", "platform-cli"];
|
|
2
|
+
export declare function orderModuleRefsForInstall(moduleRefs: readonly string[]): string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const FROZEN_DEPLOYMENT_INSTALL_ORDER = [
|
|
2
|
+
"chrome-runtime",
|
|
3
|
+
"execution-browser-extension",
|
|
4
|
+
"agent-controller-dev",
|
|
5
|
+
"agent-product",
|
|
6
|
+
"agent-test-ops",
|
|
7
|
+
"agent-gateway",
|
|
8
|
+
"dev-tunnel",
|
|
9
|
+
"agent-runtime",
|
|
10
|
+
"platform-host",
|
|
11
|
+
"execution-runtime",
|
|
12
|
+
"execution-local",
|
|
13
|
+
"model-provider-api",
|
|
14
|
+
"model-runtime",
|
|
15
|
+
"task-orchestration",
|
|
16
|
+
"task-store-sqlite",
|
|
17
|
+
"task-migration-runner",
|
|
18
|
+
"execution-contracts",
|
|
19
|
+
"model-contracts",
|
|
20
|
+
"module-contract",
|
|
21
|
+
"module-skill",
|
|
22
|
+
"module-template",
|
|
23
|
+
"deployment-conformance",
|
|
24
|
+
"platform-cli",
|
|
25
|
+
];
|
|
26
|
+
const installRank = new Map(FROZEN_DEPLOYMENT_INSTALL_ORDER.map((moduleRef, index) => [moduleRef, index]));
|
|
27
|
+
export function orderModuleRefsForInstall(moduleRefs) {
|
|
28
|
+
return [...moduleRefs].sort((left, right) => {
|
|
29
|
+
const leftRank = installRank.get(left);
|
|
30
|
+
const rightRank = installRank.get(right);
|
|
31
|
+
if (leftRank !== undefined && rightRank !== undefined)
|
|
32
|
+
return leftRank - rightRank;
|
|
33
|
+
if (leftRank !== undefined)
|
|
34
|
+
return -1;
|
|
35
|
+
if (rightRank !== undefined)
|
|
36
|
+
return 1;
|
|
37
|
+
return left.localeCompare(right);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -6,5 +6,6 @@ export interface ModuleDispatchResult {
|
|
|
6
6
|
command: ModuleManagementCommand;
|
|
7
7
|
result: ModuleOperationResult;
|
|
8
8
|
observedEffects: string[];
|
|
9
|
+
externalAvailabilityClaim?: "AVAILABLE" | "UNAVAILABLE";
|
|
9
10
|
}
|
|
10
11
|
export declare function dispatchModuleCommand(catalog: ModuleCatalog, module: ResolvedModule, command: ModuleManagementCommand, context: ModuleCommandContext): Promise<ModuleDispatchResult>;
|
|
@@ -24,6 +24,10 @@ function normalizeInvocation(raw) {
|
|
|
24
24
|
observedEffects: Array.isArray(raw.observedEffects)
|
|
25
25
|
? raw.observedEffects.filter((item) => typeof item === "string")
|
|
26
26
|
: [],
|
|
27
|
+
...(raw.externalAvailabilityClaim === "AVAILABLE" ||
|
|
28
|
+
raw.externalAvailabilityClaim === "UNAVAILABLE"
|
|
29
|
+
? { externalAvailabilityClaim: raw.externalAvailabilityClaim }
|
|
30
|
+
: {}),
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
export async function dispatchModuleCommand(catalog, module, command, context) {
|
|
@@ -32,7 +36,7 @@ export async function dispatchModuleCommand(catalog, module, command, context) {
|
|
|
32
36
|
const invoke = adapter[command];
|
|
33
37
|
if (!isCommandFn(invoke))
|
|
34
38
|
throw new PlatformError("COMMAND_FAILED", `module ${module.moduleRef} does not implement standard command "${command}"`);
|
|
35
|
-
const { result, observedEffects } = normalizeInvocation(await invoke(context));
|
|
39
|
+
const { result, observedEffects, externalAvailabilityClaim } = normalizeInvocation(await invoke(context));
|
|
36
40
|
const parsed = moduleOperationResultSchema.safeParse(result);
|
|
37
41
|
if (!parsed.success)
|
|
38
42
|
throw new PlatformError("COMMAND_FAILED", `module ${module.moduleRef} "${command}" returned an invalid result: ${parsed.error.message}`);
|
|
@@ -41,5 +45,8 @@ export async function dispatchModuleCommand(catalog, module, command, context) {
|
|
|
41
45
|
command,
|
|
42
46
|
result: parsed.data,
|
|
43
47
|
observedEffects,
|
|
48
|
+
...(externalAvailabilityClaim === undefined
|
|
49
|
+
? {}
|
|
50
|
+
: { externalAvailabilityClaim }),
|
|
44
51
|
};
|
|
45
52
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { moduleStatusObservationSchema, } from "@tomflow/proflow-module-contract";
|
|
2
|
+
import { orderModuleRefsForInstall } from "../deployment-order.js";
|
|
2
3
|
import { PlatformError } from "../errors.js";
|
|
3
4
|
import { buildDependencyGraph } from "../graph/graph.js";
|
|
4
5
|
import { reportProgress } from "../progress.js";
|
|
@@ -13,6 +14,16 @@ function ordered(modules, reverse = false) {
|
|
|
13
14
|
.map((ref) => byRef.get(ref))
|
|
14
15
|
.filter((item) => item !== undefined);
|
|
15
16
|
}
|
|
17
|
+
function orderedForInstall(modules) {
|
|
18
|
+
// Keep dependency validation, but do not let dependency depth/alphabetical order
|
|
19
|
+
// dictate the user-facing package installation trajectory.
|
|
20
|
+
buildDependencyGraph(modules);
|
|
21
|
+
const refs = orderModuleRefsForInstall(modules.map((module) => module.moduleRef));
|
|
22
|
+
const byRef = new Map(modules.map((module) => [module.moduleRef, module]));
|
|
23
|
+
return refs
|
|
24
|
+
.map((ref) => byRef.get(ref))
|
|
25
|
+
.filter((item) => item !== undefined);
|
|
26
|
+
}
|
|
16
27
|
export async function observeStatuses(catalog, modules, workspaceRoot, reporter) {
|
|
17
28
|
const results = [];
|
|
18
29
|
const modulesInOrder = [...modules].sort((a, b) => a.moduleRef.localeCompare(b.moduleRef));
|
|
@@ -69,7 +80,9 @@ export async function observeDocs(catalog, modules, workspaceRoot, reporter) {
|
|
|
69
80
|
}
|
|
70
81
|
async function runOrdered(catalog, modules, workspaceRoot, command, reverse, reporter) {
|
|
71
82
|
const results = [];
|
|
72
|
-
const modulesInOrder =
|
|
83
|
+
const modulesInOrder = command === "install"
|
|
84
|
+
? orderedForInstall(modules)
|
|
85
|
+
: ordered(modules, reverse);
|
|
73
86
|
for (const [index, module] of modulesInOrder.entries()) {
|
|
74
87
|
reportProgress(reporter, {
|
|
75
88
|
command,
|
|
@@ -162,12 +175,18 @@ export async function stopModulesThin(catalog, modules, workspaceRoot, reporter)
|
|
|
162
175
|
export async function setupModulesThin(catalog, modules, workspaceRoot, target, reporter) {
|
|
163
176
|
const results = [];
|
|
164
177
|
const skipped = [];
|
|
165
|
-
|
|
178
|
+
const blockers = [];
|
|
179
|
+
const graph = buildDependencyGraph(modules);
|
|
180
|
+
const byRef = new Map(modules.map((module) => [module.moduleRef, module]));
|
|
181
|
+
if (target !== undefined && !byRef.has(target.moduleRef))
|
|
182
|
+
throw new PlatformError("INVALID_REQUEST", `setup target module ${target.moduleRef} was not discovered`);
|
|
183
|
+
const selectedRefs = new Set(target === undefined ? graph.order : [target.moduleRef]);
|
|
184
|
+
const modulesInOrder = graph.order
|
|
185
|
+
.filter((moduleRef) => selectedRefs.has(moduleRef))
|
|
186
|
+
.map((moduleRef) => byRef.get(moduleRef))
|
|
187
|
+
.filter((module) => module !== undefined);
|
|
166
188
|
let completed = true;
|
|
167
|
-
const modulesInOrder = ordered(modules);
|
|
168
189
|
for (const [index, module] of modulesInOrder.entries()) {
|
|
169
|
-
if (target !== undefined && module.moduleRef !== target.moduleRef)
|
|
170
|
-
continue;
|
|
171
190
|
reportProgress(reporter, {
|
|
172
191
|
command: "setup",
|
|
173
192
|
phase: "setup",
|
|
@@ -177,17 +196,16 @@ export async function setupModulesThin(catalog, modules, workspaceRoot, target,
|
|
|
177
196
|
status: "STARTED",
|
|
178
197
|
message: module.moduleRef,
|
|
179
198
|
});
|
|
180
|
-
matched = true;
|
|
181
199
|
const status = await dispatchModuleCommand(catalog, module, "status", context(workspaceRoot));
|
|
182
200
|
if (!succeeded(status.result)) {
|
|
183
201
|
results.push(status);
|
|
184
202
|
completed = false;
|
|
185
|
-
if (target
|
|
203
|
+
if (target?.moduleRef === module.moduleRef)
|
|
186
204
|
break;
|
|
187
205
|
continue;
|
|
188
206
|
}
|
|
189
207
|
const observed = moduleStatusObservationSchema.parse(status.result.data);
|
|
190
|
-
if (observed.setupStatus === "READY" && target
|
|
208
|
+
if (observed.setupStatus === "READY" && target === undefined) {
|
|
191
209
|
skipped.push({ moduleRef: module.moduleRef, reason: "READY" });
|
|
192
210
|
reportProgress(reporter, {
|
|
193
211
|
command: "setup",
|
|
@@ -217,13 +235,38 @@ export async function setupModulesThin(catalog, modules, workspaceRoot, target,
|
|
|
217
235
|
});
|
|
218
236
|
if (!succeeded(setup.result)) {
|
|
219
237
|
completed = false;
|
|
220
|
-
if (target !== undefined)
|
|
221
|
-
break;
|
|
222
238
|
}
|
|
239
|
+
const reconciled = await dispatchModuleCommand(catalog, module, "status", context(workspaceRoot));
|
|
240
|
+
if (!succeeded(reconciled.result)) {
|
|
241
|
+
results.push(reconciled);
|
|
242
|
+
completed = false;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
const reconciledStatus = moduleStatusObservationSchema.parse(reconciled.result.data);
|
|
246
|
+
if (reconciledStatus.setupStatus === "BLOCKED" ||
|
|
247
|
+
reconciledStatus.setupStatus === "FAILED") {
|
|
248
|
+
const issue = reconciledStatus.issues?.find((item) => item.scope === "SETUP");
|
|
249
|
+
blockers.push({
|
|
250
|
+
moduleRef: module.moduleRef,
|
|
251
|
+
setupStatus: reconciledStatus.setupStatus,
|
|
252
|
+
...(issue === undefined
|
|
253
|
+
? {}
|
|
254
|
+
: { reason: issue.message, nextCommand: issue.nextCommand }),
|
|
255
|
+
});
|
|
256
|
+
completed = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (target !== undefined &&
|
|
260
|
+
(!succeeded(setup.result) || blockers.length > 0))
|
|
261
|
+
break;
|
|
223
262
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
263
|
+
return {
|
|
264
|
+
phase: "setup",
|
|
265
|
+
results,
|
|
266
|
+
completed,
|
|
267
|
+
...(blockers[0] ? { blockedBy: blockers[0], blockers } : {}),
|
|
268
|
+
skipped,
|
|
269
|
+
};
|
|
227
270
|
}
|
|
228
271
|
export async function startModulesThin(catalog, modules, workspaceRoot, reporter) {
|
|
229
272
|
const results = [];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { NpmCommandResult, NpmCommandRunner, RegistryDiscoveryResult, RegistryModuleCandidate, RegistryRejectedPackage, } from "./npm-registry.ts";
|
|
2
|
-
export { discoverRegistryModules, PRO_FLOW_PACKAGE_PREFIX, PRO_FLOW_SCOPE, resolveScopeRegistry, systemNpmRunner, } from "./npm-registry.ts";
|
|
2
|
+
export { discoverRegistryModules, PRO_FLOW_PACKAGE_PREFIX, PRO_FLOW_SCOPE, RETIRED_PRO_FLOW_PACKAGES, resolveScopeRegistry, systemNpmRunner, } from "./npm-registry.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { discoverRegistryModules, PRO_FLOW_PACKAGE_PREFIX, PRO_FLOW_SCOPE, resolveScopeRegistry, systemNpmRunner, } from "./npm-registry.js";
|
|
1
|
+
export { discoverRegistryModules, PRO_FLOW_PACKAGE_PREFIX, PRO_FLOW_SCOPE, RETIRED_PRO_FLOW_PACKAGES, resolveScopeRegistry, systemNpmRunner, } from "./npm-registry.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const PRO_FLOW_SCOPE = "@tomflow";
|
|
2
2
|
export declare const PRO_FLOW_PACKAGE_PREFIX = "@tomflow/proflow-";
|
|
3
|
+
export declare const RETIRED_PRO_FLOW_PACKAGES: Set<string>;
|
|
3
4
|
export interface NpmCommandResult {
|
|
4
5
|
stdout: string;
|
|
5
6
|
stderr: string;
|
|
@@ -26,6 +27,7 @@ export interface RegistryDiscoveryResult {
|
|
|
26
27
|
registry: string;
|
|
27
28
|
candidates: RegistryModuleCandidate[];
|
|
28
29
|
rejected: RegistryRejectedPackage[];
|
|
30
|
+
retired: string[];
|
|
29
31
|
}
|
|
30
32
|
export declare function systemNpmRunner(): NpmCommandRunner;
|
|
31
33
|
export declare function resolveScopeRegistry(workspaceRoot: string, runner?: NpmCommandRunner): Promise<string>;
|
|
@@ -6,6 +6,9 @@ import { versionSatisfies } from "../modules.js";
|
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
export const PRO_FLOW_SCOPE = "@tomflow";
|
|
8
8
|
export const PRO_FLOW_PACKAGE_PREFIX = "@tomflow/proflow-";
|
|
9
|
+
export const RETIRED_PRO_FLOW_PACKAGES = new Set([
|
|
10
|
+
"@tomflow/proflow-chatgpt-carrier",
|
|
11
|
+
]);
|
|
9
12
|
export function systemNpmRunner() {
|
|
10
13
|
return {
|
|
11
14
|
async run(args, cwd, timeoutMs) {
|
|
@@ -42,15 +45,17 @@ export async function discoverRegistryModules(options) {
|
|
|
42
45
|
const names = options.packageName === undefined
|
|
43
46
|
? await searchPackageNames(options.workspaceRoot, registry, runner)
|
|
44
47
|
: [validateRequestedPackageName(options.packageName)];
|
|
45
|
-
|
|
48
|
+
const retired = names.filter((name) => RETIRED_PRO_FLOW_PACKAGES.has(name));
|
|
49
|
+
const activeNames = names.filter((name) => !RETIRED_PRO_FLOW_PACKAGES.has(name));
|
|
50
|
+
options.onSearchComplete?.(activeNames.length);
|
|
46
51
|
const candidates = [];
|
|
47
52
|
const rejected = [];
|
|
48
53
|
let nextIndex = 0;
|
|
49
54
|
let completed = 0;
|
|
50
55
|
const worker = async () => {
|
|
51
|
-
while (nextIndex <
|
|
56
|
+
while (nextIndex < activeNames.length) {
|
|
52
57
|
const index = nextIndex++;
|
|
53
|
-
const packageName =
|
|
58
|
+
const packageName = activeNames[index];
|
|
54
59
|
if (packageName === undefined)
|
|
55
60
|
return;
|
|
56
61
|
const manifest = await viewManifest(options.workspaceRoot, registry, packageName, runner);
|
|
@@ -62,15 +67,15 @@ export async function discoverRegistryModules(options) {
|
|
|
62
67
|
completed += 1;
|
|
63
68
|
options.onPackageChecked?.({
|
|
64
69
|
current: completed,
|
|
65
|
-
total:
|
|
70
|
+
total: activeNames.length,
|
|
66
71
|
packageName,
|
|
67
72
|
});
|
|
68
73
|
}
|
|
69
74
|
};
|
|
70
|
-
await Promise.all(Array.from({ length: Math.min(4,
|
|
75
|
+
await Promise.all(Array.from({ length: Math.min(4, activeNames.length) }, () => worker()));
|
|
71
76
|
candidates.sort((left, right) => left.packageName.localeCompare(right.packageName));
|
|
72
77
|
rejected.sort((left, right) => left.packageName.localeCompare(right.packageName));
|
|
73
|
-
return { registry, candidates, rejected };
|
|
78
|
+
return { registry, candidates, rejected, retired };
|
|
74
79
|
}
|
|
75
80
|
async function searchPackageNames(workspaceRoot, registry, runner) {
|
|
76
81
|
const result = await runner.run([
|
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.38",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"SETUP.md"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@tomflow/proflow-module-contract": "^0.1.
|
|
27
|
+
"@tomflow/proflow-module-contract": "^0.1.13"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@tomflow/proflow-deployment-conformance": "^0.1.
|
|
31
|
-
"@tomflow/proflow-module-template": "^0.1.
|
|
30
|
+
"@tomflow/proflow-deployment-conformance": "^0.1.12",
|
|
31
|
+
"@tomflow/proflow-module-template": "^0.1.10"
|
|
32
32
|
},
|
|
33
33
|
"description": "Thin Platform CLI for Module discovery, documentation, package synchronization and lifecycle orchestration.",
|
|
34
34
|
"keywords": [
|
package/proflow.module.json
CHANGED