@actiondock/core 2.0.12 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -30
- package/dist/app/app.d.ts +73 -0
- package/dist/app/app.js +700 -0
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +2 -0
- package/dist/app/types.d.ts +283 -0
- package/dist/app/types.js +1 -0
- package/dist/catalog/action-index.d.ts +1 -1
- package/dist/catalog/action-index.js +93 -0
- package/dist/catalog/action-resolver.d.ts +2 -2
- package/dist/catalog/action-resolver.js +95 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -0
- package/dist/catalog/location-registry.d.ts +5 -5
- package/dist/catalog/location-registry.js +138 -0
- package/dist/catalog/package-catalog.d.ts +2 -2
- package/dist/catalog/package-catalog.js +76 -0
- package/dist/catalog/types.d.ts +2 -2
- package/dist/catalog/types.js +1 -0
- package/dist/doctor/doctor.d.ts +2 -1
- package/dist/doctor/doctor.js +613 -0
- package/dist/doctor/index.d.ts +2 -2
- package/dist/doctor/index.js +2 -0
- package/dist/doctor/types.js +1 -0
- package/dist/errors.d.ts +122 -0
- package/dist/errors.js +123 -0
- package/dist/execution/index.d.ts +2 -2
- package/dist/execution/index.js +2 -0
- package/dist/execution/service.d.ts +46 -41
- package/dist/execution/service.js +633 -0
- package/dist/execution/types.d.ts +59 -2
- package/dist/execution/types.js +1 -0
- package/dist/export/index.d.ts +1 -1
- package/dist/export/index.js +1 -0
- package/dist/export/templates.d.ts +45 -7
- package/dist/export/templates.js +621 -0
- package/dist/filter/index.d.ts +1 -1
- package/dist/filter/index.js +1 -0
- package/dist/filter/intent.js +123 -0
- package/dist/host/host.d.ts +55 -0
- package/dist/host/host.js +740 -0
- package/dist/host/index.d.ts +2 -0
- package/dist/host/index.js +2 -0
- package/dist/host/types.d.ts +81 -0
- package/dist/host/types.js +1 -0
- package/dist/index.d.ts +21 -16
- package/dist/index.js +20 -8458
- package/dist/ipc/diagnostic.d.ts +65 -0
- package/dist/ipc/diagnostic.js +129 -0
- package/dist/ipc/host.d.ts +7 -0
- package/dist/ipc/host.js +93 -0
- package/dist/ipc/index.d.ts +4 -0
- package/dist/ipc/index.js +4 -0
- package/dist/ipc/target.d.ts +56 -0
- package/dist/ipc/target.js +297 -0
- package/dist/ipc/types.d.ts +42 -0
- package/dist/ipc/types.js +1 -0
- package/dist/platform/default.d.ts +32 -0
- package/dist/platform/default.js +40 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.js +3 -0
- package/dist/platform/node-fs.d.ts +37 -0
- package/dist/platform/node-fs.js +81 -0
- package/dist/platform/types.d.ts +104 -0
- package/dist/platform/types.js +1 -0
- package/dist/profile/client.d.ts +58 -12
- package/dist/profile/client.js +467 -0
- package/dist/profile/index.d.ts +3 -3
- package/dist/profile/index.js +3 -0
- package/dist/profile/manager.d.ts +2 -2
- package/dist/profile/manager.js +294 -0
- package/dist/profile/types.d.ts +1 -1
- package/dist/profile/types.js +1 -0
- package/dist/project/closure.js +68 -0
- package/dist/project/digest.d.ts +29 -0
- package/dist/project/digest.js +324 -0
- package/dist/project/index.d.ts +10 -5
- package/dist/project/index.js +10 -0
- package/dist/project/init.d.ts +3 -4
- package/dist/project/init.js +175 -0
- package/dist/project/loader.d.ts +21 -27
- package/dist/project/loader.js +484 -0
- package/dist/project/lockfile.d.ts +55 -0
- package/dist/project/lockfile.js +175 -0
- package/dist/project/manifest.d.ts +6 -28
- package/dist/project/manifest.js +220 -0
- package/dist/project/resolver.d.ts +116 -0
- package/dist/project/resolver.js +376 -0
- package/dist/project/transactions.d.ts +103 -0
- package/dist/project/transactions.js +1203 -0
- package/dist/project/types-generator.d.ts +33 -0
- package/dist/project/types-generator.js +168 -0
- package/dist/project/types.d.ts +58 -82
- package/dist/project/types.js +1 -0
- package/dist/registry/index.d.ts +5 -2
- package/dist/registry/index.js +5 -0
- package/dist/registry/lock.d.ts +27 -0
- package/dist/registry/lock.js +93 -0
- package/dist/registry/registry.d.ts +32 -11
- package/dist/registry/registry.js +611 -0
- package/dist/registry/resolve.d.ts +62 -0
- package/dist/registry/resolve.js +195 -0
- package/dist/registry/scan.d.ts +38 -0
- package/dist/registry/scan.js +135 -0
- package/dist/registry/types.d.ts +1 -1
- package/dist/registry/types.js +1 -0
- package/dist/runtime/action-collection.d.ts +27 -0
- package/dist/runtime/action-collection.js +57 -0
- package/dist/runtime/clock.d.ts +0 -2
- package/dist/runtime/clock.js +17 -0
- package/dist/runtime/context.d.ts +16 -5
- package/dist/runtime/context.js +242 -0
- package/dist/runtime/env.d.ts +3 -1
- package/dist/runtime/env.js +159 -0
- package/dist/runtime/events.d.ts +46 -14
- package/dist/runtime/events.js +604 -0
- package/dist/runtime/execution-manager.d.ts +1 -1
- package/dist/runtime/execution-manager.js +66 -0
- package/dist/runtime/index.d.ts +10 -9
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/module-loader.d.ts +0 -8
- package/dist/runtime/module-loader.js +16 -0
- package/dist/runtime/process.d.ts +2 -4
- package/dist/runtime/process.js +146 -0
- package/dist/runtime/runner.d.ts +117 -10
- package/dist/runtime/runner.js +984 -0
- package/dist/runtime/standalone.d.ts +68 -19
- package/dist/runtime/standalone.js +536 -0
- package/dist/schema/validator.js +116 -0
- package/dist/server/body.js +93 -0
- package/dist/server/index.d.ts +5 -6
- package/dist/server/index.js +5 -0
- package/dist/server/routes/actions.d.ts +2 -2
- package/dist/server/routes/actions.js +298 -0
- package/dist/server/routes/common.d.ts +28 -17
- package/dist/server/routes/common.js +104 -0
- package/dist/server/routes/config.d.ts +2 -1
- package/dist/server/routes/config.js +173 -0
- package/dist/server/routes/doctor.d.ts +2 -2
- package/dist/server/routes/doctor.js +63 -0
- package/dist/server/routes/health.d.ts +2 -2
- package/dist/server/routes/health.js +35 -0
- package/dist/server/routes/index.d.ts +9 -9
- package/dist/server/routes/index.js +9 -0
- package/dist/server/routes/info.d.ts +4 -2
- package/dist/server/routes/info.js +158 -0
- package/dist/server/routes/playbooks.d.ts +2 -2
- package/dist/server/routes/playbooks.js +134 -0
- package/dist/server/routes/runs.d.ts +2 -2
- package/dist/server/routes/runs.js +343 -0
- package/dist/server/routes/state.d.ts +2 -1
- package/dist/server/routes/state.js +169 -0
- package/dist/server/security.d.ts +11 -4
- package/dist/server/security.js +101 -0
- package/dist/server/server.d.ts +6 -6
- package/dist/server/server.js +355 -0
- package/dist/server/types.d.ts +27 -8
- package/dist/server/types.js +1 -0
- package/dist/storage/data-dir-lock.d.ts +119 -0
- package/dist/storage/data-dir-lock.js +1016 -0
- package/dist/storage/driver.d.ts +4 -10
- package/dist/storage/driver.js +59 -0
- package/dist/storage/index.d.ts +30 -10
- package/dist/storage/index.js +98 -0
- package/dist/storage/lazy.d.ts +8 -0
- package/dist/storage/lazy.js +44 -0
- package/dist/storage/mask.d.ts +12 -5
- package/dist/storage/mask.js +48 -0
- package/dist/storage/params.d.ts +13 -0
- package/dist/storage/params.js +32 -0
- package/dist/storage/sqlite.d.ts +19 -6
- package/dist/storage/sqlite.js +689 -0
- package/dist/storage/types.d.ts +57 -6
- package/dist/storage/types.js +14 -0
- package/dist/target/index.d.ts +4 -0
- package/dist/target/index.js +4 -0
- package/dist/target/local.d.ts +52 -0
- package/dist/target/local.js +343 -0
- package/dist/target/remote.d.ts +76 -0
- package/dist/target/remote.js +839 -0
- package/dist/target/target.d.ts +6 -0
- package/dist/target/target.js +35 -0
- package/dist/target/types.d.ts +246 -0
- package/dist/target/types.js +34 -0
- package/dist/utils/index.d.ts +22 -2
- package/dist/utils/index.js +180 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +4 -0
- package/package.json +6 -7
- package/dist/build/index.d.ts +0 -1
- package/dist/build/templates.d.ts +0 -19
- package/dist/server/runtime-registry.d.ts +0 -78
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { findProjectRoot, loadActions, loadPlaybooks, loadProjectConfig } from "../project/loader.js";
|
|
4
|
+
import { loadManifest } from "../project/manifest.js";
|
|
5
|
+
import { getPackageSlug } from "../utils/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* 实体解析唯一流程(生成器表达):
|
|
8
|
+
* 当前项目探测 → scoped 标识符拆分 → 注册表精确匹配 → 遍历链接包 →
|
|
9
|
+
* 单命中返回、多命中报错、零命中报错。
|
|
10
|
+
*
|
|
11
|
+
* 仅将可能异步的操作(探针、链接列表获取)以 thunk 形式 yield,
|
|
12
|
+
* 由 runFlowSync / runFlowAsync 双驱动器分别以同步调用或 await 方式执行。
|
|
13
|
+
*/
|
|
14
|
+
export function* resolveEntityFlow(opts) {
|
|
15
|
+
const { identifier, entityNoun } = opts;
|
|
16
|
+
// 当前项目(或其父级项目)优先探测
|
|
17
|
+
const currentRoot = findProjectRoot(opts.cwd);
|
|
18
|
+
if (currentRoot) {
|
|
19
|
+
try {
|
|
20
|
+
const config = loadProjectConfig(currentRoot);
|
|
21
|
+
const hit = yield () => opts.probe(currentRoot, config, identifier);
|
|
22
|
+
if (hit !== undefined) {
|
|
23
|
+
return opts.buildResult(currentRoot, config.id, identifier, hit);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// 当前项目配置损坏或探测失败:忽略并继续注册表查找
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// scoped 标识符拆分:<package-id>/<entity-id> 或 <package-id>:<entity-id>
|
|
31
|
+
let targetPackage;
|
|
32
|
+
let pureEntityId = identifier;
|
|
33
|
+
if (identifier.includes("/")) {
|
|
34
|
+
const slashIdx = identifier.lastIndexOf("/");
|
|
35
|
+
targetPackage = identifier.slice(0, slashIdx);
|
|
36
|
+
pureEntityId = identifier.slice(slashIdx + 1);
|
|
37
|
+
}
|
|
38
|
+
else if (identifier.includes(":")) {
|
|
39
|
+
const colonIdx = identifier.lastIndexOf(":");
|
|
40
|
+
targetPackage = identifier.slice(0, colonIdx);
|
|
41
|
+
pureEntityId = identifier.slice(colonIdx + 1);
|
|
42
|
+
}
|
|
43
|
+
const linkedList = yield () => opts.listLinkedPackages();
|
|
44
|
+
if (targetPackage) {
|
|
45
|
+
let targetRoot;
|
|
46
|
+
let targetPkgId = targetPackage;
|
|
47
|
+
if (currentRoot) {
|
|
48
|
+
try {
|
|
49
|
+
const config = loadProjectConfig(currentRoot);
|
|
50
|
+
if (config.id === targetPackage || getPackageSlug(config.id) === targetPackage) {
|
|
51
|
+
targetRoot = currentRoot;
|
|
52
|
+
targetPkgId = config.id;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// 当前项目配置损坏:忽略,回退注册表匹配
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
let pkg;
|
|
60
|
+
if (!targetRoot) {
|
|
61
|
+
pkg = linkedList.find((p) => p.id === targetPackage || getPackageSlug(p.id) === targetPackage);
|
|
62
|
+
if (pkg && existsSync(pkg.path)) {
|
|
63
|
+
targetRoot = pkg.path;
|
|
64
|
+
targetPkgId = pkg.id;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!targetRoot || !existsSync(targetRoot)) {
|
|
68
|
+
throw new Error(`Linked package '${targetPackage}' not found or path no longer exists (${pkg?.path || "unregistered"}). Run 'ad link' in the package directory.`);
|
|
69
|
+
}
|
|
70
|
+
const config = loadProjectConfig(targetRoot);
|
|
71
|
+
const hit = yield () => opts.probe(targetRoot, config, pureEntityId);
|
|
72
|
+
if (hit === undefined) {
|
|
73
|
+
throw new Error(`${entityNoun} '${pureEntityId}' not found in package '${targetPkgId}' (${targetRoot})`);
|
|
74
|
+
}
|
|
75
|
+
return opts.buildResult(targetRoot, targetPkgId, pureEntityId, hit);
|
|
76
|
+
}
|
|
77
|
+
// 遍历全部链接包搜索
|
|
78
|
+
const matches = [];
|
|
79
|
+
for (const pkg of linkedList) {
|
|
80
|
+
if (!existsSync(pkg.path))
|
|
81
|
+
continue;
|
|
82
|
+
try {
|
|
83
|
+
const config = loadProjectConfig(pkg.path);
|
|
84
|
+
const hit = yield () => opts.probe(pkg.path, config, identifier);
|
|
85
|
+
if (hit !== undefined) {
|
|
86
|
+
matches.push({ entry: pkg, entityId: identifier, value: hit });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// 忽略损坏的链接包:单个包配置或探测异常不应中断其余包的匹配
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (matches.length === 1) {
|
|
94
|
+
const m = matches[0];
|
|
95
|
+
return opts.buildResult(m.entry.path, m.entry.id, m.entityId, m.value);
|
|
96
|
+
}
|
|
97
|
+
if (matches.length > 1) {
|
|
98
|
+
const pkgList = matches.map((m) => `'${m.entry.id}'`).join(", ");
|
|
99
|
+
throw new Error(`${entityNoun} '${identifier}' is provided by multiple linked packages: ${pkgList}. Please specify using '<package-id>/${identifier}'.`);
|
|
100
|
+
}
|
|
101
|
+
if (currentRoot) {
|
|
102
|
+
throw new Error(`${entityNoun} '${identifier}' not found in current project or any linked packages`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
throw new Error(`${entityNoun} '${identifier}' not found. You are not in an ActionDock project, and no linked package provides '${identifier}'. Use 'ad link' to register your package.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 同步驱动器:逐个调用 thunk 并把结果回灌生成器,
|
|
110
|
+
* thunk 抛出的异常经 it.throw 回灌生成器内部的 try/catch 处理。
|
|
111
|
+
* 同步流程中误注入异步 thunk 时立即抛错,避免 Promise 被当作命中值静默错判。
|
|
112
|
+
*/
|
|
113
|
+
export function runFlowSync(flow) {
|
|
114
|
+
let step = flow.next();
|
|
115
|
+
while (!step.done) {
|
|
116
|
+
const value = step.value();
|
|
117
|
+
if (value !== undefined && typeof value.then === "function") {
|
|
118
|
+
throw new Error("Synchronous resolution received an asynchronous effect; check the injected probe and linked-list loader");
|
|
119
|
+
}
|
|
120
|
+
let next;
|
|
121
|
+
try {
|
|
122
|
+
next = flow.next(value);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
next = flow.throw(err);
|
|
126
|
+
}
|
|
127
|
+
step = next;
|
|
128
|
+
}
|
|
129
|
+
return step.value;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 异步驱动器:await 每个 thunk 后回灌结果,拒绝原因经 it.throw 回灌。
|
|
133
|
+
*/
|
|
134
|
+
export async function runFlowAsync(flow) {
|
|
135
|
+
let step = flow.next();
|
|
136
|
+
while (!step.done) {
|
|
137
|
+
let next;
|
|
138
|
+
try {
|
|
139
|
+
next = flow.next(await step.value());
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
next = flow.throw(err);
|
|
143
|
+
}
|
|
144
|
+
step = next;
|
|
145
|
+
}
|
|
146
|
+
return step.value;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Action 探针(同步):manifest 声明优先,其次探测源码文件是否落盘。
|
|
150
|
+
*/
|
|
151
|
+
export function probeActionSync(projectRoot, config, actionId) {
|
|
152
|
+
const manifest = loadManifest(projectRoot);
|
|
153
|
+
if (manifest?.actions && actionId in manifest.actions) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
const dir = join(projectRoot, config.actionsDir || "actions");
|
|
157
|
+
if (!existsSync(dir)) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
if (actionId.includes("..") || actionId.startsWith("/") || actionId.startsWith("\\")) {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
if (existsSync(join(dir, `${actionId}.ts`)) || existsSync(join(dir, `${actionId}.js`))) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
const relFile = actionId.replace(/\./g, "/");
|
|
167
|
+
if (existsSync(join(dir, `${relFile}.ts`)) || existsSync(join(dir, `${relFile}.js`))) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Action 探针(异步):manifest 声明优先,其次加载源码模块;
|
|
174
|
+
* 模块加载失败时回退同步探测,保证与同步路径判定一致。
|
|
175
|
+
*/
|
|
176
|
+
export async function probeActionAsync(projectRoot, config, actionId) {
|
|
177
|
+
const manifest = loadManifest(projectRoot);
|
|
178
|
+
if (manifest?.actions && actionId in manifest.actions) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const actions = await loadActions(projectRoot, config.actionsDir, { autoInstall: false });
|
|
183
|
+
return actions.has(actionId) ? true : undefined;
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return probeActionSync(projectRoot, config, actionId);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Playbook 探针:以 actiondock.json 的 playbooks 声明为唯一事实源,命中返回规程定义。
|
|
191
|
+
*/
|
|
192
|
+
export function probePlaybook(projectRoot, config, playbookId) {
|
|
193
|
+
const playbooks = loadPlaybooks(projectRoot, config.playbooksDir);
|
|
194
|
+
return playbooks.get(playbookId);
|
|
195
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { loadProjectConfig } from "../project/loader.js";
|
|
2
|
+
import type { LinkedPackageEntry } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 目录扫描时跳过的非项目目录(依赖缓存、构建产物与编辑器配置等)。
|
|
5
|
+
*/
|
|
6
|
+
export declare const IGNORED_SCAN_DIRS: Set<string>;
|
|
7
|
+
/**
|
|
8
|
+
* 递归扫描包含 actiondock.json 的子项目根目录(同步版本)。
|
|
9
|
+
*/
|
|
10
|
+
export declare function discoverProjects(dir: string, maxDepth?: number): string[];
|
|
11
|
+
/**
|
|
12
|
+
* 递归扫描包含 actiondock.json 的子项目根目录(异步版本,逻辑与同步版一致)。
|
|
13
|
+
*/
|
|
14
|
+
export declare function discoverProjectsAsync(dir: string, maxDepth?: number): Promise<string[]>;
|
|
15
|
+
/**
|
|
16
|
+
* 扫描并加载全部子项目配置(同步版本)。
|
|
17
|
+
* 损坏项目(配置缺失或非法)跳过不中断:注册表操作面对的是外部任意目录,
|
|
18
|
+
* 单个损坏项目不应阻塞其余项目的正常链接与解析。
|
|
19
|
+
*/
|
|
20
|
+
export declare function discoverProjectConfigs(dir: string, maxDepth?: number): Array<{
|
|
21
|
+
root: string;
|
|
22
|
+
config: ReturnType<typeof loadProjectConfig>;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* 扫描并加载全部子项目配置(异步版本,跳过策略与同步版一致)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function discoverProjectConfigsAsync(dir: string, maxDepth?: number): Promise<Array<{
|
|
28
|
+
root: string;
|
|
29
|
+
config: ReturnType<typeof loadProjectConfig>;
|
|
30
|
+
}>>;
|
|
31
|
+
/**
|
|
32
|
+
* 由项目配置构造注册表链接条目(纯函数,无副作用)。
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildLinkedPackageEntry(config: ReturnType<typeof loadProjectConfig>, path: string, linkedAt: string, workspaceRoot?: string): LinkedPackageEntry;
|
|
35
|
+
/**
|
|
36
|
+
* 异步探测路径是否存在。
|
|
37
|
+
*/
|
|
38
|
+
export declare function pathExistsAsync(path: string): Promise<boolean>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { readdirSync } from "node:fs";
|
|
2
|
+
import { readdir, stat } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { loadProjectConfig } from "../project/loader.js";
|
|
5
|
+
/**
|
|
6
|
+
* 目录扫描时跳过的非项目目录(依赖缓存、构建产物与编辑器配置等)。
|
|
7
|
+
*/
|
|
8
|
+
export const IGNORED_SCAN_DIRS = new Set([
|
|
9
|
+
"node_modules",
|
|
10
|
+
".git",
|
|
11
|
+
"dist",
|
|
12
|
+
"build",
|
|
13
|
+
".gemini",
|
|
14
|
+
".actiondock",
|
|
15
|
+
".claude",
|
|
16
|
+
".idea",
|
|
17
|
+
".vscode",
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* 递归扫描包含 actiondock.json 的子项目根目录(同步版本)。
|
|
21
|
+
*/
|
|
22
|
+
export function discoverProjects(dir, maxDepth = 3) {
|
|
23
|
+
const results = [];
|
|
24
|
+
const resolvedDir = resolve(dir);
|
|
25
|
+
function walk(currentDir, currentDepth) {
|
|
26
|
+
if (currentDepth > maxDepth)
|
|
27
|
+
return;
|
|
28
|
+
try {
|
|
29
|
+
const entries = readdirSync(currentDir, { withFileTypes: true });
|
|
30
|
+
const hasActiondock = entries.some((e) => e.isFile() && e.name === "actiondock.json");
|
|
31
|
+
if (hasActiondock && currentDir !== resolvedDir) {
|
|
32
|
+
results.push(currentDir);
|
|
33
|
+
return; // 不再向项目内部子目录递归
|
|
34
|
+
}
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
if (entry.isDirectory() && !IGNORED_SCAN_DIRS.has(entry.name)) {
|
|
37
|
+
walk(join(currentDir, entry.name), currentDepth + 1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// 忽略无法读取的目录:扫描是尽力而为的探测,单目录不可读不应中断整体发现
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
walk(resolvedDir, 1);
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 递归扫描包含 actiondock.json 的子项目根目录(异步版本,逻辑与同步版一致)。
|
|
50
|
+
*/
|
|
51
|
+
export async function discoverProjectsAsync(dir, maxDepth = 3) {
|
|
52
|
+
const results = [];
|
|
53
|
+
const resolvedDir = resolve(dir);
|
|
54
|
+
async function walk(currentDir, currentDepth) {
|
|
55
|
+
if (currentDepth > maxDepth)
|
|
56
|
+
return;
|
|
57
|
+
let entries;
|
|
58
|
+
try {
|
|
59
|
+
entries = await readdir(currentDir, { withFileTypes: true });
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// 忽略无法读取的目录:扫描是尽力而为的探测,单目录不可读不应中断整体发现
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const hasActiondock = entries.some((e) => e.isFile() && e.name === "actiondock.json");
|
|
66
|
+
if (hasActiondock && currentDir !== resolvedDir) {
|
|
67
|
+
results.push(currentDir);
|
|
68
|
+
return; // 不再向项目内部子目录递归
|
|
69
|
+
}
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
if (entry.isDirectory() && !IGNORED_SCAN_DIRS.has(entry.name)) {
|
|
72
|
+
await walk(join(currentDir, entry.name), currentDepth + 1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
await walk(resolvedDir, 1);
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 扫描并加载全部子项目配置(同步版本)。
|
|
81
|
+
* 损坏项目(配置缺失或非法)跳过不中断:注册表操作面对的是外部任意目录,
|
|
82
|
+
* 单个损坏项目不应阻塞其余项目的正常链接与解析。
|
|
83
|
+
*/
|
|
84
|
+
export function discoverProjectConfigs(dir, maxDepth = 3) {
|
|
85
|
+
const results = [];
|
|
86
|
+
for (const root of discoverProjects(dir, maxDepth)) {
|
|
87
|
+
try {
|
|
88
|
+
results.push({ root, config: loadProjectConfig(root) });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// 跳过损坏项目:其 actiondock.json 缺失必要字段或非法,无法构成有效链接条目
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 扫描并加载全部子项目配置(异步版本,跳过策略与同步版一致)。
|
|
98
|
+
*/
|
|
99
|
+
export async function discoverProjectConfigsAsync(dir, maxDepth = 3) {
|
|
100
|
+
const results = [];
|
|
101
|
+
for (const root of await discoverProjectsAsync(dir, maxDepth)) {
|
|
102
|
+
try {
|
|
103
|
+
results.push({ root, config: loadProjectConfig(root) });
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// 跳过损坏项目:其 actiondock.json 缺失必要字段或非法,无法构成有效链接条目
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 由项目配置构造注册表链接条目(纯函数,无副作用)。
|
|
113
|
+
*/
|
|
114
|
+
export function buildLinkedPackageEntry(config, path, linkedAt, workspaceRoot) {
|
|
115
|
+
return {
|
|
116
|
+
id: config.id,
|
|
117
|
+
name: config.name || config.id,
|
|
118
|
+
version: config.version || "0.0.0",
|
|
119
|
+
path,
|
|
120
|
+
linkedAt,
|
|
121
|
+
...(workspaceRoot ? { workspaceRoot } : {}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 异步探测路径是否存在。
|
|
126
|
+
*/
|
|
127
|
+
export async function pathExistsAsync(path) {
|
|
128
|
+
try {
|
|
129
|
+
await stat(path);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
package/dist/registry/types.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ActionDefinition } from "@actiondock/sdk";
|
|
2
|
+
import type { ActionSpec } from "../app/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 归一化 Action 集合的产物结构。
|
|
5
|
+
*/
|
|
6
|
+
export interface NormalizedActionCollection {
|
|
7
|
+
/** Action 标识到定义的映射表 */
|
|
8
|
+
actionsMap: Map<string, ActionDefinition>;
|
|
9
|
+
/** Action 标识到元数据规范的映射表 */
|
|
10
|
+
actionSpecs: Record<string, ActionSpec>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 将任意形态的 Action 集合输入归一化为统一结构。
|
|
14
|
+
*
|
|
15
|
+
* 支持三种输入形态:
|
|
16
|
+
* - Map 映射表:键即 Action 标识。
|
|
17
|
+
* - 对象数组:每项以 id 字段定位,action 字段或自身作为定义。
|
|
18
|
+
* - 普通对象:键值对即标识与定义。
|
|
19
|
+
*
|
|
20
|
+
* 作为 app 层与独立运行分发器的归一化逻辑单一事实源(Runner 构造仅接受 Map 形态,无需归一化)。
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeActionCollection(rawActions?: Map<string, ActionDefinition> | Array<({
|
|
23
|
+
id: string;
|
|
24
|
+
action?: ActionDefinition;
|
|
25
|
+
} & Partial<ActionSpec>) | (ActionDefinition & {
|
|
26
|
+
id: string;
|
|
27
|
+
})> | Record<string, ActionDefinition>): NormalizedActionCollection;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将任意形态的 Action 集合输入归一化为统一结构。
|
|
3
|
+
*
|
|
4
|
+
* 支持三种输入形态:
|
|
5
|
+
* - Map 映射表:键即 Action 标识。
|
|
6
|
+
* - 对象数组:每项以 id 字段定位,action 字段或自身作为定义。
|
|
7
|
+
* - 普通对象:键值对即标识与定义。
|
|
8
|
+
*
|
|
9
|
+
* 作为 app 层与独立运行分发器的归一化逻辑单一事实源(Runner 构造仅接受 Map 形态,无需归一化)。
|
|
10
|
+
*/
|
|
11
|
+
export function normalizeActionCollection(rawActions) {
|
|
12
|
+
const actionsMap = new Map();
|
|
13
|
+
const actionSpecs = {};
|
|
14
|
+
if (!rawActions) {
|
|
15
|
+
return { actionsMap, actionSpecs };
|
|
16
|
+
}
|
|
17
|
+
if (rawActions instanceof Map) {
|
|
18
|
+
for (const [k, v] of rawActions) {
|
|
19
|
+
actionsMap.set(k, v);
|
|
20
|
+
actionSpecs[k] = {
|
|
21
|
+
id: k,
|
|
22
|
+
description: v.description,
|
|
23
|
+
inputSchema: v.inputSchema,
|
|
24
|
+
outputSchema: v.outputSchema,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return { actionsMap, actionSpecs };
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(rawActions)) {
|
|
30
|
+
for (const item of rawActions) {
|
|
31
|
+
const id = item.id;
|
|
32
|
+
const act = item.action ?? item;
|
|
33
|
+
if (id) {
|
|
34
|
+
actionsMap.set(id, act);
|
|
35
|
+
actionSpecs[id] = {
|
|
36
|
+
id,
|
|
37
|
+
description: item.description ?? act.description,
|
|
38
|
+
inputSchema: item.inputSchema ?? act.inputSchema,
|
|
39
|
+
outputSchema: item.outputSchema ?? act.outputSchema,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { actionsMap, actionSpecs };
|
|
44
|
+
}
|
|
45
|
+
if (typeof rawActions === "object") {
|
|
46
|
+
for (const [k, v] of Object.entries(rawActions)) {
|
|
47
|
+
actionsMap.set(k, v);
|
|
48
|
+
actionSpecs[k] = {
|
|
49
|
+
id: k,
|
|
50
|
+
description: v.description,
|
|
51
|
+
inputSchema: v.inputSchema,
|
|
52
|
+
outputSchema: v.outputSchema,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { actionsMap, actionSpecs };
|
|
57
|
+
}
|
package/dist/runtime/clock.d.ts
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生产环境系统时钟实现。
|
|
3
|
+
*/
|
|
4
|
+
export class SystemClock {
|
|
5
|
+
now() {
|
|
6
|
+
return new Date();
|
|
7
|
+
}
|
|
8
|
+
monotonic() {
|
|
9
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
10
|
+
return performance.now();
|
|
11
|
+
}
|
|
12
|
+
return Date.now();
|
|
13
|
+
}
|
|
14
|
+
sleep(ms) {
|
|
15
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { ActionContext,
|
|
2
|
-
import type { ProjectConfig } from "../project/types";
|
|
3
|
-
import type { RuntimeStorage } from "../storage/types";
|
|
1
|
+
import type { ActionContext, ActionRef, Config, Logger, ProcessAPI, ProgressReporter, StateStore } from "@actiondock/sdk";
|
|
2
|
+
import type { ProjectConfig } from "../project/types.js";
|
|
3
|
+
import type { RuntimeStorage } from "../storage/types.js";
|
|
4
4
|
/**
|
|
5
5
|
* 生产级配置解析器实现。
|
|
6
6
|
* 严格践行 5 层配置解析优先级链:
|
|
7
7
|
* 1. CLI 临时参数覆写 (Overrides)
|
|
8
|
-
* 2.
|
|
8
|
+
* 2. 包级持久化存储 (Package SQLite: ~/.actiondock/data/<package-id>/runtime.db)
|
|
9
9
|
* 3. 全局共享持久化存储 (Global SQLite: ~/.actiondock/global.db)
|
|
10
10
|
* 4. 操作系统环境变量 (process.env: 显式绑定 / 包名前缀 / SNAKE_CASE / 类型转换)
|
|
11
11
|
* 5. 项目默认配置 (actiondock.json 中的 default 字段)
|
|
@@ -20,6 +20,16 @@ export declare class RuntimeConfig implements Config {
|
|
|
20
20
|
get<T = unknown>(key: string): T | undefined;
|
|
21
21
|
get<T = unknown>(key: string, defaultValue: T): T;
|
|
22
22
|
has(key: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* 结构化解析指定配置项的来源与取值视图。
|
|
25
|
+
*
|
|
26
|
+
* 作为五层优先级链的唯一事实源读取视图,供 app 层 getConfig 安全视图直接委托,
|
|
27
|
+
* 避免重复实现解析链导致行为漂移。
|
|
28
|
+
*/
|
|
29
|
+
describe<T = unknown>(key: string): {
|
|
30
|
+
source: "overrides" | "package" | "global" | "env" | "default";
|
|
31
|
+
value: T | undefined;
|
|
32
|
+
};
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* 生产级状态存储实现,将状态持久化到 SQLite 中,完整支持命名空间分段隔离与 TTL。
|
|
@@ -52,6 +62,7 @@ export declare class StderrLogger implements Logger {
|
|
|
52
62
|
* 创建 ActionContext 上下文所需的选项集合。
|
|
53
63
|
*/
|
|
54
64
|
export interface ContextOptions {
|
|
65
|
+
actionId?: string;
|
|
55
66
|
storage: RuntimeStorage;
|
|
56
67
|
globalStorage?: RuntimeStorage;
|
|
57
68
|
overrides?: Record<string, unknown>;
|
|
@@ -64,7 +75,7 @@ export interface ContextOptions {
|
|
|
64
75
|
process?: ProcessAPI;
|
|
65
76
|
progress?: ProgressReporter;
|
|
66
77
|
logger?: Logger;
|
|
67
|
-
onActionInvoke?: (action:
|
|
78
|
+
onActionInvoke?: (action: ActionRef | string, input: unknown, parentRunId?: string) => Promise<unknown>;
|
|
68
79
|
}
|
|
69
80
|
/**
|
|
70
81
|
* 构建并装配传递给 Action 的完整 ActionContext 运行时上下文。
|