@actiondock/core 2.15.0 → 2.16.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/dist/catalog/discovery.d.ts +3 -3
- package/dist/catalog/graph.d.ts +8 -6
- package/dist/catalog/graph.js +62 -197
- package/dist/catalog/resolve-playbook.d.ts +2 -2
- package/dist/catalog/resolve-playbook.js +53 -12
- package/dist/execution/types.d.ts +2 -2
- package/dist/host/routing.d.ts +1 -1
- package/dist/host/routing.js +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +0 -1
- package/dist/package/runtime.d.ts +2 -2
- package/dist/package/runtime.js +1 -3
- package/dist/package/static-index.d.ts +6 -4
- package/dist/package/static-index.js +60 -12
- package/dist/package/types.d.ts +5 -5
- package/dist/project/index.d.ts +0 -1
- package/dist/project/index.js +0 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +2 -4
- package/dist/project/loader.js +34 -38
- package/dist/project/manifest.d.ts +0 -2
- package/dist/project/manifest.js +1 -17
- package/dist/project/types.d.ts +0 -31
- package/dist/registry/registry.js +15 -27
- package/dist/runtime/context.d.ts +3 -3
- package/dist/runtime/standalone-commands.js +2 -8
- package/dist/runtime/standalone.d.ts +0 -2
- package/dist/utils/semver.d.ts +1 -2
- package/dist/utils/semver.js +5 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/project/skill-dir.d.ts +0 -72
- package/dist/project/skill-dir.js +0 -244
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
2
3
|
import { loadPlaybooks } from "../project/loader.js";
|
|
4
|
+
import { MANIFEST_FILE_NAME } from "../project/manifest.js";
|
|
3
5
|
/**
|
|
4
6
|
* 将增量声明合并到既有 Action 规范之上(纯函数,单一事实源)。
|
|
5
7
|
*
|
|
@@ -84,21 +86,67 @@ export function buildStaticActionMap(input) {
|
|
|
84
86
|
}
|
|
85
87
|
/**
|
|
86
88
|
* 静态读取并聚合指定包的 Playbook 规范索引。
|
|
87
|
-
*
|
|
89
|
+
*
|
|
90
|
+
* 聚合来源:磁盘规程目录扫描(以 actiondock.json 声明为事实源)与
|
|
91
|
+
* 项目配置中声明的 playbooks;同键时配置声明覆盖磁盘扫描结果。
|
|
88
92
|
*/
|
|
89
93
|
export function buildStaticPlaybookMap(input) {
|
|
90
94
|
const { packageRoot, packageId, projectConfig } = input;
|
|
91
95
|
const map = new Map();
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
// 扫描磁盘规程文件
|
|
97
|
+
if (packageRoot) {
|
|
98
|
+
const playbooksDir = projectConfig?.playbooksDir || "playbooks";
|
|
99
|
+
const dirPath = join(packageRoot, playbooksDir);
|
|
100
|
+
const manifestPath = join(packageRoot, MANIFEST_FILE_NAME);
|
|
101
|
+
if (existsSync(manifestPath) || existsSync(dirPath)) {
|
|
102
|
+
try {
|
|
103
|
+
const loaded = loadPlaybooks(packageRoot, playbooksDir);
|
|
104
|
+
for (const [id, def] of loaded) {
|
|
105
|
+
map.set(id, {
|
|
106
|
+
id: def.id,
|
|
107
|
+
packageId,
|
|
108
|
+
description: def.description,
|
|
109
|
+
actions: def.actions,
|
|
110
|
+
content: def.content,
|
|
111
|
+
filePath: def.filePath,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// 规程加载失败(清单声明非法、规程文件损坏等)输出告警并跳过磁盘部分,保持返回可用列表
|
|
117
|
+
console.warn(`[App] Failed to load playbooks for package '${packageId}' from '${dirPath}': ${err?.message || String(err)}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// 读取项目配置文件中的 playbooks
|
|
122
|
+
if (projectConfig && projectConfig.playbooks) {
|
|
123
|
+
const rawPlaybooks = projectConfig.playbooks;
|
|
124
|
+
if (typeof rawPlaybooks === "object" && rawPlaybooks !== null) {
|
|
125
|
+
for (const [id, item] of Object.entries(rawPlaybooks)) {
|
|
126
|
+
const existing = map.get(id);
|
|
127
|
+
let content = item.content ?? existing?.content ?? "";
|
|
128
|
+
let filePath = item.entry && packageRoot
|
|
129
|
+
? resolve(packageRoot, item.entry)
|
|
130
|
+
: existing?.filePath;
|
|
131
|
+
if (!content && filePath && existsSync(filePath)) {
|
|
132
|
+
try {
|
|
133
|
+
content = readFileSync(filePath, "utf-8");
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
// 读取失败(权限、IO 错误等)输出告警并保持空正文,不再无声吞没
|
|
137
|
+
console.warn(`[App] Failed to read playbook '${id}' content from '${filePath}' in package '${packageId}': ${err?.message || String(err)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
map.set(id, {
|
|
141
|
+
id,
|
|
142
|
+
packageId,
|
|
143
|
+
description: item.description ?? existing?.description,
|
|
144
|
+
actions: item.actions ?? existing?.actions,
|
|
145
|
+
content,
|
|
146
|
+
filePath,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
102
150
|
}
|
|
103
151
|
return map;
|
|
104
152
|
}
|
package/dist/package/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ActionDefinition, ExecutionEvent, ExecutionResult, JsonValue, Logger, ProcessAPI, RunRecord } from "@actiondock/sdk";
|
|
2
2
|
import type { ActionInvoker, CancelResult, ExecutionTicket, LocalActionResolver } from "../execution/types.js";
|
|
3
3
|
import type { InvocationContext, RunOptions } from "../invocation/types.js";
|
|
4
|
-
import type { ConfigItemDefinition, ProjectConfig
|
|
4
|
+
import type { ConfigItemDefinition, ProjectConfig } from "../project/types.js";
|
|
5
5
|
import type { EventSink } from "../runtime/events.js";
|
|
6
6
|
import type { RuntimePlatform, StorageFactory, StorageFactoryOptions } from "../platform/types.js";
|
|
7
7
|
import type { RuntimeStorage, StateEntry } from "../storage/types.js";
|
|
@@ -156,8 +156,8 @@ export interface StateOptions {
|
|
|
156
156
|
export interface PackageRuntimeOptions {
|
|
157
157
|
/** 项目根目录绝对物理路径 */
|
|
158
158
|
packageRoot?: string;
|
|
159
|
-
/** 项目配置文件 (actiondock.json)
|
|
160
|
-
projectConfig?: ProjectConfig
|
|
159
|
+
/** 项目配置文件 (actiondock.json) 对象 */
|
|
160
|
+
projectConfig?: ProjectConfig;
|
|
161
161
|
/** 数据持久化存储目录 */
|
|
162
162
|
dataDir?: string;
|
|
163
163
|
/** 自定义家目录绝对路径 */
|
|
@@ -241,8 +241,8 @@ export interface PackageRuntime {
|
|
|
241
241
|
readonly generationId?: string;
|
|
242
242
|
/** 包根目录绝对物理路径 */
|
|
243
243
|
readonly packageRoot?: string;
|
|
244
|
-
/** 项目配置对象(actiondock.json
|
|
245
|
-
readonly projectConfig: ProjectConfig
|
|
244
|
+
/** 项目配置对象(actiondock.json 解析结果) */
|
|
245
|
+
readonly projectConfig: ProjectConfig;
|
|
246
246
|
/** 是否采用纯内存运行模式 */
|
|
247
247
|
readonly inMemory?: boolean;
|
|
248
248
|
/**
|
package/dist/project/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export * from "./init.js";
|
|
|
3
3
|
export * from "./loader.js";
|
|
4
4
|
export * from "./lockfile.js";
|
|
5
5
|
export * from "./manifest.js";
|
|
6
|
-
export * from "./skill-dir.js";
|
|
7
6
|
export { SNAPSHOT_TRACKED_FILES, type TransactionFileRecord, type TransactionMetadata, type ProjectTransaction, isProjectLockHeld, acquireProjectLock, runFrozenInstall, hasPendingTransactions, beginTransaction, recoverPendingTransactions, } from "./transactions.js";
|
|
8
7
|
export * from "./types.js";
|
|
9
8
|
export * from "./types-generator.js";
|
package/dist/project/index.js
CHANGED
|
@@ -3,7 +3,6 @@ export * from "./init.js";
|
|
|
3
3
|
export * from "./loader.js";
|
|
4
4
|
export * from "./lockfile.js";
|
|
5
5
|
export * from "./manifest.js";
|
|
6
|
-
export * from "./skill-dir.js";
|
|
7
6
|
export { SNAPSHOT_TRACKED_FILES, isProjectLockHeld, acquireProjectLock, runFrozenInstall, hasPendingTransactions, beginTransaction, recoverPendingTransactions, } from "./transactions.js";
|
|
8
7
|
export * from "./types.js";
|
|
9
8
|
export * from "./types-generator.js";
|
package/dist/project/init.js
CHANGED
|
@@ -86,10 +86,10 @@ export function initProject(targetDir, options = {}) {
|
|
|
86
86
|
node: ">=24.12.0",
|
|
87
87
|
},
|
|
88
88
|
dependencies: {
|
|
89
|
-
"@actiondock/sdk": "^2.
|
|
89
|
+
"@actiondock/sdk": "^2.16.0",
|
|
90
90
|
},
|
|
91
91
|
devDependencies: {
|
|
92
|
-
"@actiondock/testing": "^2.
|
|
92
|
+
"@actiondock/testing": "^2.16.0",
|
|
93
93
|
"@types/node": "^22.13.0",
|
|
94
94
|
"tsx": "^4.19.0",
|
|
95
95
|
"typescript": "^5.7.0",
|
package/dist/project/loader.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ActionDefinition } from "@actiondock/sdk";
|
|
2
2
|
import { type ModuleLoader } from "../platform/module-loader.js";
|
|
3
|
-
import type { ActionDockManifest, PlaybookDefinition, PlaybookManifestEntry,
|
|
3
|
+
import type { ActionDockManifest, PlaybookDefinition, PlaybookManifestEntry, ProjectConfig } from "./types.js";
|
|
4
4
|
/**
|
|
5
5
|
* 从指定目录开始向上逐级递归查找包含 `actiondock.json` 的项目根目录。
|
|
6
6
|
*
|
|
@@ -16,8 +16,6 @@ export declare function findProjectRoot(cwd?: string): string | null;
|
|
|
16
16
|
* @throws {Error} 若文件不存在或 JSON 格式错误、缺失必要字段
|
|
17
17
|
*/
|
|
18
18
|
export declare function loadProjectConfig(projectRoot: string): ProjectConfig;
|
|
19
|
-
/** 在运行时装配边界补全未声明的磁盘规程;显式规程来源(包括空集合)始终优先。 */
|
|
20
|
-
export declare function completeRuntimeProjectConfig(projectRoot: string | undefined, config: RuntimeProjectConfig): RuntimeProjectConfig;
|
|
21
19
|
export declare const ALLOWED_INSTALLERS: Set<string>;
|
|
22
20
|
/**
|
|
23
21
|
* 探测宿主系统中可用的包管理工具。
|
|
@@ -73,4 +71,4 @@ export declare function parsePlaybookContent(content: string, filePath: string,
|
|
|
73
71
|
* @param customManifest 可选的显式清单对象(若未提供则从磁盘加载)
|
|
74
72
|
* @returns Map<PlaybookId, PlaybookDefinition> 映射
|
|
75
73
|
*/
|
|
76
|
-
export declare function loadPlaybooks(projectRoot: string, _playbooksDir?: string, customManifest?: ActionDockManifest |
|
|
74
|
+
export declare function loadPlaybooks(projectRoot: string, _playbooksDir?: string, customManifest?: ActionDockManifest | null): Map<string, PlaybookDefinition>;
|
package/dist/project/loader.js
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { NodeModuleLoader, unwrapDefaultExport } from "../platform/module-loader.js";
|
|
5
5
|
import { ActionDockError, ACTION_LOAD_FAILED, describeActionLoadFailure, INVALID_ACTION_ID, INVALID_JSON, INVALID_PACKAGE_ID, INVALID_PLAYBOOK_ID, MANIFEST_LOAD_FAILED, PLAYBOOK_NOT_FOUND, PROJECT_CONFIG_NOT_FOUND, } from "../errors.js";
|
|
6
|
-
import { loadManifest,
|
|
6
|
+
import { loadManifest, ACTION_ID_REGEX, PLAYBOOK_ID_REGEX } from "./manifest.js";
|
|
7
7
|
/**
|
|
8
8
|
* 从指定目录开始向上逐级递归查找包含 `actiondock.json` 的项目根目录。
|
|
9
9
|
*
|
|
@@ -68,7 +68,7 @@ export function loadProjectConfig(projectRoot) {
|
|
|
68
68
|
if (parsed.playbooksDir) {
|
|
69
69
|
assertWithinProjectRoot(projectRoot, parsed.playbooksDir, "playbooksDir");
|
|
70
70
|
}
|
|
71
|
-
return
|
|
71
|
+
return parsed;
|
|
72
72
|
}
|
|
73
73
|
catch (err) {
|
|
74
74
|
if (err instanceof ActionDockError) {
|
|
@@ -77,15 +77,6 @@ export function loadProjectConfig(projectRoot) {
|
|
|
77
77
|
throw new ActionDockError(INVALID_JSON, `Failed to parse actiondock.json: ${err.message}`);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
/** 在运行时装配边界补全未声明的磁盘规程;显式规程来源(包括空集合)始终优先。 */
|
|
81
|
-
export function completeRuntimeProjectConfig(projectRoot, config) {
|
|
82
|
-
if (!projectRoot || config.playbooks !== undefined)
|
|
83
|
-
return config;
|
|
84
|
-
const diskManifest = loadManifest(projectRoot);
|
|
85
|
-
return diskManifest?.playbooks === undefined
|
|
86
|
-
? config
|
|
87
|
-
: { ...config, playbooks: diskManifest.playbooks };
|
|
88
|
-
}
|
|
89
80
|
export const ALLOWED_INSTALLERS = new Set(["npm", "bun"]);
|
|
90
81
|
/**
|
|
91
82
|
* 异步探测包管理器可用性(通过执行 --version 并检查退出码)。
|
|
@@ -317,38 +308,43 @@ export function parsePlaybookContent(content, filePath, metadata) {
|
|
|
317
308
|
*/
|
|
318
309
|
export function loadPlaybooks(projectRoot, _playbooksDir = "playbooks", customManifest) {
|
|
319
310
|
const playbooks = new Map();
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
311
|
+
let manifest = null;
|
|
312
|
+
if (customManifest !== undefined) {
|
|
313
|
+
manifest = customManifest;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
try {
|
|
317
|
+
manifest = loadManifest(projectRoot);
|
|
327
318
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
319
|
+
catch (err) {
|
|
320
|
+
// 容错与可观测性取舍说明:
|
|
321
|
+
// - 工程无清单时 loadManifest 返回 null,按空规程集处理属正常场景;
|
|
322
|
+
// - 清单文件存在但内容损坏或解析失败时,记录可观测警告后安全降级,避免静默吞没异常。
|
|
323
|
+
const reason = err instanceof Error ? err.message : String(err ?? "Unknown error");
|
|
324
|
+
process.stderr.write(`[actiondock] Warning: Failed to load manifest in ${projectRoot}: ${reason}\n`);
|
|
325
|
+
return playbooks;
|
|
334
326
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
327
|
+
}
|
|
328
|
+
// 以 actiondock.json 为唯一事实源
|
|
329
|
+
if (manifest?.playbooks && Object.keys(manifest.playbooks).length > 0) {
|
|
330
|
+
for (const [playbookId, pbEntry] of Object.entries(manifest.playbooks)) {
|
|
331
|
+
if (!PLAYBOOK_ID_REGEX.test(playbookId)) {
|
|
332
|
+
throw new ActionDockError(INVALID_PLAYBOOK_ID, `Invalid playbook ID '${playbookId}' in actiondock.json. Playbook IDs must match ${PLAYBOOK_ID_REGEX}`);
|
|
338
333
|
}
|
|
339
|
-
|
|
340
|
-
assertPathWithinRoot(projectRoot,
|
|
341
|
-
if (!existsSync(
|
|
342
|
-
throw new ActionDockError(PLAYBOOK_NOT_FOUND, `Playbook file '${
|
|
334
|
+
const fullPath = resolve(projectRoot, pbEntry.entry);
|
|
335
|
+
assertPathWithinRoot(projectRoot, fullPath, `playbook entry '${pbEntry.entry}'`);
|
|
336
|
+
if (!existsSync(fullPath)) {
|
|
337
|
+
throw new ActionDockError(PLAYBOOK_NOT_FOUND, `Playbook file '${pbEntry.entry}' for '${playbookId}' not found in ${projectRoot}`);
|
|
343
338
|
}
|
|
344
|
-
content = readFileSync(
|
|
339
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
340
|
+
const def = parsePlaybookContent(content, fullPath, {
|
|
341
|
+
id: playbookId,
|
|
342
|
+
name: pbEntry?.name,
|
|
343
|
+
description: pbEntry.description,
|
|
344
|
+
actions: pbEntry.actions,
|
|
345
|
+
});
|
|
346
|
+
playbooks.set(playbookId, def);
|
|
345
347
|
}
|
|
346
|
-
playbooks.set(playbookId, parsePlaybookContent(content, filePath, {
|
|
347
|
-
id: playbookId,
|
|
348
|
-
name: entry.name,
|
|
349
|
-
description: entry.description,
|
|
350
|
-
actions: entry.actions,
|
|
351
|
-
}));
|
|
352
348
|
}
|
|
353
349
|
return playbooks;
|
|
354
350
|
}
|
|
@@ -2,8 +2,6 @@ import type { ActionDockManifest } from "./types.js";
|
|
|
2
2
|
export declare const MANIFEST_FILE_NAME = "actiondock.json";
|
|
3
3
|
export declare const ACTION_ID_REGEX: RegExp;
|
|
4
4
|
export declare const PLAYBOOK_ID_REGEX: RegExp;
|
|
5
|
-
/** 磁盘规程始终采用文件声明,不能把非契约 content 字段带入运行时内联来源。 */
|
|
6
|
-
export declare function normalizeFilePlaybookEntries(manifest: ActionDockManifest): ActionDockManifest;
|
|
7
5
|
/**
|
|
8
6
|
* 读取并解析项目的声明式清单文件(actiondock.json 为唯一事实源)。
|
|
9
7
|
* 若文件不存在则返回 null。
|
package/dist/project/manifest.js
CHANGED
|
@@ -5,22 +5,6 @@ import { ActionDockError, MANIFEST_CORRUPTED, MANIFEST_INVALID, MANIFEST_READ_FA
|
|
|
5
5
|
export const MANIFEST_FILE_NAME = "actiondock.json";
|
|
6
6
|
export const ACTION_ID_REGEX = /^[a-z0-9][a-z0-9._-]*$/;
|
|
7
7
|
export const PLAYBOOK_ID_REGEX = /^[a-z0-9][a-z0-9._-]*$/;
|
|
8
|
-
/** 磁盘规程始终采用文件声明,不能把非契约 content 字段带入运行时内联来源。 */
|
|
9
|
-
export function normalizeFilePlaybookEntries(manifest) {
|
|
10
|
-
if (!manifest.playbooks || typeof manifest.playbooks !== "object" || Array.isArray(manifest.playbooks)) {
|
|
11
|
-
return manifest;
|
|
12
|
-
}
|
|
13
|
-
let changed = false;
|
|
14
|
-
const playbooks = Object.fromEntries(Object.entries(manifest.playbooks).map(([id, entry]) => {
|
|
15
|
-
if (entry && typeof entry === "object" && "content" in entry) {
|
|
16
|
-
const { content: _inlineContent, ...fileEntry } = entry;
|
|
17
|
-
changed = true;
|
|
18
|
-
return [id, fileEntry];
|
|
19
|
-
}
|
|
20
|
-
return [id, entry];
|
|
21
|
-
}));
|
|
22
|
-
return changed ? { ...manifest, playbooks } : manifest;
|
|
23
|
-
}
|
|
24
8
|
/**
|
|
25
9
|
* 读取并解析项目的声明式清单文件(actiondock.json 为唯一事实源)。
|
|
26
10
|
* 若文件不存在则返回 null。
|
|
@@ -54,7 +38,7 @@ export function loadManifest(projectRoot) {
|
|
|
54
38
|
if (!parsed.id) {
|
|
55
39
|
parsed.id = basename(projectRoot);
|
|
56
40
|
}
|
|
57
|
-
return
|
|
41
|
+
return parsed;
|
|
58
42
|
}
|
|
59
43
|
/**
|
|
60
44
|
* 保存声明式清单文件至项目根目录(actiondock.json)。
|
package/dist/project/types.d.ts
CHANGED
|
@@ -53,25 +53,6 @@ export interface PlaybookManifestEntry {
|
|
|
53
53
|
/** 该 Playbook 所依赖/调用的 Action ID 列表 */
|
|
54
54
|
actions?: string[];
|
|
55
55
|
}
|
|
56
|
-
/**
|
|
57
|
-
* 内存运行时或测试中使用的内联 Playbook 声明项。
|
|
58
|
-
*/
|
|
59
|
-
export interface InlinePlaybookSourceEntry {
|
|
60
|
-
/** Playbook Markdown 正文内容(纯 Markdown 规程内容,含空字符串) */
|
|
61
|
-
content: string;
|
|
62
|
-
/** 可选的虚拟入口相对路径(如 "playbooks/calc-sop.md") */
|
|
63
|
-
entry?: string;
|
|
64
|
-
/** Playbook 展示名称,缺省回落文件名派生 */
|
|
65
|
-
name?: string;
|
|
66
|
-
/** Playbook 任务描述 */
|
|
67
|
-
description?: string;
|
|
68
|
-
/** 该 Playbook 所依赖/调用的 Action ID 列表 */
|
|
69
|
-
actions?: string[];
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Playbook 来源定义条目(支持磁盘清单声明项与内存内联正文声明项)。
|
|
73
|
-
*/
|
|
74
|
-
export type PlaybookSourceEntry = PlaybookManifestEntry | InlinePlaybookSourceEntry;
|
|
75
56
|
/**
|
|
76
57
|
* ActionDock 声明式元数据清单契约(actiondock.json 为唯一事实源)。
|
|
77
58
|
*/
|
|
@@ -94,8 +75,6 @@ export interface ActionDockManifest {
|
|
|
94
75
|
actions?: Record<string, ActionManifestEntry>;
|
|
95
76
|
/** 声明的 Playbooks 集合(唯一事实源) */
|
|
96
77
|
playbooks?: Record<string, PlaybookManifestEntry>;
|
|
97
|
-
/** 包级静态依赖引用,与 Action 的 uses 共用引用语义。 */
|
|
98
|
-
uses?: string[];
|
|
99
78
|
/** 跨包外部依赖映射(逻辑包 ID 到 npm 包名) */
|
|
100
79
|
dependencies?: Record<string, string>;
|
|
101
80
|
/** 框架导出与分发边界文件列表 */
|
|
@@ -112,20 +91,10 @@ export interface ActionDockManifest {
|
|
|
112
91
|
[key: string]: unknown;
|
|
113
92
|
};
|
|
114
93
|
}
|
|
115
|
-
/**
|
|
116
|
-
* 内存运行时或图模型中支持内联正文的规程来源清单契约。
|
|
117
|
-
*/
|
|
118
|
-
export type PlaybookSourceManifest = Omit<ActionDockManifest, "playbooks"> & {
|
|
119
|
-
playbooks?: Record<string, PlaybookSourceEntry>;
|
|
120
|
-
};
|
|
121
94
|
/**
|
|
122
95
|
* ActionDock 项目根配置文件契约(等同于 ActionDockManifest,actiondock.json 为单一事实源)。
|
|
123
96
|
*/
|
|
124
97
|
export type ProjectConfig = ActionDockManifest;
|
|
125
|
-
/**
|
|
126
|
-
* 内存运行时或图模型中支持内联正文的项目配置契约。
|
|
127
|
-
*/
|
|
128
|
-
export type RuntimeProjectConfig = PlaybookSourceManifest;
|
|
129
98
|
/**
|
|
130
99
|
* 解析后的完整 Playbook 定义对象。
|
|
131
100
|
*/
|
|
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync, readFileSync, renameSync, statSync } from "node:
|
|
|
2
2
|
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { findProjectRoot, loadProjectConfig } from "../project/loader.js";
|
|
5
|
-
import { inspectLocalPackageDirectory, isExplicitPath } from "../project/skill-dir.js";
|
|
6
5
|
import { getActionDockHome, getPackageSlug } from "../utils/index.js";
|
|
7
6
|
import { ActionDockError, MANIFEST_NOT_FOUND, REGISTRY_CORRUPTED } from "../errors.js";
|
|
8
7
|
import { withRegistryLock } from "./lock.js";
|
|
@@ -400,42 +399,31 @@ export function resolvePackageRoot(packageIdOrPath, cwd, customHome) {
|
|
|
400
399
|
const resolvedPath = resolve(baseDir, packageIdOrPath);
|
|
401
400
|
// 检查 packageIdOrPath 是否为磁盘上现存的目录或文件路径
|
|
402
401
|
if (existsSync(resolvedPath)) {
|
|
403
|
-
let info;
|
|
404
402
|
try {
|
|
405
|
-
info = statSync(resolvedPath);
|
|
406
|
-
}
|
|
407
|
-
catch (err) {
|
|
408
|
-
if (err?.code !== "ENOENT" && err?.code !== "ENOTDIR") {
|
|
409
|
-
throw err;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
if (info) {
|
|
403
|
+
const info = statSync(resolvedPath);
|
|
413
404
|
const targetDir = info.isDirectory() ? resolvedPath : dirname(resolvedPath);
|
|
414
|
-
// 普通开发包根目录:直接包含 actiondock.json 清单。
|
|
415
|
-
// 普通清单根目录定位与封闭 Skill 执行校验分离,不能被当成只含一个包的 Skill 闭包拒绝。
|
|
416
405
|
if (existsSync(join(targetDir, "actiondock.json"))) {
|
|
417
|
-
loadProjectConfig(targetDir);
|
|
418
406
|
return targetDir;
|
|
419
407
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
return localSkill.root;
|
|
424
|
-
}
|
|
425
|
-
// 具体文件查找所属工程根目录:仅当 packageIdOrPath 指向具体文件(非目录)时,
|
|
426
|
-
// 才尝试向上查找所属工程根目录;目录形态绝不向上回退,防止显式目录越界命中父级工程。
|
|
427
|
-
if (!info.isDirectory()) {
|
|
428
|
-
const parentRoot = findProjectRoot(targetDir);
|
|
429
|
-
if (parentRoot) {
|
|
430
|
-
loadProjectConfig(parentRoot);
|
|
431
|
-
return parentRoot;
|
|
432
|
-
}
|
|
408
|
+
const parentRoot = findProjectRoot(targetDir);
|
|
409
|
+
if (parentRoot) {
|
|
410
|
+
return parentRoot;
|
|
433
411
|
}
|
|
434
412
|
}
|
|
413
|
+
catch {
|
|
414
|
+
// stat 失败(如并发删除):忽略并继续走标识符解析路径
|
|
415
|
+
}
|
|
435
416
|
}
|
|
436
417
|
// 显式路径形态但未解析成功的场景:
|
|
437
418
|
// scoped package 标识符(如 @team/tools)虽含 '/' 但属于包 ID 而非文件路径
|
|
438
|
-
|
|
419
|
+
const isScopedPackage = packageIdOrPath.startsWith("@");
|
|
420
|
+
const isExplicitPath = !isScopedPackage &&
|
|
421
|
+
(packageIdOrPath.startsWith(".") ||
|
|
422
|
+
packageIdOrPath.startsWith("/") ||
|
|
423
|
+
packageIdOrPath.startsWith("~") ||
|
|
424
|
+
packageIdOrPath.includes("/") ||
|
|
425
|
+
packageIdOrPath.includes("\\"));
|
|
426
|
+
if (isExplicitPath) {
|
|
439
427
|
// 显式路径不存在或不是 ActionDock 项目时必须失败,禁止静默回退
|
|
440
428
|
return null;
|
|
441
429
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ActionContext, ActionRef, Config, Logger, ProcessAPI, ProgressReporter, StateStore } from "@actiondock/sdk";
|
|
2
|
-
import type { ProjectConfig
|
|
2
|
+
import type { ProjectConfig } from "../project/types.js";
|
|
3
3
|
import type { RuntimeStorage } from "../storage/types.js";
|
|
4
4
|
import { ProcessManager, type ProcessOwner } from "../process/index.js";
|
|
5
5
|
/**
|
|
@@ -17,7 +17,7 @@ export declare class RuntimeConfig implements Config {
|
|
|
17
17
|
private storage;
|
|
18
18
|
private projectConfig?;
|
|
19
19
|
private globalStorage?;
|
|
20
|
-
constructor(storage: RuntimeStorage, overrides?: Record<string, unknown>, projectConfig?: ProjectConfig
|
|
20
|
+
constructor(storage: RuntimeStorage, overrides?: Record<string, unknown>, projectConfig?: ProjectConfig, globalStorage?: RuntimeStorage);
|
|
21
21
|
get<T = unknown>(key: string): T | undefined;
|
|
22
22
|
get<T = unknown>(key: string, defaultValue: T): T;
|
|
23
23
|
has(key: string): boolean;
|
|
@@ -70,7 +70,7 @@ export interface ContextOptions {
|
|
|
70
70
|
storage: RuntimeStorage;
|
|
71
71
|
globalStorage?: RuntimeStorage;
|
|
72
72
|
overrides?: Record<string, unknown>;
|
|
73
|
-
projectConfig?: ProjectConfig
|
|
73
|
+
projectConfig?: ProjectConfig;
|
|
74
74
|
parentRunId?: string;
|
|
75
75
|
runId?: string;
|
|
76
76
|
rootRunId?: string;
|
|
@@ -29,7 +29,7 @@ export async function handleList(ctx, subArgs) {
|
|
|
29
29
|
const effectiveIntent = intent || (positionalPatterns.length > 0 ? positionalPatterns.join("|") : undefined);
|
|
30
30
|
const actions = await ctx.service.discovery.listActions();
|
|
31
31
|
const list = actions.map((a) => ({
|
|
32
|
-
id:
|
|
32
|
+
id: a.id,
|
|
33
33
|
description: a.description || "",
|
|
34
34
|
}));
|
|
35
35
|
const filterRes = filterWithFallbackInfo(list, effectiveIntent, [(a) => a.id, (a) => a.description], !noFallback);
|
|
@@ -66,7 +66,7 @@ export async function handleDescribe(ctx, subArgs) {
|
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
const payload = buildActionDescribePayload(action, {
|
|
69
|
-
packageId:
|
|
69
|
+
packageId: ctx.options.packageId,
|
|
70
70
|
});
|
|
71
71
|
if (isJson) {
|
|
72
72
|
ctx.writeOut(JSON.stringify(payload, null, 2));
|
|
@@ -274,9 +274,6 @@ function isServiceCapabilityError(err) {
|
|
|
274
274
|
code === "TARGET_CAPABILITY_UNAVAILABLE");
|
|
275
275
|
}
|
|
276
276
|
export async function handleConfig(ctx, subArgs) {
|
|
277
|
-
if (ctx.options.multiPackage) {
|
|
278
|
-
return ctx.emitError(subArgs.includes("--json"), "CAPABILITY_UNAVAILABLE", "Multi-package entries do not support config/state management; configure actions using --config and --data-dir.", ExitCode.INVALID_ARGUMENT);
|
|
279
|
-
}
|
|
280
277
|
const sub = subArgs[0] || "list";
|
|
281
278
|
if (!ctx.service.management) {
|
|
282
279
|
ctx.writeErr("Error: management port is not enabled on this service");
|
|
@@ -353,9 +350,6 @@ function decodeStateKeyArg(key) {
|
|
|
353
350
|
}
|
|
354
351
|
}
|
|
355
352
|
export async function handleState(ctx, subArgs) {
|
|
356
|
-
if (ctx.options.multiPackage) {
|
|
357
|
-
return ctx.emitError(subArgs.includes("--json"), "CAPABILITY_UNAVAILABLE", "Multi-package entries do not support config/state management; configure actions using --config and --data-dir.", ExitCode.INVALID_ARGUMENT);
|
|
358
|
-
}
|
|
359
353
|
const sub = subArgs[0] || "list";
|
|
360
354
|
let namespace;
|
|
361
355
|
let isAll = false;
|
package/dist/utils/semver.d.ts
CHANGED
|
@@ -6,11 +6,10 @@ export interface SemVer {
|
|
|
6
6
|
minor: number;
|
|
7
7
|
patch: number;
|
|
8
8
|
prerelease?: string;
|
|
9
|
-
build?: string;
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
11
|
* 解析基础 SemVer 版本字符串(单一事实源)。
|
|
13
|
-
* 仅接受可选 v/=
|
|
12
|
+
* 仅接受可选 v/= 前缀的严格三段式语义化版本,可携带预发布后缀;
|
|
14
13
|
* 其余形态(两段式、非数值等)返回 null,由调用方自行兜底。
|
|
15
14
|
*
|
|
16
15
|
* 本模块不依赖任何 Node 内建与 core 领域模块,可在无 loader 的原生
|
package/dist/utils/semver.js
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 解析基础 SemVer 版本字符串(单一事实源)。
|
|
3
|
-
* 仅接受可选 v/=
|
|
3
|
+
* 仅接受可选 v/= 前缀的严格三段式语义化版本,可携带预发布后缀;
|
|
4
4
|
* 其余形态(两段式、非数值等)返回 null,由调用方自行兜底。
|
|
5
5
|
*
|
|
6
6
|
* 本模块不依赖任何 Node 内建与 core 领域模块,可在无 loader 的原生
|
|
7
7
|
* Node 直接以 .ts 形态导入(工程脚本域复用此处单一事实源)。
|
|
8
8
|
*/
|
|
9
9
|
export function parseSemVer(v) {
|
|
10
|
-
const match = v.trim().replace(/^[v=]/, "").match(/^(
|
|
10
|
+
const match = v.trim().replace(/^[v=]/, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
|
|
11
11
|
if (!match)
|
|
12
12
|
return null;
|
|
13
|
-
const [major, minor, patch] = match.slice(1, 4).map(Number);
|
|
14
|
-
if (![major, minor, patch].every(Number.isSafeInteger))
|
|
15
|
-
return null;
|
|
16
|
-
if (match[4]?.split(".").some((id) => /^\d+$/.test(id) && id.length > 1 && id.startsWith("0")))
|
|
17
|
-
return null;
|
|
18
13
|
return {
|
|
19
|
-
major,
|
|
20
|
-
minor,
|
|
21
|
-
patch,
|
|
14
|
+
major: parseInt(match[1], 10),
|
|
15
|
+
minor: parseInt(match[2], 10),
|
|
16
|
+
patch: parseInt(match[3], 10),
|
|
22
17
|
prerelease: match[4],
|
|
23
|
-
...(match[5] === undefined ? {} : { build: match[5] }),
|
|
24
18
|
};
|
|
25
19
|
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actiondock/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.0",
|
|
4
4
|
"description": "ActionDock Core Engine - Project loader, runtime execution, SQLite storage, standalone builder, and skill exporter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"test": "node ../../scripts/run-tests.ts"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@actiondock/sdk": "^2.
|
|
62
|
+
"@actiondock/sdk": "^2.16.0",
|
|
63
63
|
"ajv": "^8.17.1",
|
|
64
64
|
"ajv-formats": "^3.0.1",
|
|
65
65
|
"undici": "^7.29.1"
|