@actiondock/core 2.0.11 → 2.0.12

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.
Files changed (119) hide show
  1. package/dist/build/templates.d.ts +19 -0
  2. package/dist/catalog/action-index.d.ts +9 -0
  3. package/dist/catalog/action-resolver.d.ts +20 -0
  4. package/dist/catalog/location-registry.d.ts +15 -0
  5. package/dist/catalog/package-catalog.d.ts +7 -0
  6. package/dist/catalog/types.d.ts +68 -0
  7. package/dist/doctor/doctor.d.ts +6 -0
  8. package/dist/doctor/types.d.ts +23 -0
  9. package/dist/execution/index.d.ts +2 -0
  10. package/dist/execution/service.d.ts +74 -0
  11. package/dist/execution/types.d.ts +74 -0
  12. package/dist/export/templates.d.ts +33 -0
  13. package/dist/filter/intent.d.ts +33 -0
  14. package/{src/index.ts → dist/index.d.ts} +1 -1
  15. package/dist/index.js +8458 -0
  16. package/dist/profile/client.d.ts +116 -0
  17. package/dist/profile/manager.d.ts +47 -0
  18. package/dist/profile/types.d.ts +61 -0
  19. package/dist/project/closure.d.ts +25 -0
  20. package/{src/project/index.ts → dist/project/index.d.ts} +1 -0
  21. package/dist/project/init.d.ts +27 -0
  22. package/dist/project/loader.d.ts +105 -0
  23. package/dist/project/manifest.d.ts +44 -0
  24. package/dist/project/types.d.ts +131 -0
  25. package/dist/registry/registry.d.ts +24 -0
  26. package/dist/registry/types.d.ts +117 -0
  27. package/dist/runtime/clock.d.ts +21 -0
  28. package/dist/runtime/context.d.ts +75 -0
  29. package/dist/runtime/env.d.ts +54 -0
  30. package/dist/runtime/events.d.ts +61 -0
  31. package/dist/runtime/execution-manager.d.ts +48 -0
  32. package/{src/runtime/index.ts → dist/runtime/index.d.ts} +0 -1
  33. package/dist/runtime/module-loader.d.ts +42 -0
  34. package/dist/runtime/process.d.ts +11 -0
  35. package/dist/runtime/runner.d.ts +186 -0
  36. package/dist/runtime/standalone.d.ts +40 -0
  37. package/dist/schema/validator.d.ts +28 -0
  38. package/dist/server/body.d.ts +40 -0
  39. package/{src/server/index.ts → dist/server/index.d.ts} +0 -1
  40. package/dist/server/routes/actions.d.ts +5 -0
  41. package/dist/server/routes/common.d.ts +36 -0
  42. package/dist/server/routes/config.d.ts +5 -0
  43. package/dist/server/routes/doctor.d.ts +5 -0
  44. package/dist/server/routes/health.d.ts +5 -0
  45. package/dist/server/routes/info.d.ts +5 -0
  46. package/dist/server/routes/playbooks.d.ts +5 -0
  47. package/dist/server/routes/runs.d.ts +5 -0
  48. package/dist/server/routes/state.d.ts +5 -0
  49. package/dist/server/runtime-registry.d.ts +78 -0
  50. package/dist/server/security.d.ts +37 -0
  51. package/dist/server/server.d.ts +15 -0
  52. package/dist/server/types.d.ts +59 -0
  53. package/dist/storage/driver.d.ts +15 -0
  54. package/dist/storage/index.d.ts +44 -0
  55. package/{src/storage/mask.ts → dist/storage/mask.d.ts} +5 -20
  56. package/dist/storage/sqlite.d.ts +66 -0
  57. package/dist/storage/types.d.ts +121 -0
  58. package/dist/utils/index.d.ts +29 -0
  59. package/dist/version.d.ts +4 -0
  60. package/package.json +11 -10
  61. package/src/build/templates.ts +0 -59
  62. package/src/catalog/action-index.ts +0 -92
  63. package/src/catalog/action-resolver.ts +0 -120
  64. package/src/catalog/location-registry.ts +0 -134
  65. package/src/catalog/package-catalog.ts +0 -87
  66. package/src/catalog/types.ts +0 -75
  67. package/src/doctor/doctor.ts +0 -419
  68. package/src/doctor/types.ts +0 -25
  69. package/src/execution/index.ts +0 -2
  70. package/src/execution/service.ts +0 -322
  71. package/src/execution/types.ts +0 -73
  72. package/src/export/templates.ts +0 -590
  73. package/src/filter/intent.ts +0 -154
  74. package/src/profile/client.ts +0 -552
  75. package/src/profile/manager.ts +0 -341
  76. package/src/profile/types.ts +0 -71
  77. package/src/project/init.ts +0 -242
  78. package/src/project/loader.ts +0 -479
  79. package/src/project/manifest.ts +0 -299
  80. package/src/project/types.ts +0 -141
  81. package/src/registry/registry.ts +0 -940
  82. package/src/registry/types.ts +0 -127
  83. package/src/runtime/clock.ts +0 -41
  84. package/src/runtime/context.ts +0 -259
  85. package/src/runtime/env.ts +0 -172
  86. package/src/runtime/events.ts +0 -142
  87. package/src/runtime/execution-manager.ts +0 -74
  88. package/src/runtime/module-loader.ts +0 -67
  89. package/src/runtime/process.ts +0 -245
  90. package/src/runtime/runner.ts +0 -527
  91. package/src/runtime/standalone.ts +0 -429
  92. package/src/schema/validator.ts +0 -61
  93. package/src/server/body.ts +0 -112
  94. package/src/server/routes/actions.ts +0 -262
  95. package/src/server/routes/common.ts +0 -126
  96. package/src/server/routes/config.ts +0 -147
  97. package/src/server/routes/doctor.ts +0 -29
  98. package/src/server/routes/health.ts +0 -40
  99. package/src/server/routes/info.ts +0 -221
  100. package/src/server/routes/playbooks.ts +0 -109
  101. package/src/server/routes/runs.ts +0 -301
  102. package/src/server/routes/state.ts +0 -133
  103. package/src/server/runtime-registry.ts +0 -115
  104. package/src/server/security.ts +0 -115
  105. package/src/server/server.ts +0 -251
  106. package/src/server/types.ts +0 -57
  107. package/src/storage/driver.ts +0 -126
  108. package/src/storage/index.ts +0 -81
  109. package/src/storage/sqlite.ts +0 -714
  110. package/src/storage/types.ts +0 -139
  111. package/src/utils/index.ts +0 -62
  112. /package/{src/build/index.ts → dist/build/index.d.ts} +0 -0
  113. /package/{src/catalog/index.ts → dist/catalog/index.d.ts} +0 -0
  114. /package/{src/doctor/index.ts → dist/doctor/index.d.ts} +0 -0
  115. /package/{src/export/index.ts → dist/export/index.d.ts} +0 -0
  116. /package/{src/filter/index.ts → dist/filter/index.d.ts} +0 -0
  117. /package/{src/profile/index.ts → dist/profile/index.d.ts} +0 -0
  118. /package/{src/registry/index.ts → dist/registry/index.d.ts} +0 -0
  119. /package/{src/server/routes/index.ts → dist/server/routes/index.d.ts} +0 -0
@@ -1,127 +0,0 @@
1
- /**
2
- * 本地软链接(Link)注册的 Package 实体记录。
3
- */
4
- export interface LinkedPackageEntry {
5
- /** Package 唯一 ID */
6
- id: string;
7
- /** 展示名称 */
8
- name: string;
9
- /** 版本号 */
10
- version: string;
11
- /** 源码物理目录绝对路径 */
12
- path: string;
13
- /** 建立软链接的时间戳(ISO 8601) */
14
- linkedAt: string;
15
- /** 所属 Workspace 根目录(如果是通过 Workspace 自动关联的) */
16
- workspaceRoot?: string;
17
- }
18
-
19
- /**
20
- * 本地软链接(Link)注册的 Workspace 工作区目录记录。
21
- */
22
- export interface LinkedWorkspaceEntry {
23
- /** 工作区物理目录绝对路径 */
24
- path: string;
25
- /** 建立软链接的时间戳(ISO 8601) */
26
- linkedAt: string;
27
- }
28
-
29
- /**
30
- * 全局 Registry 数据结构(~/.actiondock/registry.json)。
31
- */
32
- export interface GlobalRegistryData {
33
- version: "2.0.0";
34
- packages: Record<string, LinkedPackageEntry>;
35
- workspaces?: Record<string, LinkedWorkspaceEntry>;
36
- }
37
-
38
- /**
39
- * Link 操作返回结果。
40
- */
41
- export interface LinkResult {
42
- id: string;
43
- name: string;
44
- version: string;
45
- path: string;
46
- linkedAt: string;
47
- isWorkspace?: boolean;
48
- entries: LinkedPackageEntry[];
49
- workspace?: LinkedWorkspaceEntry;
50
- }
51
-
52
- /**
53
- * Unlink 操作返回结果。
54
- */
55
- export interface UnlinkResult {
56
- type: "package" | "workspace";
57
- id: string;
58
- path: string;
59
- packagesCount?: number;
60
- removedPackage?: LinkedPackageEntry;
61
- removedWorkspace?: LinkedWorkspaceEntry;
62
- }
63
-
64
- /**
65
- * 注册表树形层级节点。
66
- */
67
- export interface RegistryTreeItem {
68
- type: "workspace" | "package";
69
- id: string;
70
- name?: string;
71
- version?: string;
72
- path: string;
73
- status: "active" | "stale";
74
- packagesCount?: number;
75
- children?: Array<{
76
- id: string;
77
- name: string;
78
- version: string;
79
- path: string;
80
- status: "active" | "stale";
81
- }>;
82
- }
83
-
84
- /**
85
- * 注册表健康状态与列表报告。
86
- */
87
- export interface RegistryStatusReport {
88
- workspaces: RegistryTreeItem[];
89
- packages: RegistryTreeItem[];
90
- staleCount: number;
91
- totalPackagesCount: number;
92
- }
93
-
94
- /**
95
- * 失效清理结果。
96
- */
97
- export interface PruneResult {
98
- prunedPackages: LinkedPackageEntry[];
99
- prunedWorkspaces: LinkedWorkspaceEntry[];
100
- }
101
-
102
- /**
103
- * Action 归属项目解析结果。
104
- */
105
- export interface ResolvedActionProject {
106
- /** 所在项目的根目录绝对路径 */
107
- projectRoot: string;
108
- /** 所属 Package ID */
109
- packageId: string;
110
- /** 匹配到的 Action ID */
111
- actionId: string;
112
- }
113
-
114
- /**
115
- * Playbook 归属项目解析结果。
116
- */
117
- export interface ResolvedPlaybookProject {
118
- /** 所在项目的根目录绝对路径 */
119
- projectRoot: string;
120
- /** 所属 Package ID */
121
- packageId: string;
122
- /** 匹配到的 Playbook ID */
123
- playbookId: string;
124
- /** Playbook 实体数据 */
125
- playbook: import("../project/types").PlaybookDefinition;
126
- }
127
-
@@ -1,41 +0,0 @@
1
- /**
2
- * 统一时间与时钟接口。
3
- */
4
- export interface Clock {
5
- /** 获取当前系统墙上时间 */
6
- now(): Date;
7
- /** 获取单调递增时间戳(单位:毫秒) */
8
- monotonic(): number;
9
- /** 异步休眠指定毫秒 */
10
- sleep(ms: number): Promise<void>;
11
- }
12
-
13
- /**
14
- * 生产环境系统时钟实现。
15
- */
16
- export class SystemClock implements Clock {
17
- now(): Date {
18
- return new Date();
19
- }
20
-
21
- monotonic(): number {
22
- if (typeof performance !== "undefined" && typeof performance.now === "function") {
23
- return performance.now();
24
- }
25
- return Date.now();
26
- }
27
-
28
- sleep(ms: number): Promise<void> {
29
- return new Promise((resolve) => setTimeout(resolve, ms));
30
- }
31
- }
32
-
33
- let defaultClock: Clock = new SystemClock();
34
-
35
- export function getSystemClock(): Clock {
36
- return defaultClock;
37
- }
38
-
39
- export function setSystemClock(clock: Clock): void {
40
- defaultClock = clock;
41
- }
@@ -1,259 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import type {
3
- ActionContext,
4
- ActionDefinition,
5
- ActionInvoker,
6
- ActionRef,
7
- Config,
8
- Logger,
9
- ProcessAPI,
10
- ProgressReporter,
11
- StateStore,
12
- } from "@actiondock/sdk";
13
- import type { ProjectConfig } from "../project/types";
14
- import { createGlobalStorage } from "../storage";
15
- import type { RuntimeStorage } from "../storage/types";
16
- import { resolveEnvValue } from "./env";
17
- import { getProcessExecutor } from "./process";
18
-
19
- /**
20
- * 生产级配置解析器实现。
21
- * 严格践行 5 层配置解析优先级链:
22
- * 1. CLI 临时参数覆写 (Overrides)
23
- * 2. 本地项目持久化存储 (Local SQLite: .actiondock/runtime.db)
24
- * 3. 全局共享持久化存储 (Global SQLite: ~/.actiondock/global.db)
25
- * 4. 操作系统环境变量 (process.env: 显式绑定 / 包名前缀 / SNAKE_CASE / 类型转换)
26
- * 5. 项目默认配置 (actiondock.json 中的 default 字段)
27
- * 6. 代码级默认回退值 (fallback)
28
- */
29
- export class RuntimeConfig implements Config {
30
- private overrides: Map<string, unknown>;
31
- private storage: RuntimeStorage;
32
- private projectConfig?: ProjectConfig;
33
- private globalStorage?: RuntimeStorage;
34
-
35
- constructor(
36
- storage: RuntimeStorage,
37
- overrides: Record<string, unknown> = {},
38
- projectConfig?: ProjectConfig,
39
- globalStorage?: RuntimeStorage
40
- ) {
41
- this.storage = storage;
42
- this.overrides = new Map(Object.entries(overrides));
43
- this.projectConfig = projectConfig;
44
- this.globalStorage = globalStorage !== undefined ? globalStorage : createGlobalStorage();
45
- }
46
-
47
- get<T = unknown>(key: string): T | undefined;
48
- get<T = unknown>(key: string, defaultValue: T): T;
49
- get<T = unknown>(key: string, defaultValue?: T): T | undefined {
50
- // 1. CLI 临时参数覆盖
51
- if (this.overrides.has(key)) {
52
- return this.overrides.get(key) as T;
53
- }
54
-
55
- // 2. 本地项目 SQLite 存储
56
- const stored = this.storage.getConfig<T>(key);
57
- if (stored !== undefined) {
58
- return stored;
59
- }
60
-
61
- // 3. 全局 SQLite 存储 (~/.actiondock/global.db)
62
- if (this.globalStorage) {
63
- try {
64
- const globalStored = this.globalStorage.getConfig<T>(key);
65
- if (globalStored !== undefined) {
66
- return globalStored;
67
- }
68
- } catch {
69
- // 忽略全局存储读取异常
70
- }
71
- }
72
-
73
- // 4. 环境变量(支持包名前缀、SNAKE_CASE 转换与类型自动推断)
74
- const itemDef = this.projectConfig?.config?.[key];
75
- const envResolved = resolveEnvValue(key, itemDef, this.projectConfig?.id);
76
- if (envResolved !== undefined) {
77
- return envResolved.value as T;
78
- }
79
-
80
- // 5. 项目声明的默认值 (actiondock.json)
81
- if (itemDef?.default !== undefined) {
82
- return itemDef.default as T;
83
- }
84
-
85
- // 6. 调用方传入的代码级回退默认值
86
- return defaultValue;
87
- }
88
-
89
- has(key: string): boolean {
90
- if (this.overrides.has(key)) return true;
91
- if (this.storage.getConfig(key) !== undefined) return true;
92
- if (this.globalStorage?.getConfig(key) !== undefined) return true;
93
- const itemDef = this.projectConfig?.config?.[key];
94
- if (resolveEnvValue(key, itemDef, this.projectConfig?.id) !== undefined) return true;
95
- if (itemDef?.default !== undefined) return true;
96
- return false;
97
- }
98
- }
99
-
100
- /**
101
- * 生产级状态存储实现,将状态持久化到 SQLite 中,完整支持命名空间分段隔离与 TTL。
102
- */
103
- export class RuntimeStateStore implements StateStore {
104
- private storage: RuntimeStorage;
105
- private namespace: string;
106
-
107
- constructor(storage: RuntimeStorage, namespace = "") {
108
- this.storage = storage;
109
- this.namespace = namespace;
110
- }
111
-
112
- async get<T = unknown>(key: string): Promise<T | undefined> {
113
- return this.storage.getState<T>(this.namespace, key);
114
- }
115
-
116
- async set<T = unknown>(
117
- key: string,
118
- value: T,
119
- ttl?: number
120
- ): Promise<void> {
121
- return this.storage.setState<T>(this.namespace, key, value, ttl);
122
- }
123
-
124
- async delete(key: string): Promise<boolean> {
125
- return this.storage.deleteState(this.namespace, key);
126
- }
127
-
128
- async clear(prefix = ""): Promise<number> {
129
- return this.storage.clearState({
130
- namespace: this.namespace,
131
- prefix: prefix || undefined,
132
- });
133
- }
134
-
135
- async keys(prefix = ""): Promise<string[]> {
136
- return this.storage.listStateKeys(this.namespace, prefix);
137
- }
138
-
139
- scope(namespace: string): StateStore {
140
- const nextNs = this.namespace
141
- ? `${this.namespace}:${namespace}`
142
- : namespace;
143
- return new RuntimeStateStore(this.storage, nextNs);
144
- }
145
- }
146
-
147
- /**
148
- * 标准 Stderr 日志记录器实现。
149
- * 遵循 Unix 哲学:所有诊断与追踪日志输出至 stderr,确保 stdout 纯净保留 JSON 信封。
150
- */
151
- export class StderrLogger implements Logger {
152
- private prefix: string;
153
-
154
- constructor(prefix = "") {
155
- this.prefix = prefix ? `[${prefix}] ` : "";
156
- }
157
-
158
- private format(level: string, message: string, data?: unknown): string {
159
- const time = new Date().toISOString().slice(11, 19);
160
- const base = `[${time}] [${level.toUpperCase()}] ${this.prefix}${message}`;
161
- if (data !== undefined) {
162
- return `${base} ${typeof data === "object" ? JSON.stringify(data) : data}`;
163
- }
164
- return base;
165
- }
166
-
167
- debug(message: string, data?: unknown): void {
168
- process.stderr.write(this.format("debug", message, data) + "\n");
169
- }
170
-
171
- info(message: string, data?: unknown): void {
172
- process.stderr.write(this.format("info", message, data) + "\n");
173
- }
174
-
175
- warn(message: string, data?: unknown): void {
176
- process.stderr.write(this.format("warn", message, data) + "\n");
177
- }
178
-
179
- error(message: string, data?: unknown): void {
180
- process.stderr.write(this.format("error", message, data) + "\n");
181
- }
182
- }
183
-
184
- /**
185
- * 创建 ActionContext 上下文所需的选项集合。
186
- */
187
- export interface ContextOptions {
188
- storage: RuntimeStorage;
189
- overrides?: Record<string, unknown>;
190
- projectConfig?: ProjectConfig;
191
- parentRunId?: string;
192
- runId?: string;
193
- rootRunId?: string;
194
- callStack?: string[];
195
- signal?: AbortSignal;
196
- process?: ProcessAPI;
197
- progress?: ProgressReporter;
198
- logger?: Logger;
199
- onActionInvoke?: (
200
- action: ActionDefinition | ActionRef | string,
201
- input: unknown,
202
- parentRunId?: string
203
- ) => Promise<unknown>;
204
- }
205
-
206
- /**
207
- * 构建并装配传递给 Action 的完整 ActionContext 运行时上下文。
208
- *
209
- * @param options 上下文构建参数
210
- * @returns 组装完毕的 ActionContext 实例
211
- */
212
- export function createActionContext(options: ContextOptions): ActionContext {
213
- const config = new RuntimeConfig(
214
- options.storage,
215
- options.overrides,
216
- options.projectConfig
217
- );
218
- const state = new RuntimeStateStore(options.storage);
219
- const log = options.logger || new StderrLogger();
220
- const signal = options.signal ?? new AbortController().signal;
221
- const currentRunId = options.runId || randomUUID();
222
- const currentRootRunId = options.rootRunId || options.parentRunId || currentRunId;
223
-
224
- const invoker: ActionInvoker = {
225
- async invoke<I, O>(
226
- action: ActionDefinition<I, O> | ActionRef | string,
227
- input?: I
228
- ): Promise<O> {
229
- if (options.onActionInvoke) {
230
- return (await options.onActionInvoke(
231
- action as any,
232
- input,
233
- currentRunId
234
- )) as O;
235
- }
236
- throw new Error("ActionInvoker not configured with an invocation delegate");
237
- },
238
- };
239
-
240
- const processApi = options.process || getProcessExecutor();
241
- const progressApi: ProgressReporter = options.progress || {
242
- report() {},
243
- };
244
-
245
- return {
246
- config,
247
- state,
248
- actions: invoker,
249
- process: processApi,
250
- log,
251
- progress: progressApi,
252
- signal,
253
- run: {
254
- id: currentRunId,
255
- rootId: currentRootRunId,
256
- parentId: options.parentRunId,
257
- },
258
- };
259
- }
@@ -1,172 +0,0 @@
1
- import type { ConfigItemDefinition, ConfigValueType } from "../project/types";
2
-
3
- /**
4
- * 从环境变量成功解析后的结构体。
5
- */
6
- export interface ResolvedEnv {
7
- /** 转换类型后的配置值 */
8
- value: unknown;
9
- /** 命中的具体环境变量键名 */
10
- envKey: string;
11
- /** 数据来源标识 */
12
- source: "env";
13
- }
14
-
15
- /**
16
- * 将任意命名格式的字符串转换为标准的大写蛇形命名(UPPER_SNAKE_CASE)。
17
- * 兼容处理 camelCase、kebab-case、点号分隔以及斜杠等符号。
18
- *
19
- * @param str 输入字符串,如 "apiKey"、"team4u.github-tools"
20
- * @returns 转换后的字符串,如 "API_KEY"、"TEAM4U_GITHUB_TOOLS"
21
- */
22
- export function toSnakeUpperCase(str: string): string {
23
- return str
24
- .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
25
- .replace(/[-.\s/]+/g, "_")
26
- .toUpperCase();
27
- }
28
-
29
- /**
30
- * 当未显式声明类型时,根据默认值的值类型智能推断目标配置类型。
31
- *
32
- * @param defaultVal 默认值
33
- * @returns 推断出的 ConfigValueType 或 undefined
34
- */
35
- export function inferTypeFromDefault(defaultVal: unknown): ConfigValueType | undefined {
36
- if (defaultVal === undefined || defaultVal === null) return undefined;
37
- if (typeof defaultVal === "boolean") return "boolean";
38
- if (typeof defaultVal === "number") return "number";
39
- if (Array.isArray(defaultVal)) return "array";
40
- if (typeof defaultVal === "object") return "object";
41
- if (typeof defaultVal === "string") return "string";
42
- return undefined;
43
- }
44
-
45
- /**
46
- * 将从 process.env 获取的原始字符串安全转换为目标类型。
47
- *
48
- * 支持类型:
49
- * - boolean: "true"/"1"/"yes"/"on" -> true; "false"/"0"/"no"/"off" -> false
50
- * - number: 自动转换为数字,非数字时回退为原始字符串
51
- * - object / array: 自动尝试 JSON.parse 反序列化
52
- * - 自动探测: 当 targetType 未指定时,自动识别布尔值及 JSON 对象/数组
53
- *
54
- * @param rawValue process.env 中的原始字符串
55
- * @param targetType 期望转换的目标类型
56
- */
57
- export function coerceEnvValue(
58
- rawValue: string,
59
- targetType?: ConfigValueType
60
- ): unknown {
61
- if (targetType === "boolean") {
62
- const lower = rawValue.trim().toLowerCase();
63
- if (["true", "1", "yes", "on"].includes(lower)) return true;
64
- if (["false", "0", "no", "off"].includes(lower)) return false;
65
- return Boolean(rawValue);
66
- }
67
-
68
- if (targetType === "number") {
69
- const trimmed = rawValue.trim();
70
- const num = Number(trimmed);
71
- return isNaN(num) ? rawValue : num;
72
- }
73
-
74
- if (targetType === "object" || targetType === "array") {
75
- try {
76
- return JSON.parse(rawValue);
77
- } catch {
78
- return rawValue;
79
- }
80
- }
81
-
82
- if (targetType === "string") {
83
- return rawValue;
84
- }
85
-
86
- // 智能自动探测
87
- const trimmed = rawValue.trim();
88
- const lower = trimmed.toLowerCase();
89
- if (lower === "true") return true;
90
- if (lower === "false") return false;
91
- if (
92
- (trimmed.startsWith("{") && trimmed.endsWith("}")) ||
93
- (trimmed.startsWith("[") && trimmed.endsWith("]"))
94
- ) {
95
- try {
96
- return JSON.parse(trimmed);
97
- } catch {
98
- // 保持为字符串
99
- }
100
- }
101
-
102
- return rawValue;
103
- }
104
-
105
- /**
106
- * 从操作系统环境变量 (process.env) 中解析配置值。
107
- * 严格遵循多层回退候选链:
108
- * 1. actiondock.json 中声明的显式环境变量绑定 (itemDef.env)
109
- * 2. 带包名前缀的变量: `ACTIONDOCK_<PACKAGE>_<KEY>` 以及 `<PACKAGE>_<KEY>`
110
- * 3. 标准大写蛇形变量: `<KEY>` (SNAKE_CASE)
111
- * 4. 原始键名原样匹配
112
- *
113
- * @param key 配置键名
114
- * @param itemDef 配置项元数据定义
115
- * @param packageId 所属包 ID
116
- * @returns 命中的 ResolvedEnv 对象或 undefined
117
- */
118
- export function resolveEnvValue(
119
- key: string,
120
- itemDef?: ConfigItemDefinition,
121
- packageId?: string
122
- ): ResolvedEnv | undefined {
123
- if (typeof process === "undefined" || !process.env) {
124
- return undefined;
125
- }
126
-
127
- const candidateKeys = new Set<string>();
128
-
129
- // 1. actiondock.json 中显式声明的 env 变量名
130
- if (itemDef?.env) {
131
- if (Array.isArray(itemDef.env)) {
132
- for (const e of itemDef.env) {
133
- if (typeof e === "string" && e.trim()) {
134
- candidateKeys.add(e.trim());
135
- }
136
- }
137
- } else if (typeof itemDef.env === "string" && itemDef.env.trim()) {
138
- candidateKeys.add(itemDef.env.trim());
139
- }
140
- }
141
-
142
- // 2. 包名前缀的环境变量 (例如 ACTIONDOCK_GITHUB_TOOLS_API_KEY)
143
- const snakeKey = toSnakeUpperCase(key);
144
- if (packageId) {
145
- const cleanPkg = toSnakeUpperCase(packageId);
146
- candidateKeys.add(`ACTIONDOCK_${cleanPkg}_${snakeKey}`);
147
- candidateKeys.add(`${cleanPkg}_${snakeKey}`);
148
- }
149
-
150
- // 3. 标准大写蛇形变量名 (例如 API_KEY)
151
- candidateKeys.add(snakeKey);
152
-
153
- // 4. 原始键名 (例如 apiKey)
154
- candidateKeys.add(key);
155
-
156
- // 按优先级顺序依次检索环境变量
157
- const effectiveType = itemDef?.type || inferTypeFromDefault(itemDef?.default);
158
-
159
- for (const envKey of candidateKeys) {
160
- const rawVal = process.env[envKey];
161
- if (rawVal !== undefined) {
162
- const coerced = coerceEnvValue(rawVal, effectiveType);
163
- return {
164
- value: coerced,
165
- envKey,
166
- source: "env",
167
- };
168
- }
169
- }
170
-
171
- return undefined;
172
- }